From 2b7f87b5fa43336ed1237747f60fd9095a41ea3d Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Thu, 2 Jul 2020 12:11:57 +0800 Subject: [PATCH 0001/1052] Liballoc tweak use *const T instead of *const i8 *const T is also used in the same parts and also used for arith_offset. --- library/alloc/src/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 786d1b6ba82f2..2ff82a5dd3f03 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -2705,7 +2705,7 @@ impl Iterator for IntoIter { // purposefully don't use 'ptr.offset' because for // vectors with 0-size elements this would return the // same pointer. - self.ptr = arith_offset(self.ptr as *const i8, 1) as *mut T; + self.ptr = arith_offset(self.ptr as *const T, 1) as *mut T; // Make up a value of this ZST. Some(mem::zeroed()) From cc0d6345500932e8118ba65e98944a6a3bac3277 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Thu, 2 Jul 2020 12:13:17 +0800 Subject: [PATCH 0002/1052] Liballoc IntoIter limit unsafe to pointer arithmethic --- library/alloc/src/vec.rs | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 2ff82a5dd3f03..aefcbf5ad5ddd 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -2697,25 +2697,21 @@ impl Iterator for IntoIter { #[inline] fn next(&mut self) -> Option { - unsafe { - if self.ptr as *const _ == self.end { - None - } else { - if mem::size_of::() == 0 { - // purposefully don't use 'ptr.offset' because for - // vectors with 0-size elements this would return the - // same pointer. - self.ptr = arith_offset(self.ptr as *const T, 1) as *mut T; - - // Make up a value of this ZST. - Some(mem::zeroed()) - } else { - let old = self.ptr; - self.ptr = self.ptr.offset(1); + if self.ptr as *const _ == self.end { + None + } else if mem::size_of::() == 0 { + // purposefully don't use 'ptr.offset' because for + // vectors with 0-size elements this would return the + // same pointer. + self.ptr = unsafe { arith_offset(self.ptr as *const T, 1) as *mut T }; + + // Make up a value of this ZST. + Some(unsafe { mem::zeroed() }) + } else { + let old = self.ptr; + self.ptr = unsafe { self.ptr.offset(1) }; - Some(ptr::read(old)) - } - } + Some(unsafe { ptr::read(old) }) } } From 50315238aa8ffae08f29b260aa36511e03b5e070 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Sun, 5 Jul 2020 12:27:23 +0800 Subject: [PATCH 0003/1052] Liballoc DoubleEndedIterator limit unsafe to pointer arithmethic --- library/alloc/src/vec.rs | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index aefcbf5ad5ddd..559030e6c8a34 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -2703,7 +2703,7 @@ impl Iterator for IntoIter { // purposefully don't use 'ptr.offset' because for // vectors with 0-size elements this would return the // same pointer. - self.ptr = unsafe { arith_offset(self.ptr as *const T, 1) as *mut T }; + self.ptr = unsafe { arith_offset(self.ptr as *const i8, 1) as *mut T }; // Make up a value of this ZST. Some(unsafe { mem::zeroed() }) @@ -2735,22 +2735,18 @@ impl Iterator for IntoIter { impl DoubleEndedIterator for IntoIter { #[inline] fn next_back(&mut self) -> Option { - unsafe { - if self.end == self.ptr { - None - } else { - if mem::size_of::() == 0 { - // See above for why 'ptr.offset' isn't used - self.end = arith_offset(self.end as *const i8, -1) as *mut T; + if self.end == self.ptr { + None + } else if mem::size_of::() == 0 { + // See above for why 'ptr.offset' isn't used + self.end = unsafe { arith_offset(self.end as *const i8, -1) as *mut T }; - // Make up a value of this ZST. - Some(mem::zeroed()) - } else { - self.end = self.end.offset(-1); + // Make up a value of this ZST. + Some(unsafe { mem::zeroed() }) + } else { + self.end = unsafe { self.end.offset(-1) }; - Some(ptr::read(self.end)) - } - } + Some(unsafe { ptr::read(self.end) }) } } } From 73e27b3e18dcbbef3a36620c4a44306e2bbdcd13 Mon Sep 17 00:00:00 2001 From: Marcel Hellwig Date: Thu, 2 Jul 2020 09:16:04 +0200 Subject: [PATCH 0004/1052] deny(unsafe_op_in_unsafe_fn) in libstd/process.rs --- library/std/src/process.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 4ba1940fd0ece..9048d93cbbfcf 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -105,6 +105,7 @@ //! [`Read`]: ../io/trait.Read.html #![stable(feature = "process", since = "1.0.0")] +#![deny(unsafe_op_in_unsafe_fn)] use crate::io::prelude::*; @@ -311,7 +312,8 @@ impl Read for ChildStdout { #[inline] unsafe fn initializer(&self) -> Initializer { - Initializer::nop() + // SAFETY: Read is guaranteed to work on uninitialized memory + unsafe { Initializer::nop() } } } @@ -372,7 +374,8 @@ impl Read for ChildStderr { #[inline] unsafe fn initializer(&self) -> Initializer { - Initializer::nop() + // SAFETY: Read is guaranteed to work on uninitialized memory + unsafe { Initializer::nop() } } } From 00d537dcd03f9ff5ebdf8b86e039dbdb0a7f850c Mon Sep 17 00:00:00 2001 From: Marcel Hellwig Date: Thu, 2 Jul 2020 09:32:41 +0200 Subject: [PATCH 0005/1052] deny(unsafe_op_in_unsafe_fn) in libstd/path.rs --- library/std/src/path.rs | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index e3d529df7de16..92c0f61972c83 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -60,6 +60,7 @@ //! [`push`]: PathBuf::push #![stable(feature = "rust1", since = "1.0.0")] +#![deny(unsafe_op_in_unsafe_fn)] use crate::borrow::{Borrow, Cow}; use crate::cmp; @@ -293,7 +294,8 @@ fn os_str_as_u8_slice(s: &OsStr) -> &[u8] { unsafe { &*(s as *const OsStr as *const [u8]) } } unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr { - &*(s as *const [u8] as *const OsStr) + // SAFETY: see the comment of `os_str_as_u8_slice` + unsafe { &*(s as *const [u8] as *const OsStr) } } // Detect scheme on Redox @@ -313,24 +315,21 @@ fn has_physical_root(s: &[u8], prefix: Option>) -> bool { // basic workhorse for splitting stem and extension fn split_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) { - unsafe { - if os_str_as_u8_slice(file) == b".." { - return (Some(file), None); - } - - // The unsafety here stems from converting between &OsStr and &[u8] - // and back. This is safe to do because (1) we only look at ASCII - // contents of the encoding and (2) new &OsStr values are produced - // only from ASCII-bounded slices of existing &OsStr values. - - let mut iter = os_str_as_u8_slice(file).rsplitn(2, |b| *b == b'.'); - let after = iter.next(); - let before = iter.next(); - if before == Some(b"") { - (Some(file), None) - } else { - (before.map(|s| u8_slice_as_os_str(s)), after.map(|s| u8_slice_as_os_str(s))) - } + if os_str_as_u8_slice(file) == b".." { + return (Some(file), None); + } + + // The unsafety here stems from converting between &OsStr and &[u8] + // and back. This is safe to do because (1) we only look at ASCII + // contents of the encoding and (2) new &OsStr values are produced + // only from ASCII-bounded slices of existing &OsStr values. + let mut iter = os_str_as_u8_slice(file).rsplitn(2, |b| *b == b'.'); + let after = iter.next(); + let before = iter.next(); + if before == Some(b"") { + (Some(file), None) + } else { + unsafe { (before.map(|s| u8_slice_as_os_str(s)), after.map(|s| u8_slice_as_os_str(s))) } } } @@ -1701,7 +1700,7 @@ impl Path { // The following (private!) function allows construction of a path from a u8 // slice, which is only safe when it is known to follow the OsStr encoding. unsafe fn from_u8_slice(s: &[u8]) -> &Path { - Path::new(u8_slice_as_os_str(s)) + unsafe { Path::new(u8_slice_as_os_str(s)) } } // The following (private!) function reveals the byte encoding used for OsStr. fn as_u8_slice(&self) -> &[u8] { From 73ada2d40429488aaaacf37b608bababc137b910 Mon Sep 17 00:00:00 2001 From: Laurence Tratt Date: Wed, 12 Aug 2020 15:07:38 +0100 Subject: [PATCH 0006/1052] Explicitly document the size guarantees that Option makes. Triggered by a discussion on wg-unsafe-code-guidelines about which layouts of `Option` one can guarantee are optimised to a single pointer. --- library/core/src/option.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 3c7211fe040dc..745b0f1ae8d47 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -70,10 +70,18 @@ //! } //! ``` //! -//! This usage of [`Option`] to create safe nullable pointers is so -//! common that Rust does special optimizations to make the -//! representation of [`Option`]`<`[`Box`]`>` a single pointer. Optional pointers -//! in Rust are stored as efficiently as any other pointer type. +//! # Representation +//! +//! Rust guarantees to optimise the following inner types such that an [`Option`] which contains +//! them has the same size as a pointer: +//! +//! * `&T` +//! * `&mut T` +//! * `extern "C" fn` +//! * [`num::NonZero*`] +//! * [`ptr::NonNull`] +//! * `#[repr(transparent)]` struct around one of the types in this list. +//! * [`Box`] //! //! # Examples //! From f5118a525fcf9db4102d903650331039158eff11 Mon Sep 17 00:00:00 2001 From: Laurence Tratt Date: Wed, 12 Aug 2020 15:36:55 +0100 Subject: [PATCH 0007/1052] Clarify and add guarantee about `transmute`. --- library/core/src/option.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 745b0f1ae8d47..c1837f79840d5 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -72,16 +72,19 @@ //! //! # Representation //! -//! Rust guarantees to optimise the following inner types such that an [`Option`] which contains -//! them has the same size as a pointer: +//! Rust guarantees to optimize the following types `` such that an +//! [`Option`] has the same size as `T`: //! +//! * [`Box`] //! * `&T` //! * `&mut T` //! * `extern "C" fn` //! * [`num::NonZero*`] //! * [`ptr::NonNull`] //! * `#[repr(transparent)]` struct around one of the types in this list. -//! * [`Box`] +//! +//! For the above cases, it is guaranteed that one can use [`mem::transmute`] +//! between `T` and `Option` and vice versa. //! //! # Examples //! From 83f47aa11bd664ed8a15ef9833063833b7b3e71c Mon Sep 17 00:00:00 2001 From: Laurence Tratt Date: Wed, 12 Aug 2020 15:47:37 +0100 Subject: [PATCH 0008/1052] Be clear about the reverse `transmute` guarantees. --- library/core/src/option.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index c1837f79840d5..db7583b04190a 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -83,8 +83,9 @@ //! * [`ptr::NonNull`] //! * `#[repr(transparent)]` struct around one of the types in this list. //! -//! For the above cases, it is guaranteed that one can use [`mem::transmute`] -//! between `T` and `Option` and vice versa. +//! For the above cases, it is guaranteed that one can [`mem::transmute`] +//! from all valid values of `T` to `Option` but only from non-`None` +//! Option` to `T`. //! //! # Examples //! From f3d7196caec3f54e572c7389b1cef9fd9e62c1ed Mon Sep 17 00:00:00 2001 From: Laurence Tratt Date: Wed, 12 Aug 2020 15:53:58 +0100 Subject: [PATCH 0009/1052] Be clearer about Some/None transmute. --- library/core/src/option.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index db7583b04190a..a8337c171a5ba 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -84,8 +84,9 @@ //! * `#[repr(transparent)]` struct around one of the types in this list. //! //! For the above cases, it is guaranteed that one can [`mem::transmute`] -//! from all valid values of `T` to `Option` but only from non-`None` -//! Option` to `T`. +//! from all valid values of `T` to `Option` but only from +//! `Option::Some(T)` to `T` (i.e. transmuting `None` to `` is undefined +//! behaviour). //! //! # Examples //! From 8cb8955d570c76631840bfc98825ca49c0dd8eea Mon Sep 17 00:00:00 2001 From: Laurence Tratt Date: Wed, 12 Aug 2020 15:19:46 +0000 Subject: [PATCH 0010/1052] Change notation. Co-authored-by: Ralf Jung --- library/core/src/option.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index a8337c171a5ba..b8a501298c4f7 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -84,8 +84,8 @@ //! * `#[repr(transparent)]` struct around one of the types in this list. //! //! For the above cases, it is guaranteed that one can [`mem::transmute`] -//! from all valid values of `T` to `Option` but only from -//! `Option::Some(T)` to `T` (i.e. transmuting `None` to `` is undefined +//! from all valid values of `T` to `Option` and from +//! `Some::(_)` to `T` (but transmuting `None::` to `T` is undefined //! behaviour). //! //! # Examples From 55802e3bf3bf6d1db5c76aea581a7912bd752890 Mon Sep 17 00:00:00 2001 From: Laurence Tratt Date: Wed, 12 Aug 2020 15:38:18 +0000 Subject: [PATCH 0011/1052] Add Rust function pointers. Co-authored-by: Ralf Jung --- library/core/src/option.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index b8a501298c4f7..70b1abbc2a5dc 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -78,7 +78,7 @@ //! * [`Box`] //! * `&T` //! * `&mut T` -//! * `extern "C" fn` +//! * `fn`, `extern "C" fn` //! * [`num::NonZero*`] //! * [`ptr::NonNull`] //! * `#[repr(transparent)]` struct around one of the types in this list. From 68209c3fe4e0f5c3758f18e98efc175af31c2e51 Mon Sep 17 00:00:00 2001 From: Laurence Tratt Date: Mon, 17 Aug 2020 09:31:09 +0100 Subject: [PATCH 0012/1052] Rename the types for clarity. --- library/core/src/option.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 70b1abbc2a5dc..9789bce82dda1 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -72,15 +72,15 @@ //! //! # Representation //! -//! Rust guarantees to optimize the following types `` such that an +//! Rust guarantees to optimize the following types `T` such that //! [`Option`] has the same size as `T`: //! -//! * [`Box`] -//! * `&T` -//! * `&mut T` +//! * [`Box`] +//! * `&U` +//! * `&mut U` //! * `fn`, `extern "C" fn` //! * [`num::NonZero*`] -//! * [`ptr::NonNull`] +//! * [`ptr::NonNull`] //! * `#[repr(transparent)]` struct around one of the types in this list. //! //! For the above cases, it is guaranteed that one can [`mem::transmute`] From 9bac5774d7b452b2227c9fb77a4c6de3f432ee55 Mon Sep 17 00:00:00 2001 From: Laurence Tratt Date: Mon, 17 Aug 2020 09:34:15 +0100 Subject: [PATCH 0013/1052] Grammar tweak. --- library/core/src/option.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 9789bce82dda1..2f588e79bda4c 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -83,10 +83,10 @@ //! * [`ptr::NonNull`] //! * `#[repr(transparent)]` struct around one of the types in this list. //! -//! For the above cases, it is guaranteed that one can [`mem::transmute`] -//! from all valid values of `T` to `Option` and from -//! `Some::(_)` to `T` (but transmuting `None::` to `T` is undefined -//! behaviour). +//! It is further guaranteed that, for the cases above, one can +//! [`mem::transmute`] from all valid values of `T` to `Option` and +//! from `Some::(_)` to `T` (but transmuting `None::` to `T` +//! is undefined behaviour). //! //! # Examples //! From 2ecc2ac864739cff6aed2609021e2467dedb117a Mon Sep 17 00:00:00 2001 From: Tim Nielens Date: Fri, 21 Aug 2020 00:07:56 +0200 Subject: [PATCH 0014/1052] unit-arg - improve suggestion --- clippy_lints/src/types.rs | 88 +++++++++++--------- tests/ui/unit_arg.rs | 7 +- tests/ui/unit_arg.stderr | 111 ++++++++++++-------------- tests/ui/unit_arg_empty_blocks.stderr | 21 ++--- 4 files changed, 115 insertions(+), 112 deletions(-) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 7e9190bef5e78..3f5b3a5bcd5d7 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -11,8 +11,8 @@ use rustc_hir as hir; use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor}; use rustc_hir::{ BinOpKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericParamKind, HirId, ImplItem, - ImplItemKind, Item, ItemKind, Lifetime, Local, MatchSource, MutTy, Mutability, QPath, Stmt, StmtKind, TraitFn, - TraitItem, TraitItemKind, TyKind, UnOp, + ImplItemKind, Item, ItemKind, Lifetime, Local, MatchSource, MutTy, Mutability, Node, QPath, Stmt, StmtKind, + TraitFn, TraitItem, TraitItemKind, TyKind, UnOp, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; @@ -29,10 +29,10 @@ use rustc_typeck::hir_ty_to_ty; use crate::consts::{constant, Constant}; use crate::utils::paths; use crate::utils::{ - clip, comparisons, differing_macro_contexts, higher, in_constant, indent_of, int_bits, is_type_diagnostic_item, + clip, comparisons, differing_macro_contexts, higher, in_constant, int_bits, is_type_diagnostic_item, last_path_segment, match_def_path, match_path, method_chain_args, multispan_sugg, numeric_literal::NumericLiteral, - qpath_res, sext, snippet, snippet_block_with_applicability, snippet_opt, snippet_with_applicability, - snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, unsext, + qpath_res, sext, snippet, snippet_opt, snippet_with_applicability, snippet_with_macro_callsite, span_lint, + span_lint_and_help, span_lint_and_sugg, span_lint_and_then, unsext, }; declare_clippy_lint! { @@ -844,43 +844,54 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp Applicability::MaybeIncorrect, ); or = "or "; + applicability = Applicability::MaybeIncorrect; }); - let sugg = args_to_recover + + let arg_snippets: Vec = args_to_recover + .iter() + .filter_map(|arg| snippet_opt(cx, arg.span)) + .collect(); + let arg_snippets_without_empty_blocks: Vec = args_to_recover .iter() .filter(|arg| !is_empty_block(arg)) - .enumerate() - .map(|(i, arg)| { - let indent = if i == 0 { - 0 - } else { - indent_of(cx, expr.span).unwrap_or(0) - }; - format!( - "{}{};", - " ".repeat(indent), - snippet_block_with_applicability(cx, arg.span, "..", Some(expr.span), &mut applicability) - ) - }) - .collect::>(); - let mut and = ""; - if !sugg.is_empty() { - let plural = if sugg.len() > 1 { "s" } else { "" }; - db.span_suggestion( - expr.span.with_hi(expr.span.lo()), - &format!("{}move the expression{} in front of the call...", or, plural), - format!("{}\n", sugg.join("\n")), - applicability, - ); - and = "...and " + .filter_map(|arg| snippet_opt(cx, arg.span)) + .collect(); + + if let Some(mut sugg) = snippet_opt(cx, expr.span) { + arg_snippets.iter().for_each(|arg| { + sugg = sugg.replacen(arg, "()", 1); + }); + sugg = format!("{}{}{}", arg_snippets_without_empty_blocks.join("; "), "; ", sugg); + let parent_node = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(expr.hir_id)); + if !matches!(parent_node, Some(Node::Block(_))) && !matches!(parent_node, Some(Node::Stmt(_))) { + // expr is not in a block statement or result expression position, wrap in a block + sugg = format!("{{ {} }}", sugg); + } + + if arg_snippets_without_empty_blocks.is_empty() { + db.multipart_suggestion( + &format!("use {}unit literal{} instead", singular, plural), + args_to_recover + .iter() + .map(|arg| (arg.span, "()".to_string())) + .collect::>(), + applicability, + ); + } else { + let plural = arg_snippets_without_empty_blocks.len() > 1; + let empty_or_s = if plural { "s" } else { "" }; + let it_or_them = if plural { "them" } else { "it" }; + db.span_suggestion( + expr.span, + &format!( + "{}move the expression{} in front of the call and replace {} with the unit literal `()`", + or, empty_or_s, it_or_them + ), + sugg, + applicability, + ); + } } - db.multipart_suggestion( - &format!("{}use {}unit literal{} instead", and, singular, plural), - args_to_recover - .iter() - .map(|arg| (arg.span, "()".to_string())) - .collect::>(), - applicability, - ); }, ); } @@ -2055,6 +2066,7 @@ impl PartialOrd for FullInt { }) } } + impl Ord for FullInt { #[must_use] fn cmp(&self, other: &Self) -> Ordering { diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index 2992abae775b8..2e2bd054e42aa 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -1,5 +1,5 @@ #![warn(clippy::unit_arg)] -#![allow(clippy::no_effect, unused_must_use, unused_variables)] +#![allow(clippy::no_effect, unused_must_use, unused_variables, clippy::unused_unit)] use std::fmt::Debug; @@ -47,6 +47,11 @@ fn bad() { foo(3); }, ); + // here Some(foo(2)) isn't the top level statement expression, wrap the suggestion in a block + None.or(Some(foo(2))); + // in this case, the suggestion can be inlined, no need for a surrounding block + // foo(()); foo(()) instead of { foo(()); foo(()) } + foo(foo(())) } fn ok() { diff --git a/tests/ui/unit_arg.stderr b/tests/ui/unit_arg.stderr index 56f6a855dfa55..2a0cc1f18e27c 100644 --- a/tests/ui/unit_arg.stderr +++ b/tests/ui/unit_arg.stderr @@ -11,16 +11,12 @@ help: remove the semicolon from the last statement in the block | LL | 1 | -help: or move the expression in front of the call... +help: or move the expression in front of the call and replace it with the unit literal `()` | LL | { LL | 1; -LL | }; +LL | }; foo(()); | -help: ...and use a unit literal instead - | -LL | foo(()); - | ^^ error: passing a unit value to a function --> $DIR/unit_arg.rs:26:5 @@ -28,14 +24,10 @@ error: passing a unit value to a function LL | foo(foo(1)); | ^^^^^^^^^^^ | -help: move the expression in front of the call... - | -LL | foo(1); +help: move the expression in front of the call and replace it with the unit literal `()` | -help: ...and use a unit literal instead - | -LL | foo(()); - | ^^ +LL | foo(1); foo(()); + | ^^^^^^^^^^^^^^^ error: passing a unit value to a function --> $DIR/unit_arg.rs:27:5 @@ -50,17 +42,13 @@ help: remove the semicolon from the last statement in the block | LL | foo(2) | -help: or move the expression in front of the call... +help: or move the expression in front of the call and replace it with the unit literal `()` | LL | { LL | foo(1); LL | foo(2); -LL | }; - | -help: ...and use a unit literal instead +LL | }; foo(()); | -LL | foo(()); - | ^^ error: passing a unit value to a function --> $DIR/unit_arg.rs:32:5 @@ -74,16 +62,12 @@ help: remove the semicolon from the last statement in the block | LL | 1 | -help: or move the expression in front of the call... +help: or move the expression in front of the call and replace it with the unit literal `()` | LL | { LL | 1; -LL | }; +LL | }; b.bar(()); | -help: ...and use a unit literal instead - | -LL | b.bar(()); - | ^^ error: passing unit values to a function --> $DIR/unit_arg.rs:35:5 @@ -91,15 +75,10 @@ error: passing unit values to a function LL | taking_multiple_units(foo(0), foo(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: move the expressions in front of the call... - | -LL | foo(0); -LL | foo(1); - | -help: ...and use unit literals instead +help: move the expressions in front of the call and replace them with the unit literal `()` | -LL | taking_multiple_units((), ()); - | ^^ ^^ +LL | foo(0); foo(1); taking_multiple_units((), ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: passing unit values to a function --> $DIR/unit_arg.rs:36:5 @@ -114,18 +93,13 @@ help: remove the semicolon from the last statement in the block | LL | foo(2) | -help: or move the expressions in front of the call... +help: or move the expressions in front of the call and replace them with the unit literal `()` | -LL | foo(0); -LL | { +LL | foo(0); { LL | foo(1); LL | foo(2); -LL | }; - | -help: ...and use unit literals instead +LL | }; taking_multiple_units((), ()); | -LL | taking_multiple_units((), ()); - | ^^ ^^ error: passing unit values to a function --> $DIR/unit_arg.rs:40:5 @@ -147,35 +121,56 @@ help: remove the semicolon from the last statement in the block | LL | foo(3) | -help: or move the expressions in front of the call... +help: or move the expressions in front of the call and replace them with the unit literal `()` | LL | { -LL | foo(0); -LL | foo(1); -LL | }; -LL | { -LL | foo(2); +LL | foo(0); +LL | foo(1); +LL | }; { +LL | foo(2); +LL | foo(3); ... -help: ...and use unit literals instead + +error: use of `or` followed by a function call + --> $DIR/unit_arg.rs:51:10 | -LL | (), -LL | (), +LL | None.or(Some(foo(2))); + | ^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(foo(2)))` | + = note: `-D clippy::or-fun-call` implied by `-D warnings` error: passing a unit value to a function - --> $DIR/unit_arg.rs:82:5 + --> $DIR/unit_arg.rs:51:13 | -LL | Some(foo(1)) +LL | None.or(Some(foo(2))); + | ^^^^^^^^^^^^ + | +help: move the expression in front of the call and replace it with the unit literal `()` + | +LL | None.or({ foo(2); Some(()) }); + | ^^^^^^^^^^^^^^^^^^^^ + +error: passing a unit value to a function + --> $DIR/unit_arg.rs:54:5 + | +LL | foo(foo(())) | ^^^^^^^^^^^^ | -help: move the expression in front of the call... +help: move the expression in front of the call and replace it with the unit literal `()` + | +LL | foo(()); foo(()) + | + +error: passing a unit value to a function + --> $DIR/unit_arg.rs:87:5 + | +LL | Some(foo(1)) + | ^^^^^^^^^^^^ | -LL | foo(1); +help: move the expression in front of the call and replace it with the unit literal `()` | -help: ...and use a unit literal instead +LL | foo(1); Some(()) | -LL | Some(()) - | ^^ -error: aborting due to 8 previous errors +error: aborting due to 11 previous errors diff --git a/tests/ui/unit_arg_empty_blocks.stderr b/tests/ui/unit_arg_empty_blocks.stderr index bb58483584b3e..4cbbc8b8cd43e 100644 --- a/tests/ui/unit_arg_empty_blocks.stderr +++ b/tests/ui/unit_arg_empty_blocks.stderr @@ -22,14 +22,10 @@ error: passing unit values to a function LL | taking_two_units({}, foo(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: move the expression in front of the call... +help: move the expression in front of the call and replace it with the unit literal `()` | -LL | foo(0); - | -help: ...and use unit literals instead - | -LL | taking_two_units((), ()); - | ^^ ^^ +LL | foo(0); taking_two_units((), ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: passing unit values to a function --> $DIR/unit_arg_empty_blocks.rs:18:5 @@ -37,15 +33,10 @@ error: passing unit values to a function LL | taking_three_units({}, foo(0), foo(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: move the expressions in front of the call... - | -LL | foo(0); -LL | foo(1); - | -help: ...and use unit literals instead +help: move the expressions in front of the call and replace them with the unit literal `()` | -LL | taking_three_units((), (), ()); - | ^^ ^^ ^^ +LL | foo(0); foo(1); taking_three_units((), (), ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors From c5975e9b6c5781b3b7300b7921c14b060086e1c1 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Tue, 4 Aug 2020 16:10:11 +0800 Subject: [PATCH 0015/1052] Reduce duplicate in liballoc reserve error handling --- library/alloc/src/raw_vec.rs | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 99ac027bf0b9f..59e8bb087217d 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -303,11 +303,7 @@ impl RawVec { /// # } /// ``` pub fn reserve(&mut self, len: usize, additional: usize) { - match self.try_reserve(len, additional) { - Err(CapacityOverflow) => capacity_overflow(), - Err(AllocError { layout, .. }) => handle_alloc_error(layout), - Ok(()) => { /* yay */ } - } + handle_reserve(self.try_reserve(len, additional)); } /// The same as `reserve`, but returns on errors instead of panicking or aborting. @@ -337,11 +333,7 @@ impl RawVec { /// /// Aborts on OOM. pub fn reserve_exact(&mut self, len: usize, additional: usize) { - match self.try_reserve_exact(len, additional) { - Err(CapacityOverflow) => capacity_overflow(), - Err(AllocError { layout, .. }) => handle_alloc_error(layout), - Ok(()) => { /* yay */ } - } + handle_reserve(self.try_reserve_exact(len, additional)); } /// The same as `reserve_exact`, but returns on errors instead of panicking or aborting. @@ -364,11 +356,7 @@ impl RawVec { /// /// Aborts on OOM. pub fn shrink_to_fit(&mut self, amount: usize) { - match self.shrink(amount) { - Err(CapacityOverflow) => capacity_overflow(), - Err(AllocError { layout, .. }) => handle_alloc_error(layout), - Ok(()) => { /* yay */ } - } + handle_reserve(self.shrink(amount)); } } @@ -510,6 +498,16 @@ unsafe impl<#[may_dangle] T, A: AllocRef> Drop for RawVec { } } +// Central function for reserve error handling. +#[inline] +fn handle_reserve(result: Result<(), TryReserveError>) { + match result { + Err(CapacityOverflow) => capacity_overflow(), + Err(AllocError { layout, .. }) => handle_alloc_error(layout), + Ok(()) => { /* yay */ } + } +} + // We need to guarantee the following: // * We don't ever allocate `> isize::MAX` byte-size objects. // * We don't overflow `usize::MAX` and actually allocate too little. From a7468705cbf0fb551b8b1d8b420123262f7d92b2 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Mon, 24 Aug 2020 22:47:15 +0800 Subject: [PATCH 0016/1052] Use translated variable for test string Test should be educative, added english translation and pronounciation. --- library/alloc/tests/string.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs index d38655af78cb7..761561d9aaa4e 100644 --- a/library/alloc/tests/string.rs +++ b/library/alloc/tests/string.rs @@ -271,8 +271,8 @@ fn test_split_off_past_end() { #[test] #[should_panic] fn test_split_off_mid_char() { - let mut orig = String::from("山"); - let _ = orig.split_off(1); + let mut shan = String::from("山"); + let _broken_mountain = shan.split_off(1); } #[test] From 688f4471fd553c83ae3ff0306956d89b7d7c2d28 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Tue, 14 Jul 2020 15:53:40 +0200 Subject: [PATCH 0017/1052] Stabilize future readiness fns --- library/core/src/future/mod.rs | 4 ++-- library/core/src/future/pending.rs | 20 +++++++++++++------- library/core/src/future/ready.rs | 13 ++++++++----- library/core/src/task/ready.rs | 2 -- library/std/src/future.rs | 2 +- library/std/src/lib.rs | 1 - 6 files changed, 24 insertions(+), 18 deletions(-) diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs index 6d1ad9db74435..a69c4a0a6e91a 100644 --- a/library/core/src/future/mod.rs +++ b/library/core/src/future/mod.rs @@ -21,9 +21,9 @@ pub use self::future::Future; #[unstable(feature = "into_future", issue = "67644")] pub use into_future::IntoFuture; -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.47.0")] pub use pending::{pending, Pending}; -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.47.0")] pub use ready::{ready, Ready}; #[unstable(feature = "future_poll_fn", issue = "72302")] diff --git a/library/core/src/future/pending.rs b/library/core/src/future/pending.rs index 74887b68aa0fa..c1a4e0cda0320 100644 --- a/library/core/src/future/pending.rs +++ b/library/core/src/future/pending.rs @@ -1,3 +1,4 @@ +use crate::fmt::{self, Debug}; use crate::future::Future; use crate::marker; use crate::pin::Pin; @@ -10,8 +11,7 @@ use crate::task::{Context, Poll}; /// documentation for more. /// /// [`pending`]: fn.pending.html -#[unstable(feature = "future_readiness_fns", issue = "70921")] -#[derive(Debug)] +#[stable(feature = "future_readiness_fns", since = "1.47.0")] #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct Pending { _data: marker::PhantomData, @@ -23,7 +23,6 @@ pub struct Pending { /// # Examples /// /// ```no_run -/// #![feature(future_readiness_fns)] /// use core::future; /// /// # async fn run() { @@ -32,12 +31,12 @@ pub struct Pending { /// unreachable!(); /// # } /// ``` -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.47.0")] pub fn pending() -> Pending { Pending { _data: marker::PhantomData } } -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.47.0")] impl Future for Pending { type Output = T; @@ -46,10 +45,17 @@ impl Future for Pending { } } -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.47.0")] impl Unpin for Pending {} -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.47.0")] +impl Debug for Pending { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Pending").finish() + } +} + +#[stable(feature = "future_readiness_fns", since = "1.47.0")] impl Clone for Pending { fn clone(&self) -> Self { pending() diff --git a/library/core/src/future/ready.rs b/library/core/src/future/ready.rs index 31b39d7fb6cd5..ddae6cfed4bdb 100644 --- a/library/core/src/future/ready.rs +++ b/library/core/src/future/ready.rs @@ -8,15 +8,15 @@ use crate::task::{Context, Poll}; /// documentation for more. /// /// [`ready`]: fn.ready.html -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.47.0")] #[derive(Debug, Clone)] #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct Ready(Option); -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.47.0")] impl Unpin for Ready {} -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.47.0")] impl Future for Ready { type Output = T; @@ -28,10 +28,13 @@ impl Future for Ready { /// Creates a future that is immediately ready with a value. /// +/// Futures created through this function are functionally similar to those +/// created through `async {}`. The main difference is that futures created +/// through this function are named and implement `Unpin`. +/// /// # Examples /// /// ``` -/// #![feature(future_readiness_fns)] /// use core::future; /// /// # async fn run() { @@ -39,7 +42,7 @@ impl Future for Ready { /// assert_eq!(a.await, 1); /// # } /// ``` -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.47.0")] pub fn ready(t: T) -> Ready { Ready(Some(t)) } diff --git a/library/core/src/task/ready.rs b/library/core/src/task/ready.rs index d4e733eb2bcf5..e221aaf3fd6d6 100644 --- a/library/core/src/task/ready.rs +++ b/library/core/src/task/ready.rs @@ -5,7 +5,6 @@ /// # Examples /// /// ``` -/// #![feature(future_readiness_fns)] /// #![feature(ready_macro)] /// /// use core::task::{ready, Context, Poll}; @@ -27,7 +26,6 @@ /// The `ready!` call expands to: /// /// ``` -/// # #![feature(future_readiness_fns)] /// # #![feature(ready_macro)] /// # /// # use core::task::{Context, Poll}; diff --git a/library/std/src/future.rs b/library/std/src/future.rs index 89dd9fb9b2cd5..5ff74e557547c 100644 --- a/library/std/src/future.rs +++ b/library/std/src/future.rs @@ -9,7 +9,7 @@ pub use core::future::Future; pub use core::future::{from_generator, get_context, ResumeTy}; #[doc(inline)] -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.47.0")] pub use core::future::{pending, ready, Pending, Ready}; #[doc(inline)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index f0487e0dff148..c820df5d7cc77 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -268,7 +268,6 @@ #![feature(external_doc)] #![feature(fn_traits)] #![feature(format_args_nl)] -#![feature(future_readiness_fns)] #![feature(gen_future)] #![feature(generator_trait)] #![feature(global_asm)] From baf62e7a38854ff6a0039ddccb124ff329a32143 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Thu, 27 Aug 2020 14:39:09 +0200 Subject: [PATCH 0018/1052] Update changelog to beta 1.47 --- CHANGELOG.md | 108 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 105 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 137b561028a65..34d4882102351 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,113 @@ document. ## Unreleased / In Rust Nightly -[c2c07fa...master](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...master) +[09bd400...master](https://github.com/rust-lang/rust-clippy/compare/09bd400...master) + +## Rust 1.47 + +Current beta, release 2020-10-08 + +[c2c07fa...09bd400](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...09bd400) + +### New lints + +* [`derive_ord_xor_partial_ord`] [#5848](https://github.com/rust-lang/rust-clippy/pull/5848) +* [`trait_duplication_in_bounds`] [#5852](https://github.com/rust-lang/rust-clippy/pull/5852) +* [`map_identity`] [#5694](https://github.com/rust-lang/rust-clippy/pull/5694) +* [`unit_return_expecting_ord`] [#5737](https://github.com/rust-lang/rust-clippy/pull/5737) +* [`pattern_type_mismatch`] [#4841](https://github.com/rust-lang/rust-clippy/pull/4841) +* [`repeat_once`] [#5773](https://github.com/rust-lang/rust-clippy/pull/5773) +* [`same_item_push`] [#5825](https://github.com/rust-lang/rust-clippy/pull/5825) +* [`needless_arbitrary_self_type`] [#5869](https://github.com/rust-lang/rust-clippy/pull/5869) +* [`match_like_matches_macro`] [#5769](https://github.com/rust-lang/rust-clippy/pull/5769) +* [`stable_sort_primitive`] [#5809](https://github.com/rust-lang/rust-clippy/pull/5809) +* [`blanket_clippy_restriction_lints`] [#5750](https://github.com/rust-lang/rust-clippy/pull/5750) +* [`option_if_let_else`] [#5301](https://github.com/rust-lang/rust-clippy/pull/5301) + +### Moves and Deprecations + +* Deprecate [`regex_macro`] lint + [#5760](https://github.com/rust-lang/rust-clippy/pull/5760) +* Move [`range_minus_one`] to `pedantic` + [#5752](https://github.com/rust-lang/rust-clippy/pull/5752) + +### Enhancements + +* Improve [`needless_collect`] by catching `collect` calls followed by `iter` or `into_iter` calls + [#5837](https://github.com/rust-lang/rust-clippy/pull/5837) +* [`panic`], [`todo`], [`unimplemented`] and [`unreachable`] now detect calls with formatting + [#5811](https://github.com/rust-lang/rust-clippy/pull/5811) +* Detect more cases of [`suboptimal_flops`] and [`imprecise_flops`] + [#5443](https://github.com/rust-lang/rust-clippy/pull/5443) +* Handle asymmetrical implementations of `PartialEq` in [`cmp_owned`] + [#5701](https://github.com/rust-lang/rust-clippy/pull/5701) +* Make it possible to allow [`unsafe_derive_deserialize`] + [#5870](https://github.com/rust-lang/rust-clippy/pull/5870) +* Catch `ord.min(a).max(b)` where a < b in [`min_max`] + [#5871](https://github.com/rust-lang/rust-clippy/pull/5871) +* Make [`clone_on_copy`] suggestion machine applicable + [#5745](https://github.com/rust-lang/rust-clippy/pull/5745) +* Enable [`len_zero`] on ranges now that `is_empty` is stable on them + [#5961](https://github.com/rust-lang/rust-clippy/pull/5961) + +### False Positive Fixes + +* Avoid triggering [`or_fun_call`] with const fns that take no arguments + [#5889](https://github.com/rust-lang/rust-clippy/pull/5889) +* Fix [`redundant_closure_call`] false positive for closures that have multiple calls + [#5800](https://github.com/rust-lang/rust-clippy/pull/5800) +* Don't lint cases involving `ManuallyDrop` in [`redundant_clone`] + [#5824](https://github.com/rust-lang/rust-clippy/pull/5824) +* Treat a single expression the same as a single statement in the 2nd arm of a match in [`single_match_else`] + [#5771](https://github.com/rust-lang/rust-clippy/pull/5771) +* Don't trigger [`unnested_or_patterns`] if the feature `or_patterns` is not enabled + [#5758](https://github.com/rust-lang/rust-clippy/pull/5758) +* Avoid linting if key borrows in [`unnecessary_sort_by`] + [#5756](https://github.com/rust-lang/rust-clippy/pull/5756) +* Consider `Try` impl for `Poll` when generating suggestions in [`try_err`] + [#5857](https://github.com/rust-lang/rust-clippy/pull/5857) +* Take input lifetimes into account in `manual_async_fn` + [#5859](https://github.com/rust-lang/rust-clippy/pull/5859) +* Fix multiple false positives in [`type_repetition_in_bounds`] and add a configuration option + [#5761](https://github.com/rust-lang/rust-clippy/pull/5761) +* Limit the [`suspicious_arithmetic_impl`] lint to one binary operation + [#5820](https://github.com/rust-lang/rust-clippy/pull/5820) + +### Suggestion Fixes/Improvements + +* Improve readability of [`shadow_unrelated`] suggestion by truncating the RHS snippet + [#5788](https://github.com/rust-lang/rust-clippy/pull/5788) +* Suggest `filter_map` instead of `flat_map` when mapping to `Option` in [`map_flatten`] + [#5846](https://github.com/rust-lang/rust-clippy/pull/5846) +* Ensure suggestion is shown correctly for long method call chains in [`iter_nth_zero`] + [#5793](https://github.com/rust-lang/rust-clippy/pull/5793) +* Drop borrow operator in suggestions of [`redundant_pattern_matching`] + [#5815](https://github.com/rust-lang/rust-clippy/pull/5815) +* Add suggestion for [`iter_skip_next`] + [#5843](https://github.com/rust-lang/rust-clippy/pull/5843) +* Improve [`collapsible_if`] fix suggestion + [#5732](https://github.com/rust-lang/rust-clippy/pull/5732) + +### ICE Fixes + +* Fix ICE caused by [`needless_collect`] + [#5877](https://github.com/rust-lang/rust-clippy/pull/5877) +* Fix ICE caused by [`unnested_or_patterns`] + [#5784](https://github.com/rust-lang/rust-clippy/pull/5784) + +### Documentation Improvements + +* Fix grammar of [`await_holding_lock`] documentation + [#5748](https://github.com/rust-lang/rust-clippy/pull/5748) + +### Others + +* Make lints adhere to the rustc dev guide + [#5888](https://github.com/rust-lang/rust-clippy/pull/5888) ## Rust 1.46 -Current beta, release 2020-08-27 +Current stable, released 2020-08-27 [7ea7cd1...c2c07fa](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...c2c07fa) @@ -72,7 +174,7 @@ Current beta, release 2020-08-27 ## Rust 1.45 -Current stable, released 2020-07-16 +Released 2020-07-16 [891e1a8...7ea7cd1](https://github.com/rust-lang/rust-clippy/compare/891e1a8...7ea7cd1) From f3ccbef2af24d5d83f82f1fb50bd97a9b75e609f Mon Sep 17 00:00:00 2001 From: Tim Nielens Date: Thu, 27 Aug 2020 01:40:02 +0200 Subject: [PATCH 0019/1052] unit-arg - pr comments --- clippy_lints/src/types.rs | 41 ++++++++++---- clippy_lints/src/utils/mod.rs | 2 +- tests/ui/unit_arg.rs | 8 ++- tests/ui/unit_arg.stderr | 79 ++++++++++++++------------- tests/ui/unit_arg_empty_blocks.stderr | 11 ++-- 5 files changed, 88 insertions(+), 53 deletions(-) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 3f5b3a5bcd5d7..16e48d919164f 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -29,10 +29,10 @@ use rustc_typeck::hir_ty_to_ty; use crate::consts::{constant, Constant}; use crate::utils::paths; use crate::utils::{ - clip, comparisons, differing_macro_contexts, higher, in_constant, int_bits, is_type_diagnostic_item, + clip, comparisons, differing_macro_contexts, higher, in_constant, indent_of, int_bits, is_type_diagnostic_item, last_path_segment, match_def_path, match_path, method_chain_args, multispan_sugg, numeric_literal::NumericLiteral, qpath_res, sext, snippet, snippet_opt, snippet_with_applicability, snippet_with_macro_callsite, span_lint, - span_lint_and_help, span_lint_and_sugg, span_lint_and_then, unsext, + span_lint_and_help, span_lint_and_sugg, span_lint_and_then, trim_multiline, unsext, }; declare_clippy_lint! { @@ -802,6 +802,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitArg { } } +#[allow(clippy::too_many_lines)] fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Expr<'_>]) { let mut applicability = Applicability::MachineApplicable; let (singular, plural) = if args_to_recover.len() > 1 { @@ -856,18 +857,38 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp .filter(|arg| !is_empty_block(arg)) .filter_map(|arg| snippet_opt(cx, arg.span)) .collect(); + let indent = indent_of(cx, expr.span).unwrap_or(0); - if let Some(mut sugg) = snippet_opt(cx, expr.span) { - arg_snippets.iter().for_each(|arg| { - sugg = sugg.replacen(arg, "()", 1); - }); - sugg = format!("{}{}{}", arg_snippets_without_empty_blocks.join("; "), "; ", sugg); + if let Some(expr_str) = snippet_opt(cx, expr.span) { + let expr_with_replacements = arg_snippets + .iter() + .fold(expr_str, |acc, arg| acc.replacen(arg, "()", 1)); + + // expr is not in a block statement or result expression position, wrap in a block let parent_node = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(expr.hir_id)); - if !matches!(parent_node, Some(Node::Block(_))) && !matches!(parent_node, Some(Node::Stmt(_))) { - // expr is not in a block statement or result expression position, wrap in a block - sugg = format!("{{ {} }}", sugg); + let wrap_in_block = + !matches!(parent_node, Some(Node::Block(_))) && !matches!(parent_node, Some(Node::Stmt(_))); + + let stmts_indent = if wrap_in_block { indent + 4 } else { indent }; + let mut stmts_and_call = arg_snippets_without_empty_blocks.clone(); + stmts_and_call.push(expr_with_replacements); + let mut stmts_and_call_str = stmts_and_call + .into_iter() + .enumerate() + .map(|(i, v)| { + let with_indent_prefix = if i > 0 { " ".repeat(stmts_indent) + &v } else { v }; + trim_multiline(with_indent_prefix.into(), true, Some(stmts_indent)).into_owned() + }) + .collect::>() + .join(";\n"); + + if wrap_in_block { + stmts_and_call_str = " ".repeat(stmts_indent) + &stmts_and_call_str; + stmts_and_call_str = format!("{{\n{}\n{}}}", &stmts_and_call_str, " ".repeat(indent)); } + let sugg = stmts_and_call_str; + if arg_snippets_without_empty_blocks.is_empty() { db.multipart_suggestion( &format!("use {}unit literal{} instead", singular, plural), diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 2aef995cec44b..d20b33c4a1d10 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -662,7 +662,7 @@ pub fn expr_block<'a, T: LintContext>( /// Trim indentation from a multiline string with possibility of ignoring the /// first line. -fn trim_multiline(s: Cow<'_, str>, ignore_first: bool, indent: Option) -> Cow<'_, str> { +pub fn trim_multiline(s: Cow<'_, str>, ignore_first: bool, indent: Option) -> Cow<'_, str> { let s_space = trim_multiline_inner(s, ignore_first, indent, ' '); let s_tab = trim_multiline_inner(s_space, ignore_first, indent, '\t'); trim_multiline_inner(s_tab, ignore_first, indent, ' ') diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index 2e2bd054e42aa..fec115ff29d66 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -1,5 +1,11 @@ #![warn(clippy::unit_arg)] -#![allow(clippy::no_effect, unused_must_use, unused_variables, clippy::unused_unit)] +#![allow( + clippy::no_effect, + unused_must_use, + unused_variables, + clippy::unused_unit, + clippy::or_fun_call +)] use std::fmt::Debug; diff --git a/tests/ui/unit_arg.stderr b/tests/ui/unit_arg.stderr index 2a0cc1f18e27c..90fee3aab23b0 100644 --- a/tests/ui/unit_arg.stderr +++ b/tests/ui/unit_arg.stderr @@ -1,5 +1,5 @@ error: passing a unit value to a function - --> $DIR/unit_arg.rs:23:5 + --> $DIR/unit_arg.rs:29:5 | LL | / foo({ LL | | 1; @@ -15,22 +15,24 @@ help: or move the expression in front of the call and replace it with the unit l | LL | { LL | 1; -LL | }; foo(()); +LL | }; +LL | foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:26:5 + --> $DIR/unit_arg.rs:32:5 | LL | foo(foo(1)); | ^^^^^^^^^^^ | help: move the expression in front of the call and replace it with the unit literal `()` | -LL | foo(1); foo(()); - | ^^^^^^^^^^^^^^^ +LL | foo(1); +LL | foo(()); + | error: passing a unit value to a function - --> $DIR/unit_arg.rs:27:5 + --> $DIR/unit_arg.rs:33:5 | LL | / foo({ LL | | foo(1); @@ -47,11 +49,12 @@ help: or move the expression in front of the call and replace it with the unit l LL | { LL | foo(1); LL | foo(2); -LL | }; foo(()); +LL | }; +LL | foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:32:5 + --> $DIR/unit_arg.rs:38:5 | LL | / b.bar({ LL | | 1; @@ -66,22 +69,25 @@ help: or move the expression in front of the call and replace it with the unit l | LL | { LL | 1; -LL | }; b.bar(()); +LL | }; +LL | b.bar(()); | error: passing unit values to a function - --> $DIR/unit_arg.rs:35:5 + --> $DIR/unit_arg.rs:41:5 | LL | taking_multiple_units(foo(0), foo(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: move the expressions in front of the call and replace them with the unit literal `()` | -LL | foo(0); foo(1); taking_multiple_units((), ()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | foo(0); +LL | foo(1); +LL | taking_multiple_units((), ()); + | error: passing unit values to a function - --> $DIR/unit_arg.rs:36:5 + --> $DIR/unit_arg.rs:42:5 | LL | / taking_multiple_units(foo(0), { LL | | foo(1); @@ -95,14 +101,16 @@ LL | foo(2) | help: or move the expressions in front of the call and replace them with the unit literal `()` | -LL | foo(0); { +LL | foo(0); +LL | { LL | foo(1); LL | foo(2); -LL | }; taking_multiple_units((), ()); +LL | }; +LL | taking_multiple_units((), ()); | error: passing unit values to a function - --> $DIR/unit_arg.rs:40:5 + --> $DIR/unit_arg.rs:46:5 | LL | / taking_multiple_units( LL | | { @@ -124,53 +132,50 @@ LL | foo(3) help: or move the expressions in front of the call and replace them with the unit literal `()` | LL | { -LL | foo(0); -LL | foo(1); -LL | }; { -LL | foo(2); -LL | foo(3); +LL | foo(0); +LL | foo(1); +LL | }; +LL | { +LL | foo(2); ... -error: use of `or` followed by a function call - --> $DIR/unit_arg.rs:51:10 - | -LL | None.or(Some(foo(2))); - | ^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(foo(2)))` - | - = note: `-D clippy::or-fun-call` implied by `-D warnings` - error: passing a unit value to a function - --> $DIR/unit_arg.rs:51:13 + --> $DIR/unit_arg.rs:57:13 | LL | None.or(Some(foo(2))); | ^^^^^^^^^^^^ | help: move the expression in front of the call and replace it with the unit literal `()` | -LL | None.or({ foo(2); Some(()) }); - | ^^^^^^^^^^^^^^^^^^^^ +LL | None.or({ +LL | foo(2); +LL | Some(()) +LL | }); + | error: passing a unit value to a function - --> $DIR/unit_arg.rs:54:5 + --> $DIR/unit_arg.rs:60:5 | LL | foo(foo(())) | ^^^^^^^^^^^^ | help: move the expression in front of the call and replace it with the unit literal `()` | -LL | foo(()); foo(()) +LL | foo(()); +LL | foo(()) | error: passing a unit value to a function - --> $DIR/unit_arg.rs:87:5 + --> $DIR/unit_arg.rs:93:5 | LL | Some(foo(1)) | ^^^^^^^^^^^^ | help: move the expression in front of the call and replace it with the unit literal `()` | -LL | foo(1); Some(()) +LL | foo(1); +LL | Some(()) | -error: aborting due to 11 previous errors +error: aborting due to 10 previous errors diff --git a/tests/ui/unit_arg_empty_blocks.stderr b/tests/ui/unit_arg_empty_blocks.stderr index 4cbbc8b8cd43e..456b12a2c6b16 100644 --- a/tests/ui/unit_arg_empty_blocks.stderr +++ b/tests/ui/unit_arg_empty_blocks.stderr @@ -24,8 +24,9 @@ LL | taking_two_units({}, foo(0)); | help: move the expression in front of the call and replace it with the unit literal `()` | -LL | foo(0); taking_two_units((), ()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | foo(0); +LL | taking_two_units((), ()); + | error: passing unit values to a function --> $DIR/unit_arg_empty_blocks.rs:18:5 @@ -35,8 +36,10 @@ LL | taking_three_units({}, foo(0), foo(1)); | help: move the expressions in front of the call and replace them with the unit literal `()` | -LL | foo(0); foo(1); taking_three_units((), (), ()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | foo(0); +LL | foo(1); +LL | taking_three_units((), (), ()); + | error: aborting due to 4 previous errors From 459969f88ff95c94b7b34043a7f0e13de91de4f8 Mon Sep 17 00:00:00 2001 From: Vali Schneider Date: Thu, 27 Aug 2020 16:18:05 -0700 Subject: [PATCH 0020/1052] added restriction lint that prohibits the usage of unimplemented, unreachable or panic in a function of type result or option --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 5 ++ clippy_lints/src/panic_in_result.rs | 100 ++++++++++++++++++++++++++ src/lintlist/mod.rs | 7 ++ tests/ui/panic_in_result.rs | 62 ++++++++++++++++ tests/ui/panic_in_result.stderr | 105 ++++++++++++++++++++++++++++ 6 files changed, 280 insertions(+) create mode 100644 clippy_lints/src/panic_in_result.rs create mode 100644 tests/ui/panic_in_result.rs create mode 100644 tests/ui/panic_in_result.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 137b561028a65..7af3b666cca00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1651,6 +1651,7 @@ Released 2018-09-13 [`out_of_bounds_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#out_of_bounds_indexing [`overflow_check_conditional`]: https://rust-lang.github.io/rust-clippy/master/index.html#overflow_check_conditional [`panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic +[`panic_in_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result [`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params [`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 577ce6523b491..b70d126af5bf8 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -267,6 +267,7 @@ mod open_options; mod option_env_unwrap; mod option_if_let_else; mod overflow_check_conditional; +mod panic_in_result; mod panic_unimplemented; mod partialeq_ne_impl; mod path_buf_push_overwrite; @@ -747,6 +748,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &option_env_unwrap::OPTION_ENV_UNWRAP, &option_if_let_else::OPTION_IF_LET_ELSE, &overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, + &panic_in_result::PANIC_IN_RESULT, &panic_unimplemented::PANIC, &panic_unimplemented::PANIC_PARAMS, &panic_unimplemented::TODO, @@ -1086,6 +1088,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box manual_async_fn::ManualAsyncFn); store.register_early_pass(|| box redundant_field_names::RedundantFieldNames); store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero); + store.register_late_pass(|| box panic_in_result::PanicInResult); + let single_char_binding_names_threshold = conf.single_char_binding_names_threshold; store.register_early_pass(move || box non_expressive_names::NonExpressiveNames { single_char_binding_names_threshold, @@ -1128,6 +1132,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS), LintId::of(&missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS), LintId::of(&modulo_arithmetic::MODULO_ARITHMETIC), + LintId::of(&panic_in_result::PANIC_IN_RESULT), LintId::of(&panic_unimplemented::PANIC), LintId::of(&panic_unimplemented::TODO), LintId::of(&panic_unimplemented::UNIMPLEMENTED), diff --git a/clippy_lints/src/panic_in_result.rs b/clippy_lints/src/panic_in_result.rs new file mode 100644 index 0000000000000..3a71a0db6fe2e --- /dev/null +++ b/clippy_lints/src/panic_in_result.rs @@ -0,0 +1,100 @@ +use crate::utils::{is_expn_of, is_type_diagnostic_item, return_ty, span_lint_and_then}; +use if_chain::if_chain; +use rustc_hir as hir; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::map::Map; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::Span; + +declare_clippy_lint! { + /// **What it does:** Checks for usage of `panic!`, `unimplemented!` or `unreachable!` in a function of type result/option. + /// + /// **Why is this bad?** For some codebases, + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// fn option_with_panic() -> Option // should emit lint + /// { + /// panic!("error"); + /// } + /// ``` + + pub PANIC_IN_RESULT, + restriction, + "functions of type `Result<..>` / `Option`<...> that contain `panic!()` or `unreachable()` or `unimplemented()` " +} + +declare_lint_pass!(PanicInResult => [PANIC_IN_RESULT]); + +impl<'tcx> LateLintPass<'tcx> for PanicInResult { + fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) { + if_chain! { + // first check if it's a method or function + if let hir::ImplItemKind::Fn(ref _signature, _) = impl_item.kind; + // checking if its return type is `result` or `option` + if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(result_type)) + || is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(option_type)); + then { + lint_impl_body(cx, impl_item.span, impl_item); + } + } + } +} + +use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::{Expr, ImplItemKind}; + +struct FindPanicUnimplementedUnreachable { + result: Vec, +} + +impl<'tcx> Visitor<'tcx> for FindPanicUnimplementedUnreachable { + type Map = Map<'tcx>; + + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { + if is_expn_of(expr.span, "unimplemented").is_some() { + self.result.push(expr.span); + } else if is_expn_of(expr.span, "unreachable").is_some() { + self.result.push(expr.span); + } else if is_expn_of(expr.span, "panic").is_some() { + self.result.push(expr.span); + } + + // and check sub-expressions + intravisit::walk_expr(self, expr); + } + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } +} + +fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tcx hir::ImplItem<'_>) { + if_chain! { + if let ImplItemKind::Fn(_, body_id) = impl_item.kind; + then { + let body = cx.tcx.hir().body(body_id); + let mut fpu = FindPanicUnimplementedUnreachable { + result: Vec::new(), + }; + fpu.visit_expr(&body.value); + + // if we've found one, lint + if !fpu.result.is_empty() { + span_lint_and_then( + cx, + PANIC_IN_RESULT, + impl_span, + "used unimplemented, unreachable or panic in a function that returns result or option", + move |diag| { + diag.help( + "unimplemented, unreachable or panic should not be used in a function that returns result or option" ); + diag.span_note(fpu.result, "will cause the application to crash."); + }); + } + } + } +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 687fac7baa848..ad57146048ea0 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1704,6 +1704,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "panic_unimplemented", }, + Lint { + name: "panic_in_result", + group: "restriction", + desc: "default lint description", + deprecation: None, + module: "panic_in_result", + }, Lint { name: "panic_params", group: "style", diff --git a/tests/ui/panic_in_result.rs b/tests/ui/panic_in_result.rs new file mode 100644 index 0000000000000..21e9efca87bfd --- /dev/null +++ b/tests/ui/panic_in_result.rs @@ -0,0 +1,62 @@ +#![warn(clippy::panic_in_result)] + +struct A; + +impl A { + fn result_with_panic() -> Result // should emit lint + { + panic!("error"); + } + + fn result_with_unimplemented() -> Result // should emit lint + { + unimplemented!(); + } + + fn result_with_unreachable() -> Result // should emit lint + { + unreachable!(); + } + + fn option_with_unreachable() -> Option // should emit lint + { + unreachable!(); + } + + fn option_with_unimplemented() -> Option // should emit lint + { + unimplemented!(); + } + + fn option_with_panic() -> Option // should emit lint + { + panic!("error"); + } + + fn other_with_panic() // should not emit lint + { + panic!(""); + } + + fn other_with_unreachable() // should not emit lint + { + unreachable!(); + } + + fn other_with_unimplemented() // should not emit lint + { + unimplemented!(); + } + + fn result_without_banned_functions() -> Result // should not emit lint + { + Ok(true) + } + + fn option_without_banned_functions() -> Option // should not emit lint + { + Some(true) + } +} + +fn main() {} diff --git a/tests/ui/panic_in_result.stderr b/tests/ui/panic_in_result.stderr new file mode 100644 index 0000000000000..74273bd9abb2b --- /dev/null +++ b/tests/ui/panic_in_result.stderr @@ -0,0 +1,105 @@ +error: used unimplemented, unreachable or panic in a function that returns result or option + --> $DIR/panic_in_result.rs:6:5 + | +LL | / fn result_with_panic() -> Result // should emit lint +LL | | { +LL | | panic!("error"); +LL | | } + | |_____^ + | + = note: `-D clippy::panic-in-result` implied by `-D warnings` + = help: unimplemented, unreachable or panic should not be used in a function that returns result or option +note: will cause the application to crash. + --> $DIR/panic_in_result.rs:8: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 or panic in a function that returns result or option + --> $DIR/panic_in_result.rs:11:5 + | +LL | / fn result_with_unimplemented() -> Result // should emit lint +LL | | { +LL | | unimplemented!(); +LL | | } + | |_____^ + | + = help: unimplemented, unreachable or panic should not be used in a function that returns result or option +note: will cause the application to crash. + --> $DIR/panic_in_result.rs:13: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 or panic in a function that returns result or option + --> $DIR/panic_in_result.rs:16:5 + | +LL | / fn result_with_unreachable() -> Result // should emit lint +LL | | { +LL | | unreachable!(); +LL | | } + | |_____^ + | + = help: unimplemented, unreachable or panic should not be used in a function that returns result or option +note: will cause the application to crash. + --> $DIR/panic_in_result.rs:18: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 or panic in a function that returns result or option + --> $DIR/panic_in_result.rs:21:5 + | +LL | / fn option_with_unreachable() -> Option // should emit lint +LL | | { +LL | | unreachable!(); +LL | | } + | |_____^ + | + = help: unimplemented, unreachable or panic should not be used in a function that returns result or option +note: will cause the application to crash. + --> $DIR/panic_in_result.rs:23: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 or panic in a function that returns result or option + --> $DIR/panic_in_result.rs:26:5 + | +LL | / fn option_with_unimplemented() -> Option // should emit lint +LL | | { +LL | | unimplemented!(); +LL | | } + | |_____^ + | + = help: unimplemented, unreachable or panic should not be used in a function that returns result or option +note: will cause the application to crash. + --> $DIR/panic_in_result.rs:28: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 or panic in a function that returns result or option + --> $DIR/panic_in_result.rs:31:5 + | +LL | / fn option_with_panic() -> Option // should emit lint +LL | | { +LL | | panic!("error"); +LL | | } + | |_____^ + | + = help: unimplemented, unreachable or panic should not be used in a function that returns result or option +note: will cause the application to crash. + --> $DIR/panic_in_result.rs:33:9 + | +LL | panic!("error"); + | ^^^^^^^^^^^^^^^^ + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 6 previous errors + From ceab1a9167655eba9f9556f8766f8702e49dfef3 Mon Sep 17 00:00:00 2001 From: Vali Schneider Date: Thu, 27 Aug 2020 16:19:24 -0700 Subject: [PATCH 0021/1052] removed unnecessary comment --- clippy_lints/src/panic_in_result.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/panic_in_result.rs b/clippy_lints/src/panic_in_result.rs index 3a71a0db6fe2e..4e08c991bd02a 100644 --- a/clippy_lints/src/panic_in_result.rs +++ b/clippy_lints/src/panic_in_result.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// **Example:** /// /// ```rust - /// fn option_with_panic() -> Option // should emit lint + /// fn option_with_panic() -> Option /// { /// panic!("error"); /// } From 8462cce96081b87eba7a5bc89130a1a09fe1f6d0 Mon Sep 17 00:00:00 2001 From: Vali Schneider Date: Thu, 27 Aug 2020 16:22:37 -0700 Subject: [PATCH 0022/1052] edited documentation --- clippy_lints/src/panic_in_result.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/panic_in_result.rs b/clippy_lints/src/panic_in_result.rs index 4e08c991bd02a..239b4bdbdb1d4 100644 --- a/clippy_lints/src/panic_in_result.rs +++ b/clippy_lints/src/panic_in_result.rs @@ -9,7 +9,7 @@ use rustc_span::Span; declare_clippy_lint! { /// **What it does:** Checks for usage of `panic!`, `unimplemented!` or `unreachable!` in a function of type result/option. /// - /// **Why is this bad?** For some codebases, + /// **Why is this bad?** For some codebases, it is desirable for functions of type option/result to return an error instead of crashing. Hence unimplemented, panic and unreachable should be avoided. /// /// **Known problems:** None. /// From b2d8ca9a766703469178ea37d4d46067bb6fa926 Mon Sep 17 00:00:00 2001 From: Vali Schneider Date: Thu, 27 Aug 2020 16:30:49 -0700 Subject: [PATCH 0023/1052] ran cargo dev update lints --- src/lintlist/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index ad57146048ea0..b4f20ca7f14d6 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1707,7 +1707,7 @@ pub static ref ALL_LINTS: Vec = vec![ Lint { name: "panic_in_result", group: "restriction", - desc: "default lint description", + desc: "functions of type `Result<..>` / `Option`<...> that contain `panic!()` or `unreachable()` or `unimplemented()` ", deprecation: None, module: "panic_in_result", }, From b006522393a3c3c2656e1ccdfbb0076ff1bd7e99 Mon Sep 17 00:00:00 2001 From: Vali Schneider Date: Thu, 27 Aug 2020 16:55:23 -0700 Subject: [PATCH 0024/1052] added lint for todo and removed option --- clippy_lints/src/panic_in_result.rs | 26 ++++++------- src/lintlist/mod.rs | 2 +- tests/ui/panic_in_result.rs | 22 +++-------- tests/ui/panic_in_result.stderr | 60 +++++++---------------------- 4 files changed, 32 insertions(+), 78 deletions(-) diff --git a/clippy_lints/src/panic_in_result.rs b/clippy_lints/src/panic_in_result.rs index 239b4bdbdb1d4..2901f393fc65b 100644 --- a/clippy_lints/src/panic_in_result.rs +++ b/clippy_lints/src/panic_in_result.rs @@ -7,16 +7,16 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; declare_clippy_lint! { - /// **What it does:** Checks for usage of `panic!`, `unimplemented!` or `unreachable!` in a function of type result/option. + /// **What it does:** Checks for usage of `panic!`, `unimplemented!`, `todo!` or `unreachable!` in a function of type result. /// - /// **Why is this bad?** For some codebases, it is desirable for functions of type option/result to return an error instead of crashing. Hence unimplemented, panic and unreachable should be avoided. + /// **Why is this bad?** For some codebases, it is desirable for functions of type result to return an error instead of crashing. Hence unimplemented, panic and unreachable should be avoided. /// /// **Known problems:** None. /// /// **Example:** /// /// ```rust - /// fn option_with_panic() -> Option + /// fn result_with_panic() -> Result /// { /// panic!("error"); /// } @@ -24,7 +24,7 @@ declare_clippy_lint! { pub PANIC_IN_RESULT, restriction, - "functions of type `Result<..>` / `Option`<...> that contain `panic!()` or `unreachable()` or `unimplemented()` " + "functions of type `Result<..>` that contain `panic!()`, `todo!()` or `unreachable()` or `unimplemented()` " } declare_lint_pass!(PanicInResult => [PANIC_IN_RESULT]); @@ -35,8 +35,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResult { // first check if it's a method or function if let hir::ImplItemKind::Fn(ref _signature, _) = impl_item.kind; // checking if its return type is `result` or `option` - if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(result_type)) - || is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(option_type)); + if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(result_type)); then { lint_impl_body(cx, impl_item.span, impl_item); } @@ -55,14 +54,13 @@ impl<'tcx> Visitor<'tcx> for FindPanicUnimplementedUnreachable { type Map = Map<'tcx>; fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if is_expn_of(expr.span, "unimplemented").is_some() { - self.result.push(expr.span); - } else if is_expn_of(expr.span, "unreachable").is_some() { - self.result.push(expr.span); - } else if is_expn_of(expr.span, "panic").is_some() { + if is_expn_of(expr.span, "unimplemented").is_some() + || is_expn_of(expr.span, "unreachable").is_some() + || is_expn_of(expr.span, "panic").is_some() + || is_expn_of(expr.span, "todo").is_some() + { self.result.push(expr.span); } - // and check sub-expressions intravisit::walk_expr(self, expr); } @@ -88,10 +86,10 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tc cx, PANIC_IN_RESULT, impl_span, - "used unimplemented, unreachable or panic in a function that returns result or option", + "used unimplemented, unreachable, todo or panic in a function that returns result", move |diag| { diag.help( - "unimplemented, unreachable or panic should not be used in a function that returns result or option" ); + "unimplemented, unreachable, todo or panic should not be used in a function that returns result" ); diag.span_note(fpu.result, "will cause the application to crash."); }); } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index b4f20ca7f14d6..1f56c56f081d3 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1707,7 +1707,7 @@ pub static ref ALL_LINTS: Vec = vec![ Lint { name: "panic_in_result", group: "restriction", - desc: "functions of type `Result<..>` / `Option`<...> that contain `panic!()` or `unreachable()` or `unimplemented()` ", + desc: "functions of type `Result<..>` that contain `panic!()`, `todo!()` or `unreachable()` or `unimplemented()` ", deprecation: None, module: "panic_in_result", }, diff --git a/tests/ui/panic_in_result.rs b/tests/ui/panic_in_result.rs index 21e9efca87bfd..056778995a4ca 100644 --- a/tests/ui/panic_in_result.rs +++ b/tests/ui/panic_in_result.rs @@ -18,19 +18,9 @@ impl A { unreachable!(); } - fn option_with_unreachable() -> Option // should emit lint + fn result_with_todo() -> Result // should emit lint { - unreachable!(); - } - - fn option_with_unimplemented() -> Option // should emit lint - { - unimplemented!(); - } - - fn option_with_panic() -> Option // should emit lint - { - panic!("error"); + todo!("Finish this"); } fn other_with_panic() // should not emit lint @@ -48,14 +38,14 @@ impl A { unimplemented!(); } - fn result_without_banned_functions() -> Result // should not emit lint + fn other_with_todo() // should not emit lint { - Ok(true) + todo!("finish this") } - fn option_without_banned_functions() -> Option // should not emit lint + fn result_without_banned_functions() -> Result // should not emit lint { - Some(true) + Ok(true) } } diff --git a/tests/ui/panic_in_result.stderr b/tests/ui/panic_in_result.stderr index 74273bd9abb2b..3b9ac69f20dd6 100644 --- a/tests/ui/panic_in_result.stderr +++ b/tests/ui/panic_in_result.stderr @@ -1,4 +1,4 @@ -error: used unimplemented, unreachable or panic in a function that returns result or option +error: used unimplemented, unreachable, todo or panic in a function that returns result --> $DIR/panic_in_result.rs:6:5 | LL | / fn result_with_panic() -> Result // should emit lint @@ -8,7 +8,7 @@ LL | | } | |_____^ | = note: `-D clippy::panic-in-result` implied by `-D warnings` - = help: unimplemented, unreachable or panic should not be used in a function that returns result or option + = help: unimplemented, unreachable, todo or panic should not be used in a function that returns result note: will cause the application to crash. --> $DIR/panic_in_result.rs:8:9 | @@ -16,7 +16,7 @@ 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 or panic in a function that returns result or option +error: used unimplemented, unreachable, todo or panic in a function that returns result --> $DIR/panic_in_result.rs:11:5 | LL | / fn result_with_unimplemented() -> Result // should emit lint @@ -25,7 +25,7 @@ LL | | unimplemented!(); LL | | } | |_____^ | - = help: unimplemented, unreachable or panic should not be used in a function that returns result or option + = help: unimplemented, unreachable, todo or panic should not be used in a function that returns result note: will cause the application to crash. --> $DIR/panic_in_result.rs:13:9 | @@ -33,7 +33,7 @@ LL | unimplemented!(); | ^^^^^^^^^^^^^^^^^ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: used unimplemented, unreachable or panic in a function that returns result or option +error: used unimplemented, unreachable, todo or panic in a function that returns result --> $DIR/panic_in_result.rs:16:5 | LL | / fn result_with_unreachable() -> Result // should emit lint @@ -42,7 +42,7 @@ LL | | unreachable!(); LL | | } | |_____^ | - = help: unimplemented, unreachable or panic should not be used in a function that returns result or option + = help: unimplemented, unreachable, todo or panic should not be used in a function that returns result note: will cause the application to crash. --> $DIR/panic_in_result.rs:18:9 | @@ -50,56 +50,22 @@ LL | unreachable!(); | ^^^^^^^^^^^^^^^ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: used unimplemented, unreachable or panic in a function that returns result or option +error: used unimplemented, unreachable, todo or panic in a function that returns result --> $DIR/panic_in_result.rs:21:5 | -LL | / fn option_with_unreachable() -> Option // should emit lint +LL | / fn result_with_todo() -> Result // should emit lint LL | | { -LL | | unreachable!(); +LL | | todo!("Finish this"); LL | | } | |_____^ | - = help: unimplemented, unreachable or panic should not be used in a function that returns result or option + = help: unimplemented, unreachable, todo or panic should not be used in a function that returns result note: will cause the application to crash. --> $DIR/panic_in_result.rs:23: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 or panic in a function that returns result or option - --> $DIR/panic_in_result.rs:26:5 - | -LL | / fn option_with_unimplemented() -> Option // should emit lint -LL | | { -LL | | unimplemented!(); -LL | | } - | |_____^ - | - = help: unimplemented, unreachable or panic should not be used in a function that returns result or option -note: will cause the application to crash. - --> $DIR/panic_in_result.rs:28: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 or panic in a function that returns result or option - --> $DIR/panic_in_result.rs:31:5 - | -LL | / fn option_with_panic() -> Option // should emit lint -LL | | { -LL | | panic!("error"); -LL | | } - | |_____^ - | - = help: unimplemented, unreachable or panic should not be used in a function that returns result or option -note: will cause the application to crash. - --> $DIR/panic_in_result.rs:33:9 - | -LL | panic!("error"); - | ^^^^^^^^^^^^^^^^ +LL | todo!("Finish this"); + | ^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors From 5574182b4d2d08c848a88a1ac5633fc194e0465e Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Fri, 28 Aug 2020 18:40:22 +0900 Subject: [PATCH 0025/1052] Add a new lint to prevent `create_dir` from being used --- CHANGELOG.md | 1 + clippy_lints/src/create_dir.rs | 50 ++++++++++++++++++++++++++++++++++ clippy_lints/src/lib.rs | 4 +++ src/lintlist/mod.rs | 7 +++++ tests/ui/create_dir.fixed | 13 +++++++++ tests/ui/create_dir.rs | 13 +++++++++ tests/ui/create_dir.stderr | 16 +++++++++++ 7 files changed, 104 insertions(+) create mode 100644 clippy_lints/src/create_dir.rs create mode 100644 tests/ui/create_dir.fixed create mode 100644 tests/ui/create_dir.rs create mode 100644 tests/ui/create_dir.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 137b561028a65..b37273af44d22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1444,6 +1444,7 @@ Released 2018-09-13 [`collapsible_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if [`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain [`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator +[`create_dir`]: https://rust-lang.github.io/rust-clippy/master/index.html#create_dir [`crosspointer_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#crosspointer_transmute [`dbg_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro [`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs new file mode 100644 index 0000000000000..229536bd67307 --- /dev/null +++ b/clippy_lints/src/create_dir.rs @@ -0,0 +1,50 @@ +use crate::utils::{match_qpath, snippet, span_lint_and_sugg}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::*; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** Checks usage of `std::fs::create_dir` and suggest using `std::fs::create_dir_all` instead. + /// + /// **Why is this bad?** Sometimes `std::fs::crate_dir` is mistakenly chosen over `std::fs::create_dir_all`. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// std::fs::create_dir("foo") + /// ``` + /// Use instead: + /// ```rust + /// std::fs::create_dir_all("foo") + /// ``` + pub CREATE_DIR, + restriction, + "calling `std::fs::create_dir` instead of `std::fs::create_dir_all`" +} + +declare_lint_pass!(CreateDir => [CREATE_DIR]); + +impl LateLintPass<'_> for CreateDir { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + if_chain! { + if let ExprKind::Call(ref func, ref args) = expr.kind; + if let ExprKind::Path(ref path) = func.kind; + if match_qpath(path, &["std", "fs", "create_dir"]); + then { + span_lint_and_sugg( + cx, + CREATE_DIR, + expr.span, + "calling `std::fs::create_dir` where there may be a better way", + "consider calling `std::fs::create_dir_all` instead", + format!("std::fs::create_dir_all({})", snippet(cx, args[0].span, "..")), + Applicability::MachineApplicable, + ) + } + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 577ce6523b491..7943be34c6238 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -169,6 +169,7 @@ mod collapsible_if; mod comparison_chain; mod copies; mod copy_iterator; +mod create_dir; mod dbg_macro; mod default_trait_access; mod dereference; @@ -511,6 +512,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &copies::MATCH_SAME_ARMS, &copies::SAME_FUNCTIONS_IN_IF_CONDITION, ©_iterator::COPY_ITERATOR, + &create_dir::CREATE_DIR, &dbg_macro::DBG_MACRO, &default_trait_access::DEFAULT_TRAIT_ACCESS, &dereference::EXPLICIT_DEREF_METHODS, @@ -1042,6 +1044,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| box items_after_statements::ItemsAfterStatements); store.register_early_pass(|| box precedence::Precedence); store.register_early_pass(|| box needless_continue::NeedlessContinue); + store.register_late_pass(|| box create_dir::CreateDir); store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType); store.register_early_pass(|| box redundant_static_lifetimes::RedundantStaticLifetimes); store.register_late_pass(|| box cargo_common_metadata::CargoCommonMetadata); @@ -1104,6 +1107,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&arithmetic::FLOAT_ARITHMETIC), LintId::of(&arithmetic::INTEGER_ARITHMETIC), LintId::of(&as_conversions::AS_CONVERSIONS), + LintId::of(&create_dir::CREATE_DIR), LintId::of(&dbg_macro::DBG_MACRO), LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE), LintId::of(&exit::EXIT), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 687fac7baa848..e51345109226c 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -290,6 +290,13 @@ pub static ref ALL_LINTS: Vec = vec![ 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", diff --git a/tests/ui/create_dir.fixed b/tests/ui/create_dir.fixed new file mode 100644 index 0000000000000..50f31f0c9c540 --- /dev/null +++ b/tests/ui/create_dir.fixed @@ -0,0 +1,13 @@ +// run-rustfix +#![allow(unused_must_use)] +#![warn(clippy::create_dir)] + +fn not_create_dir() {} + +fn main() { + std::fs::create_dir_all("foo"); + std::fs::create_dir_all("bar").unwrap(); + + not_create_dir(); + std::fs::create_dir_all("foobar"); +} diff --git a/tests/ui/create_dir.rs b/tests/ui/create_dir.rs new file mode 100644 index 0000000000000..00ef37f413f77 --- /dev/null +++ b/tests/ui/create_dir.rs @@ -0,0 +1,13 @@ +// run-rustfix +#![allow(unused_must_use)] +#![warn(clippy::create_dir)] + +fn not_create_dir() {} + +fn main() { + std::fs::create_dir("foo"); + std::fs::create_dir("bar").unwrap(); + + not_create_dir(); + std::fs::create_dir_all("foobar"); +} diff --git a/tests/ui/create_dir.stderr b/tests/ui/create_dir.stderr new file mode 100644 index 0000000000000..3ae4680d9296e --- /dev/null +++ b/tests/ui/create_dir.stderr @@ -0,0 +1,16 @@ +error: calling `std::fs::create_dir` where there may be a better way + --> $DIR/create_dir.rs:8:5 + | +LL | std::fs::create_dir("foo"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `std::fs::create_dir_all` instead: `std::fs::create_dir_all("foo")` + | + = note: `-D clippy::create-dir` implied by `-D warnings` + +error: calling `std::fs::create_dir` where there may be a better way + --> $DIR/create_dir.rs:9:5 + | +LL | std::fs::create_dir("bar").unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `std::fs::create_dir_all` instead: `std::fs::create_dir_all("bar")` + +error: aborting due to 2 previous errors + From 607905d126c55422668007737c22d7a7a89c0d57 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Fri, 28 Aug 2020 18:53:15 +0900 Subject: [PATCH 0026/1052] Add STD_FS_CREATE_DIR into paths --- clippy_lints/src/create_dir.rs | 4 ++-- clippy_lints/src/utils/paths.rs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs index 229536bd67307..7ba6facda6aeb 100644 --- a/clippy_lints/src/create_dir.rs +++ b/clippy_lints/src/create_dir.rs @@ -1,4 +1,4 @@ -use crate::utils::{match_qpath, snippet, span_lint_and_sugg}; +use crate::utils::{match_qpath, paths, snippet, span_lint_and_sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::*; @@ -33,7 +33,7 @@ impl LateLintPass<'_> for CreateDir { if_chain! { if let ExprKind::Call(ref func, ref args) = expr.kind; if let ExprKind::Path(ref path) = func.kind; - if match_qpath(path, &["std", "fs", "create_dir"]); + if match_qpath(path, &paths::STD_FS_CREATE_DIR); then { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index d44854aefe97a..65320d6a0e0bd 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -110,6 +110,7 @@ pub const SLICE_ITER: [&str; 3] = ["core", "slice", "Iter"]; pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"]; pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"]; pub const STD_CONVERT_IDENTITY: [&str; 3] = ["std", "convert", "identity"]; +pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"]; pub const STD_MEM_TRANSMUTE: [&str; 3] = ["std", "mem", "transmute"]; pub const STD_PTR_NULL: [&str; 3] = ["std", "ptr", "null"]; pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"]; From 34e302e67c08c9b97d58d062ea83cc1fd860c56e Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Fri, 28 Aug 2020 19:35:04 +0900 Subject: [PATCH 0027/1052] Fix clippy error --- clippy_lints/src/create_dir.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs index 7ba6facda6aeb..4fede8857c702 100644 --- a/clippy_lints/src/create_dir.rs +++ b/clippy_lints/src/create_dir.rs @@ -1,7 +1,7 @@ use crate::utils::{match_qpath, paths, snippet, span_lint_and_sugg}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; From eebd2483654456e332d7cf53218b56b9cbd6f2f5 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Fri, 28 Aug 2020 19:56:03 +0900 Subject: [PATCH 0028/1052] Fix errors --- clippy_lints/src/create_dir.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs index 4fede8857c702..bf47c1f84a27d 100644 --- a/clippy_lints/src/create_dir.rs +++ b/clippy_lints/src/create_dir.rs @@ -15,11 +15,11 @@ declare_clippy_lint! { /// **Example:** /// /// ```rust - /// std::fs::create_dir("foo") + /// std::fs::create_dir("foo"); /// ``` /// Use instead: /// ```rust - /// std::fs::create_dir_all("foo") + /// std::fs::create_dir_all("foo"); /// ``` pub CREATE_DIR, restriction, From 282c59820b8e1d8c76f440484b81a190c576f91b Mon Sep 17 00:00:00 2001 From: flip1995 Date: Fri, 28 Aug 2020 16:10:16 +0200 Subject: [PATCH 0029/1052] Merge commit '3d0b0e66afdfaa519d8855b338b35b4605775945' into clippyup --- .cargo/config | 2 +- .github/workflows/clippy.yml | 7 + CHANGELOG.md | 6 + CONTRIBUTING.md | 58 ++- Cargo.toml | 4 +- clippy_dev/src/new_lint.rs | 2 +- clippy_lints/Cargo.toml | 4 +- clippy_lints/src/assign_ops.rs | 14 +- clippy_lints/src/attrs.rs | 2 +- clippy_lints/src/booleans.rs | 10 +- clippy_lints/src/copies.rs | 7 +- clippy_lints/src/doc.rs | 75 +++- clippy_lints/src/double_comparison.rs | 5 +- clippy_lints/src/duration_subsec.rs | 2 +- clippy_lints/src/enum_clike.rs | 2 +- clippy_lints/src/enum_variants.rs | 6 +- clippy_lints/src/eq_op.rs | 4 +- .../src/float_equality_without_abs.rs | 110 +++++ clippy_lints/src/floating_point_arithmetic.rs | 24 +- clippy_lints/src/if_let_some_result.rs | 4 +- clippy_lints/src/if_not_else.rs | 4 +- clippy_lints/src/implicit_saturating_sub.rs | 4 +- clippy_lints/src/inherent_impl.rs | 4 +- clippy_lints/src/int_plus_one.rs | 6 +- clippy_lints/src/len_zero.rs | 17 +- clippy_lints/src/let_and_return.rs | 124 ------ clippy_lints/src/lib.rs | 45 +- clippy_lints/src/loops.rs | 30 +- clippy_lints/src/map_clone.rs | 12 +- clippy_lints/src/match_on_vec_items.rs | 2 +- clippy_lints/src/methods/mod.rs | 403 +++++++++++++---- .../src/methods/unnecessary_lazy_eval.rs | 111 +++++ clippy_lints/src/misc.rs | 3 +- clippy_lints/src/mut_reference.rs | 17 +- clippy_lints/src/mutex_atomic.rs | 4 +- clippy_lints/src/non_copy_const.rs | 15 +- clippy_lints/src/precedence.rs | 59 +-- clippy_lints/src/ptr.rs | 17 +- clippy_lints/src/question_mark.rs | 6 +- clippy_lints/src/redundant_closure_call.rs | 19 +- clippy_lints/src/repeat_once.rs | 14 +- clippy_lints/src/returns.rs | 420 +++++++++--------- clippy_lints/src/self_assignment.rs | 51 +++ clippy_lints/src/stable_sort_primitive.rs | 10 +- clippy_lints/src/suspicious_trait_impl.rs | 10 +- clippy_lints/src/swap.rs | 14 +- clippy_lints/src/to_string_in_display.rs | 122 +++++ clippy_lints/src/transmute.rs | 10 +- .../src/trivially_copy_pass_by_ref.rs | 9 +- clippy_lints/src/try_err.rs | 6 +- clippy_lints/src/types.rs | 15 +- clippy_lints/src/unnested_or_patterns.rs | 4 +- clippy_lints/src/unused_unit.rs | 144 ++++++ clippy_lints/src/unwrap_in_result.rs | 140 ++++++ clippy_lints/src/use_self.rs | 2 +- clippy_lints/src/useless_conversion.rs | 5 +- clippy_lints/src/utils/ast_utils.rs | 2 +- clippy_lints/src/utils/author.rs | 21 +- clippy_lints/src/utils/conf.rs | 2 +- clippy_lints/src/utils/higher.rs | 76 ++-- clippy_lints/src/utils/hir_utils.rs | 45 +- clippy_lints/src/utils/internal_lints.rs | 5 +- clippy_lints/src/utils/mod.rs | 44 +- clippy_lints/src/utils/paths.rs | 3 + clippy_lints/src/vec.rs | 97 ++-- clippy_lints/src/wildcard_imports.rs | 7 +- clippy_lints/src/write.rs | 31 +- doc/adding_lints.md | 6 + src/lintlist/mod.rs | 48 +- tests/fmt.rs | 9 +- tests/ui/auxiliary/wildcard_imports_helper.rs | 6 + tests/ui/borrow_interior_mutable_const.rs | 35 +- tests/ui/borrow_interior_mutable_const.stderr | 32 +- tests/ui/crashes/ice-5944.rs | 13 + tests/ui/duration_subsec.stderr | 10 +- tests/ui/enum_clike_unportable_variant.stderr | 18 +- tests/ui/enum_variants.stderr | 20 +- tests/ui/float_equality_without_abs.rs | 31 ++ tests/ui/float_equality_without_abs.stderr | 92 ++++ tests/ui/if_let_some_result.stderr | 8 +- tests/ui/if_not_else.stderr | 4 +- tests/ui/impl.stderr | 8 +- tests/ui/implicit_saturating_sub.stderr | 46 +- tests/ui/int_plus_one.stderr | 8 +- tests/ui/iter_next_slice.stderr | 8 +- tests/ui/len_zero.fixed | 8 - tests/ui/len_zero.rs | 8 - tests/ui/len_zero_ranges.fixed | 10 +- tests/ui/len_zero_ranges.rs | 10 +- tests/ui/len_zero_ranges.stderr | 10 +- tests/ui/let_and_return.rs | 21 + tests/ui/let_and_return.stderr | 16 +- tests/ui/map_clone.stderr | 24 +- tests/ui/methods.rs | 68 +-- tests/ui/methods.stderr | 36 +- tests/ui/mut_reference.stderr | 6 +- tests/ui/mutex_atomic.stderr | 14 +- tests/ui/needless_doc_main.rs | 68 ++- tests/ui/needless_doc_main.stderr | 12 +- tests/ui/needless_return.fixed | 17 + tests/ui/needless_return.rs | 17 + tests/ui/needless_return.stderr | 14 +- tests/ui/new_ret_no_self.rs | 134 +++++- tests/ui/new_ret_no_self.stderr | 30 +- tests/ui/option_as_ref_deref.fixed | 3 + tests/ui/option_as_ref_deref.rs | 3 + tests/ui/option_as_ref_deref.stderr | 8 +- tests/ui/precedence.fixed | 8 + tests/ui/precedence.rs | 8 + tests/ui/precedence.stderr | 20 +- tests/ui/redundant_allocation.fixed | 2 +- tests/ui/redundant_allocation.stderr | 2 +- tests/ui/redundant_closure_call_early.stderr | 4 +- .../ui/redundant_closure_call_fixable.stderr | 2 +- tests/ui/redundant_closure_call_late.rs | 12 + tests/ui/same_item_push.rs | 8 + tests/ui/self_assignment.rs | 67 +++ tests/ui/self_assignment.stderr | 70 +++ tests/ui/should_impl_trait/corner_cases.rs | 83 ++++ tests/ui/should_impl_trait/method_list_1.rs | 87 ++++ .../ui/should_impl_trait/method_list_1.stderr | 143 ++++++ tests/ui/should_impl_trait/method_list_2.rs | 88 ++++ .../ui/should_impl_trait/method_list_2.stderr | 153 +++++++ tests/ui/single_char_push_str.fixed | 15 + tests/ui/single_char_push_str.rs | 15 + tests/ui/single_char_push_str.stderr | 34 ++ tests/ui/stable_sort_primitive.stderr | 14 +- tests/ui/suspicious_arithmetic_impl.rs | 52 ++- tests/ui/suspicious_arithmetic_impl.stderr | 44 +- tests/ui/to_string_in_display.rs | 69 +++ tests/ui/to_string_in_display.stderr | 10 + tests/ui/transmute.rs | 24 +- tests/ui/transmute.stderr | 66 +-- tests/ui/transmute_float_to_int.rs | 16 +- tests/ui/transmute_float_to_int.stderr | 12 +- tests/ui/trivially_copy_pass_by_ref.rs | 18 + tests/ui/trivially_copy_pass_by_ref.stderr | 14 +- tests/ui/unnecessary_clone.rs | 18 + tests/ui/unnecessary_clone.stderr | 8 +- tests/ui/unnecessary_lazy_eval.fixed | 117 +++++ tests/ui/unnecessary_lazy_eval.rs | 117 +++++ tests/ui/unnecessary_lazy_eval.stderr | 148 ++++++ tests/ui/unwrap_in_result.rs | 44 ++ tests/ui/unwrap_in_result.stderr | 41 ++ tests/ui/useless_conversion.fixed | 5 + tests/ui/useless_conversion.rs | 5 + tests/ui/useless_conversion.stderr | 8 +- tests/ui/vec.fixed | 7 + tests/ui/vec.rs | 7 + tests/ui/wildcard_imports.fixed | 2 + tests/ui/wildcard_imports.rs | 2 + tests/ui/wildcard_imports.stderr | 28 +- tests/ui/wrong_self_convention.rs | 13 + tests/ui/wrong_self_convention.stderr | 24 +- 154 files changed, 4160 insertions(+), 1092 deletions(-) create mode 100644 clippy_lints/src/float_equality_without_abs.rs delete mode 100644 clippy_lints/src/let_and_return.rs create mode 100644 clippy_lints/src/methods/unnecessary_lazy_eval.rs create mode 100644 clippy_lints/src/self_assignment.rs create mode 100644 clippy_lints/src/to_string_in_display.rs create mode 100644 clippy_lints/src/unused_unit.rs create mode 100644 clippy_lints/src/unwrap_in_result.rs create mode 100644 tests/ui/crashes/ice-5944.rs create mode 100644 tests/ui/float_equality_without_abs.rs create mode 100644 tests/ui/float_equality_without_abs.stderr create mode 100644 tests/ui/self_assignment.rs create mode 100644 tests/ui/self_assignment.stderr create mode 100644 tests/ui/should_impl_trait/corner_cases.rs create mode 100644 tests/ui/should_impl_trait/method_list_1.rs create mode 100644 tests/ui/should_impl_trait/method_list_1.stderr create mode 100644 tests/ui/should_impl_trait/method_list_2.rs create mode 100644 tests/ui/should_impl_trait/method_list_2.stderr create mode 100644 tests/ui/single_char_push_str.fixed create mode 100644 tests/ui/single_char_push_str.rs create mode 100644 tests/ui/single_char_push_str.stderr create mode 100644 tests/ui/to_string_in_display.rs create mode 100644 tests/ui/to_string_in_display.stderr create mode 100644 tests/ui/unnecessary_lazy_eval.fixed create mode 100644 tests/ui/unnecessary_lazy_eval.rs create mode 100644 tests/ui/unnecessary_lazy_eval.stderr create mode 100644 tests/ui/unwrap_in_result.rs create mode 100644 tests/ui/unwrap_in_result.stderr diff --git a/.cargo/config b/.cargo/config index 2bad3b9c57f0c..e70da43ab47ab 100644 --- a/.cargo/config +++ b/.cargo/config @@ -1,6 +1,6 @@ [alias] uitest = "test --test compile-test" -dev = "run --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --" +dev = "run --target-dir clippy_dev/target --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --" [build] rustflags = ["-Zunstable-options"] diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index 5fa8009a8b42c..99e371631b149 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -92,6 +92,13 @@ jobs: env: OS: ${{ runner.os }} + - name: Test cargo dev new lint + run: | + cargo dev new_lint --name new_early_pass --pass early + cargo dev new_lint --name new_late_pass --pass late + cargo check + git reset --hard HEAD + # Cleanup - name: Run cargo-cache --autoclean run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e9ed54c84820..137b561028a65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1498,6 +1498,7 @@ Released 2018-09-13 [`float_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_arithmetic [`float_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp [`float_cmp_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp_const +[`float_equality_without_abs`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_equality_without_abs [`fn_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_address_comparisons [`fn_params_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools [`fn_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast @@ -1690,6 +1691,7 @@ Released 2018-09-13 [`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition [`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push [`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some +[`self_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_assignment [`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse [`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse [`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same @@ -1699,6 +1701,7 @@ Released 2018-09-13 [`should_implement_trait`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait [`similar_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#similar_names [`single_char_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern +[`single_char_push_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_push_str [`single_component_path_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_component_path_imports [`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match [`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else @@ -1723,6 +1726,7 @@ Released 2018-09-13 [`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment [`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr [`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some +[`to_string_in_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_display [`todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo [`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments [`too_many_lines`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines @@ -1752,6 +1756,7 @@ Released 2018-09-13 [`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast [`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map [`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold +[`unnecessary_lazy_evaluations`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations [`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed [`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 @@ -1773,6 +1778,7 @@ Released 2018-09-13 [`unused_label`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_label [`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self [`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit +[`unwrap_in_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_in_result [`unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used [`use_debug`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_debug [`use_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_self diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5f7b1e85ee9a1..54777810abbdf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -189,6 +189,35 @@ Clippy in the `rust-lang/rust` repository. For general information about `subtree`s in the Rust repository see [Rust's `CONTRIBUTING.md`][subtree]. +### Patching git-subtree to work with big repos + +Currently there's a bug in `git-subtree` that prevents it from working properly +with the [`rust-lang/rust`] repo. There's an open PR to fix that, but it's stale. +Before continuing with the following steps, we need to manually apply that fix to +our local copy of `git-subtree`. + +You can get the patched version of `git-subtree` from [here][gitgitgadget-pr]. +Put this file under `/usr/lib/git-core` (taking a backup of the previous file) +and make sure it has the proper permissions: + +```bash +sudo cp --backup /path/to/patched/git-subtree.sh /usr/lib/git-core/git-subtree +sudo chmod --reference=/usr/lib/git-core/git-subtree~ /usr/lib/git-core/git-subtree +sudo chown --reference=/usr/lib/git-core/git-subtree~ /usr/lib/git-core/git-subtree +``` + +_Note:_ The first time running `git subtree push` a cache has to be built. This +involves going through the complete Clippy history once. For this you have to +increase the stack limit though, which you can do with `ulimit -s 60000`. +Make sure to run the `ulimit` command from the same session you call git subtree. + +_Note:_ If you are a Debian user, `dash` is the shell used by default for scripts instead of `sh`. +This shell has a hardcoded recursion limit set to 1000. In order to make this process work, +you need to force the script to run `bash` instead. You can do this by editing the first +line of the `git-subtree` script and changing `sh` to `bash`. + +### Performing the sync + Here is a TL;DR version of the sync process (all of the following commands have to be run inside the `rust` directory): @@ -198,6 +227,7 @@ to be run inside the `rust` directory): # Make sure to change `your-github-name` to your github name in the following command git subtree push -P src/tools/clippy git@github.com:your-github-name/rust-clippy sync-from-rust ``` + _Note:_ This will directly push to the remote repository. You can also push to your local copy by replacing the remote address with `/path/to/rust-clippy` directory. @@ -213,14 +243,30 @@ to be run inside the `rust` directory): 3. Open a PR to `rust-lang/rust-clippy` and wait for it to get merged (to accelerate the process ping the `@rust-lang/clippy` team in your PR and/or ~~annoy~~ ask them in the [Discord] channel.) -4. Sync the `rust-lang/rust-clippy` master to the rust-copy of Clippy: + +### Syncing back changes in Clippy to [`rust-lang/rust`] + +To avoid flooding the [`rust-lang/rust`] PR queue, changes in Clippy's repo are synced back +in a bi-weekly basis if there's no urgent changes. This is done starting on the day of +the Rust stable release and then every other week. That way we guarantee that +every feature in Clippy is available for 2 weeks in nightly, before it can get to beta. +For reference, the first sync following this cadence was performed the 2020-08-27. + +All of the following commands have to be run inside the `rust` directory. + +1. Make sure Clippy itself is up-to-date by following the steps outlined in the previous +section if necessary. + +2. Sync the `rust-lang/rust-clippy` master to the rust-copy of Clippy: ```bash git checkout -b sync-from-clippy git subtree pull -P src/tools/clippy https://github.com/rust-lang/rust-clippy master ``` -5. Open a PR to [`rust-lang/rust`] +3. Open a PR to [`rust-lang/rust`] + +### Defining remotes -Also, you may want to define remotes, so you don't have to type out the remote +You may want to define remotes, so you don't have to type out the remote addresses on every sync. You can do this with the following commands (these commands still have to be run inside the `rust` directory): @@ -241,12 +287,6 @@ You can then sync with the remote names from above, e.g.: $ git subtree push -P src/tools/clippy clippy-local sync-from-rust ``` -_Note:_ The first time running `git subtree push` a cache has to be built. This -involves going through the complete Clippy history once. For this you have to -increase the stack limit though, which you can do with `ulimit -s 60000`. For -this to work, you will need the fix of `git subtree` available -[here][gitgitgadget-pr]. - [gitgitgadget-pr]: https://github.com/gitgitgadget/git/pull/493 [subtree]: https://rustc-dev-guide.rust-lang.org/contributing.html#external-dependencies-subtree [`rust-lang/rust`]: https://github.com/rust-lang/rust diff --git a/Cargo.toml b/Cargo.toml index 836897927b015..c7a3099b8ab0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,13 +31,13 @@ path = "src/driver.rs" # begin automatic update clippy_lints = { version = "0.0.212", path = "clippy_lints" } # end automatic update -semver = "0.9" +semver = "0.10" rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util"} tempfile = { version = "3.1.0", optional = true } lazy_static = "1.0" [dev-dependencies] -cargo_metadata = "0.9.1" +cargo_metadata = "0.11.1" compiletest_rs = { version = "0.5.0", features = ["tmp"] } tester = "0.7" lazy_static = "1.0" diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 1e032a7bc20cd..d951ca0e6308d 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -47,7 +47,7 @@ pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str fn create_lint(lint: &LintData) -> io::Result<()> { let (pass_type, pass_lifetimes, pass_import, context_import) = match lint.pass { "early" => ("EarlyLintPass", "", "use rustc_ast::ast::*;", "EarlyContext"), - "late" => ("LateLintPass", "<'_, '_>", "use rustc_hir::*;", "LateContext"), + "late" => ("LateLintPass", "<'_>", "use rustc_hir::*;", "LateContext"), _ => { unreachable!("`pass_type` should only ever be `early` or `late`!"); }, diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index e959c1a651122..cc7d3a04f003e 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -17,7 +17,7 @@ keywords = ["clippy", "lint", "plugin"] edition = "2018" [dependencies] -cargo_metadata = "0.9.1" +cargo_metadata = "0.11.1" if_chain = "1.0.0" itertools = "0.9" lazy_static = "1.0.2" @@ -28,7 +28,7 @@ serde = { version = "1.0", features = ["derive"] } smallvec = { version = "1", features = ["union"] } toml = "0.5.3" unicode-normalization = "0.1" -semver = "0.9.0" +semver = "0.10.0" # NOTE: cargo requires serde feat in its url dep # see url = { version = "2.1.0", features = ["serde"] } diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index dab1e96e282f0..b3185b8884014 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -1,5 +1,5 @@ use crate::utils::{ - get_trait_def_id, implements_trait, snippet_opt, span_lint_and_then, trait_ref_of_method, SpanlessEq, + eq_expr_value, get_trait_def_id, implements_trait, snippet_opt, span_lint_and_then, trait_ref_of_method, }; use crate::utils::{higher, sugg}; use if_chain::if_chain; @@ -70,11 +70,11 @@ impl<'tcx> LateLintPass<'tcx> for AssignOps { return; } // lhs op= l op r - if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, l) { + if eq_expr_value(cx, lhs, l) { lint_misrefactored_assign_op(cx, expr, *op, rhs, lhs, r); } // lhs op= l commutative_op r - if is_commutative(op.node) && SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, r) { + if is_commutative(op.node) && eq_expr_value(cx, lhs, r) { lint_misrefactored_assign_op(cx, expr, *op, rhs, lhs, l); } } @@ -161,14 +161,12 @@ impl<'tcx> LateLintPass<'tcx> for AssignOps { if visitor.counter == 1 { // a = a op b - if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, l) { + if eq_expr_value(cx, assignee, l) { lint(assignee, r); } // a = b commutative_op a // Limited to primitive type as these ops are know to be commutative - if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, r) - && cx.typeck_results().expr_ty(assignee).is_primitive_ty() - { + if eq_expr_value(cx, assignee, r) && cx.typeck_results().expr_ty(assignee).is_primitive_ty() { match op.node { hir::BinOpKind::Add | hir::BinOpKind::Mul @@ -253,7 +251,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ExprVisitor<'a, 'tcx> { type Map = Map<'tcx>; fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { - if SpanlessEq::new(self.cx).ignore_fn().eq_expr(self.assignee, expr) { + if eq_expr_value(self.cx, self.assignee, expr) { self.counter += 1; } diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 76ccf2e4bb98b..cfcc1b3c5f356 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -5,8 +5,8 @@ use crate::utils::{ span_lint_and_sugg, span_lint_and_then, without_block_comments, }; use if_chain::if_chain; -use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; use rustc_ast::util::lev_distance::find_best_match_for_name; +use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; use rustc_errors::Applicability; use rustc_hir::{ Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitFn, TraitItem, TraitItemKind, diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 18529f2113e77..280a2c7fe6770 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -1,6 +1,6 @@ use crate::utils::{ - get_trait_def_id, implements_trait, in_macro, is_type_diagnostic_item, paths, snippet_opt, span_lint_and_sugg, - span_lint_and_then, SpanlessEq, + eq_expr_value, get_trait_def_id, implements_trait, in_macro, is_type_diagnostic_item, paths, snippet_opt, + span_lint_and_sugg, span_lint_and_then, }; use if_chain::if_chain; use rustc_ast::ast::LitKind; @@ -128,7 +128,7 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { } } for (n, expr) in self.terminals.iter().enumerate() { - if SpanlessEq::new(self.cx).ignore_fn().eq_expr(e, expr) { + if eq_expr_value(self.cx, e, expr) { #[allow(clippy::cast_possible_truncation)] return Ok(Bool::Term(n as u8)); } @@ -138,8 +138,8 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { if implements_ord(self.cx, e_lhs); if let ExprKind::Binary(expr_binop, expr_lhs, expr_rhs) = &expr.kind; if negate(e_binop.node) == Some(expr_binop.node); - if SpanlessEq::new(self.cx).ignore_fn().eq_expr(e_lhs, expr_lhs); - if SpanlessEq::new(self.cx).ignore_fn().eq_expr(e_rhs, expr_rhs); + if eq_expr_value(self.cx, e_lhs, expr_lhs); + if eq_expr_value(self.cx, e_rhs, expr_rhs); then { #[allow(clippy::cast_possible_truncation)] return Ok(Bool::Not(Box::new(Bool::Term(n as u8)))); diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 1f8bff8d71e0f..10a64769585e5 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,5 +1,5 @@ +use crate::utils::{eq_expr_value, SpanlessEq, SpanlessHash}; use crate::utils::{get_parent_expr, higher, if_sequence, snippet, span_lint_and_note, span_lint_and_then}; -use crate::utils::{SpanlessEq, SpanlessHash}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{Arm, Block, Expr, ExprKind, MatchSource, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -197,8 +197,7 @@ fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>]) { h.finish() }; - let eq: &dyn Fn(&&Expr<'_>, &&Expr<'_>) -> bool = - &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, rhs) }; + let eq: &dyn Fn(&&Expr<'_>, &&Expr<'_>) -> bool = &|&lhs, &rhs| -> bool { eq_expr_value(cx, lhs, rhs) }; for (i, j) in search_same(conds, hash, eq) { span_lint_and_note( @@ -222,7 +221,7 @@ fn lint_same_fns_in_if_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>]) { let eq: &dyn Fn(&&Expr<'_>, &&Expr<'_>) -> bool = &|&lhs, &rhs| -> bool { // Do not spawn warning if `IFS_SAME_COND` already produced it. - if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, rhs) { + if eq_expr_value(cx, lhs, rhs) { return false; } SpanlessEq::new(cx).eq_expr(lhs, rhs) diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 6ce36fd2360e1..9555459e240e9 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -1,16 +1,22 @@ use crate::utils::{implements_trait, is_entrypoint_fn, is_type_diagnostic_item, return_ty, span_lint}; use if_chain::if_chain; use itertools::Itertools; -use rustc_ast::ast::{AttrKind, Attribute}; +use rustc_ast::ast::{Async, AttrKind, Attribute, FnRetTy, ItemKind}; use rustc_ast::token::CommentKind; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::sync::Lrc; +use rustc_errors::emitter::EmitterWriter; +use rustc_errors::Handler; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; +use rustc_parse::maybe_new_parser_from_source_str; +use rustc_session::parse::ParseSess; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::source_map::{BytePos, MultiSpan, Span}; -use rustc_span::Pos; +use rustc_span::source_map::{BytePos, FilePathMapping, MultiSpan, SourceMap, Span}; +use rustc_span::{FileName, Pos}; +use std::io; use std::ops::Range; use url::Url; @@ -431,10 +437,67 @@ fn check_doc<'a, Events: Iterator, Range, text: &str, span: Span) { - if text.contains("fn main() {") && !LEAVE_MAIN_PATTERNS.iter().any(|p| text.contains(p)) { + fn has_needless_main(code: &str) -> bool { + let filename = FileName::anon_source_code(code); + + let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let emitter = EmitterWriter::new(box io::sink(), None, false, false, false, None, false); + let handler = Handler::with_emitter(false, None, box emitter); + let sess = ParseSess::with_span_handler(handler, sm); + + let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code.into()) { + Ok(p) => p, + Err(errs) => { + for mut err in errs { + err.cancel(); + } + return false; + }, + }; + + let mut relevant_main_found = false; + loop { + match parser.parse_item() { + Ok(Some(item)) => match &item.kind { + // Tests with one of these items are ignored + ItemKind::Static(..) + | ItemKind::Const(..) + | ItemKind::ExternCrate(..) + | ItemKind::ForeignMod(..) => return false, + // We found a main function ... + ItemKind::Fn(_, sig, _, Some(block)) if item.ident.name == sym!(main) => { + let is_async = matches!(sig.header.asyncness, Async::Yes{..}); + let returns_nothing = match &sig.decl.output { + FnRetTy::Default(..) => true, + FnRetTy::Ty(ty) if ty.kind.is_unit() => true, + _ => false, + }; + + if returns_nothing && !is_async && !block.stmts.is_empty() { + // This main function should be linted, but only if there are no other functions + relevant_main_found = true; + } else { + // This main function should not be linted, we're done + return false; + } + }, + // Another function was found; this case is ignored too + ItemKind::Fn(..) => return false, + _ => {}, + }, + Ok(None) => break, + Err(mut e) => { + e.cancel(); + return false; + }, + } + } + + relevant_main_found + } + + if has_needless_main(text) { span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest"); } } diff --git a/clippy_lints/src/double_comparison.rs b/clippy_lints/src/double_comparison.rs index bae7c4647d487..19f56195ec1b4 100644 --- a/clippy_lints/src/double_comparison.rs +++ b/clippy_lints/src/double_comparison.rs @@ -6,7 +6,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; -use crate::utils::{snippet_with_applicability, span_lint_and_sugg, SpanlessEq}; +use crate::utils::{eq_expr_value, snippet_with_applicability, span_lint_and_sugg}; declare_clippy_lint! { /// **What it does:** Checks for double comparisons that could be simplified to a single expression. @@ -46,8 +46,7 @@ impl<'tcx> DoubleComparisons { }, _ => return, }; - let mut spanless_eq = SpanlessEq::new(cx).ignore_fn(); - if !(spanless_eq.eq_expr(&llhs, &rlhs) && spanless_eq.eq_expr(&lrhs, &rrhs)) { + if !(eq_expr_value(cx, &llhs, &rlhs) && eq_expr_value(cx, &lrhs, &rrhs)) { return; } macro_rules! lint_double_comparison { diff --git a/clippy_lints/src/duration_subsec.rs b/clippy_lints/src/duration_subsec.rs index 1dfb2eaa57972..8ece44878fe32 100644 --- a/clippy_lints/src/duration_subsec.rs +++ b/clippy_lints/src/duration_subsec.rs @@ -56,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for DurationSubsec { cx, DURATION_SUBSEC, expr.span, - &format!("Calling `{}()` is more concise than this calculation", suggested_fn), + &format!("calling `{}()` is more concise than this calculation", suggested_fn), "try", format!( "{}.{}()", diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index 91214f277be69..48caf48dbdb2c 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -72,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant { cx, ENUM_CLIKE_UNPORTABLE_VARIANT, var.span, - "Clike enum variant discriminant is not portable to 32-bit targets", + "C-like enum variant discriminant is not portable to 32-bit targets", ); }; } diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index cb0fd59a2d407..a9294a87f15d0 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -183,10 +183,10 @@ fn check_variant( && name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase()) && name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric()) { - span_lint(cx, lint, var.span, "Variant name starts with the enum's name"); + span_lint(cx, lint, var.span, "variant name starts with the enum's name"); } if partial_rmatch(item_name, &name) == item_name_chars { - span_lint(cx, lint, var.span, "Variant name ends with the enum's name"); + span_lint(cx, lint, var.span, "variant name ends with the enum's name"); } } let first = &def.variants[0].ident.name.as_str(); @@ -227,7 +227,7 @@ fn check_variant( cx, lint, span, - &format!("All variants have the same {}fix: `{}`", what, value), + &format!("all variants have the same {}fix: `{}`", what, value), None, &format!( "remove the {}fixes and use full paths to \ diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 140cd21c34e67..e16ec783fab79 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -1,5 +1,5 @@ use crate::utils::{ - implements_trait, in_macro, is_copy, multispan_sugg, snippet, span_lint, span_lint_and_then, SpanlessEq, + eq_expr_value, implements_trait, in_macro, is_copy, multispan_sugg, snippet, span_lint, span_lint_and_then, }; use rustc_errors::Applicability; use rustc_hir::{BinOp, BinOpKind, BorrowKind, Expr, ExprKind}; @@ -69,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { if macro_with_not_op(&left.kind) || macro_with_not_op(&right.kind) { return; } - if is_valid_operator(op) && SpanlessEq::new(cx).ignore_fn().eq_expr(left, right) { + if is_valid_operator(op) && eq_expr_value(cx, left, right) { span_lint( cx, EQ_OP, diff --git a/clippy_lints/src/float_equality_without_abs.rs b/clippy_lints/src/float_equality_without_abs.rs new file mode 100644 index 0000000000000..9ac5a45eb4590 --- /dev/null +++ b/clippy_lints/src/float_equality_without_abs.rs @@ -0,0 +1,110 @@ +use crate::utils::{match_qpath, paths, span_lint_and_then, sugg}; +use if_chain::if_chain; +use rustc_ast::util::parser::AssocOp; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::source_map::Spanned; + +declare_clippy_lint! { + /// **What it does:** Checks for statements of the form `(a - b) < f32::EPSILON` or + /// `(a - b) < f64::EPSILON`. Notes the missing `.abs()`. + /// + /// **Why is this bad?** The code without `.abs()` is more likely to have a bug. + /// + /// **Known problems:** If the user can ensure that b is larger than a, the `.abs()` is + /// technically unneccessary. However, it will make the code more robust and doesn't have any + /// large performance implications. If the abs call was deliberately left out for performance + /// reasons, it is probably better to state this explicitly in the code, which then can be done + /// with an allow. + /// + /// **Example:** + /// + /// ```rust + /// pub fn is_roughly_equal(a: f32, b: f32) -> bool { + /// (a - b) < f32::EPSILON + /// } + /// ``` + /// Use instead: + /// ```rust + /// pub fn is_roughly_equal(a: f32, b: f32) -> bool { + /// (a - b).abs() < f32::EPSILON + /// } + /// ``` + pub FLOAT_EQUALITY_WITHOUT_ABS, + correctness, + "float equality check without `.abs()`" +} + +declare_lint_pass!(FloatEqualityWithoutAbs => [FLOAT_EQUALITY_WITHOUT_ABS]); + +impl<'tcx> LateLintPass<'tcx> for FloatEqualityWithoutAbs { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + let lhs; + let rhs; + + // check if expr is a binary expression with a lt or gt operator + if let ExprKind::Binary(op, ref left, ref right) = expr.kind { + match op.node { + BinOpKind::Lt => { + lhs = left; + rhs = right; + }, + BinOpKind::Gt => { + lhs = right; + rhs = left; + }, + _ => return, + }; + } else { + return; + } + + if_chain! { + + // left hand side is a substraction + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Sub, + .. + }, + val_l, + val_r, + ) = lhs.kind; + + // right hand side matches either f32::EPSILON or f64::EPSILON + if let ExprKind::Path(ref epsilon_path) = rhs.kind; + if match_qpath(epsilon_path, &paths::F32_EPSILON) || match_qpath(epsilon_path, &paths::F64_EPSILON); + + // values of the substractions on the left hand side are of the type float + let t_val_l = cx.typeck_results().expr_ty(val_l); + let t_val_r = cx.typeck_results().expr_ty(val_r); + if let ty::Float(_) = t_val_l.kind; + if let ty::Float(_) = t_val_r.kind; + + then { + let sug_l = sugg::Sugg::hir(cx, &val_l, ".."); + let sug_r = sugg::Sugg::hir(cx, &val_r, ".."); + // format the suggestion + let suggestion = format!("{}.abs()", sugg::make_assoc(AssocOp::Subtract, &sug_l, &sug_r).maybe_par()); + // spans the lint + span_lint_and_then( + cx, + FLOAT_EQUALITY_WITHOUT_ABS, + expr.span, + "float equality check without `.abs()`", + | diag | { + diag.span_suggestion( + lhs.span, + "add `.abs()`", + suggestion, + Applicability::MaybeIncorrect, + ); + } + ); + } + } + } +} diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 93f6ec92ec713..1b02cee126d03 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -2,7 +2,7 @@ use crate::consts::{ constant, constant_simple, Constant, Constant::{Int, F32, F64}, }; -use crate::utils::{get_parent_expr, higher, numeric_literal, span_lint_and_sugg, sugg, SpanlessEq}; +use crate::utils::{eq_expr_value, get_parent_expr, higher, numeric_literal, span_lint_and_sugg, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp}; @@ -363,8 +363,8 @@ fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option { if_chain! { if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref lmul_lhs, ref lmul_rhs) = add_lhs.kind; if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref rmul_lhs, ref rmul_rhs) = add_rhs.kind; - if are_exprs_equal(cx, lmul_lhs, lmul_rhs); - if are_exprs_equal(cx, rmul_lhs, rmul_rhs); + if eq_expr_value(cx, lmul_lhs, lmul_rhs); + if eq_expr_value(cx, rmul_lhs, rmul_rhs); then { return Some(format!("{}.hypot({})", Sugg::hir(cx, &lmul_lhs, ".."), Sugg::hir(cx, &rmul_lhs, ".."))); } @@ -502,8 +502,8 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) { fn is_testing_positive(cx: &LateContext<'_>, expr: &Expr<'_>, test: &Expr<'_>) -> bool { if let ExprKind::Binary(Spanned { node: op, .. }, left, right) = expr.kind { match op { - BinOpKind::Gt | BinOpKind::Ge => is_zero(cx, right) && are_exprs_equal(cx, left, test), - BinOpKind::Lt | BinOpKind::Le => is_zero(cx, left) && are_exprs_equal(cx, right, test), + BinOpKind::Gt | BinOpKind::Ge => is_zero(cx, right) && eq_expr_value(cx, left, test), + BinOpKind::Lt | BinOpKind::Le => is_zero(cx, left) && eq_expr_value(cx, right, test), _ => false, } } else { @@ -515,8 +515,8 @@ fn is_testing_positive(cx: &LateContext<'_>, expr: &Expr<'_>, test: &Expr<'_>) - fn is_testing_negative(cx: &LateContext<'_>, expr: &Expr<'_>, test: &Expr<'_>) -> bool { if let ExprKind::Binary(Spanned { node: op, .. }, left, right) = expr.kind { match op { - BinOpKind::Gt | BinOpKind::Ge => is_zero(cx, left) && are_exprs_equal(cx, right, test), - BinOpKind::Lt | BinOpKind::Le => is_zero(cx, right) && are_exprs_equal(cx, left, test), + BinOpKind::Gt | BinOpKind::Ge => is_zero(cx, left) && eq_expr_value(cx, right, test), + BinOpKind::Lt | BinOpKind::Le => is_zero(cx, right) && eq_expr_value(cx, left, test), _ => false, } } else { @@ -524,10 +524,6 @@ fn is_testing_negative(cx: &LateContext<'_>, expr: &Expr<'_>, test: &Expr<'_>) - } } -fn are_exprs_equal(cx: &LateContext<'_>, expr1: &Expr<'_>, expr2: &Expr<'_>) -> bool { - SpanlessEq::new(cx).ignore_fn().eq_expr(expr1, expr2) -} - /// Returns true iff expr is some zero literal fn is_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { match constant_simple(cx, cx.typeck_results(), expr) { @@ -546,12 +542,12 @@ fn is_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// returns None. fn are_negated<'a>(cx: &LateContext<'_>, expr1: &'a Expr<'a>, expr2: &'a Expr<'a>) -> Option<(bool, &'a Expr<'a>)> { if let ExprKind::Unary(UnOp::UnNeg, expr1_negated) = &expr1.kind { - if are_exprs_equal(cx, expr1_negated, expr2) { + if eq_expr_value(cx, expr1_negated, expr2) { return Some((false, expr2)); } } if let ExprKind::Unary(UnOp::UnNeg, expr2_negated) = &expr2.kind { - if are_exprs_equal(cx, expr1, expr2_negated) { + if eq_expr_value(cx, expr1, expr2_negated) { return Some((true, expr1)); } } @@ -614,7 +610,7 @@ fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_> args_a.len() == args_b.len() && ( ["ln", "log2", "log10"].contains(&&*method_name_a.as_str()) || - method_name_a.as_str() == "log" && args_a.len() == 2 && are_exprs_equal(cx, &args_a[1], &args_b[1]) + method_name_a.as_str() == "log" && args_a.len() == 2 && eq_expr_value(cx, &args_a[1], &args_b[1]) ); } } diff --git a/clippy_lints/src/if_let_some_result.rs b/clippy_lints/src/if_let_some_result.rs index 5b22df5fe491e..28b20cdeac343 100644 --- a/clippy_lints/src/if_let_some_result.rs +++ b/clippy_lints/src/if_let_some_result.rs @@ -61,8 +61,8 @@ impl<'tcx> LateLintPass<'tcx> for OkIfLet { cx, IF_LET_SOME_RESULT, expr.span.with_hi(op.span.hi()), - "Matching on `Some` with `ok()` is redundant", - &format!("Consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string), + "matching on `Some` with `ok()` is redundant", + &format!("consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string), sugg, applicability, ); diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index c11e291f98e4b..b86d2e766566b 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -60,7 +60,7 @@ impl EarlyLintPass for IfNotElse { cx, IF_NOT_ELSE, item.span, - "Unnecessary boolean `not` operation", + "unnecessary boolean `not` operation", None, "remove the `!` and swap the blocks of the `if`/`else`", ); @@ -70,7 +70,7 @@ impl EarlyLintPass for IfNotElse { cx, IF_NOT_ELSE, item.span, - "Unnecessary `!=` operation", + "unnecessary `!=` operation", None, "change to `==` and swap the blocks of the `if`/`else`", ); diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 5f931a0addedf..b57fe8dc4269e 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -158,9 +158,9 @@ fn print_lint_and_sugg(cx: &LateContext<'_>, var_name: &str, expr: &Expr<'_>) { cx, IMPLICIT_SATURATING_SUB, expr.span, - "Implicitly performing saturating subtraction", + "implicitly performing saturating subtraction", "try", - format!("{} = {}.saturating_sub({});", var_name, var_name, 1.to_string()), + format!("{} = {}.saturating_sub({});", var_name, var_name, '1'), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index 9fb10c7f62768..4e6bb60478541 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -81,9 +81,9 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { cx, MULTIPLE_INHERENT_IMPL, *additional_span, - "Multiple implementations of this structure", + "multiple implementations of this structure", |diag| { - diag.span_note(*initial_span, "First implementation here"); + diag.span_note(*initial_span, "first implementation here"); }, ) }) diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index e91fb0c2f27cd..c629ee05ab97c 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -152,7 +152,7 @@ impl IntPlusOne { cx, INT_PLUS_ONE, block.span, - "Unnecessary `>= y + 1` or `x - 1 >=`", + "unnecessary `>= y + 1` or `x - 1 >=`", "change it to", recommendation, Applicability::MachineApplicable, // snippet @@ -163,8 +163,8 @@ impl IntPlusOne { impl EarlyLintPass for IntPlusOne { fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) { if let ExprKind::Binary(ref kind, ref lhs, ref rhs) = item.kind { - if let Some(ref rec) = Self::check_binop(cx, kind.node, lhs, rhs) { - Self::emit_warning(cx, item, rec.clone()); + if let Some(rec) = Self::check_binop(cx, kind.node, lhs, rhs) { + Self::emit_warning(cx, item, rec); } } } diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index e5daa30f8ca15..b691d363d2f21 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -1,4 +1,4 @@ -use crate::utils::{get_item_name, higher, snippet_with_applicability, span_lint, span_lint_and_sugg, walk_ptrs_ty}; +use crate::utils::{get_item_name, snippet_with_applicability, span_lint, span_lint_and_sugg, walk_ptrs_ty}; use rustc_ast::ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -260,17 +260,6 @@ fn check_len( /// Checks if this type has an `is_empty` method. fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - /// Special case ranges until `range_is_empty` is stabilized. See issue 3807. - fn should_skip_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - higher::range(expr).map_or(false, |_| { - !cx.tcx - .features() - .declared_lib_features - .iter() - .any(|(name, _)| name.as_str() == "range_is_empty") - }) - } - /// Gets an `AssocItem` and return true if it matches `is_empty(self)`. fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool { if let ty::AssocKind::Fn = item.kind { @@ -296,10 +285,6 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { }) } - if should_skip_range(cx, expr) { - return false; - } - let ty = &walk_ptrs_ty(cx.typeck_results().expr_ty(expr)); match ty.kind { ty::Dynamic(ref tt, ..) => tt.principal().map_or(false, |principal| { diff --git a/clippy_lints/src/let_and_return.rs b/clippy_lints/src/let_and_return.rs deleted file mode 100644 index fa560ffb980c8..0000000000000 --- a/clippy_lints/src/let_and_return.rs +++ /dev/null @@ -1,124 +0,0 @@ -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; -use rustc_hir::{Block, Expr, ExprKind, PatKind, StmtKind}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::hir::map::Map; -use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::subst::GenericArgKind; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -use crate::utils::{fn_def_id, in_macro, match_qpath, snippet_opt, span_lint_and_then}; - -declare_clippy_lint! { - /// **What it does:** Checks for `let`-bindings, which are subsequently - /// returned. - /// - /// **Why is this bad?** It is just extraneous code. Remove it to make your code - /// more rusty. - /// - /// **Known problems:** None. - /// - /// **Example:** - /// ```rust - /// fn foo() -> String { - /// let x = String::new(); - /// x - /// } - /// ``` - /// instead, use - /// ``` - /// fn foo() -> String { - /// String::new() - /// } - /// ``` - pub LET_AND_RETURN, - style, - "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block" -} - -declare_lint_pass!(LetReturn => [LET_AND_RETURN]); - -impl<'tcx> LateLintPass<'tcx> for LetReturn { - fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) { - // we need both a let-binding stmt and an expr - if_chain! { - if let Some(retexpr) = block.expr; - if let Some(stmt) = block.stmts.iter().last(); - if let StmtKind::Local(local) = &stmt.kind; - if local.ty.is_none(); - if local.attrs.is_empty(); - if let Some(initexpr) = &local.init; - if let PatKind::Binding(.., ident, _) = local.pat.kind; - if let ExprKind::Path(qpath) = &retexpr.kind; - if match_qpath(qpath, &[&*ident.name.as_str()]); - if !last_statement_borrows(cx, initexpr); - if !in_external_macro(cx.sess(), initexpr.span); - if !in_external_macro(cx.sess(), retexpr.span); - if !in_external_macro(cx.sess(), local.span); - if !in_macro(local.span); - then { - span_lint_and_then( - cx, - LET_AND_RETURN, - retexpr.span, - "returning the result of a `let` binding from a block", - |err| { - err.span_label(local.span, "unnecessary `let` binding"); - - if let Some(snippet) = snippet_opt(cx, initexpr.span) { - err.multipart_suggestion( - "return the expression directly", - vec![ - (local.span, String::new()), - (retexpr.span, snippet), - ], - Applicability::MachineApplicable, - ); - } else { - err.span_help(initexpr.span, "this expression can be directly returned"); - } - }, - ); - } - } - } -} - -fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { - let mut visitor = BorrowVisitor { cx, borrows: false }; - walk_expr(&mut visitor, expr); - visitor.borrows -} - -struct BorrowVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - borrows: bool, -} - -impl<'tcx> Visitor<'tcx> for BorrowVisitor<'_, 'tcx> { - type Map = Map<'tcx>; - - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if self.borrows { - return; - } - - if let Some(def_id) = fn_def_id(self.cx, expr) { - self.borrows = self - .cx - .tcx - .fn_sig(def_id) - .output() - .skip_binder() - .walk() - .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_))); - } - - walk_expr(self, expr); - } - - fn nested_visit_map(&mut self) -> NestedVisitorMap { - NestedVisitorMap::None - } -} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index aa1002636406a..577ce6523b491 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -193,6 +193,7 @@ mod excessive_bools; mod exit; mod explicit_write; mod fallible_impl_from; +mod float_equality_without_abs; mod float_literal; mod floating_point_arithmetic; mod format; @@ -218,7 +219,6 @@ mod large_const_arrays; mod large_enum_variant; mod large_stack_arrays; mod len_zero; -mod let_and_return; mod let_if_seq; mod let_underscore; mod lifetimes; @@ -285,6 +285,7 @@ mod reference; mod regex; mod repeat_once; mod returns; +mod self_assignment; mod serde_api; mod shadow; mod single_component_path_imports; @@ -296,6 +297,7 @@ mod swap; mod tabs_in_doc_comments; mod temporary_assignment; mod to_digit_is_some; +mod to_string_in_display; mod trait_bounds; mod transmute; mod transmuting_null; @@ -310,7 +312,9 @@ mod unnested_or_patterns; mod unsafe_removed_from_name; mod unused_io_amount; mod unused_self; +mod unused_unit; mod unwrap; +mod unwrap_in_result; mod use_self; mod useless_conversion; mod vec; @@ -547,6 +551,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &exit::EXIT, &explicit_write::EXPLICIT_WRITE, &fallible_impl_from::FALLIBLE_IMPL_FROM, + &float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS, &float_literal::EXCESSIVE_PRECISION, &float_literal::LOSSY_FLOAT_LITERAL, &floating_point_arithmetic::IMPRECISE_FLOPS, @@ -586,7 +591,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &large_stack_arrays::LARGE_STACK_ARRAYS, &len_zero::LEN_WITHOUT_IS_EMPTY, &len_zero::LEN_ZERO, - &let_and_return::LET_AND_RETURN, &let_if_seq::USELESS_LET_IF_SEQ, &let_underscore::LET_UNDERSCORE_LOCK, &let_underscore::LET_UNDERSCORE_MUST_USE, @@ -677,6 +681,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::SEARCH_IS_SOME, &methods::SHOULD_IMPLEMENT_TRAIT, &methods::SINGLE_CHAR_PATTERN, + &methods::SINGLE_CHAR_PUSH_STR, &methods::SKIP_WHILE_NEXT, &methods::STRING_EXTEND_CHARS, &methods::SUSPICIOUS_MAP, @@ -684,6 +689,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::UNINIT_ASSUMED_INIT, &methods::UNNECESSARY_FILTER_MAP, &methods::UNNECESSARY_FOLD, + &methods::UNNECESSARY_LAZY_EVALUATIONS, &methods::UNWRAP_USED, &methods::USELESS_ASREF, &methods::WRONG_PUB_SELF_CONVENTION, @@ -769,8 +775,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: ®ex::INVALID_REGEX, ®ex::TRIVIAL_REGEX, &repeat_once::REPEAT_ONCE, + &returns::LET_AND_RETURN, &returns::NEEDLESS_RETURN, - &returns::UNUSED_UNIT, + &self_assignment::SELF_ASSIGNMENT, &serde_api::SERDE_API_MISUSE, &shadow::SHADOW_REUSE, &shadow::SHADOW_SAME, @@ -788,6 +795,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &tabs_in_doc_comments::TABS_IN_DOC_COMMENTS, &temporary_assignment::TEMPORARY_ASSIGNMENT, &to_digit_is_some::TO_DIGIT_IS_SOME, + &to_string_in_display::TO_STRING_IN_DISPLAY, &trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS, &trait_bounds::TYPE_REPETITION_IN_BOUNDS, &transmute::CROSSPOINTER_TRANSMUTE, @@ -840,8 +848,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, &unused_io_amount::UNUSED_IO_AMOUNT, &unused_self::UNUSED_SELF, + &unused_unit::UNUSED_UNIT, &unwrap::PANICKING_UNWRAP, &unwrap::UNNECESSARY_UNWRAP, + &unwrap_in_result::UNWRAP_IN_RESULT, &use_self::USE_SELF, &useless_conversion::USELESS_CONVERSION, &utils::internal_lints::CLIPPY_LINTS_INTERNAL, @@ -930,11 +940,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || box cognitive_complexity::CognitiveComplexity::new(cognitive_complexity_threshold)); let too_large_for_stack = conf.too_large_for_stack; store.register_late_pass(move || box escape::BoxedLocal{too_large_for_stack}); + store.register_late_pass(move || box vec::UselessVec{too_large_for_stack}); store.register_late_pass(|| box panic_unimplemented::PanicUnimplemented); store.register_late_pass(|| box strings::StringLitAsBytes); store.register_late_pass(|| box derive::Derive); store.register_late_pass(|| box types::CharLitAsU8); - store.register_late_pass(|| box vec::UselessVec); store.register_late_pass(|| box drop_bounds::DropBounds); store.register_late_pass(|| box get_last_with_len::GetLastWithLen); store.register_late_pass(|| box drop_forget_ref::DropForgetRef); @@ -1017,6 +1027,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| box reference::DerefAddrOf); store.register_early_pass(|| box reference::RefInDeref); store.register_early_pass(|| box double_parens::DoubleParens); + store.register_late_pass(|| box to_string_in_display::ToStringInDisplay::new()); store.register_early_pass(|| box unsafe_removed_from_name::UnsafeNameRemoval); store.register_early_pass(|| box if_not_else::IfNotElse); store.register_early_pass(|| box else_if_without_else::ElseIfWithoutElse); @@ -1025,8 +1036,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| box misc_early::MiscEarlyLints); store.register_early_pass(|| box redundant_closure_call::RedundantClosureCall); store.register_late_pass(|| box redundant_closure_call::RedundantClosureCall); - store.register_early_pass(|| box returns::Return); - store.register_late_pass(|| box let_and_return::LetReturn); + store.register_early_pass(|| box unused_unit::UnusedUnit); + store.register_late_pass(|| box returns::Return); store.register_early_pass(|| box collapsible_if::CollapsibleIf); store.register_early_pass(|| box items_after_statements::ItemsAfterStatements); store.register_early_pass(|| box precedence::Precedence); @@ -1085,6 +1096,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box pattern_type_mismatch::PatternTypeMismatch); store.register_late_pass(|| box stable_sort_primitive::StableSortPrimitive); store.register_late_pass(|| box repeat_once::RepeatOnce); + store.register_late_pass(|| box unwrap_in_result::UnwrapInResult); + store.register_late_pass(|| box self_assignment::SelfAssignment); + store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1122,6 +1136,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&shadow::SHADOW_REUSE), LintId::of(&shadow::SHADOW_SAME), LintId::of(&strings::STRING_ADD), + LintId::of(&unwrap_in_result::UNWRAP_IN_RESULT), LintId::of(&verbose_file_reads::VERBOSE_FILE_READS), LintId::of(&write::PRINT_STDOUT), LintId::of(&write::USE_DEBUG), @@ -1260,6 +1275,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&eval_order_dependence::DIVERGING_SUB_EXPRESSION), LintId::of(&eval_order_dependence::EVAL_ORDER_DEPENDENCE), LintId::of(&explicit_write::EXPLICIT_WRITE), + LintId::of(&float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS), LintId::of(&float_literal::EXCESSIVE_PRECISION), LintId::of(&format::USELESS_FORMAT), LintId::of(&formatting::POSSIBLE_MISSING_COMMA), @@ -1284,7 +1300,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&large_enum_variant::LARGE_ENUM_VARIANT), LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY), LintId::of(&len_zero::LEN_ZERO), - LintId::of(&let_and_return::LET_AND_RETURN), LintId::of(&let_underscore::LET_UNDERSCORE_LOCK), LintId::of(&lifetimes::EXTRA_UNUSED_LIFETIMES), LintId::of(&lifetimes::NEEDLESS_LIFETIMES), @@ -1349,6 +1364,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::SEARCH_IS_SOME), LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT), LintId::of(&methods::SINGLE_CHAR_PATTERN), + LintId::of(&methods::SINGLE_CHAR_PUSH_STR), LintId::of(&methods::SKIP_WHILE_NEXT), LintId::of(&methods::STRING_EXTEND_CHARS), LintId::of(&methods::SUSPICIOUS_MAP), @@ -1356,6 +1372,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::UNINIT_ASSUMED_INIT), LintId::of(&methods::UNNECESSARY_FILTER_MAP), LintId::of(&methods::UNNECESSARY_FOLD), + LintId::of(&methods::UNNECESSARY_LAZY_EVALUATIONS), LintId::of(&methods::USELESS_ASREF), LintId::of(&methods::WRONG_SELF_CONVENTION), LintId::of(&methods::ZST_OFFSET), @@ -1413,8 +1430,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(®ex::INVALID_REGEX), LintId::of(®ex::TRIVIAL_REGEX), LintId::of(&repeat_once::REPEAT_ONCE), + LintId::of(&returns::LET_AND_RETURN), LintId::of(&returns::NEEDLESS_RETURN), - LintId::of(&returns::UNUSED_UNIT), + LintId::of(&self_assignment::SELF_ASSIGNMENT), LintId::of(&serde_api::SERDE_API_MISUSE), LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), @@ -1427,6 +1445,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS), LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT), LintId::of(&to_digit_is_some::TO_DIGIT_IS_SOME), + LintId::of(&to_string_in_display::TO_STRING_IN_DISPLAY), LintId::of(&transmute::CROSSPOINTER_TRANSMUTE), LintId::of(&transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS), LintId::of(&transmute::TRANSMUTE_BYTES_TO_STR), @@ -1460,6 +1479,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), 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(&unwrap::PANICKING_UNWRAP), LintId::of(&unwrap::UNNECESSARY_UNWRAP), LintId::of(&useless_conversion::USELESS_CONVERSION), @@ -1500,7 +1520,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&inherent_to_string::INHERENT_TO_STRING), LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY), LintId::of(&len_zero::LEN_ZERO), - LintId::of(&let_and_return::LET_AND_RETURN), LintId::of(&literal_representation::INCONSISTENT_DIGIT_GROUPING), LintId::of(&loops::EMPTY_LOOP), LintId::of(&loops::FOR_KV_MAP), @@ -1532,8 +1551,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::OPTION_MAP_OR_NONE), LintId::of(&methods::RESULT_MAP_OR_INTO_OPTION), LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT), + LintId::of(&methods::SINGLE_CHAR_PUSH_STR), LintId::of(&methods::STRING_EXTEND_CHARS), LintId::of(&methods::UNNECESSARY_FOLD), + LintId::of(&methods::UNNECESSARY_LAZY_EVALUATIONS), LintId::of(&methods::WRONG_SELF_CONVENTION), LintId::of(&misc::TOPLEVEL_REF_ARG), LintId::of(&misc::ZERO_PTR), @@ -1554,8 +1575,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES), LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), LintId::of(®ex::TRIVIAL_REGEX), + LintId::of(&returns::LET_AND_RETURN), LintId::of(&returns::NEEDLESS_RETURN), - LintId::of(&returns::UNUSED_UNIT), LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), LintId::of(&strings::STRING_LIT_AS_BYTES), LintId::of(&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS), @@ -1564,6 +1585,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::FN_TO_NUMERIC_CAST), LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), + LintId::of(&unused_unit::UNUSED_UNIT), LintId::of(&write::PRINTLN_EMPTY_STRING), LintId::of(&write::PRINT_LITERAL), LintId::of(&write::PRINT_WITH_NEWLINE), @@ -1672,6 +1694,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT), LintId::of(&eq_op::EQ_OP), LintId::of(&erasing_op::ERASING_OP), + LintId::of(&float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS), LintId::of(&formatting::POSSIBLE_MISSING_COMMA), LintId::of(&functions::NOT_UNSAFE_PTR_ARG_DEREF), LintId::of(&if_let_mutex::IF_LET_MUTEX), @@ -1704,10 +1727,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&ptr::MUT_FROM_REF), LintId::of(&ranges::REVERSED_EMPTY_RANGES), LintId::of(®ex::INVALID_REGEX), + LintId::of(&self_assignment::SELF_ASSIGNMENT), LintId::of(&serde_api::SERDE_API_MISUSE), LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), LintId::of(&swap::ALMOST_SWAPPED), + LintId::of(&to_string_in_display::TO_STRING_IN_DISPLAY), LintId::of(&transmute::UNSOUND_COLLECTION_TRANSMUTE), LintId::of(&transmute::WRONG_TRANSMUTE), LintId::of(&transmuting_null::TRANSMUTING_NULL), diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 8ffcd417d1df1..c95e43a943044 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1141,11 +1141,31 @@ fn detect_same_item_push<'tcx>( if same_item_push_visitor.should_lint { if let Some((vec, pushed_item)) = same_item_push_visitor.vec_push { // Make sure that the push does not involve possibly mutating values - if mutated_variables(pushed_item, cx).map_or(false, |mutvars| mutvars.is_empty()) { - if let PatKind::Wild = pat.kind { - let vec_str = snippet_with_macro_callsite(cx, vec.span, ""); - let item_str = snippet_with_macro_callsite(cx, pushed_item.span, ""); - + if let PatKind::Wild = pat.kind { + let vec_str = snippet_with_macro_callsite(cx, vec.span, ""); + let item_str = snippet_with_macro_callsite(cx, pushed_item.span, ""); + if let ExprKind::Path(ref qpath) = pushed_item.kind { + if_chain! { + if let Res::Local(hir_id) = qpath_res(cx, qpath, pushed_item.hir_id); + let node = cx.tcx.hir().get(hir_id); + if let Node::Binding(pat) = node; + if let PatKind::Binding(bind_ann, ..) = pat.kind; + if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable); + then { + span_lint_and_help( + cx, + SAME_ITEM_PUSH, + vec.span, + "it looks like the same item is being pushed into this Vec", + None, + &format!( + "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", + item_str, vec_str, item_str + ), + ) + } + } + } else if mutated_variables(pushed_item, cx).map_or(false, |mutvars| mutvars.is_empty()) { span_lint_and_help( cx, SAME_ITEM_PUSH, diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 641e6a1704324..1cd5b2012922f 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -111,8 +111,8 @@ fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) { cx, MAP_CLONE, root.trim_start(receiver).unwrap(), - "You are needlessly cloning iterator elements", - "Remove the `map` call", + "you are needlessly cloning iterator elements", + "remove the `map` call", String::new(), Applicability::MachineApplicable, ) @@ -125,8 +125,8 @@ fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) { cx, MAP_CLONE, replace, - "You are using an explicit closure for copying elements", - "Consider calling the dedicated `copied` method", + "you are using an explicit closure for copying elements", + "consider calling the dedicated `copied` method", format!( "{}.copied()", snippet_with_applicability(cx, root, "..", &mut applicability) @@ -138,8 +138,8 @@ fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) { cx, MAP_CLONE, replace, - "You are using an explicit closure for cloning elements", - "Consider calling the dedicated `cloned` method", + "you are using an explicit closure for cloning elements", + "consider calling the dedicated `cloned` method", format!( "{}.cloned()", snippet_with_applicability(cx, root, "..", &mut applicability) diff --git a/clippy_lints/src/match_on_vec_items.rs b/clippy_lints/src/match_on_vec_items.rs index faa20687ef61f..57966452253d5 100644 --- a/clippy_lints/src/match_on_vec_items.rs +++ b/clippy_lints/src/match_on_vec_items.rs @@ -1,5 +1,5 @@ -use crate::utils::{is_type_diagnostic_item, is_type_lang_item, snippet, span_lint_and_sugg}; use crate::utils::walk_ptrs_ty; +use crate::utils::{is_type_diagnostic_item, is_type_lang_item, snippet, span_lint_and_sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, MatchSource}; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 2265a1888556a..9996df69470f0 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3,6 +3,7 @@ mod inefficient_to_string; mod manual_saturating_arithmetic; mod option_map_unwrap_or; mod unnecessary_filter_map; +mod unnecessary_lazy_eval; use std::borrow::Cow; use std::fmt; @@ -14,11 +15,11 @@ use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::{TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, Ty, TyS}; +use rustc_middle::ty::{self, TraitRef, Ty, TyS}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::symbol::{sym, SymbolStr}; @@ -26,12 +27,12 @@ use rustc_span::symbol::{sym, SymbolStr}; use crate::consts::{constant, Constant}; use crate::utils::usage::mutated_variables; use crate::utils::{ - get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro, is_copy, - is_ctor_or_promotable_const_function, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, - match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls, method_chain_args, paths, - remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, - span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty, - walk_ptrs_ty_depth, SpanlessEq, + contains_ty, get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro, + is_copy, is_ctor_or_promotable_const_function, is_expn_of, is_type_diagnostic_item, iter_input_pats, + last_path_segment, match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls, + method_chain_args, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, + snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, + span_lint_and_then, sugg, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq, }; declare_clippy_lint! { @@ -723,6 +724,7 @@ declare_clippy_lint! { /// **Known problems:** None. /// /// **Example:** + /// In an impl block: /// ```rust /// # struct Foo; /// # struct NotAFoo; @@ -735,25 +737,40 @@ declare_clippy_lint! { /// /// ```rust /// # struct Foo; - /// # struct FooError; + /// struct Bar(Foo); /// impl Foo { - /// // Good. Return type contains `Self` - /// fn new() -> Result { - /// # Ok(Foo) + /// // Bad. The type name must contain `Self` + /// fn new() -> Bar { + /// # Bar(Foo) /// } /// } /// ``` /// /// ```rust /// # struct Foo; - /// struct Bar(Foo); + /// # struct FooError; /// impl Foo { - /// // Bad. The type name must contain `Self`. - /// fn new() -> Bar { - /// # Bar(Foo) + /// // Good. Return type contains `Self` + /// fn new() -> Result { + /// # Ok(Foo) /// } /// } /// ``` + /// + /// Or in a trait definition: + /// ```rust + /// pub trait Trait { + /// // Bad. The type name must contain `Self` + /// fn new(); + /// } + /// ``` + /// + /// ```rust + /// pub trait Trait { + /// // Good. Return type contains `Self` + /// fn new() -> Self; + /// } + /// ``` pub NEW_RET_NO_SELF, style, "not returning type containing `Self` in a `new` method" @@ -799,7 +816,7 @@ declare_clippy_lint! { /// call_some_ffi_func(c_str); /// } /// ``` - /// Here `c_str` point to a freed address. The correct use would be: + /// Here `c_str` points to a freed address. The correct use would be: /// ```rust /// # use std::ffi::CString; /// # fn call_some_ffi_func(_: *const i8) {} @@ -1306,6 +1323,65 @@ declare_clippy_lint! { "using `.iter().next()` on a sliced array, which can be shortened to just `.get()`" } +declare_clippy_lint! { + /// **What it does:** Warns when using push_str with a single-character string literal, + /// and push with a char would work fine. + /// + /// **Why is this bad?** It's less clear that we are pushing a single character + /// + /// **Known problems:** None + /// + /// **Example:** + /// ``` + /// let mut string = String::new(); + /// string.push_str("R"); + /// ``` + /// Could be written as + /// ``` + /// let mut string = String::new(); + /// string.push('R'); + /// ``` + pub SINGLE_CHAR_PUSH_STR, + style, + "`push_str()` used with a single-character string literal as parameter" +} + +declare_clippy_lint! { + /// **What it does:** As the counterpart to `or_fun_call`, this lint looks for unnecessary + /// lazily evaluated closures on `Option` and `Result`. + /// + /// This lint suggests changing the following functions, when eager evaluation results in + /// simpler code: + /// - `unwrap_or_else` to `unwrap_or` + /// - `and_then` to `and` + /// - `or_else` to `or` + /// - `get_or_insert_with` to `get_or_insert` + /// - `ok_or_else` to `ok_or` + /// + /// **Why is this bad?** Using eager evaluation is shorter and simpler in some cases. + /// + /// **Known problems:** It is possible, but not recommended for `Deref` and `Index` to have + /// side effects. Eagerly evaluating them can change the semantics of the program. + /// + /// **Example:** + /// + /// ```rust + /// // example code where clippy issues a warning + /// let opt: Option = None; + /// + /// opt.unwrap_or_else(|| 42); + /// ``` + /// Use instead: + /// ```rust + /// let opt: Option = None; + /// + /// opt.unwrap_or(42); + /// ``` + pub UNNECESSARY_LAZY_EVALUATIONS, + style, + "using unnecessary lazy evaluation, which can be replaced with simpler eager evaluation" +} + declare_lint_pass!(Methods => [ UNWRAP_USED, EXPECT_USED, @@ -1327,6 +1403,7 @@ declare_lint_pass!(Methods => [ INEFFICIENT_TO_STRING, NEW_RET_NO_SELF, SINGLE_CHAR_PATTERN, + SINGLE_CHAR_PUSH_STR, SEARCH_IS_SOME, TEMPORARY_CSTRING_AS_PTR, FILTER_NEXT, @@ -1354,6 +1431,7 @@ declare_lint_pass!(Methods => [ ZST_OFFSET, FILETYPE_IS_FILE, OPTION_AS_REF_DEREF, + UNNECESSARY_LAZY_EVALUATIONS, ]); impl<'tcx> LateLintPass<'tcx> for Methods { @@ -1374,13 +1452,19 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["expect", "ok"] => lint_ok_expect(cx, expr, arg_lists[1]), ["expect", ..] => lint_expect(cx, expr, arg_lists[0]), ["unwrap_or", "map"] => option_map_unwrap_or::lint(cx, expr, arg_lists[1], arg_lists[0], method_spans[1]), - ["unwrap_or_else", "map"] => lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0]), + ["unwrap_or_else", "map"] => { + if !lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0]) { + unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "unwrap_or"); + } + }, ["map_or", ..] => lint_map_or_none(cx, expr, arg_lists[0]), ["and_then", ..] => { + unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], false, "and"); bind_instead_of_map::OptionAndThenSome::lint(cx, expr, arg_lists[0]); bind_instead_of_map::ResultAndThenOk::lint(cx, expr, arg_lists[0]); }, ["or_else", ..] => { + unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], false, "or"); bind_instead_of_map::ResultOrElseErrInfo::lint(cx, expr, arg_lists[0]); }, ["next", "filter"] => lint_filter_next(cx, expr, arg_lists[1]), @@ -1424,6 +1508,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["is_file", ..] => lint_filetype_is_file(cx, expr, arg_lists[0]), ["map", "as_ref"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], false), ["map", "as_mut"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true), + ["unwrap_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "unwrap_or"), + ["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "get_or_insert"), + ["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "ok_or"), _ => {}, } @@ -1441,6 +1528,12 @@ impl<'tcx> LateLintPass<'tcx> for Methods { inefficient_to_string::lint(cx, expr, &args[0], self_ty); } + if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { + if match_def_path(cx, fn_def_id, &paths::PUSH_STR) { + lint_single_char_push_string(cx, expr, args); + } + } + match self_ty.kind { ty::Ref(_, ty, _) if ty.kind == ty::Str => { for &(method, pos) in &PATTERN_METHODS { @@ -1470,6 +1563,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } } + #[allow(clippy::too_many_lines)] fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) { if in_external_macro(cx.sess(), impl_item.span) { return; @@ -1495,16 +1589,31 @@ impl<'tcx> LateLintPass<'tcx> for Methods { then { if cx.access_levels.is_exported(impl_item.hir_id) { - // check missing trait implementations - for &(method_name, n_args, fn_header, self_kind, out_type, trait_name) in &TRAIT_METHODS { - if name == method_name && - sig.decl.inputs.len() == n_args && - out_type.matches(cx, &sig.decl.output) && - self_kind.matches(cx, self_ty, first_arg_ty) && - fn_header_equals(*fn_header, sig.header) { - span_lint(cx, SHOULD_IMPLEMENT_TRAIT, impl_item.span, &format!( - "defining a method called `{}` on this type; consider implementing \ - the `{}` trait or choosing a less ambiguous name", name, trait_name)); + // check missing trait implementations + for method_config in &TRAIT_METHODS { + if name == method_config.method_name && + sig.decl.inputs.len() == method_config.param_count && + method_config.output_type.matches(cx, &sig.decl.output) && + method_config.self_kind.matches(cx, self_ty, first_arg_ty) && + fn_header_equals(method_config.fn_header, sig.header) && + method_config.lifetime_param_cond(&impl_item) + { + span_lint_and_help( + cx, + SHOULD_IMPLEMENT_TRAIT, + impl_item.span, + &format!( + "method `{}` can be confused for the standard trait method `{}::{}`", + method_config.method_name, + method_config.trait_name, + method_config.method_name + ), + None, + &format!( + "consider implementing the trait `{}` or choosing a less ambiguous method name", + method_config.trait_name + ) + ); } } } @@ -1538,19 +1647,16 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } } + // if this impl block implements a trait, lint in trait definition instead + if let hir::ItemKind::Impl { of_trait: Some(_), .. } = item.kind { + return; + } + if let hir::ImplItemKind::Fn(_, _) = impl_item.kind { let ret_ty = return_ty(cx, impl_item.hir_id); - let contains_self_ty = |ty: Ty<'tcx>| { - ty.walk().any(|inner| match inner.unpack() { - GenericArgKind::Type(inner_ty) => TyS::same_type(self_ty, inner_ty), - - GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, - }) - }; - // walk the return type and check for Self (this does not check associated types) - if contains_self_ty(ret_ty) { + if contains_ty(ret_ty, self_ty) { return; } @@ -1560,7 +1666,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { for &(predicate, _span) in cx.tcx.predicates_of(def_id).predicates { if let ty::PredicateAtom::Projection(projection_predicate) = predicate.skip_binders() { // walk the associated type and check for Self - if contains_self_ty(projection_predicate.ty) { + if contains_ty(projection_predicate.ty, self_ty) { return; } } @@ -1577,6 +1683,26 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } } } + + fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { + if_chain! { + if !in_external_macro(cx.tcx.sess, item.span); + if item.ident.name == sym!(new); + if let TraitItemKind::Fn(_, _) = item.kind; + let ret_ty = return_ty(cx, item.hir_id); + let self_ty = TraitRef::identity(cx.tcx, item.hir_id.owner.to_def_id()).self_ty(); + if !contains_ty(ret_ty, self_ty); + + then { + span_lint( + cx, + NEW_RET_NO_SELF, + item.span, + "methods called `new` usually return `Self`", + ); + } + } + } } /// Checks for the `OR_FUN_CALL` lint. @@ -2057,18 +2183,15 @@ fn lint_clone_on_ref_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir:: return; }; + let snippet = snippet_with_macro_callsite(cx, arg.span, "_"); + span_lint_and_sugg( cx, CLONE_ON_REF_PTR, expr.span, "using `.clone()` on a ref-counted pointer", "try this", - format!( - "{}::<{}>::clone(&{})", - caller_type, - subst.type_at(0), - snippet(cx, arg.span, "_") - ), + format!("{}::<{}>::clone(&{})", caller_type, subst.type_at(0), snippet), Applicability::Unspecified, // Sometimes unnecessary ::<_> after Rc/Arc/Weak ); } @@ -2280,7 +2403,7 @@ fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_ cx, ITER_NEXT_SLICE, expr.span, - "Using `.iter().next()` on a Slice without end index.", + "using `.iter().next()` on a Slice without end index", "try calling", format!("{}.get({})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability), start_idx), applicability, @@ -2299,7 +2422,7 @@ fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_ cx, ITER_NEXT_SLICE, expr.span, - "Using `.iter().next()` on an array", + "using `.iter().next()` on an array", "try calling", format!( "{}.get(0)", @@ -2618,12 +2741,13 @@ fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map } /// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s +/// Return true if lint triggered fn lint_map_unwrap_or_else<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_args: &'tcx [hir::Expr<'_>], unwrap_args: &'tcx [hir::Expr<'_>], -) { +) -> bool { // lint if the caller of `map()` is an `Option` let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(option_type)); let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(result_type)); @@ -2635,10 +2759,10 @@ fn lint_map_unwrap_or_else<'tcx>( let unwrap_mutated_vars = mutated_variables(&unwrap_args[1], cx); if let (Some(map_mutated_vars), Some(unwrap_mutated_vars)) = (map_mutated_vars, unwrap_mutated_vars) { if map_mutated_vars.intersection(&unwrap_mutated_vars).next().is_some() { - return; + return false; } } else { - return; + return false; } // lint message @@ -2668,10 +2792,14 @@ fn lint_map_unwrap_or_else<'tcx>( map_snippet, unwrap_snippet, ), ); + return true; } else if same_span && multiline { span_lint(cx, MAP_UNWRAP_OR, expr.span, msg); - }; + return true; + } } + + false } /// lint use of `_.map_or(None, _)` for `Option`s and `Result`s @@ -3124,15 +3252,18 @@ fn lint_chars_last_cmp_with_unwrap<'tcx>(cx: &LateContext<'tcx>, info: &BinaryEx } } -/// lint for length-1 `str`s for methods in `PATTERN_METHODS` -fn lint_single_char_pattern<'tcx>(cx: &LateContext<'tcx>, _expr: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>) { +fn get_hint_if_single_char_arg( + cx: &LateContext<'_>, + arg: &hir::Expr<'_>, + applicability: &mut Applicability, +) -> Option { if_chain! { if let hir::ExprKind::Lit(lit) = &arg.kind; if let ast::LitKind::Str(r, style) = lit.node; - if r.as_str().len() == 1; + let string = r.as_str(); + if string.len() == 1; then { - let mut applicability = Applicability::MachineApplicable; - let snip = snippet_with_applicability(cx, arg.span, "..", &mut applicability); + let snip = snippet_with_applicability(cx, arg.span, &string, applicability); let ch = if let ast::StrStyle::Raw(nhash) = style { let nhash = nhash as usize; // for raw string: r##"a"## @@ -3142,19 +3273,47 @@ fn lint_single_char_pattern<'tcx>(cx: &LateContext<'tcx>, _expr: &'tcx hir::Expr &snip[1..(snip.len() - 1)] }; let hint = format!("'{}'", if ch == "'" { "\\'" } else { ch }); - span_lint_and_sugg( - cx, - SINGLE_CHAR_PATTERN, - arg.span, - "single-character string constant used as pattern", - "try using a `char` instead", - hint, - applicability, - ); + Some(hint) + } else { + None } } } +/// lint for length-1 `str`s for methods in `PATTERN_METHODS` +fn lint_single_char_pattern(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) { + let mut applicability = Applicability::MachineApplicable; + if let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability) { + span_lint_and_sugg( + cx, + SINGLE_CHAR_PATTERN, + arg.span, + "single-character string constant used as pattern", + "try using a `char` instead", + hint, + applicability, + ); + } +} + +/// lint for length-1 `str`s as argument for `push_str` +fn lint_single_char_push_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { + let mut applicability = Applicability::MachineApplicable; + if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) { + let base_string_snippet = snippet_with_applicability(cx, args[0].span, "_", &mut applicability); + let sugg = format!("{}.push({})", base_string_snippet, extension_string); + span_lint_and_sugg( + cx, + SINGLE_CHAR_PUSH_STR, + expr.span, + "calling `push_str()` using a single-character string literal", + "consider using `push` with a character literal", + sugg, + applicability, + ); + } +} + /// Checks for the `USELESS_ASREF` lint. fn lint_asref(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_ref_args: &[hir::Expr<'_>]) { // when we get here, we've already checked that the call name is "as_ref" or "as_mut" @@ -3292,7 +3451,12 @@ fn lint_option_as_ref_deref<'tcx>( ]; let is_deref = match map_args[1].kind { - hir::ExprKind::Path(ref expr_qpath) => deref_aliases.iter().any(|path| match_qpath(expr_qpath, path)), + hir::ExprKind::Path(ref expr_qpath) => cx + .qpath_res(expr_qpath, map_args[1].hir_id) + .opt_def_id() + .map_or(false, |fun_def_id| { + deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path)) + }), hir::ExprKind::Closure(_, _, body_id, _, _) => { let closure_body = cx.tcx.hir().body(body_id); let closure_expr = remove_blocks(&closure_body.value); @@ -3403,38 +3567,85 @@ const FN_HEADER: hir::FnHeader = hir::FnHeader { abi: rustc_target::spec::abi::Abi::Rust, }; +struct ShouldImplTraitCase { + trait_name: &'static str, + method_name: &'static str, + param_count: usize, + fn_header: hir::FnHeader, + // implicit self kind expected (none, self, &self, ...) + self_kind: SelfKind, + // checks against the output type + output_type: OutType, + // certain methods with explicit lifetimes can't implement the equivalent trait method + lint_explicit_lifetime: bool, +} +impl ShouldImplTraitCase { + const fn new( + trait_name: &'static str, + method_name: &'static str, + param_count: usize, + fn_header: hir::FnHeader, + self_kind: SelfKind, + output_type: OutType, + lint_explicit_lifetime: bool, + ) -> ShouldImplTraitCase { + ShouldImplTraitCase { + trait_name, + method_name, + param_count, + fn_header, + self_kind, + output_type, + lint_explicit_lifetime, + } + } + + fn lifetime_param_cond(&self, impl_item: &hir::ImplItem<'_>) -> bool { + self.lint_explicit_lifetime + || !impl_item.generics.params.iter().any(|p| { + matches!( + p.kind, + hir::GenericParamKind::Lifetime { + kind: hir::LifetimeParamKind::Explicit + } + ) + }) + } +} + #[rustfmt::skip] -const TRAIT_METHODS: [(&str, usize, &hir::FnHeader, SelfKind, OutType, &str); 30] = [ - ("add", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Add"), - ("as_mut", 1, &FN_HEADER, SelfKind::RefMut, OutType::Ref, "std::convert::AsMut"), - ("as_ref", 1, &FN_HEADER, SelfKind::Ref, OutType::Ref, "std::convert::AsRef"), - ("bitand", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::BitAnd"), - ("bitor", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::BitOr"), - ("bitxor", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::BitXor"), - ("borrow", 1, &FN_HEADER, SelfKind::Ref, OutType::Ref, "std::borrow::Borrow"), - ("borrow_mut", 1, &FN_HEADER, SelfKind::RefMut, OutType::Ref, "std::borrow::BorrowMut"), - ("clone", 1, &FN_HEADER, SelfKind::Ref, OutType::Any, "std::clone::Clone"), - ("cmp", 2, &FN_HEADER, SelfKind::Ref, OutType::Any, "std::cmp::Ord"), - ("default", 0, &FN_HEADER, SelfKind::No, OutType::Any, "std::default::Default"), - ("deref", 1, &FN_HEADER, SelfKind::Ref, OutType::Ref, "std::ops::Deref"), - ("deref_mut", 1, &FN_HEADER, SelfKind::RefMut, OutType::Ref, "std::ops::DerefMut"), - ("div", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Div"), - ("drop", 1, &FN_HEADER, SelfKind::RefMut, OutType::Unit, "std::ops::Drop"), - ("eq", 2, &FN_HEADER, SelfKind::Ref, OutType::Bool, "std::cmp::PartialEq"), - ("from_iter", 1, &FN_HEADER, SelfKind::No, OutType::Any, "std::iter::FromIterator"), - ("from_str", 1, &FN_HEADER, SelfKind::No, OutType::Any, "std::str::FromStr"), - ("hash", 2, &FN_HEADER, SelfKind::Ref, OutType::Unit, "std::hash::Hash"), - ("index", 2, &FN_HEADER, SelfKind::Ref, OutType::Ref, "std::ops::Index"), - ("index_mut", 2, &FN_HEADER, SelfKind::RefMut, OutType::Ref, "std::ops::IndexMut"), - ("into_iter", 1, &FN_HEADER, SelfKind::Value, OutType::Any, "std::iter::IntoIterator"), - ("mul", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Mul"), - ("neg", 1, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Neg"), - ("next", 1, &FN_HEADER, SelfKind::RefMut, OutType::Any, "std::iter::Iterator"), - ("not", 1, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Not"), - ("rem", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Rem"), - ("shl", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Shl"), - ("shr", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Shr"), - ("sub", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Sub"), +const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [ + ShouldImplTraitCase::new("std::ops::Add", "add", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::convert::AsMut", "as_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), + ShouldImplTraitCase::new("std::convert::AsRef", "as_ref", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true), + ShouldImplTraitCase::new("std::ops::BitAnd", "bitand", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::BitOr", "bitor", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::BitXor", "bitxor", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::borrow::Borrow", "borrow", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true), + ShouldImplTraitCase::new("std::borrow::BorrowMut", "borrow_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), + ShouldImplTraitCase::new("std::clone::Clone", "clone", 1, FN_HEADER, SelfKind::Ref, OutType::Any, true), + ShouldImplTraitCase::new("std::cmp::Ord", "cmp", 2, FN_HEADER, SelfKind::Ref, OutType::Any, true), + // FIXME: default doesn't work + ShouldImplTraitCase::new("std::default::Default", "default", 0, FN_HEADER, SelfKind::No, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Deref", "deref", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true), + ShouldImplTraitCase::new("std::ops::DerefMut", "deref_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), + ShouldImplTraitCase::new("std::ops::Div", "div", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Drop", "drop", 1, FN_HEADER, SelfKind::RefMut, OutType::Unit, true), + ShouldImplTraitCase::new("std::cmp::PartialEq", "eq", 2, FN_HEADER, SelfKind::Ref, OutType::Bool, true), + ShouldImplTraitCase::new("std::iter::FromIterator", "from_iter", 1, FN_HEADER, SelfKind::No, OutType::Any, true), + ShouldImplTraitCase::new("std::str::FromStr", "from_str", 1, FN_HEADER, SelfKind::No, OutType::Any, true), + ShouldImplTraitCase::new("std::hash::Hash", "hash", 2, FN_HEADER, SelfKind::Ref, OutType::Unit, true), + ShouldImplTraitCase::new("std::ops::Index", "index", 2, FN_HEADER, SelfKind::Ref, OutType::Ref, true), + ShouldImplTraitCase::new("std::ops::IndexMut", "index_mut", 2, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), + ShouldImplTraitCase::new("std::iter::IntoIterator", "into_iter", 1, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Mul", "mul", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Neg", "neg", 1, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::iter::Iterator", "next", 1, FN_HEADER, SelfKind::RefMut, OutType::Any, false), + ShouldImplTraitCase::new("std::ops::Not", "not", 1, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Rem", "rem", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Shl", "shl", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Shr", "shr", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Sub", "sub", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), ]; #[rustfmt::skip] diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs new file mode 100644 index 0000000000000..31517659c34dc --- /dev/null +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -0,0 +1,111 @@ +use crate::utils::{is_type_diagnostic_item, match_qpath, snippet, span_lint_and_sugg}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; + +use super::UNNECESSARY_LAZY_EVALUATIONS; + +// Return true if the expression is an accessor of any of the arguments +fn expr_uses_argument(expr: &hir::Expr<'_>, params: &[hir::Param<'_>]) -> bool { + params.iter().any(|arg| { + if_chain! { + if let hir::PatKind::Binding(_, _, ident, _) = arg.pat.kind; + if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = expr.kind; + if let [p, ..] = path.segments; + then { + ident.name == p.ident.name + } else { + false + } + } + }) +} + +fn match_any_qpath(path: &hir::QPath<'_>, paths: &[&[&str]]) -> bool { + paths.iter().any(|candidate| match_qpath(path, candidate)) +} + +fn can_simplify(expr: &hir::Expr<'_>, params: &[hir::Param<'_>], variant_calls: bool) -> bool { + match expr.kind { + // Closures returning literals can be unconditionally simplified + hir::ExprKind::Lit(_) => true, + + hir::ExprKind::Index(ref object, ref index) => { + // arguments are not being indexed into + if expr_uses_argument(object, params) { + false + } else { + // arguments are not used as index + !expr_uses_argument(index, params) + } + }, + + // Reading fields can be simplified if the object is not an argument of the closure + hir::ExprKind::Field(ref object, _) => !expr_uses_argument(object, params), + + // Paths can be simplified if the root is not the argument, this also covers None + hir::ExprKind::Path(_) => !expr_uses_argument(expr, params), + + // Calls to Some, Ok, Err can be considered literals if they don't derive an argument + hir::ExprKind::Call(ref func, ref args) => if_chain! { + if variant_calls; // Disable lint when rules conflict with bind_instead_of_map + if let hir::ExprKind::Path(ref path) = func.kind; + if match_any_qpath(path, &[&["Some"], &["Ok"], &["Err"]]); + then { + // Recursively check all arguments + args.iter().all(|arg| can_simplify(arg, params, variant_calls)) + } else { + false + } + }, + + // For anything more complex than the above, a closure is probably the right solution, + // or the case is handled by an other lint + _ => false, + } +} + +/// lint use of `_else(simple closure)` for `Option`s and `Result`s that can be +/// replaced with `(return value of simple closure)` +pub(super) fn lint<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + args: &'tcx [hir::Expr<'_>], + allow_variant_calls: bool, + simplify_using: &str, +) { + let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym!(option_type)); + let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym!(result_type)); + + if is_option || is_result { + if let hir::ExprKind::Closure(_, _, eid, _, _) = args[1].kind { + let body = cx.tcx.hir().body(eid); + let ex = &body.value; + let params = &body.params; + + if can_simplify(ex, params, allow_variant_calls) { + let msg = if is_option { + "unnecessary closure used to substitute value for `Option::None`" + } else { + "unnecessary closure used to substitute value for `Result::Err`" + }; + + span_lint_and_sugg( + cx, + UNNECESSARY_LAZY_EVALUATIONS, + expr.span, + msg, + &format!("Use `{}` instead", simplify_using), + format!( + "{0}.{1}({2})", + snippet(cx, args[0].span, ".."), + simplify_using, + snippet(cx, ex.span, ".."), + ), + Applicability::MachineApplicable, + ); + } + } + } +} diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 482a563572db2..06f367a8b775f 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -433,8 +433,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { return; } let binding = match expr.kind { - ExprKind::Path(hir::QPath::LangItem(..)) => None, - ExprKind::Path(ref qpath) => { + ExprKind::Path(ref qpath) if !matches!(qpath, hir::QPath::LangItem(..)) => { let binding = last_path_segment(qpath).ident.as_str(); if binding.starts_with('_') && !binding.starts_with("__") && diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index b8dc508163297..c506440ed7987 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -9,8 +9,8 @@ declare_clippy_lint! { /// **What it does:** Detects passing a mutable reference to a function that only /// requires an immutable reference. /// - /// **Why is this bad?** The immutable reference rules out all other references - /// to the value. Also the code misleads about the intent of the call site. + /// **Why is this bad?** The mutable reference rules out all other references to + /// the value. Also the code misleads about the intent of the call site. /// /// **Known problems:** None. /// @@ -39,6 +39,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed { arguments, cx.typeck_results().expr_ty(fn_expr), &rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)), + "function", ); } }, @@ -46,14 +47,20 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed { let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap(); let substs = cx.typeck_results().node_substs(e.hir_id); let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs); - check_arguments(cx, arguments, method_type, &path.ident.as_str()) + check_arguments(cx, arguments, method_type, &path.ident.as_str(), "method") }, _ => (), } } } -fn check_arguments<'tcx>(cx: &LateContext<'tcx>, arguments: &[Expr<'_>], type_definition: Ty<'tcx>, name: &str) { +fn check_arguments<'tcx>( + cx: &LateContext<'tcx>, + arguments: &[Expr<'_>], + type_definition: Ty<'tcx>, + name: &str, + fn_kind: &str, +) { match type_definition.kind { ty::FnDef(..) | ty::FnPtr(_) => { let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs(); @@ -68,7 +75,7 @@ fn check_arguments<'tcx>(cx: &LateContext<'tcx>, arguments: &[Expr<'_>], type_de cx, UNNECESSARY_MUT_PASSED, argument.span, - &format!("The function/method `{}` doesn't need a mutable reference", name), + &format!("the {} `{}` doesn't need a mutable reference", fn_kind, name), ); } }, diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 568898aa5c9b7..21efee7126986 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -72,8 +72,8 @@ impl<'tcx> LateLintPass<'tcx> for Mutex { let mutex_param = subst.type_at(0); if let Some(atomic_name) = get_atomic_name(mutex_param) { let msg = format!( - "Consider using an `{}` instead of a `Mutex` here. If you just want the locking \ - behavior and not the internal type, consider using `Mutex<()>`.", + "consider using an `{}` instead of a `Mutex` here; if you just want the locking \ + behavior and not the internal type, consider using `Mutex<()>`", atomic_name ); match mutex_param.kind { diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 031d69e86a13e..f1df634701dd2 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -211,8 +211,21 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { needs_check_adjustment = false; }, ExprKind::Field(..) => { - dereferenced_expr = parent_expr; needs_check_adjustment = true; + + // Check whether implicit dereferences happened; + // if so, no need to go further up + // because of the same reason as the `ExprKind::Unary` case. + if cx + .typeck_results() + .expr_adjustments(dereferenced_expr) + .iter() + .any(|adj| matches!(adj.kind, Adjust::Deref(_))) + { + break; + } + + dereferenced_expr = parent_expr; }, ExprKind::Index(e, _) if ptr::eq(&**e, cur_expr) => { // `e[i]` => desugared to `*Index::index(&e, i)`, diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index 4797771e7bdbb..c9d18c3cb7287 100644 --- a/clippy_lints/src/precedence.rs +++ b/clippy_lints/src/precedence.rs @@ -1,4 +1,5 @@ use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; +use if_chain::if_chain; use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind, UnOp}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; @@ -102,36 +103,36 @@ impl EarlyLintPass for Precedence { } } - if let ExprKind::Unary(UnOp::Neg, ref rhs) = expr.kind { - if let ExprKind::MethodCall(ref path_segment, ref args, _) = rhs.kind { + if let ExprKind::Unary(UnOp::Neg, operand) = &expr.kind { + let mut arg = operand; + + let mut all_odd = true; + while let ExprKind::MethodCall(path_segment, args, _) = &arg.kind { let path_segment_str = path_segment.ident.name.as_str(); - if let Some(slf) = args.first() { - if let ExprKind::Lit(ref lit) = slf.kind { - match lit.kind { - LitKind::Int(..) | LitKind::Float(..) => { - if ALLOWED_ODD_FUNCTIONS - .iter() - .any(|odd_function| **odd_function == *path_segment_str) - { - return; - } - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - PRECEDENCE, - expr.span, - "unary minus has lower precedence than method call", - "consider adding parentheses to clarify your intent", - format!( - "-({})", - snippet_with_applicability(cx, rhs.span, "..", &mut applicability) - ), - applicability, - ); - }, - _ => (), - } - } + all_odd &= ALLOWED_ODD_FUNCTIONS + .iter() + .any(|odd_function| **odd_function == *path_segment_str); + arg = args.first().expect("A method always has a receiver."); + } + + if_chain! { + if !all_odd; + if let ExprKind::Lit(lit) = &arg.kind; + if let LitKind::Int(..) | LitKind::Float(..) = &lit.kind; + then { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + PRECEDENCE, + expr.span, + "unary minus has lower precedence than method call", + "consider adding parentheses to clarify your intent", + format!( + "-({})", + snippet_with_applicability(cx, operand.span, "..", &mut applicability) + ), + applicability, + ); } } } diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 460d631fab0fd..7dafb1555dc6e 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -36,14 +36,27 @@ declare_clippy_lint! { /// argument may also fail to compile if you change the argument. Applying /// this lint on them will fix the problem, but they may be in other crates. /// + /// One notable example of a function that may cause issues, and which cannot + /// easily be changed due to being in the standard library is `Vec::contains`. + /// when called on a `Vec>`. If a `&Vec` is passed to that method then + /// it will compile, but if a `&[T]` is passed then it will not compile. + /// + /// ```ignore + /// fn cannot_take_a_slice(v: &Vec) -> bool { + /// let vec_of_vecs: Vec> = some_other_fn(); + /// + /// vec_of_vecs.contains(v) + /// } + /// ``` + /// /// Also there may be `fn(&Vec)`-typed references pointing to your function. /// If you have them, you will get a compiler error after applying this lint's /// suggestions. You then have the choice to undo your changes or change the /// type of the reference. /// /// Note that if the function is part of your public interface, there may be - /// other crates referencing it you may not be aware. Carefully deprecate the - /// function before applying the lint suggestions in this case. + /// other crates referencing it, of which you may not be aware. Carefully + /// deprecate the function before applying the lint suggestions in this case. /// /// **Example:** /// ```ignore diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index fb12c565afd86..dbc676ae22408 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -7,8 +7,8 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use crate::utils::sugg::Sugg; use crate::utils::{ - higher, is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet_with_applicability, - span_lint_and_sugg, SpanlessEq, + eq_expr_value, higher, is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet_with_applicability, + span_lint_and_sugg, }; declare_clippy_lint! { @@ -65,7 +65,7 @@ impl QuestionMark { if let ExprKind::Block(block, None) = &else_.kind; if block.stmts.is_empty(); if let Some(block_expr) = &block.expr; - if SpanlessEq::new(cx).ignore_fn().eq_expr(subject, block_expr); + if eq_expr_value(cx, subject, block_expr); then { replacement = Some(format!("Some({}?)", receiver_str)); } diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index 8aa478ea2d69f..49cb2ffc4e372 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -77,7 +77,7 @@ impl EarlyLintPass for RedundantClosureCall { cx, REDUNDANT_CLOSURE_CALL, expr.span, - "try not to call a closure in the expression where it is declared.", + "try not to call a closure in the expression where it is declared", |diag| { if decl.inputs.is_empty() { let mut app = Applicability::MachineApplicable; @@ -95,12 +95,17 @@ impl EarlyLintPass for RedundantClosureCall { impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) { - fn count_closure_usage<'tcx>(block: &'tcx hir::Block<'_>, path: &'tcx hir::Path<'tcx>) -> usize { - struct ClosureUsageCount<'tcx> { + fn count_closure_usage<'a, 'tcx>( + cx: &'a LateContext<'tcx>, + block: &'tcx hir::Block<'_>, + path: &'tcx hir::Path<'tcx>, + ) -> usize { + struct ClosureUsageCount<'a, 'tcx> { + cx: &'a LateContext<'tcx>, path: &'tcx hir::Path<'tcx>, count: usize, }; - impl<'tcx> hir_visit::Visitor<'tcx> for ClosureUsageCount<'tcx> { + impl<'a, 'tcx> hir_visit::Visitor<'tcx> for ClosureUsageCount<'a, 'tcx> { type Map = Map<'tcx>; fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { @@ -117,10 +122,10 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { } fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap { - hir_visit::NestedVisitorMap::None + hir_visit::NestedVisitorMap::OnlyBodies(self.cx.tcx.hir()) } }; - let mut closure_usage_count = ClosureUsageCount { path, count: 0 }; + let mut closure_usage_count = ClosureUsageCount { cx, path, count: 0 }; closure_usage_count.visit_block(block); closure_usage_count.count } @@ -136,7 +141,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { if let hir::ExprKind::Call(ref closure, _) = call.kind; if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = closure.kind; if ident == path.segments[0].ident; - if count_closure_usage(block, path) == 1; + if count_closure_usage(cx, block, path) == 1; then { span_lint( cx, diff --git a/clippy_lints/src/repeat_once.rs b/clippy_lints/src/repeat_once.rs index 77c206002ea79..c0890018d46ab 100644 --- a/clippy_lints/src/repeat_once.rs +++ b/clippy_lints/src/repeat_once.rs @@ -39,12 +39,12 @@ declare_lint_pass!(RepeatOnce => [REPEAT_ONCE]); impl<'tcx> LateLintPass<'tcx> for RepeatOnce { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) { if_chain! { - if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind; + if let ExprKind::MethodCall(path, _, [receiver, count], _) = &expr.kind; if path.ident.name == sym!(repeat); - if let Some(Constant::Int(1)) = constant_context(cx, cx.typeck_results()).expr(&args[1]); - if !in_macro(args[0].span); + if let Some(Constant::Int(1)) = constant_context(cx, cx.typeck_results()).expr(&count); + if !in_macro(receiver.span); then { - let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0])); + let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&receiver)); if ty.is_str() { span_lint_and_sugg( cx, @@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for RepeatOnce { expr.span, "calling `repeat(1)` on str", "consider using `.to_string()` instead", - format!("{}.to_string()", snippet(cx, args[0].span, r#""...""#)), + format!("{}.to_string()", snippet(cx, receiver.span, r#""...""#)), Applicability::MachineApplicable, ); } else if ty.builtin_index().is_some() { @@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for RepeatOnce { expr.span, "calling `repeat(1)` on slice", "consider using `.to_vec()` instead", - format!("{}.to_vec()", snippet(cx, args[0].span, r#""...""#)), + format!("{}.to_vec()", snippet(cx, receiver.span, r#""...""#)), Applicability::MachineApplicable, ); } else if is_type_diagnostic_item(cx, ty, sym!(string_type)) { @@ -72,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for RepeatOnce { expr.span, "calling `repeat(1)` on a string literal", "consider using `.clone()` instead", - format!("{}.clone()", snippet(cx, args[0].span, r#""...""#)), + format!("{}.clone()", snippet(cx, receiver.span, r#""...""#)), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 8ed20995a70af..a6e4252a0c825 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -1,60 +1,67 @@ use if_chain::if_chain; -use rustc_ast::ast; -use rustc_ast::visit::FnKind; +use rustc_ast::ast::Attribute; use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_hir::intravisit::{walk_expr, FnKind, NestedVisitorMap, Visitor}; +use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, MatchSource, PatKind, StmtKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::subst::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; -use rustc_span::BytePos; -use crate::utils::{snippet_opt, span_lint_and_sugg, span_lint_and_then}; +use crate::utils::{fn_def_id, in_macro, match_qpath, snippet_opt, span_lint_and_sugg, span_lint_and_then}; declare_clippy_lint! { - /// **What it does:** Checks for return statements at the end of a block. + /// **What it does:** Checks for `let`-bindings, which are subsequently + /// returned. /// - /// **Why is this bad?** Removing the `return` and semicolon will make the code + /// **Why is this bad?** It is just extraneous code. Remove it to make your code /// more rusty. /// - /// **Known problems:** If the computation returning the value borrows a local - /// variable, removing the `return` may run afoul of the borrow checker. + /// **Known problems:** None. /// /// **Example:** /// ```rust - /// fn foo(x: usize) -> usize { - /// return x; + /// fn foo() -> String { + /// let x = String::new(); + /// x /// } /// ``` - /// simplify to - /// ```rust - /// fn foo(x: usize) -> usize { - /// x + /// instead, use + /// ``` + /// fn foo() -> String { + /// String::new() /// } /// ``` - pub NEEDLESS_RETURN, + pub LET_AND_RETURN, style, - "using a return statement like `return expr;` where an expression would suffice" + "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block" } declare_clippy_lint! { - /// **What it does:** Checks for unit (`()`) expressions that can be removed. + /// **What it does:** Checks for return statements at the end of a block. /// - /// **Why is this bad?** Such expressions add no value, but can make the code - /// less readable. Depending on formatting they can make a `break` or `return` - /// statement look like a function call. + /// **Why is this bad?** Removing the `return` and semicolon will make the code + /// more rusty. /// - /// **Known problems:** The lint currently misses unit return types in types, - /// e.g., the `F` in `fn generic_unit ()>(f: F) { .. }`. + /// **Known problems:** None. /// /// **Example:** /// ```rust - /// fn return_unit() -> () { - /// () + /// fn foo(x: usize) -> usize { + /// return x; /// } /// ``` - pub UNUSED_UNIT, + /// simplify to + /// ```rust + /// fn foo(x: usize) -> usize { + /// x + /// } + /// ``` + pub NEEDLESS_RETURN, style, - "needless unit expression" + "using a return statement like `return expr;` where an expression would suffice" } #[derive(PartialEq, Eq, Copy, Clone)] @@ -63,221 +70,220 @@ enum RetReplacement { Block, } -declare_lint_pass!(Return => [NEEDLESS_RETURN, UNUSED_UNIT]); +declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN]); -impl Return { - // Check the final stmt or expr in a block for unnecessary return. - fn check_block_return(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) { - if let Some(stmt) = block.stmts.last() { - match stmt.kind { - ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => { - self.check_final_expr(cx, expr, Some(stmt.span), RetReplacement::Empty); - }, - _ => (), +impl<'tcx> LateLintPass<'tcx> for Return { + fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) { + // we need both a let-binding stmt and an expr + if_chain! { + if let Some(retexpr) = block.expr; + if let Some(stmt) = block.stmts.iter().last(); + if let StmtKind::Local(local) = &stmt.kind; + if local.ty.is_none(); + if local.attrs.is_empty(); + if let Some(initexpr) = &local.init; + if let PatKind::Binding(.., ident, _) = local.pat.kind; + if let ExprKind::Path(qpath) = &retexpr.kind; + if match_qpath(qpath, &[&*ident.name.as_str()]); + if !last_statement_borrows(cx, initexpr); + if !in_external_macro(cx.sess(), initexpr.span); + if !in_external_macro(cx.sess(), retexpr.span); + if !in_external_macro(cx.sess(), local.span); + if !in_macro(local.span); + then { + span_lint_and_then( + cx, + LET_AND_RETURN, + retexpr.span, + "returning the result of a `let` binding from a block", + |err| { + err.span_label(local.span, "unnecessary `let` binding"); + + if let Some(mut snippet) = snippet_opt(cx, initexpr.span) { + if !cx.typeck_results().expr_adjustments(&retexpr).is_empty() { + snippet.push_str(" as _"); + } + err.multipart_suggestion( + "return the expression directly", + vec![ + (local.span, String::new()), + (retexpr.span, snippet), + ], + Applicability::MachineApplicable, + ); + } else { + err.span_help(initexpr.span, "this expression can be directly returned"); + } + }, + ); } } } - // Check the final expression in a block if it's a return. - fn check_final_expr( + fn check_fn( &mut self, - cx: &EarlyContext<'_>, - expr: &ast::Expr, - span: Option, - replacement: RetReplacement, + cx: &LateContext<'tcx>, + kind: FnKind<'tcx>, + _: &'tcx FnDecl<'tcx>, + body: &'tcx Body<'tcx>, + _: Span, + _: HirId, ) { - match expr.kind { - // simple return is always "bad" - ast::ExprKind::Ret(ref inner) => { - // allow `#[cfg(a)] return a; #[cfg(b)] return b;` - if !expr.attrs.iter().any(attr_is_cfg) { - Self::emit_return_lint( - cx, - span.expect("`else return` is not possible"), - inner.as_ref().map(|i| i.span), - replacement, - ); - } - }, - // a whole block? check it! - ast::ExprKind::Block(ref block, _) => { - self.check_block_return(cx, block); - }, - // an if/if let expr, check both exprs - // note, if without else is going to be a type checking error anyways - // (except for unit type functions) so we don't match it - ast::ExprKind::If(_, ref ifblock, Some(ref elsexpr)) => { - self.check_block_return(cx, ifblock); - self.check_final_expr(cx, elsexpr, None, RetReplacement::Empty); - }, - // a match expr, check all arms - ast::ExprKind::Match(_, ref arms) => { - for arm in arms { - self.check_final_expr(cx, &arm.body, Some(arm.body.span), RetReplacement::Block); + match kind { + FnKind::Closure(_) => check_final_expr(cx, &body.value, Some(body.value.span), RetReplacement::Empty), + FnKind::ItemFn(..) | FnKind::Method(..) => { + if let ExprKind::Block(ref block, _) = body.value.kind { + check_block_return(cx, block); } }, - _ => (), } } +} - fn emit_return_lint(cx: &EarlyContext<'_>, ret_span: Span, inner_span: Option, replacement: RetReplacement) { - match inner_span { - Some(inner_span) => { - if in_external_macro(cx.sess(), inner_span) || inner_span.from_expansion() { - return; - } +fn attr_is_cfg(attr: &Attribute) -> bool { + attr.meta_item_list().is_some() && attr.has_name(sym!(cfg)) +} - span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded `return` statement", |diag| { - if let Some(snippet) = snippet_opt(cx, inner_span) { - diag.span_suggestion(ret_span, "remove `return`", snippet, Applicability::MachineApplicable); - } - }) +fn check_block_return<'tcx>(cx: &LateContext<'tcx>, block: &Block<'tcx>) { + if let Some(expr) = block.expr { + check_final_expr(cx, expr, Some(expr.span), RetReplacement::Empty); + } else if let Some(stmt) = block.stmts.iter().last() { + match stmt.kind { + StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => { + check_final_expr(cx, expr, Some(stmt.span), RetReplacement::Empty); }, - None => match replacement { - RetReplacement::Empty => { - span_lint_and_sugg( - cx, - NEEDLESS_RETURN, - ret_span, - "unneeded `return` statement", - "remove `return`", - String::new(), - Applicability::MachineApplicable, - ); - }, - RetReplacement::Block => { - span_lint_and_sugg( + _ => (), + } + } +} + +fn check_final_expr<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + span: Option, + replacement: RetReplacement, +) { + match expr.kind { + // simple return is always "bad" + ExprKind::Ret(ref inner) => { + // allow `#[cfg(a)] return a; #[cfg(b)] return b;` + if !expr.attrs.iter().any(attr_is_cfg) { + let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner)); + if !borrows { + emit_return_lint( cx, - NEEDLESS_RETURN, - ret_span, - "unneeded `return` statement", - "replace `return` with an empty block", - "{}".to_string(), - Applicability::MachineApplicable, + span.expect("`else return` is not possible"), + inner.as_ref().map(|i| i.span), + replacement, ); - }, + } + } + }, + // a whole block? check it! + ExprKind::Block(ref block, _) => { + check_block_return(cx, block); + }, + // a match expr, check all arms + // an if/if let expr, check both exprs + // note, if without else is going to be a type checking error anyways + // (except for unit type functions) so we don't match it + ExprKind::Match(_, ref arms, source) => match source { + MatchSource::Normal => { + for arm in arms.iter() { + check_final_expr(cx, &arm.body, Some(arm.body.span), RetReplacement::Block); + } }, - } + MatchSource::IfDesugar { + contains_else_clause: true, + } + | MatchSource::IfLetDesugar { + contains_else_clause: true, + } => { + if let ExprKind::Block(ref ifblock, _) = arms[0].body.kind { + check_block_return(cx, ifblock); + } + check_final_expr(cx, arms[1].body, None, RetReplacement::Empty); + }, + _ => (), + }, + _ => (), } } -impl EarlyLintPass for Return { - fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, span: Span, _: ast::NodeId) { - match kind { - FnKind::Fn(.., Some(block)) => self.check_block_return(cx, block), - FnKind::Closure(_, body) => self.check_final_expr(cx, body, Some(body.span), RetReplacement::Empty), - FnKind::Fn(.., None) => {}, - } - if_chain! { - if let ast::FnRetTy::Ty(ref ty) = kind.decl().output; - if let ast::TyKind::Tup(ref vals) = ty.kind; - if vals.is_empty() && !ty.span.from_expansion() && get_def(span) == get_def(ty.span); - then { - lint_unneeded_unit_return(cx, ty, span); +fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, inner_span: Option, replacement: RetReplacement) { + match inner_span { + Some(inner_span) => { + if in_external_macro(cx.tcx.sess, inner_span) || inner_span.from_expansion() { + return; } - } - } - fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) { - if_chain! { - if let Some(ref stmt) = block.stmts.last(); - if let ast::StmtKind::Expr(ref expr) = stmt.kind; - if is_unit_expr(expr) && !stmt.span.from_expansion(); - then { - let sp = expr.span; + span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded `return` statement", |diag| { + if let Some(snippet) = snippet_opt(cx, inner_span) { + diag.span_suggestion(ret_span, "remove `return`", snippet, Applicability::MachineApplicable); + } + }) + }, + None => match replacement { + RetReplacement::Empty => { span_lint_and_sugg( cx, - UNUSED_UNIT, - sp, - "unneeded unit expression", - "remove the final `()`", + NEEDLESS_RETURN, + ret_span, + "unneeded `return` statement", + "remove `return`", String::new(), Applicability::MachineApplicable, ); - } - } - } - - fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { - match e.kind { - ast::ExprKind::Ret(Some(ref expr)) | ast::ExprKind::Break(_, Some(ref expr)) => { - if is_unit_expr(expr) && !expr.span.from_expansion() { - span_lint_and_sugg( - cx, - UNUSED_UNIT, - expr.span, - "unneeded `()`", - "remove the `()`", - String::new(), - Applicability::MachineApplicable, - ); - } }, - _ => (), - } - } - - fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef, _: &ast::TraitBoundModifier) { - let segments = &poly.trait_ref.path.segments; - - if_chain! { - if segments.len() == 1; - if ["Fn", "FnMut", "FnOnce"].contains(&&*segments[0].ident.name.as_str()); - if let Some(args) = &segments[0].args; - if let ast::GenericArgs::Parenthesized(generic_args) = &**args; - if let ast::FnRetTy::Ty(ty) = &generic_args.output; - if ty.kind.is_unit(); - then { - lint_unneeded_unit_return(cx, ty, generic_args.span); - } - } + RetReplacement::Block => { + span_lint_and_sugg( + cx, + NEEDLESS_RETURN, + ret_span, + "unneeded `return` statement", + "replace `return` with an empty block", + "{}".to_string(), + Applicability::MachineApplicable, + ); + }, + }, } } -fn attr_is_cfg(attr: &ast::Attribute) -> bool { - attr.meta_item_list().is_some() && attr.has_name(sym!(cfg)) +fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { + let mut visitor = BorrowVisitor { cx, borrows: false }; + walk_expr(&mut visitor, expr); + visitor.borrows } -// get the def site -#[must_use] -fn get_def(span: Span) -> Option { - if span.from_expansion() { - Some(span.ctxt().outer_expn_data().def_site) - } else { - None - } +struct BorrowVisitor<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + borrows: bool, } -// is this expr a `()` unit? -fn is_unit_expr(expr: &ast::Expr) -> bool { - if let ast::ExprKind::Tup(ref vals) = expr.kind { - vals.is_empty() - } else { - false +impl<'tcx> Visitor<'tcx> for BorrowVisitor<'_, 'tcx> { + type Map = Map<'tcx>; + + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { + if self.borrows { + return; + } + + if let Some(def_id) = fn_def_id(self.cx, expr) { + self.borrows = self + .cx + .tcx + .fn_sig(def_id) + .output() + .skip_binder() + .walk() + .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_))); + } + + walk_expr(self, expr); } -} -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| { - ( - #[allow(clippy::cast_possible_truncation)] - ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)), - Applicability::MachineApplicable, - ) - }) - } else { - (ty.span, Applicability::MaybeIncorrect) - }; - span_lint_and_sugg( - cx, - UNUSED_UNIT, - ret_span, - "unneeded unit return type", - "remove the `-> ()`", - String::new(), - appl, - ); + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } } diff --git a/clippy_lints/src/self_assignment.rs b/clippy_lints/src/self_assignment.rs new file mode 100644 index 0000000000000..e096c9aebc122 --- /dev/null +++ b/clippy_lints/src/self_assignment.rs @@ -0,0 +1,51 @@ +use crate::utils::{eq_expr_value, snippet, span_lint}; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** Checks for explicit self-assignments. + /// + /// **Why is this bad?** Self-assignments are redundant and unlikely to be + /// intentional. + /// + /// **Known problems:** If expression contains any deref coercions or + /// indexing operations they are assumed not to have any side effects. + /// + /// **Example:** + /// + /// ```rust + /// struct Event { + /// id: usize, + /// x: i32, + /// y: i32, + /// } + /// + /// fn copy_position(a: &mut Event, b: &Event) { + /// a.x = b.x; + /// a.y = a.y; + /// } + /// ``` + pub SELF_ASSIGNMENT, + correctness, + "explicit self-assignment" +} + +declare_lint_pass!(SelfAssignment => [SELF_ASSIGNMENT]); + +impl<'tcx> LateLintPass<'tcx> for SelfAssignment { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if let ExprKind::Assign(lhs, rhs, _) = &expr.kind { + if eq_expr_value(cx, lhs, rhs) { + let lhs = snippet(cx, lhs.span, ""); + let rhs = snippet(cx, rhs.span, ""); + span_lint( + cx, + SELF_ASSIGNMENT, + expr.span, + &format!("self-assignment of `{}` to `{}`", rhs, lhs), + ); + } + } + } +} diff --git a/clippy_lints/src/stable_sort_primitive.rs b/clippy_lints/src/stable_sort_primitive.rs index cd7056620a2e0..99e4b293ac680 100644 --- a/clippy_lints/src/stable_sort_primitive.rs +++ b/clippy_lints/src/stable_sort_primitive.rs @@ -86,6 +86,7 @@ struct LintDetection { slice_name: String, method: SortingKind, method_args: String, + slice_type: String, } fn detect_stable_sort_primitive(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { @@ -93,10 +94,10 @@ fn detect_stable_sort_primitive(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option if let ExprKind::MethodCall(method_name, _, args, _) = &expr.kind; if let Some(slice) = &args.get(0); if let Some(method) = SortingKind::from_stable_name(&method_name.ident.name.as_str()); - if is_slice_of_primitives(cx, slice); + if let Some(slice_type) = is_slice_of_primitives(cx, slice); then { let args_str = args.iter().skip(1).map(|arg| Sugg::hir(cx, arg, "..").to_string()).collect::>().join(", "); - Some(LintDetection { slice_name: Sugg::hir(cx, slice, "..").to_string(), method, method_args: args_str }) + Some(LintDetection { slice_name: Sugg::hir(cx, slice, "..").to_string(), method, method_args: args_str, slice_type }) } else { None } @@ -111,9 +112,10 @@ impl LateLintPass<'_> for StableSortPrimitive { STABLE_SORT_PRIMITIVE, expr.span, format!( - "Use {} instead of {}", + "used {} instead of {} to sort primitive type `{}`", + detection.method.stable_name(), detection.method.unstable_name(), - detection.method.stable_name() + detection.slice_type, ) .as_str(), "try", diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index 4e335a0222f20..3a688a7bbef32 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -86,12 +86,20 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl { cx, expr, binop.node, - &["Add", "Sub", "Mul", "Div"], + &[ + "Add", "Sub", "Mul", "Div", "Rem", "BitAnd", "BitOr", "BitXor", "Shl", "Shr", + ], &[ hir::BinOpKind::Add, hir::BinOpKind::Sub, hir::BinOpKind::Mul, hir::BinOpKind::Div, + hir::BinOpKind::Rem, + hir::BinOpKind::BitAnd, + hir::BinOpKind::BitOr, + hir::BinOpKind::BitXor, + hir::BinOpKind::Shl, + hir::BinOpKind::Shr, ], ) { span_lint( diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 754f87e6b55e2..cc39f060fc7f3 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -1,7 +1,7 @@ use crate::utils::sugg::Sugg; use crate::utils::{ - differing_macro_contexts, is_type_diagnostic_item, snippet_with_applicability, span_lint_and_then, walk_ptrs_ty, - SpanlessEq, + differing_macro_contexts, eq_expr_value, is_type_diagnostic_item, snippet_with_applicability, span_lint_and_then, + walk_ptrs_ty, }; use if_chain::if_chain; use rustc_errors::Applicability; @@ -92,8 +92,8 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) { if rhs2.segments.len() == 1; if ident.as_str() == rhs2.segments[0].ident.as_str(); - if SpanlessEq::new(cx).ignore_fn().eq_expr(tmp_init, lhs1); - if SpanlessEq::new(cx).ignore_fn().eq_expr(rhs1, lhs2); + if eq_expr_value(cx, tmp_init, lhs1); + if eq_expr_value(cx, rhs1, lhs2); then { if let ExprKind::Field(ref lhs1, _) = lhs1.kind { if let ExprKind::Field(ref lhs2, _) = lhs2.kind { @@ -193,7 +193,7 @@ enum Slice<'a> { fn check_for_slice<'a>(cx: &LateContext<'_>, lhs1: &'a Expr<'_>, lhs2: &'a Expr<'_>) -> Slice<'a> { if let ExprKind::Index(ref lhs1, ref idx1) = lhs1.kind { if let ExprKind::Index(ref lhs2, ref idx2) = lhs2.kind { - if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs1, lhs2) { + if eq_expr_value(cx, lhs1, lhs2) { let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(lhs1)); if matches!(ty.kind, ty::Slice(_)) @@ -221,8 +221,8 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) { if !differing_macro_contexts(first.span, second.span); if let ExprKind::Assign(ref lhs0, ref rhs0, _) = first.kind; if let ExprKind::Assign(ref lhs1, ref rhs1, _) = second.kind; - if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs0, rhs1); - if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs1, rhs0); + if eq_expr_value(cx, lhs0, rhs1); + if eq_expr_value(cx, lhs1, rhs0); then { let lhs0 = Sugg::hir_opt(cx, lhs0); let rhs0 = Sugg::hir_opt(cx, rhs0); diff --git a/clippy_lints/src/to_string_in_display.rs b/clippy_lints/src/to_string_in_display.rs new file mode 100644 index 0000000000000..006d7a3a12d9a --- /dev/null +++ b/clippy_lints/src/to_string_in_display.rs @@ -0,0 +1,122 @@ +use crate::utils::{match_def_path, match_trait_method, paths, qpath_res, span_lint}; +use if_chain::if_chain; +use rustc_hir::def::Res; +use rustc_hir::{Expr, ExprKind, HirId, ImplItem, ImplItemKind, Item, ItemKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; + +declare_clippy_lint! { + /// **What it does:** Checks for uses of `to_string()` in `Display` traits. + /// + /// **Why is this bad?** Usually `to_string` is implemented indirectly + /// via `Display`. Hence using it while implementing `Display` would + /// lead to infinite recursion. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// use std::fmt; + /// + /// struct Structure(i32); + /// impl fmt::Display for Structure { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// write!(f, "{}", self.to_string()) + /// } + /// } + /// + /// ``` + /// Use instead: + /// ```rust + /// use std::fmt; + /// + /// struct Structure(i32); + /// impl fmt::Display for Structure { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// write!(f, "{}", self.0) + /// } + /// } + /// ``` + pub TO_STRING_IN_DISPLAY, + correctness, + "`to_string` method used while implementing `Display` trait" +} + +#[derive(Default)] +pub struct ToStringInDisplay { + in_display_impl: bool, + self_hir_id: Option, +} + +impl ToStringInDisplay { + pub fn new() -> Self { + Self { + in_display_impl: false, + self_hir_id: None, + } + } +} + +impl_lint_pass!(ToStringInDisplay => [TO_STRING_IN_DISPLAY]); + +impl LateLintPass<'_> for ToStringInDisplay { + fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { + if is_display_impl(cx, item) { + self.in_display_impl = true; + } + } + + fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { + if is_display_impl(cx, item) { + self.in_display_impl = false; + self.self_hir_id = None; + } + } + + fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &ImplItem<'_>) { + if_chain! { + if self.in_display_impl; + if let ImplItemKind::Fn(.., body_id) = &impl_item.kind; + let body = cx.tcx.hir().body(*body_id); + if !body.params.is_empty(); + then { + let self_param = &body.params[0]; + self.self_hir_id = Some(self_param.pat.hir_id); + } + } + } + + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + if_chain! { + if let ExprKind::MethodCall(ref path, _, args, _) = expr.kind; + if path.ident.name == sym!(to_string); + if match_trait_method(cx, expr, &paths::TO_STRING); + if self.in_display_impl; + if let ExprKind::Path(ref qpath) = args[0].kind; + if let Res::Local(hir_id) = qpath_res(cx, qpath, args[0].hir_id); + if let Some(self_hir_id) = self.self_hir_id; + if hir_id == self_hir_id; + then { + span_lint( + cx, + TO_STRING_IN_DISPLAY, + expr.span, + "using `to_string` in `fmt::Display` implementation might lead to infinite recursion", + ); + } + } + } +} + +fn is_display_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool { + if_chain! { + if let ItemKind::Impl { of_trait: Some(trait_ref), .. } = &item.kind; + if let Some(did) = trait_ref.trait_def_id(); + then { + match_def_path(cx, did, &paths::DISPLAY_TRAIT) + } else { + false + } + } +} diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index 28fd55f6ff0ad..50d9c93f9d405 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -1,5 +1,5 @@ use crate::utils::{ - is_normalizable, last_path_segment, match_def_path, paths, snippet, span_lint, span_lint_and_sugg, + in_constant, is_normalizable, last_path_segment, match_def_path, paths, snippet, span_lint, span_lint_and_sugg, span_lint_and_then, sugg, }; use if_chain::if_chain; @@ -331,6 +331,10 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::TRANSMUTE); then { + // Avoid suggesting from/to bits in const contexts. + // See https://github.com/rust-lang/rust/issues/73736 for progress on making them `const fn`. + let const_context = in_constant(cx, e.hir_id); + let from_ty = cx.typeck_results().expr_ty(&args[0]); let to_ty = cx.typeck_results().expr_ty(e); @@ -544,7 +548,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { }, ) }, - (ty::Int(_) | ty::Uint(_), ty::Float(_)) => span_lint_and_then( + (ty::Int(_) | ty::Uint(_), ty::Float(_)) if !const_context => span_lint_and_then( cx, TRANSMUTE_INT_TO_FLOAT, e.span, @@ -567,7 +571,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { ); }, ), - (ty::Float(float_ty), ty::Int(_) | ty::Uint(_)) => span_lint_and_then( + (ty::Float(float_ty), ty::Int(_) | ty::Uint(_)) if !const_context => span_lint_and_then( cx, TRANSMUTE_FLOAT_TO_INT, e.span, diff --git a/clippy_lints/src/trivially_copy_pass_by_ref.rs b/clippy_lints/src/trivially_copy_pass_by_ref.rs index 7948d99162b81..92f42168a1eab 100644 --- a/clippy_lints/src/trivially_copy_pass_by_ref.rs +++ b/clippy_lints/src/trivially_copy_pass_by_ref.rs @@ -2,6 +2,7 @@ use std::cmp; use crate::utils::{is_copy, is_self_ty, snippet, span_lint_and_sugg}; use if_chain::if_chain; +use rustc_ast::attr; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; @@ -155,8 +156,12 @@ impl<'tcx> LateLintPass<'tcx> for TriviallyCopyPassByRef { return; } for a in attrs { - if a.meta_item_list().is_some() && a.has_name(sym!(proc_macro_derive)) { - return; + if let Some(meta_items) = a.meta_item_list() { + if a.has_name(sym!(proc_macro_derive)) + || (a.has_name(sym!(inline)) && attr::list_contains_name(&meta_items, sym!(always))) + { + return; + } } } }, diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index a74104e92820a..a4676e505b6f3 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -1,10 +1,10 @@ use crate::utils::{ - is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet, - snippet_with_macro_callsite, span_lint_and_sugg, + 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; -use rustc_hir::{Expr, ExprKind, QPath, LangItem, MatchSource}; +use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 0fd70550fa0c2..7e9190bef5e78 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -353,14 +353,25 @@ impl Types { ); return; // don't recurse into the type } - if let Some(span) = match_type_parameter(cx, qpath, &paths::BOX) { + if match_type_parameter(cx, qpath, &paths::BOX).is_some() { + let box_ty = match &last_path_segment(qpath).args.unwrap().args[0] { + GenericArg::Type(ty) => match &ty.kind { + TyKind::Path(qpath) => qpath, + _ => return, + }, + _ => return, + }; + let inner_span = match &last_path_segment(&box_ty).args.unwrap().args[0] { + GenericArg::Type(ty) => ty.span, + _ => return, + }; span_lint_and_sugg( cx, REDUNDANT_ALLOCATION, hir_ty.span, "usage of `Rc>`", "try", - snippet(cx, span, "..").to_string(), + format!("Rc<{}>", snippet(cx, inner_span, "..")), Applicability::MachineApplicable, ); return; // don't recurse into the type diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index 9fe771cef45bf..7f4f16f8faf96 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -2,9 +2,9 @@ use crate::utils::ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path}; use crate::utils::{over, span_lint_and_then}; -use rustc_ast::{self as ast, Pat, PatKind, PatKind::*, DUMMY_NODE_ID}; use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; +use rustc_ast::{self as ast, Pat, PatKind, PatKind::*, DUMMY_NODE_ID}; use rustc_ast_pretty::pprust; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; @@ -340,7 +340,7 @@ fn take_pat(from: &mut Pat) -> Pat { id: DUMMY_NODE_ID, kind: Wild, span: DUMMY_SP, - tokens: None + tokens: None, }; mem::replace(from, dummy) } diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs new file mode 100644 index 0000000000000..7548c6afa973a --- /dev/null +++ b/clippy_lints/src/unused_unit.rs @@ -0,0 +1,144 @@ +use if_chain::if_chain; +use rustc_ast::ast; +use rustc_ast::visit::FnKind; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::source_map::Span; +use rustc_span::BytePos; + +use crate::utils::span_lint_and_sugg; + +declare_clippy_lint! { + /// **What it does:** Checks for unit (`()`) expressions that can be removed. + /// + /// **Why is this bad?** Such expressions add no value, but can make the code + /// less readable. Depending on formatting they can make a `break` or `return` + /// statement look like a function call. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust + /// fn return_unit() -> () { + /// () + /// } + /// ``` + pub UNUSED_UNIT, + style, + "needless unit expression" +} + +declare_lint_pass!(UnusedUnit => [UNUSED_UNIT]); + +impl EarlyLintPass for UnusedUnit { + fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, span: Span, _: ast::NodeId) { + if_chain! { + if let ast::FnRetTy::Ty(ref ty) = kind.decl().output; + if let ast::TyKind::Tup(ref vals) = ty.kind; + if vals.is_empty() && !ty.span.from_expansion() && get_def(span) == get_def(ty.span); + then { + lint_unneeded_unit_return(cx, ty, span); + } + } + } + + fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) { + if_chain! { + if let Some(ref stmt) = block.stmts.last(); + if let ast::StmtKind::Expr(ref expr) = stmt.kind; + if is_unit_expr(expr) && !stmt.span.from_expansion(); + then { + let sp = expr.span; + span_lint_and_sugg( + cx, + UNUSED_UNIT, + sp, + "unneeded unit expression", + "remove the final `()`", + String::new(), + Applicability::MachineApplicable, + ); + } + } + } + + fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { + match e.kind { + ast::ExprKind::Ret(Some(ref expr)) | ast::ExprKind::Break(_, Some(ref expr)) => { + if is_unit_expr(expr) && !expr.span.from_expansion() { + span_lint_and_sugg( + cx, + UNUSED_UNIT, + expr.span, + "unneeded `()`", + "remove the `()`", + String::new(), + Applicability::MachineApplicable, + ); + } + }, + _ => (), + } + } + + fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef, _: &ast::TraitBoundModifier) { + let segments = &poly.trait_ref.path.segments; + + if_chain! { + if segments.len() == 1; + if ["Fn", "FnMut", "FnOnce"].contains(&&*segments[0].ident.name.as_str()); + if let Some(args) = &segments[0].args; + if let ast::GenericArgs::Parenthesized(generic_args) = &**args; + if let ast::FnRetTy::Ty(ty) = &generic_args.output; + if ty.kind.is_unit(); + then { + lint_unneeded_unit_return(cx, ty, generic_args.span); + } + } + } +} + +// get the def site +#[must_use] +fn get_def(span: Span) -> Option { + if span.from_expansion() { + Some(span.ctxt().outer_expn_data().def_site) + } else { + None + } +} + +// is this expr a `()` unit? +fn is_unit_expr(expr: &ast::Expr) -> bool { + if let ast::ExprKind::Tup(ref vals) = expr.kind { + vals.is_empty() + } else { + false + } +} + +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| { + ( + #[allow(clippy::cast_possible_truncation)] + ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)), + Applicability::MachineApplicable, + ) + }) + } else { + (ty.span, Applicability::MaybeIncorrect) + }; + span_lint_and_sugg( + cx, + UNUSED_UNIT, + ret_span, + "unneeded unit return type", + "remove the `-> ()`", + String::new(), + appl, + ); +} diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs new file mode 100644 index 0000000000000..1c7e62ecd3d2c --- /dev/null +++ b/clippy_lints/src/unwrap_in_result.rs @@ -0,0 +1,140 @@ +use crate::utils::{is_type_diagnostic_item, method_chain_args, return_ty, span_lint_and_then, walk_ptrs_ty}; +use if_chain::if_chain; +use rustc_hir as hir; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::map::Map; +use rustc_middle::ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::Span; + +declare_clippy_lint! { + /// **What it does:** Checks for functions of type Result that contain `expect()` or `unwrap()` + /// + /// **Why is this bad?** These functions promote recoverable errors to non-recoverable errors which may be undesirable in code bases which wish to avoid panics. + /// + /// **Known problems:** This can cause false positives in functions that handle both recoverable and non recoverable errors. + /// + /// **Example:** + /// Before: + /// ```rust + /// fn divisible_by_3(i_str: String) -> Result<(), String> { + /// let i = i_str + /// .parse::() + /// .expect("cannot divide the input by three"); + /// + /// if i % 3 != 0 { + /// Err("Number is not divisible by 3")? + /// } + /// + /// Ok(()) + /// } + /// ``` + /// + /// After: + /// ```rust + /// fn divisible_by_3(i_str: String) -> Result<(), String> { + /// let i = i_str + /// .parse::() + /// .map_err(|e| format!("cannot divide the input by three: {}", e))?; + /// + /// if i % 3 != 0 { + /// Err("Number is not divisible by 3")? + /// } + /// + /// Ok(()) + /// } + /// ``` + pub UNWRAP_IN_RESULT, + restriction, + "functions of type `Result<..>` or `Option`<...> that contain `expect()` or `unwrap()`" +} + +declare_lint_pass!(UnwrapInResult=> [UNWRAP_IN_RESULT]); + +impl<'tcx> LateLintPass<'tcx> for UnwrapInResult { + fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) { + if_chain! { + // first check if it's a method or function + if let hir::ImplItemKind::Fn(ref _signature, _) = impl_item.kind; + // checking if its return type is `result` or `option` + if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(result_type)) + || is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(option_type)); + then { + lint_impl_body(cx, impl_item.span, impl_item); + } + } + } +} + +use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::{Expr, ImplItemKind}; + +struct FindExpectUnwrap<'a, 'tcx> { + lcx: &'a LateContext<'tcx>, + typeck_results: &'tcx ty::TypeckResults<'tcx>, + result: Vec, +} + +impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> { + type Map = Map<'tcx>; + + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { + // check for `expect` + if let Some(arglists) = method_chain_args(expr, &["expect"]) { + let reciever_ty = walk_ptrs_ty(self.typeck_results.expr_ty(&arglists[0][0])); + if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type)) + || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type)) + { + self.result.push(expr.span); + } + } + + // check for `unwrap` + if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { + let reciever_ty = walk_ptrs_ty(self.typeck_results.expr_ty(&arglists[0][0])); + if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type)) + || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type)) + { + self.result.push(expr.span); + } + } + + // and check sub-expressions + intravisit::walk_expr(self, expr); + } + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } +} + +fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tcx hir::ImplItem<'_>) { + if_chain! { + + if let ImplItemKind::Fn(_, body_id) = impl_item.kind; + then { + let body = cx.tcx.hir().body(body_id); + let impl_item_def_id = cx.tcx.hir().local_def_id(impl_item.hir_id); + let mut fpu = FindExpectUnwrap { + lcx: cx, + typeck_results: cx.tcx.typeck(impl_item_def_id), + result: Vec::new(), + }; + fpu.visit_expr(&body.value); + + // if we've found one, lint + if !fpu.result.is_empty() { + span_lint_and_then( + cx, + UNWRAP_IN_RESULT, + impl_span, + "used unwrap or expect in a function that returns result or option", + move |diag| { + diag.help( + "unwrap and expect should not be used in a function that returns result or option" ); + diag.span_note(fpu.result, "potential non-recoverable error(s)"); + }); + } + } + } +} diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 776c6bc57ca6f..427a1b6577315 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -50,7 +50,7 @@ declare_clippy_lint! { /// ``` pub USE_SELF, nursery, - "Unnecessary structure name repetition whereas `Self` is applicable" + "unnecessary structure name repetition whereas `Self` is applicable" } declare_lint_pass!(UseSelf => [USE_SELF]); diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 1bf37632e326c..4ab2b5e796deb 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -1,3 +1,4 @@ +use crate::utils::sugg::Sugg; use crate::utils::{ get_parent_expr, is_type_diagnostic_item, match_def_path, match_trait_method, paths, snippet, snippet_with_macro_callsite, span_lint_and_help, span_lint_and_sugg, @@ -158,7 +159,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if TyS::same_type(a, b); then { - let sugg = snippet(cx, args[0].span.source_callsite(), "").into_owned(); + let sugg = Sugg::hir_with_macro_callsite(cx, &args[0], "").maybe_par(); let sugg_msg = format!("consider removing `{}()`", snippet(cx, path.span, "From::from")); span_lint_and_sugg( @@ -167,7 +168,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { e.span, "useless conversion to the same type", &sugg_msg, - sugg, + sugg.to_string(), Applicability::MachineApplicable, // snippet ); } diff --git a/clippy_lints/src/utils/ast_utils.rs b/clippy_lints/src/utils/ast_utils.rs index c32c80dcd3ce6..7b419431c0f51 100644 --- a/clippy_lints/src/utils/ast_utils.rs +++ b/clippy_lints/src/utils/ast_utils.rs @@ -5,8 +5,8 @@ #![allow(clippy::similar_names, clippy::wildcard_imports, clippy::enum_glob_use)] use crate::utils::{both, over}; -use rustc_ast::{self as ast, *}; use rustc_ast::ptr::P; +use rustc_ast::{self as ast, *}; use rustc_span::symbol::Ident; use std::mem; diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 9b7a268c6287c..6eda6d1fa8340 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -175,18 +175,15 @@ impl PrintVisitor { } fn print_qpath(&mut self, path: &QPath<'_>) { - match *path { - QPath::LangItem(lang_item, _) => { - println!( - " if matches!({}, QPath::LangItem(LangItem::{:?}, _));", - self.current, lang_item, - ); - }, - _ => { - print!(" if match_qpath({}, &[", self.current); - print_path(path, &mut true); - println!("]);"); - }, + if let QPath::LangItem(lang_item, _) = *path { + println!( + " if matches!({}, QPath::LangItem(LangItem::{:?}, _));", + self.current, lang_item, + ); + } else { + print!(" if match_qpath({}, &[", self.current); + print_path(path, &mut true); + println!("]);"); } } } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index ba3492a6fff11..292dbd7ad6b48 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -138,7 +138,7 @@ define_Conf! { (type_complexity_threshold, "type_complexity_threshold": u64, 250), /// Lint: MANY_SINGLE_CHAR_NAMES. The maximum number of single char bindings a scope may have (single_char_binding_names_threshold, "single_char_binding_names_threshold": u64, 4), - /// Lint: BOXED_LOCAL. The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap + /// Lint: BOXED_LOCAL, USELESS_VEC. The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap (too_large_for_stack, "too_large_for_stack": u64, 200), /// Lint: ENUM_VARIANT_NAMES. The minimum number of enum variants for the lints about variant names to trigger (enum_variant_name_threshold, "enum_variant_name_threshold": u64, 3), diff --git a/clippy_lints/src/utils/higher.rs b/clippy_lints/src/utils/higher.rs index ba15456014d35..8563b469a30dd 100644 --- a/clippy_lints/src/utils/higher.rs +++ b/clippy_lints/src/utils/higher.rs @@ -56,43 +56,45 @@ pub fn range<'a>(expr: &'a hir::Expr<'_>) -> Option> { } match expr.kind { - hir::ExprKind::Call(ref path, ref args) if matches!( - path.kind, - hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, _)) - ) => Some(Range { - start: Some(&args[0]), - end: Some(&args[1]), - limits: ast::RangeLimits::Closed, - }), - hir::ExprKind::Struct(ref path, ref fields, None) => { - match path { - hir::QPath::LangItem(hir::LangItem::RangeFull, _) => Some(Range { - start: None, - end: None, - limits: ast::RangeLimits::HalfOpen, - }), - hir::QPath::LangItem(hir::LangItem::RangeFrom, _) => Some(Range { - start: Some(get_field("start", fields)?), - end: None, - limits: ast::RangeLimits::HalfOpen, - }), - hir::QPath::LangItem(hir::LangItem::Range, _) => Some(Range { - start: Some(get_field("start", fields)?), - end: Some(get_field("end", fields)?), - limits: ast::RangeLimits::HalfOpen, - }), - hir::QPath::LangItem(hir::LangItem::RangeToInclusive, _) => Some(Range { - start: None, - end: Some(get_field("end", fields)?), - limits: ast::RangeLimits::Closed, - }), - hir::QPath::LangItem(hir::LangItem::RangeTo, _) => Some(Range { - start: None, - end: Some(get_field("end", fields)?), - limits: ast::RangeLimits::HalfOpen, - }), - _ => None, - } + hir::ExprKind::Call(ref path, ref args) + if matches!( + path.kind, + hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, _)) + ) => + { + Some(Range { + start: Some(&args[0]), + end: Some(&args[1]), + limits: ast::RangeLimits::Closed, + }) + }, + hir::ExprKind::Struct(ref path, ref fields, None) => match path { + hir::QPath::LangItem(hir::LangItem::RangeFull, _) => Some(Range { + start: None, + end: None, + limits: ast::RangeLimits::HalfOpen, + }), + hir::QPath::LangItem(hir::LangItem::RangeFrom, _) => Some(Range { + start: Some(get_field("start", fields)?), + end: None, + limits: ast::RangeLimits::HalfOpen, + }), + hir::QPath::LangItem(hir::LangItem::Range, _) => Some(Range { + start: Some(get_field("start", fields)?), + end: Some(get_field("end", fields)?), + limits: ast::RangeLimits::HalfOpen, + }), + hir::QPath::LangItem(hir::LangItem::RangeToInclusive, _) => Some(Range { + start: None, + end: Some(get_field("end", fields)?), + limits: ast::RangeLimits::Closed, + }), + hir::QPath::LangItem(hir::LangItem::RangeTo, _) => Some(Range { + start: None, + end: Some(get_field("end", fields)?), + limits: ast::RangeLimits::HalfOpen, + }), + _ => None, }, _ => None, } diff --git a/clippy_lints/src/utils/hir_utils.rs b/clippy_lints/src/utils/hir_utils.rs index 2eefd4a38a67a..c7263f48965a5 100644 --- a/clippy_lints/src/utils/hir_utils.rs +++ b/clippy_lints/src/utils/hir_utils.rs @@ -3,9 +3,9 @@ use crate::utils::differing_macro_contexts; use rustc_ast::ast::InlineAsmTemplatePiece; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::{ - BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprKind, Field, FieldPat, - FnRetTy, GenericArg, GenericArgs, Guard, InlineAsmOperand, Lifetime, LifetimeName, ParamName, - Pat, PatKind, Path, PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding, + BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprKind, Field, FieldPat, FnRetTy, + GenericArg, GenericArgs, Guard, InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatKind, Path, + PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding, }; use rustc_lint::LateContext; use rustc_middle::ich::StableHashingContextProvider; @@ -23,9 +23,7 @@ pub struct SpanlessEq<'a, 'tcx> { /// Context used to evaluate constant expressions. cx: &'a LateContext<'tcx>, maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>, - /// If is true, never consider as equal expressions containing function - /// calls. - ignore_fn: bool, + allow_side_effects: bool, } impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { @@ -33,13 +31,14 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { Self { cx, maybe_typeck_results: cx.maybe_typeck_results(), - ignore_fn: false, + allow_side_effects: true, } } - pub fn ignore_fn(self) -> Self { + /// Consider expressions containing potential side effects as not equal. + pub fn deny_side_effects(self) -> Self { Self { - ignore_fn: true, + allow_side_effects: false, ..self } } @@ -67,7 +66,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { #[allow(clippy::similar_names)] pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool { - if self.ignore_fn && differing_macro_contexts(left.span, right.span) { + if !self.allow_side_effects && differing_macro_contexts(left.span, right.span) { return false; } @@ -90,10 +89,10 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { both(&li.label, &ri.label, |l, r| l.ident.as_str() == r.ident.as_str()) }, (&ExprKind::Assign(ref ll, ref lr, _), &ExprKind::Assign(ref rl, ref rr, _)) => { - self.eq_expr(ll, rl) && self.eq_expr(lr, rr) + self.allow_side_effects && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) }, (&ExprKind::AssignOp(ref lo, ref ll, ref lr), &ExprKind::AssignOp(ref ro, ref rl, ref rr)) => { - lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) + self.allow_side_effects && lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) }, (&ExprKind::Block(ref l, _), &ExprKind::Block(ref r, _)) => self.eq_block(l, r), (&ExprKind::Binary(l_op, ref ll, ref lr), &ExprKind::Binary(r_op, ref rl, ref rr)) => { @@ -108,7 +107,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { }, (&ExprKind::Box(ref l), &ExprKind::Box(ref r)) => self.eq_expr(l, r), (&ExprKind::Call(l_fun, l_args), &ExprKind::Call(r_fun, r_args)) => { - !self.ignore_fn && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args) + self.allow_side_effects && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args) }, (&ExprKind::Cast(ref lx, ref lt), &ExprKind::Cast(ref rx, ref rt)) | (&ExprKind::Type(ref lx, ref lt), &ExprKind::Type(ref rx, ref rt)) => { @@ -134,7 +133,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { }) }, (&ExprKind::MethodCall(l_path, _, l_args, _), &ExprKind::MethodCall(r_path, _, r_args, _)) => { - !self.ignore_fn && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args) + self.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args) }, (&ExprKind::Repeat(ref le, ref ll_id), &ExprKind::Repeat(ref re, ref rl_id)) => { let mut celcx = constant_context(self.cx, self.cx.tcx.typeck_body(ll_id.body)); @@ -186,10 +185,8 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { } pub fn eq_fieldpat(&mut self, left: &FieldPat<'_>, right: &FieldPat<'_>) -> bool { - match (&left, &right) { - (FieldPat { ident: li, pat: lp, .. }, FieldPat { ident: ri, pat: rp, .. }) => - li.name.as_str() == ri.name.as_str() && self.eq_pat(lp, rp), - } + let (FieldPat { ident: li, pat: lp, .. }, FieldPat { ident: ri, pat: rp, .. }) = (&left, &right); + li.name.as_str() == ri.name.as_str() && self.eq_pat(lp, rp) } /// Checks whether two patterns are the same. @@ -233,8 +230,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { (&QPath::TypeRelative(ref lty, ref lseg), &QPath::TypeRelative(ref rty, ref rseg)) => { self.eq_ty(lty, rty) && self.eq_path_segment(lseg, rseg) }, - (&QPath::LangItem(llang_item, _), &QPath::LangItem(rlang_item, _)) => - llang_item == rlang_item, + (&QPath::LangItem(llang_item, _), &QPath::LangItem(rlang_item, _)) => llang_item == rlang_item, _ => false, } } @@ -352,6 +348,11 @@ pub fn over(left: &[X], right: &[X], mut eq_fn: impl FnMut(&X, &X) -> bool) - left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y)) } +/// Checks if two expressions evaluate to the same value, and don't contain any side effects. +pub fn eq_expr_value(cx: &LateContext<'_>, left: &Expr<'_>, right: &Expr<'_>) -> bool { + SpanlessEq::new(cx).deny_side_effects().eq_expr(left, right) +} + /// Type used to hash an ast element. This is different from the `Hash` trait /// on ast types as this /// trait would consider IDs and spans. @@ -615,7 +616,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { }, QPath::LangItem(lang_item, ..) => { lang_item.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s); - } + }, } // self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s); } @@ -727,7 +728,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { }, QPath::LangItem(lang_item, ..) => { lang_item.hash(&mut self.s); - } + }, }, TyKind::OpaqueDef(_, arg_list) => { self.hash_generic_args(arg_list); diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 6c2356799142d..8fa5d22210a36 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -1,7 +1,6 @@ -use crate::utils::SpanlessEq; use crate::utils::{ is_expn_of, match_def_path, match_qpath, match_type, method_calls, paths, run_lints, snippet, span_lint, - span_lint_and_help, span_lint_and_sugg, walk_ptrs_ty, + span_lint_and_help, span_lint_and_sugg, walk_ptrs_ty, SpanlessEq, }; use if_chain::if_chain; use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, NodeId}; @@ -493,7 +492,7 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls { if let StmtKind::Semi(only_expr) = &stmts[0].kind; if let ExprKind::MethodCall(ref ps, _, ref span_call_args, _) = &only_expr.kind; let and_then_snippets = get_and_then_snippets(cx, and_then_args); - let mut sle = SpanlessEq::new(cx).ignore_fn(); + let mut sle = SpanlessEq::new(cx).deny_side_effects(); then { match &*ps.ident.as_str() { "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => { diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index a56b8203513e6..8200525711564 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -21,7 +21,7 @@ pub mod sugg; pub mod usage; pub use self::attrs::*; pub use self::diagnostics::*; -pub use self::hir_utils::{both, over, SpanlessEq, SpanlessHash}; +pub use self::hir_utils::{both, eq_expr_value, over, SpanlessEq, SpanlessHash}; use std::borrow::Cow; use std::mem; @@ -42,7 +42,8 @@ use rustc_hir::{ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::map::Map; -use rustc_middle::ty::{self, layout::IntegerExt, subst::GenericArg, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; +use rustc_middle::ty::{self, layout::IntegerExt, Ty, TyCtxt, TypeFoldable}; use rustc_mir::const_eval; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::original_sp; @@ -574,7 +575,7 @@ pub fn snippet_block<'a, T: LintContext>( } /// Same as `snippet_block`, but adapts the applicability level by the rules of -/// `snippet_with_applicabiliy`. +/// `snippet_with_applicability`. pub fn snippet_block_with_applicability<'a, T: LintContext>( cx: &T, span: Span, @@ -866,6 +867,14 @@ pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId) -> Ty<'tcx> cx.tcx.erase_late_bound_regions(&ret_ty) } +/// Walks into `ty` and returns `true` if any inner type is the same as `other_ty` +pub fn contains_ty(ty: Ty<'_>, other_ty: Ty<'_>) -> bool { + ty.walk().any(|inner| match inner.unpack() { + GenericArgKind::Type(inner_ty) => ty::TyS::same_type(other_ty, inner_ty), + GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, + }) +} + /// Returns `true` if the given type is an `unsafe` function. pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { match ty.kind { @@ -1304,7 +1313,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { } } -// check if expr is calling method or function with #[must_use] attribyte +// check if expr is calling method or function with #[must_use] attribute pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let did = match expr.kind { ExprKind::Call(ref path, _) => if_chain! { @@ -1409,11 +1418,13 @@ pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool { } } -/// Returns true iff the given expression is a slice of primitives (as defined in the -/// `is_recursively_primitive_type` function). -pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { +/// Returns Option where String is a textual representation of the type encapsulated in the +/// slice iff the given expression is a slice of primitives (as defined in the +/// `is_recursively_primitive_type` function) and None otherwise. +pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { let expr_type = cx.typeck_results().expr_ty_adjusted(expr); - match expr_type.kind { + let expr_kind = &expr_type.kind; + let is_primitive = match expr_kind { ty::Slice(ref element_type) | ty::Ref( _, @@ -1424,7 +1435,24 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { _, ) => is_recursively_primitive_type(element_type), _ => false, + }; + + if is_primitive { + // if we have wrappers like Array, Slice or Tuple, print these + // and get the type enclosed in the slice ref + match expr_type.peel_refs().walk().nth(1).unwrap().expect_ty().kind { + ty::Slice(..) => return Some("slice".into()), + ty::Array(..) => return Some("array".into()), + ty::Tuple(..) => return Some("tuple".into()), + _ => { + // is_recursively_primitive_type() should have taken care + // of the rest and we can rely on the type that is found + let refs_peeled = expr_type.peel_refs(); + return Some(refs_peeled.walk().last().unwrap().to_string()); + }, + } } + None } #[macro_export] diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 9c28d63d414c5..d44854aefe97a 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -35,6 +35,8 @@ pub const DROP_TRAIT: [&str; 4] = ["core", "ops", "drop", "Drop"]; pub const DURATION: [&str; 3] = ["core", "time", "Duration"]; pub const EARLY_CONTEXT: [&str; 4] = ["rustc", "lint", "context", "EarlyContext"]; pub const EXIT: [&str; 3] = ["std", "process", "exit"]; +pub const F32_EPSILON: [&str; 2] = ["f32", "EPSILON"]; +pub const F64_EPSILON: [&str; 2] = ["f64", "EPSILON"]; pub const FILE: [&str; 3] = ["std", "fs", "File"]; pub const FILE_TYPE: [&str; 3] = ["std", "fs", "FileType"]; pub const FMT_ARGUMENTS_NEW_V1: [&str; 4] = ["core", "fmt", "Arguments", "new_v1"]; @@ -84,6 +86,7 @@ pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"]; pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"]; pub const PTR_NULL: [&str; 2] = ["ptr", "null"]; pub const PTR_NULL_MUT: [&str; 2] = ["ptr", "null_mut"]; +pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"]; pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"]; pub const RC: [&str; 3] = ["alloc", "rc", "Rc"]; pub const RC_PTR_EQ: [&str; 4] = ["alloc", "rc", "Rc", "ptr_eq"]; diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index f2e76442a19ba..84e907d7125de 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -1,13 +1,20 @@ -use crate::consts::constant; +use crate::consts::{constant, Constant}; +use crate::rustc_target::abi::LayoutOf; use crate::utils::{higher, is_copy, snippet_with_applicability, span_lint_and_sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; +#[allow(clippy::module_name_repetitions)] +#[derive(Copy, Clone)] +pub struct UselessVec { + pub too_large_for_stack: u64, +} + declare_clippy_lint! { /// **What it does:** Checks for usage of `&vec![..]` when using `&[..]` would /// be possible. @@ -31,7 +38,7 @@ declare_clippy_lint! { "useless `vec!`" } -declare_lint_pass!(UselessVec => [USELESS_VEC]); +impl_lint_pass!(UselessVec => [USELESS_VEC]); impl<'tcx> LateLintPass<'tcx> for UselessVec { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { @@ -42,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { if let ExprKind::AddrOf(BorrowKind::Ref, _, ref addressee) = expr.kind; if let Some(vec_args) = higher::vec_macro(cx, addressee); then { - check_vec_macro(cx, &vec_args, expr.span); + self.check_vec_macro(cx, &vec_args, expr.span); } } @@ -60,46 +67,62 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { .ctxt() .outer_expn_data() .call_site; - check_vec_macro(cx, &vec_args, span); + self.check_vec_macro(cx, &vec_args, span); } } } } -fn check_vec_macro<'tcx>(cx: &LateContext<'tcx>, vec_args: &higher::VecArgs<'tcx>, span: Span) { - let mut applicability = Applicability::MachineApplicable; - let snippet = match *vec_args { - higher::VecArgs::Repeat(elem, len) => { - if constant(cx, cx.typeck_results(), len).is_some() { - format!( - "&[{}; {}]", - snippet_with_applicability(cx, elem.span, "elem", &mut applicability), - snippet_with_applicability(cx, len.span, "len", &mut applicability) - ) - } else { - return; - } - }, - higher::VecArgs::Vec(args) => { - if let Some(last) = args.iter().last() { - let span = args[0].span.to(last.span); +impl UselessVec { + fn check_vec_macro<'tcx>(self, cx: &LateContext<'tcx>, vec_args: &higher::VecArgs<'tcx>, span: Span) { + let mut applicability = Applicability::MachineApplicable; + let snippet = match *vec_args { + higher::VecArgs::Repeat(elem, len) => { + if let Some((Constant::Int(len_constant), _)) = constant(cx, cx.typeck_results(), len) { + #[allow(clippy::cast_possible_truncation)] + if len_constant as u64 * size_of(cx, elem) > self.too_large_for_stack { + return; + } - format!("&[{}]", snippet_with_applicability(cx, span, "..", &mut applicability)) - } else { - "&[]".into() - } - }, - }; + format!( + "&[{}; {}]", + snippet_with_applicability(cx, elem.span, "elem", &mut applicability), + snippet_with_applicability(cx, len.span, "len", &mut applicability) + ) + } else { + return; + } + }, + higher::VecArgs::Vec(args) => { + if let Some(last) = args.iter().last() { + #[allow(clippy::cast_possible_truncation)] + if args.len() as u64 * size_of(cx, last) > self.too_large_for_stack { + return; + } + let span = args[0].span.to(last.span); + + format!("&[{}]", snippet_with_applicability(cx, span, "..", &mut applicability)) + } else { + "&[]".into() + } + }, + }; + + span_lint_and_sugg( + cx, + USELESS_VEC, + span, + "useless use of `vec!`", + "you can use a slice directly", + snippet, + applicability, + ); + } +} - span_lint_and_sugg( - cx, - USELESS_VEC, - span, - "useless use of `vec!`", - "you can use a slice directly", - snippet, - applicability, - ); +fn size_of(cx: &LateContext<'_>, expr: &Expr<'_>) -> u64 { + let ty = cx.typeck_results().expr_ty_adjusted(expr); + cx.layout_of(ty).map_or(0, |l| l.size.bytes()) } /// Returns the item type of the vector (i.e., the `T` in `Vec`). diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index e7eb7c2e9802d..5683a71efea4e 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -195,13 +195,10 @@ impl WildcardImports { } } -// Allow "...prelude::*" imports. +// Allow "...prelude::..::*" imports. // Many crates have a prelude, and it is imported as a glob by design. fn is_prelude_import(segments: &[PathSegment<'_>]) -> bool { - segments - .iter() - .last() - .map_or(false, |ps| ps.ident.as_str() == "prelude") + segments.iter().any(|ps| ps.ident.as_str() == "prelude") } // Allow "super::*" imports in tests. diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 063f94582b9d1..e653240d04917 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -237,7 +237,7 @@ impl EarlyLintPass for Write { fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &MacCall) { if mac.path == sym!(println) { span_lint(cx, PRINT_STDOUT, mac.span(), "use of `println!`"); - if let (Some(fmt_str), _) = self.check_tts(cx, &mac.args.inner_tokens(), false) { + if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) { if fmt_str.symbol == Symbol::intern("") { span_lint_and_sugg( cx, @@ -252,7 +252,7 @@ impl EarlyLintPass for Write { } } else if mac.path == sym!(print) { span_lint(cx, PRINT_STDOUT, mac.span(), "use of `print!`"); - if let (Some(fmt_str), _) = self.check_tts(cx, &mac.args.inner_tokens(), false) { + if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) { if check_newlines(&fmt_str) { span_lint_and_then( cx, @@ -273,7 +273,7 @@ impl EarlyLintPass for Write { } } } else if mac.path == sym!(write) { - if let (Some(fmt_str), _) = self.check_tts(cx, &mac.args.inner_tokens(), true) { + if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), true) { if check_newlines(&fmt_str) { span_lint_and_then( cx, @@ -294,16 +294,17 @@ impl EarlyLintPass for Write { } } } else if mac.path == sym!(writeln) { - if let (Some(fmt_str), expr) = self.check_tts(cx, &mac.args.inner_tokens(), true) { + if let (Some(fmt_str), expr) = self.check_tts(cx, mac.args.inner_tokens(), true) { if fmt_str.symbol == Symbol::intern("") { let mut applicability = Applicability::MachineApplicable; - let suggestion = expr.map_or_else( - || { - applicability = Applicability::HasPlaceholders; - Cow::Borrowed("v") - }, - |e| snippet_with_applicability(cx, e.span, "v", &mut Applicability::MachineApplicable), - ); + // FIXME: remove this `#[allow(...)]` once the issue #5822 gets fixed + #[allow(clippy::option_if_let_else)] + let suggestion = if let Some(e) = expr { + snippet_with_applicability(cx, e.span, "v", &mut applicability) + } else { + applicability = Applicability::HasPlaceholders; + Cow::Borrowed("v") + }; span_lint_and_sugg( cx, @@ -364,17 +365,11 @@ impl Write { /// (Some("string to write: {}"), Some(buf)) /// ``` #[allow(clippy::too_many_lines)] - fn check_tts<'a>( - &self, - cx: &EarlyContext<'a>, - tts: &TokenStream, - is_write: bool, - ) -> (Option, Option) { + fn check_tts<'a>(&self, cx: &EarlyContext<'a>, tts: TokenStream, is_write: bool) -> (Option, Option) { use rustc_parse_format::{ AlignUnknown, ArgumentImplicitlyIs, ArgumentIs, ArgumentNamed, CountImplied, FormatSpec, ParseMode, Parser, Piece, }; - let tts = tts.clone(); let mut parser = parser::Parser::new(&cx.sess.parse_sess, tts, false, None); let mut expr: Option = None; diff --git a/doc/adding_lints.md b/doc/adding_lints.md index 168092f7329cc..3c782e9b17ff1 100644 --- a/doc/adding_lints.md +++ b/doc/adding_lints.md @@ -295,8 +295,14 @@ impl EarlyLintPass for FooFunctions { Running our UI test should now produce output that contains the lint message. +According to [the rustc-dev-guide], the text should be matter of fact and avoid +capitalization and periods, unless multiple sentences are needed. +When code or an identifier must appear in a message or label, it should be +surrounded with single acute accents \`. + [check_fn]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.EarlyLintPass.html#method.check_fn [diagnostics]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/diagnostics.rs +[the rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/diagnostics.html ## Adding the lint logic diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index bbb300296be97..687fac7baa848 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -661,6 +661,13 @@ pub static ref ALL_LINTS: Vec = vec![ 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", @@ -1037,7 +1044,7 @@ pub static ref ALL_LINTS: Vec = vec![ 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: "let_and_return", + module: "returns", }, Lint { name: "let_underscore_lock", @@ -1956,6 +1963,13 @@ pub static ref ALL_LINTS: Vec = vec![ 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", @@ -2012,6 +2026,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "methods", }, + Lint { + name: "single_char_push_str", + group: "style", + desc: "`push_str()` used with a single-character string literal as parameter", + deprecation: None, + module: "methods", + }, Lint { name: "single_component_path_imports", group: "style", @@ -2166,6 +2187,13 @@ pub static ref ALL_LINTS: Vec = vec![ 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", @@ -2369,6 +2397,13 @@ pub static ref ALL_LINTS: Vec = vec![ 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", @@ -2479,7 +2514,14 @@ pub static ref ALL_LINTS: Vec = vec![ group: "style", desc: "needless unit expression", deprecation: None, - module: "returns", + module: "unused_unit", + }, + 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", @@ -2498,7 +2540,7 @@ pub static ref ALL_LINTS: Vec = vec![ Lint { name: "use_self", group: "nursery", - desc: "Unnecessary structure name repetition whereas `Self` is applicable", + desc: "unnecessary structure name repetition whereas `Self` is applicable", deprecation: None, module: "use_self", }, diff --git a/tests/fmt.rs b/tests/fmt.rs index 3aff8741f6051..7616d8001e885 100644 --- a/tests/fmt.rs +++ b/tests/fmt.rs @@ -7,7 +7,7 @@ fn fmt() { return; } - // Skip this test if rustup nightly is unavailable + // Skip this test if nightly rustfmt is unavailable let rustup_output = Command::new("rustup") .args(&["component", "list", "--toolchain", "nightly"]) .output() @@ -19,12 +19,9 @@ fn fmt() { } let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let dev_dir = root_dir.join("clippy_dev"); - let target_dir = root_dir.join("target"); - let target_dir = target_dir.to_str().unwrap(); let output = Command::new("cargo") - .current_dir(dev_dir) - .args(&["+nightly", "run", "--target-dir", target_dir, "--", "fmt", "--check"]) + .current_dir(root_dir) + .args(&["dev", "fmt", "--check"]) .output() .unwrap(); diff --git a/tests/ui/auxiliary/wildcard_imports_helper.rs b/tests/ui/auxiliary/wildcard_imports_helper.rs index 414477aedd783..d75cdd625f9ec 100644 --- a/tests/ui/auxiliary/wildcard_imports_helper.rs +++ b/tests/ui/auxiliary/wildcard_imports_helper.rs @@ -19,3 +19,9 @@ mod extern_exports { A, } } + +pub mod prelude { + pub mod v1 { + pub struct PreludeModAnywhere; + } +} diff --git a/tests/ui/borrow_interior_mutable_const.rs b/tests/ui/borrow_interior_mutable_const.rs index fef9f4f39f809..a414832bcd362 100644 --- a/tests/ui/borrow_interior_mutable_const.rs +++ b/tests/ui/borrow_interior_mutable_const.rs @@ -2,7 +2,7 @@ #![allow(clippy::declare_interior_mutable_const, clippy::ref_in_deref)] use std::borrow::Cow; -use std::cell::Cell; +use std::cell::{Cell, UnsafeCell}; use std::fmt::Display; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Once; @@ -30,6 +30,37 @@ impl Trait for u64 { const ATOMIC: AtomicUsize = AtomicUsize::new(9); } +// 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 { + ptr: *const T, +} + +impl StaticRef { + /// 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 { + StaticRef { ptr } + } +} + +impl std::ops::Deref for StaticRef { + 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,)> = 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 @@ -82,4 +113,6 @@ fn main() { 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; } diff --git a/tests/ui/borrow_interior_mutable_const.stderr b/tests/ui/borrow_interior_mutable_const.stderr index dc738064a1718..1e0b3e4d20a52 100644 --- a/tests/ui/borrow_interior_mutable_const.stderr +++ b/tests/ui/borrow_interior_mutable_const.stderr @@ -1,5 +1,5 @@ error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:34:5 + --> $DIR/borrow_interior_mutable_const.rs:65:5 | LL | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^ @@ -8,7 +8,7 @@ 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:35:16 + --> $DIR/borrow_interior_mutable_const.rs:66:16 | LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability | ^^^^^^ @@ -16,7 +16,7 @@ LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutabi = 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:38:22 + --> $DIR/borrow_interior_mutable_const.rs:69:22 | LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -24,7 +24,7 @@ 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:39:25 + --> $DIR/borrow_interior_mutable_const.rs:70:25 | LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -32,7 +32,7 @@ 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:40:27 + --> $DIR/borrow_interior_mutable_const.rs:71:27 | LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -40,7 +40,7 @@ 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:41:26 + --> $DIR/borrow_interior_mutable_const.rs:72:26 | LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -48,7 +48,7 @@ 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:52:14 + --> $DIR/borrow_interior_mutable_const.rs:83:14 | LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -56,7 +56,7 @@ 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:53:14 + --> $DIR/borrow_interior_mutable_const.rs:84:14 | LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -64,7 +64,7 @@ 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:54:19 + --> $DIR/borrow_interior_mutable_const.rs:85:19 | LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -72,7 +72,7 @@ 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:55:14 + --> $DIR/borrow_interior_mutable_const.rs:86:14 | LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -80,7 +80,7 @@ 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:56:13 + --> $DIR/borrow_interior_mutable_const.rs:87:13 | LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mu = 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:62:13 + --> $DIR/borrow_interior_mutable_const.rs:93:13 | LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -96,7 +96,7 @@ 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:67:5 + --> $DIR/borrow_interior_mutable_const.rs:98:5 | LL | CELL.set(2); //~ ERROR interior mutability | ^^^^ @@ -104,7 +104,7 @@ 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:68:16 + --> $DIR/borrow_interior_mutable_const.rs:99:16 | LL | assert_eq!(CELL.get(), 6); //~ ERROR interior mutability | ^^^^ @@ -112,7 +112,7 @@ 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:81:5 + --> $DIR/borrow_interior_mutable_const.rs:112:5 | LL | u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^^^^^^ @@ -120,7 +120,7 @@ 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:82:16 + --> $DIR/borrow_interior_mutable_const.rs:113:16 | LL | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability | ^^^^^^^^^^^ diff --git a/tests/ui/crashes/ice-5944.rs b/tests/ui/crashes/ice-5944.rs new file mode 100644 index 0000000000000..5caf29c619735 --- /dev/null +++ b/tests/ui/crashes/ice-5944.rs @@ -0,0 +1,13 @@ +#![warn(clippy::repeat_once)] + +trait Repeat { + fn repeat(&self) {} +} + +impl Repeat for usize { + fn repeat(&self) {} +} + +fn main() { + let _ = 42.repeat(); +} diff --git a/tests/ui/duration_subsec.stderr b/tests/ui/duration_subsec.stderr index bd8adc2c57055..cdbeff6a03783 100644 --- a/tests/ui/duration_subsec.stderr +++ b/tests/ui/duration_subsec.stderr @@ -1,4 +1,4 @@ -error: Calling `subsec_millis()` is more concise than this calculation +error: calling `subsec_millis()` is more concise than this calculation --> $DIR/duration_subsec.rs:10:24 | LL | let bad_millis_1 = dur.subsec_micros() / 1_000; @@ -6,25 +6,25 @@ LL | let bad_millis_1 = dur.subsec_micros() / 1_000; | = note: `-D clippy::duration-subsec` implied by `-D warnings` -error: Calling `subsec_millis()` is more concise than this calculation +error: calling `subsec_millis()` is more concise than this calculation --> $DIR/duration_subsec.rs:11:24 | LL | let bad_millis_2 = dur.subsec_nanos() / 1_000_000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_millis()` -error: Calling `subsec_micros()` is more concise than this calculation +error: calling `subsec_micros()` is more concise than this calculation --> $DIR/duration_subsec.rs:16:22 | LL | let bad_micros = dur.subsec_nanos() / 1_000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_micros()` -error: Calling `subsec_micros()` is more concise than this calculation +error: calling `subsec_micros()` is more concise than this calculation --> $DIR/duration_subsec.rs:21:13 | LL | let _ = (&dur).subsec_nanos() / 1_000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(&dur).subsec_micros()` -error: Calling `subsec_micros()` is more concise than this calculation +error: calling `subsec_micros()` is more concise than this calculation --> $DIR/duration_subsec.rs:25:13 | LL | let _ = dur.subsec_nanos() / NANOS_IN_MICRO; diff --git a/tests/ui/enum_clike_unportable_variant.stderr b/tests/ui/enum_clike_unportable_variant.stderr index 71f3f5e083e0d..5935eea5e036e 100644 --- a/tests/ui/enum_clike_unportable_variant.stderr +++ b/tests/ui/enum_clike_unportable_variant.stderr @@ -1,4 +1,4 @@ -error: Clike enum variant discriminant is not portable to 32-bit targets +error: C-like enum variant discriminant is not portable to 32-bit targets --> $DIR/enum_clike_unportable_variant.rs:8:5 | LL | X = 0x1_0000_0000, @@ -6,49 +6,49 @@ LL | X = 0x1_0000_0000, | = note: `-D clippy::enum-clike-unportable-variant` implied by `-D warnings` -error: Clike enum variant discriminant is not portable to 32-bit targets +error: C-like enum variant discriminant is not portable to 32-bit targets --> $DIR/enum_clike_unportable_variant.rs:15:5 | LL | X = 0x1_0000_0000, | ^^^^^^^^^^^^^^^^^ -error: Clike enum variant discriminant is not portable to 32-bit targets +error: C-like enum variant discriminant is not portable to 32-bit targets --> $DIR/enum_clike_unportable_variant.rs:18:5 | LL | A = 0xFFFF_FFFF, | ^^^^^^^^^^^^^^^ -error: Clike enum variant discriminant is not portable to 32-bit targets +error: C-like enum variant discriminant is not portable to 32-bit targets --> $DIR/enum_clike_unportable_variant.rs:25:5 | LL | Z = 0xFFFF_FFFF, | ^^^^^^^^^^^^^^^ -error: Clike enum variant discriminant is not portable to 32-bit targets +error: C-like enum variant discriminant is not portable to 32-bit targets --> $DIR/enum_clike_unportable_variant.rs:26:5 | LL | A = 0x1_0000_0000, | ^^^^^^^^^^^^^^^^^ -error: Clike enum variant discriminant is not portable to 32-bit targets +error: C-like enum variant discriminant is not portable to 32-bit targets --> $DIR/enum_clike_unportable_variant.rs:28:5 | LL | C = (i32::MIN as isize) - 1, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: Clike enum variant discriminant is not portable to 32-bit targets +error: C-like enum variant discriminant is not portable to 32-bit targets --> $DIR/enum_clike_unportable_variant.rs:34:5 | LL | Z = 0xFFFF_FFFF, | ^^^^^^^^^^^^^^^ -error: Clike enum variant discriminant is not portable to 32-bit targets +error: C-like enum variant discriminant is not portable to 32-bit targets --> $DIR/enum_clike_unportable_variant.rs:35:5 | LL | A = 0x1_0000_0000, | ^^^^^^^^^^^^^^^^^ -error: Clike enum variant discriminant is not portable to 32-bit targets +error: C-like enum variant discriminant is not portable to 32-bit targets --> $DIR/enum_clike_unportable_variant.rs:40:5 | LL | X = ::Number, diff --git a/tests/ui/enum_variants.stderr b/tests/ui/enum_variants.stderr index 2835391de7f58..b1d481190ff53 100644 --- a/tests/ui/enum_variants.stderr +++ b/tests/ui/enum_variants.stderr @@ -1,4 +1,4 @@ -error: Variant name ends with the enum's name +error: variant name ends with the enum's name --> $DIR/enum_variants.rs:16:5 | LL | cFoo, @@ -6,25 +6,25 @@ LL | cFoo, | = note: `-D clippy::enum-variant-names` implied by `-D warnings` -error: Variant name starts with the enum's name +error: variant name starts with the enum's name --> $DIR/enum_variants.rs:27:5 | LL | FoodGood, | ^^^^^^^^ -error: Variant name starts with the enum's name +error: variant name starts with the enum's name --> $DIR/enum_variants.rs:28:5 | LL | FoodMiddle, | ^^^^^^^^^^ -error: Variant name starts with the enum's name +error: variant name starts with the enum's name --> $DIR/enum_variants.rs:29:5 | LL | FoodBad, | ^^^^^^^ -error: All variants have the same prefix: `Food` +error: all variants have the same prefix: `Food` --> $DIR/enum_variants.rs:26:1 | LL | / enum Food { @@ -36,7 +36,7 @@ LL | | } | = help: remove the prefixes and use full paths to the variants instead of glob imports -error: All variants have the same prefix: `CallType` +error: all variants have the same prefix: `CallType` --> $DIR/enum_variants.rs:36:1 | LL | / enum BadCallType { @@ -48,7 +48,7 @@ LL | | } | = help: remove the prefixes and use full paths to the variants instead of glob imports -error: All variants have the same prefix: `Constant` +error: all variants have the same prefix: `Constant` --> $DIR/enum_variants.rs:48:1 | LL | / enum Consts { @@ -60,7 +60,7 @@ LL | | } | = help: remove the prefixes and use full paths to the variants instead of glob imports -error: All variants have the same prefix: `With` +error: all variants have the same prefix: `With` --> $DIR/enum_variants.rs:82:1 | LL | / enum Seallll { @@ -72,7 +72,7 @@ LL | | } | = help: remove the prefixes and use full paths to the variants instead of glob imports -error: All variants have the same prefix: `Prefix` +error: all variants have the same prefix: `Prefix` --> $DIR/enum_variants.rs:88:1 | LL | / enum NonCaps { @@ -84,7 +84,7 @@ LL | | } | = help: remove the prefixes and use full paths to the variants instead of glob imports -error: All variants have the same prefix: `With` +error: all variants have the same prefix: `With` --> $DIR/enum_variants.rs:94:1 | LL | / pub enum PubSeall { diff --git a/tests/ui/float_equality_without_abs.rs b/tests/ui/float_equality_without_abs.rs new file mode 100644 index 0000000000000..d40fa00c31551 --- /dev/null +++ b/tests/ui/float_equality_without_abs.rs @@ -0,0 +1,31 @@ +#![warn(clippy::float_equality_without_abs)] + +pub fn is_roughly_equal(a: f32, b: f32) -> bool { + (a - b) < f32::EPSILON +} + +pub fn main() { + // all errors + is_roughly_equal(1.0, 2.0); + let a = 0.05; + let b = 0.0500001; + + let _ = (a - b) < f32::EPSILON; + let _ = a - b < f32::EPSILON; + let _ = a - b.abs() < f32::EPSILON; + let _ = (a as f64 - b as f64) < f64::EPSILON; + let _ = 1.0 - 2.0 < f32::EPSILON; + + let _ = f32::EPSILON > (a - b); + let _ = f32::EPSILON > a - b; + let _ = f32::EPSILON > a - b.abs(); + let _ = f64::EPSILON > (a as f64 - b as f64); + let _ = f32::EPSILON > 1.0 - 2.0; + + // those are correct + let _ = (a - b).abs() < f32::EPSILON; + let _ = (a as f64 - b as f64).abs() < f64::EPSILON; + + let _ = f32::EPSILON > (a - b).abs(); + let _ = f64::EPSILON > (a as f64 - b as f64).abs(); +} diff --git a/tests/ui/float_equality_without_abs.stderr b/tests/ui/float_equality_without_abs.stderr new file mode 100644 index 0000000000000..b34c8159da04d --- /dev/null +++ b/tests/ui/float_equality_without_abs.stderr @@ -0,0 +1,92 @@ +error: float equality check without `.abs()` + --> $DIR/float_equality_without_abs.rs:4:5 + | +LL | (a - b) < f32::EPSILON + | -------^^^^^^^^^^^^^^^ + | | + | help: add `.abs()`: `(a - b).abs()` + | + = note: `-D clippy::float-equality-without-abs` implied by `-D warnings` + +error: float equality check without `.abs()` + --> $DIR/float_equality_without_abs.rs:13:13 + | +LL | let _ = (a - b) < f32::EPSILON; + | -------^^^^^^^^^^^^^^^ + | | + | help: add `.abs()`: `(a - b).abs()` + +error: float equality check without `.abs()` + --> $DIR/float_equality_without_abs.rs:14:13 + | +LL | let _ = a - b < f32::EPSILON; + | -----^^^^^^^^^^^^^^^ + | | + | help: add `.abs()`: `(a - b).abs()` + +error: float equality check without `.abs()` + --> $DIR/float_equality_without_abs.rs:15:13 + | +LL | let _ = a - b.abs() < f32::EPSILON; + | -----------^^^^^^^^^^^^^^^ + | | + | help: add `.abs()`: `(a - b.abs()).abs()` + +error: float equality check without `.abs()` + --> $DIR/float_equality_without_abs.rs:16:13 + | +LL | let _ = (a as f64 - b as f64) < f64::EPSILON; + | ---------------------^^^^^^^^^^^^^^^ + | | + | help: add `.abs()`: `(a as f64 - b as f64).abs()` + +error: float equality check without `.abs()` + --> $DIR/float_equality_without_abs.rs:17:13 + | +LL | let _ = 1.0 - 2.0 < f32::EPSILON; + | ---------^^^^^^^^^^^^^^^ + | | + | help: add `.abs()`: `(1.0 - 2.0).abs()` + +error: float equality check without `.abs()` + --> $DIR/float_equality_without_abs.rs:19:13 + | +LL | let _ = f32::EPSILON > (a - b); + | ^^^^^^^^^^^^^^^------- + | | + | help: add `.abs()`: `(a - b).abs()` + +error: float equality check without `.abs()` + --> $DIR/float_equality_without_abs.rs:20:13 + | +LL | let _ = f32::EPSILON > a - b; + | ^^^^^^^^^^^^^^^----- + | | + | help: add `.abs()`: `(a - b).abs()` + +error: float equality check without `.abs()` + --> $DIR/float_equality_without_abs.rs:21:13 + | +LL | let _ = f32::EPSILON > a - b.abs(); + | ^^^^^^^^^^^^^^^----------- + | | + | help: add `.abs()`: `(a - b.abs()).abs()` + +error: float equality check without `.abs()` + --> $DIR/float_equality_without_abs.rs:22:13 + | +LL | let _ = f64::EPSILON > (a as f64 - b as f64); + | ^^^^^^^^^^^^^^^--------------------- + | | + | help: add `.abs()`: `(a as f64 - b as f64).abs()` + +error: float equality check without `.abs()` + --> $DIR/float_equality_without_abs.rs:23:13 + | +LL | let _ = f32::EPSILON > 1.0 - 2.0; + | ^^^^^^^^^^^^^^^--------- + | | + | help: add `.abs()`: `(1.0 - 2.0).abs()` + +error: aborting due to 11 previous errors + diff --git a/tests/ui/if_let_some_result.stderr b/tests/ui/if_let_some_result.stderr index 334ccb0101678..6afee0f36b9da 100644 --- a/tests/ui/if_let_some_result.stderr +++ b/tests/ui/if_let_some_result.stderr @@ -1,22 +1,22 @@ -error: Matching on `Some` with `ok()` is redundant +error: matching on `Some` with `ok()` is redundant --> $DIR/if_let_some_result.rs:6:5 | LL | if let Some(y) = x.parse().ok() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::if-let-some-result` implied by `-D warnings` -help: Consider matching on `Ok(y)` and removing the call to `ok` instead +help: consider matching on `Ok(y)` and removing the call to `ok` instead | LL | if let Ok(y) = x.parse() { | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: Matching on `Some` with `ok()` is redundant +error: matching on `Some` with `ok()` is redundant --> $DIR/if_let_some_result.rs:24:9 | LL | if let Some(y) = x . parse() . ok () { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: Consider matching on `Ok(y)` and removing the call to `ok` instead +help: consider matching on `Ok(y)` and removing the call to `ok` instead | LL | if let Ok(y) = x . parse() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/if_not_else.stderr b/tests/ui/if_not_else.stderr index 78bc4d4bd20a3..53d1b86d02a96 100644 --- a/tests/ui/if_not_else.stderr +++ b/tests/ui/if_not_else.stderr @@ -1,4 +1,4 @@ -error: Unnecessary boolean `not` operation +error: unnecessary boolean `not` operation --> $DIR/if_not_else.rs:9:5 | LL | / if !bla() { @@ -11,7 +11,7 @@ LL | | } = note: `-D clippy::if-not-else` implied by `-D warnings` = help: remove the `!` and swap the blocks of the `if`/`else` -error: Unnecessary `!=` operation +error: unnecessary `!=` operation --> $DIR/if_not_else.rs:14:5 | LL | / if 4 != 5 { diff --git a/tests/ui/impl.stderr b/tests/ui/impl.stderr index 585d32845d290..aab688cc2d8b2 100644 --- a/tests/ui/impl.stderr +++ b/tests/ui/impl.stderr @@ -1,4 +1,4 @@ -error: Multiple implementations of this structure +error: multiple implementations of this structure --> $DIR/impl.rs:10:1 | LL | / impl MyStruct { @@ -7,7 +7,7 @@ LL | | } | |_^ | = note: `-D clippy::multiple-inherent-impl` implied by `-D warnings` -note: First implementation here +note: first implementation here --> $DIR/impl.rs:6:1 | LL | / impl MyStruct { @@ -15,7 +15,7 @@ LL | | fn first() {} LL | | } | |_^ -error: Multiple implementations of this structure +error: multiple implementations of this structure --> $DIR/impl.rs:24:5 | LL | / impl super::MyStruct { @@ -23,7 +23,7 @@ LL | | fn third() {} LL | | } | |_____^ | -note: First implementation here +note: first implementation here --> $DIR/impl.rs:6:1 | LL | / impl MyStruct { diff --git a/tests/ui/implicit_saturating_sub.stderr b/tests/ui/implicit_saturating_sub.stderr index 2eb2023b3b9ef..5bb9a606422a1 100644 --- a/tests/ui/implicit_saturating_sub.stderr +++ b/tests/ui/implicit_saturating_sub.stderr @@ -1,4 +1,4 @@ -error: Implicitly performing saturating subtraction +error: implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:13:5 | LL | / if u_8 > 0 { @@ -8,7 +8,7 @@ LL | | } | = note: `-D clippy::implicit-saturating-sub` implied by `-D warnings` -error: Implicitly performing saturating subtraction +error: implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:20:13 | LL | / if u_8 > 0 { @@ -16,7 +16,7 @@ LL | | u_8 -= 1; LL | | } | |_____________^ help: try: `u_8 = u_8.saturating_sub(1);` -error: Implicitly performing saturating subtraction +error: implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:34:5 | LL | / if u_16 > 0 { @@ -24,7 +24,7 @@ LL | | u_16 -= 1; LL | | } | |_____^ help: try: `u_16 = u_16.saturating_sub(1);` -error: Implicitly performing saturating subtraction +error: implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:44:5 | LL | / if u_32 != 0 { @@ -32,7 +32,7 @@ LL | | u_32 -= 1; LL | | } | |_____^ help: try: `u_32 = u_32.saturating_sub(1);` -error: Implicitly performing saturating subtraction +error: implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:65:5 | LL | / if u_64 > 0 { @@ -40,7 +40,7 @@ LL | | u_64 -= 1; LL | | } | |_____^ help: try: `u_64 = u_64.saturating_sub(1);` -error: Implicitly performing saturating subtraction +error: implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:70:5 | LL | / if 0 < u_64 { @@ -48,7 +48,7 @@ LL | | u_64 -= 1; LL | | } | |_____^ help: try: `u_64 = u_64.saturating_sub(1);` -error: Implicitly performing saturating subtraction +error: implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:75:5 | LL | / if 0 != u_64 { @@ -56,7 +56,7 @@ LL | | u_64 -= 1; LL | | } | |_____^ help: try: `u_64 = u_64.saturating_sub(1);` -error: Implicitly performing saturating subtraction +error: implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:96:5 | LL | / if u_usize > 0 { @@ -64,7 +64,7 @@ LL | | u_usize -= 1; LL | | } | |_____^ help: try: `u_usize = u_usize.saturating_sub(1);` -error: Implicitly performing saturating subtraction +error: implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:108:5 | LL | / if i_8 > i8::MIN { @@ -72,7 +72,7 @@ LL | | i_8 -= 1; LL | | } | |_____^ help: try: `i_8 = i_8.saturating_sub(1);` -error: Implicitly performing saturating subtraction +error: implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:113:5 | LL | / if i_8 > i8::MIN { @@ -80,7 +80,7 @@ LL | | i_8 -= 1; LL | | } | |_____^ help: try: `i_8 = i_8.saturating_sub(1);` -error: Implicitly performing saturating subtraction +error: implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:118:5 | LL | / if i_8 != i8::MIN { @@ -88,7 +88,7 @@ LL | | i_8 -= 1; LL | | } | |_____^ help: try: `i_8 = i_8.saturating_sub(1);` -error: Implicitly performing saturating subtraction +error: implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:123:5 | LL | / if i_8 != i8::MIN { @@ -96,7 +96,7 @@ LL | | i_8 -= 1; LL | | } | |_____^ help: try: `i_8 = i_8.saturating_sub(1);` -error: Implicitly performing saturating subtraction +error: implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:133:5 | LL | / if i_16 > i16::MIN { @@ -104,7 +104,7 @@ LL | | i_16 -= 1; LL | | } | |_____^ help: try: `i_16 = i_16.saturating_sub(1);` -error: Implicitly performing saturating subtraction +error: implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:138:5 | LL | / if i_16 > i16::MIN { @@ -112,7 +112,7 @@ LL | | i_16 -= 1; LL | | } | |_____^ help: try: `i_16 = i_16.saturating_sub(1);` -error: Implicitly performing saturating subtraction +error: implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:143:5 | LL | / if i_16 != i16::MIN { @@ -120,7 +120,7 @@ LL | | i_16 -= 1; LL | | } | |_____^ help: try: `i_16 = i_16.saturating_sub(1);` -error: Implicitly performing saturating subtraction +error: implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:148:5 | LL | / if i_16 != i16::MIN { @@ -128,7 +128,7 @@ LL | | i_16 -= 1; LL | | } | |_____^ help: try: `i_16 = i_16.saturating_sub(1);` -error: Implicitly performing saturating subtraction +error: implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:158:5 | LL | / if i_32 > i32::MIN { @@ -136,7 +136,7 @@ LL | | i_32 -= 1; LL | | } | |_____^ help: try: `i_32 = i_32.saturating_sub(1);` -error: Implicitly performing saturating subtraction +error: implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:163:5 | LL | / if i_32 > i32::MIN { @@ -144,7 +144,7 @@ LL | | i_32 -= 1; LL | | } | |_____^ help: try: `i_32 = i_32.saturating_sub(1);` -error: Implicitly performing saturating subtraction +error: implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:168:5 | LL | / if i_32 != i32::MIN { @@ -152,7 +152,7 @@ LL | | i_32 -= 1; LL | | } | |_____^ help: try: `i_32 = i_32.saturating_sub(1);` -error: Implicitly performing saturating subtraction +error: implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:173:5 | LL | / if i_32 != i32::MIN { @@ -160,7 +160,7 @@ LL | | i_32 -= 1; LL | | } | |_____^ help: try: `i_32 = i_32.saturating_sub(1);` -error: Implicitly performing saturating subtraction +error: implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:183:5 | LL | / if i64::MIN < i_64 { @@ -168,7 +168,7 @@ LL | | i_64 -= 1; LL | | } | |_____^ help: try: `i_64 = i_64.saturating_sub(1);` -error: Implicitly performing saturating subtraction +error: implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:188:5 | LL | / if i64::MIN != i_64 { @@ -176,7 +176,7 @@ LL | | i_64 -= 1; LL | | } | |_____^ help: try: `i_64 = i_64.saturating_sub(1);` -error: Implicitly performing saturating subtraction +error: implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:193:5 | LL | / if i64::MIN < i_64 { diff --git a/tests/ui/int_plus_one.stderr b/tests/ui/int_plus_one.stderr index 29a6914761c9f..c5b020ba8ced5 100644 --- a/tests/ui/int_plus_one.stderr +++ b/tests/ui/int_plus_one.stderr @@ -1,4 +1,4 @@ -error: Unnecessary `>= y + 1` or `x - 1 >=` +error: unnecessary `>= y + 1` or `x - 1 >=` --> $DIR/int_plus_one.rs:9:13 | LL | let _ = x >= y + 1; @@ -6,19 +6,19 @@ LL | let _ = x >= y + 1; | = note: `-D clippy::int-plus-one` implied by `-D warnings` -error: Unnecessary `>= y + 1` or `x - 1 >=` +error: unnecessary `>= y + 1` or `x - 1 >=` --> $DIR/int_plus_one.rs:10:13 | LL | let _ = y + 1 <= x; | ^^^^^^^^^^ help: change it to: `y < x` -error: Unnecessary `>= y + 1` or `x - 1 >=` +error: unnecessary `>= y + 1` or `x - 1 >=` --> $DIR/int_plus_one.rs:12:13 | LL | let _ = x - 1 >= y; | ^^^^^^^^^^ help: change it to: `x > y` -error: Unnecessary `>= y + 1` or `x - 1 >=` +error: unnecessary `>= y + 1` or `x - 1 >=` --> $DIR/int_plus_one.rs:13:13 | LL | let _ = y <= x - 1; diff --git a/tests/ui/iter_next_slice.stderr b/tests/ui/iter_next_slice.stderr index bbf61df0cda68..8c10a252ee01b 100644 --- a/tests/ui/iter_next_slice.stderr +++ b/tests/ui/iter_next_slice.stderr @@ -1,4 +1,4 @@ -error: Using `.iter().next()` on an array +error: using `.iter().next()` on an array --> $DIR/iter_next_slice.rs:9:5 | LL | s.iter().next(); @@ -6,19 +6,19 @@ LL | s.iter().next(); | = note: `-D clippy::iter-next-slice` implied by `-D warnings` -error: Using `.iter().next()` on a Slice without end index. +error: using `.iter().next()` on a Slice without end index --> $DIR/iter_next_slice.rs:12:5 | LL | s[2..].iter().next(); | ^^^^^^^^^^^^^^^^^^^^ help: try calling: `s.get(2)` -error: Using `.iter().next()` on a Slice without end index. +error: using `.iter().next()` on a Slice without end index --> $DIR/iter_next_slice.rs:15:5 | LL | v[5..].iter().next(); | ^^^^^^^^^^^^^^^^^^^^ help: try calling: `v.get(5)` -error: Using `.iter().next()` on an array +error: using `.iter().next()` on an array --> $DIR/iter_next_slice.rs:18:5 | LL | v.iter().next(); diff --git a/tests/ui/len_zero.fixed b/tests/ui/len_zero.fixed index d81676a3d9f48..1f3b8ac99b191 100644 --- a/tests/ui/len_zero.fixed +++ b/tests/ui/len_zero.fixed @@ -141,11 +141,3 @@ fn main() { fn test_slice(b: &[u8]) { if !b.is_empty() {} } - -mod issue_3807 { - // Avoid suggesting changes to ranges if the user did not enable `range_is_empty`. - // See https://github.com/rust-lang/rust/issues/48111#issuecomment-445132965 - fn no_suggestion() { - let _ = (0..42).len() == 0; - } -} diff --git a/tests/ui/len_zero.rs b/tests/ui/len_zero.rs index ecdba921a5d0f..dc21de0001b6c 100644 --- a/tests/ui/len_zero.rs +++ b/tests/ui/len_zero.rs @@ -141,11 +141,3 @@ fn main() { fn test_slice(b: &[u8]) { if b.len() != 0 {} } - -mod issue_3807 { - // Avoid suggesting changes to ranges if the user did not enable `range_is_empty`. - // See https://github.com/rust-lang/rust/issues/48111#issuecomment-445132965 - fn no_suggestion() { - let _ = (0..42).len() == 0; - } -} diff --git a/tests/ui/len_zero_ranges.fixed b/tests/ui/len_zero_ranges.fixed index eee3db9b7d4b0..7978176624274 100644 --- a/tests/ui/len_zero_ranges.fixed +++ b/tests/ui/len_zero_ranges.fixed @@ -1,15 +1,17 @@ // run-rustfix -#![feature(range_is_empty)] #![warn(clippy::len_zero)] #![allow(unused)] -#![allow(stable_features)] // TODO: https://github.com/rust-lang/rust-clippy/issues/5956 +// Now that `Range(Inclusive)::is_empty` is stable (1.47), we can always suggest this mod issue_3807 { - // With the feature enabled, `is_empty` should be suggested - fn suggestion_is_fine() { + fn suggestion_is_fine_range() { let _ = (0..42).is_empty(); } + + fn suggestion_is_fine_range_inclusive() { + let _ = (0_u8..=42).is_empty(); + } } fn main() {} diff --git a/tests/ui/len_zero_ranges.rs b/tests/ui/len_zero_ranges.rs index be2e0f38fd164..a0eb51cc9760c 100644 --- a/tests/ui/len_zero_ranges.rs +++ b/tests/ui/len_zero_ranges.rs @@ -1,15 +1,17 @@ // run-rustfix -#![feature(range_is_empty)] #![warn(clippy::len_zero)] #![allow(unused)] -#![allow(stable_features)] // TODO: https://github.com/rust-lang/rust-clippy/issues/5956 +// Now that `Range(Inclusive)::is_empty` is stable (1.47), we can always suggest this mod issue_3807 { - // With the feature enabled, `is_empty` should be suggested - fn suggestion_is_fine() { + fn suggestion_is_fine_range() { let _ = (0..42).len() == 0; } + + fn suggestion_is_fine_range_inclusive() { + let _ = (0_u8..=42).len() == 0; + } } fn main() {} diff --git a/tests/ui/len_zero_ranges.stderr b/tests/ui/len_zero_ranges.stderr index acb85f7100a39..d0defb5a79edc 100644 --- a/tests/ui/len_zero_ranges.stderr +++ b/tests/ui/len_zero_ranges.stderr @@ -1,10 +1,16 @@ error: length comparison to zero - --> $DIR/len_zero_ranges.rs:11:17 + --> $DIR/len_zero_ranges.rs:9:17 | LL | let _ = (0..42).len() == 0; | ^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(0..42).is_empty()` | = note: `-D clippy::len-zero` implied by `-D warnings` -error: aborting due to previous error +error: length comparison to zero + --> $DIR/len_zero_ranges.rs:13:17 + | +LL | let _ = (0_u8..=42).len() == 0; + | ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(0_u8..=42).is_empty()` + +error: aborting due to 2 previous errors diff --git a/tests/ui/let_and_return.rs b/tests/ui/let_and_return.rs index 09614b8c1ad78..73e550b3df891 100644 --- a/tests/ui/let_and_return.rs +++ b/tests/ui/let_and_return.rs @@ -135,4 +135,25 @@ mod no_lint_if_stmt_borrows { } } +mod issue_5729 { + use std::sync::Arc; + + trait Foo {} + + trait FooStorage { + fn foo_cloned(&self) -> Arc; + } + + struct FooStorageImpl { + foo: Arc, + } + + impl FooStorage for FooStorageImpl { + fn foo_cloned(&self) -> Arc { + let clone = Arc::clone(&self.foo); + clone + } + } +} + fn main() {} diff --git a/tests/ui/let_and_return.stderr b/tests/ui/let_and_return.stderr index eacf948b3927a..fe878e5f20601 100644 --- a/tests/ui/let_and_return.stderr +++ b/tests/ui/let_and_return.stderr @@ -27,5 +27,19 @@ LL | LL | 5 | -error: aborting due to 2 previous errors +error: returning the result of a `let` binding from a block + --> $DIR/let_and_return.rs:154:13 + | +LL | let clone = Arc::clone(&self.foo); + | ---------------------------------- unnecessary `let` binding +LL | clone + | ^^^^^ + | +help: return the expression directly + | +LL | +LL | Arc::clone(&self.foo) as _ + | + +error: aborting due to 3 previous errors diff --git a/tests/ui/map_clone.stderr b/tests/ui/map_clone.stderr index 9eec6928e8cee..4f43cff502444 100644 --- a/tests/ui/map_clone.stderr +++ b/tests/ui/map_clone.stderr @@ -1,40 +1,40 @@ -error: You are using an explicit closure for copying elements +error: you are using an explicit closure for copying elements --> $DIR/map_clone.rs:10:22 | LL | let _: Vec = vec![5_i8; 6].iter().map(|x| *x).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `copied` method: `vec![5_i8; 6].iter().copied()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 +error: you are using an explicit closure for cloning elements --> $DIR/map_clone.rs:11:26 | LL | let _: Vec = vec![String::new()].iter().map(|x| x.clone()).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `cloned` method: `vec![String::new()].iter().cloned()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `vec![String::new()].iter().cloned()` -error: You are using an explicit closure for copying elements +error: you are using an explicit closure for copying elements --> $DIR/map_clone.rs:12:23 | LL | let _: Vec = vec![42, 43].iter().map(|&x| x).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `copied` method: `vec![42, 43].iter().copied()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![42, 43].iter().copied()` -error: You are using an explicit closure for copying elements +error: you are using an explicit closure for copying elements --> $DIR/map_clone.rs:14:26 | LL | let _: Option = Some(&16).map(|b| *b); - | ^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `copied` method: `Some(&16).copied()` + | ^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&16).copied()` -error: You are using an explicit closure for copying elements +error: you are using an explicit closure for copying elements --> $DIR/map_clone.rs:15:25 | LL | let _: Option = Some(&1).map(|x| x.clone()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `copied` method: `Some(&1).copied()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&1).copied()` -error: You are needlessly cloning iterator elements +error: you are needlessly cloning iterator elements --> $DIR/map_clone.rs:26:29 | LL | let _ = std::env::args().map(|v| v.clone()); - | ^^^^^^^^^^^^^^^^^^^ help: Remove the `map` call + | ^^^^^^^^^^^^^^^^^^^ help: remove the `map` call error: aborting due to 6 previous errors diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index 7880cf36415ff..80dd2f744b3a1 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -10,6 +10,7 @@ clippy::non_ascii_literal, clippy::new_without_default, clippy::needless_pass_by_value, + clippy::needless_lifetimes, clippy::print_stdout, clippy::must_use_candidate, clippy::use_self, @@ -33,71 +34,6 @@ use std::sync::{self, Arc}; use option_helpers::IteratorFalsePositives; -pub struct T; - -impl T { - pub fn add(self, other: T) -> T { - self - } - - // no error, not public interface - pub(crate) fn drop(&mut self) {} - - // no error, private function - fn neg(self) -> Self { - self - } - - // no error, private function - fn eq(&self, other: T) -> bool { - true - } - - // No error; self is a ref. - fn sub(&self, other: T) -> &T { - self - } - - // No error; different number of arguments. - fn div(self) -> T { - self - } - - // No error; wrong return type. - fn rem(self, other: T) {} - - // Fine - fn into_u32(self) -> u32 { - 0 - } - - fn into_u16(&self) -> u16 { - 0 - } - - fn to_something(self) -> u32 { - 0 - } - - fn new(self) -> Self { - unimplemented!(); - } -} - -pub struct T1; - -impl T1 { - // Shouldn't trigger lint as it is unsafe. - pub unsafe fn add(self, rhs: T1) -> T1 { - self - } - - // Should not trigger lint since this is an async function. - pub async fn next(&mut self) -> Option { - None - } -} - struct Lt<'a> { foo: &'a u32, } @@ -171,6 +107,8 @@ impl BadNew { } } +struct T; + impl Mul for T { type Output = T; // No error, obviously. diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index 01cf487ac148e..2a0a43e83a653 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -1,15 +1,5 @@ -error: defining a method called `add` on this type; consider implementing the `std::ops::Add` trait or choosing a less ambiguous name - --> $DIR/methods.rs:39:5 - | -LL | / pub fn add(self, other: T) -> T { -LL | | self -LL | | } - | |_____^ - | - = note: `-D clippy::should-implement-trait` implied by `-D warnings` - error: methods called `new` usually return `Self` - --> $DIR/methods.rs:169:5 + --> $DIR/methods.rs:105:5 | LL | / fn new() -> i32 { LL | | 0 @@ -19,7 +9,7 @@ LL | | } = note: `-D clippy::new-ret-no-self` implied by `-D warnings` error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead. - --> $DIR/methods.rs:188:13 + --> $DIR/methods.rs:126:13 | LL | let _ = v.iter().filter(|&x| *x < 0).next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -28,7 +18,7 @@ LL | let _ = v.iter().filter(|&x| *x < 0).next(); = note: replace `filter(|&x| *x < 0).next()` with `find(|&x| *x < 0)` error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead. - --> $DIR/methods.rs:191:13 + --> $DIR/methods.rs:129:13 | LL | let _ = v.iter().filter(|&x| { | _____________^ @@ -38,7 +28,7 @@ LL | | ).next(); | |___________________________^ error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:208:22 + --> $DIR/methods.rs:146:22 | LL | let _ = v.iter().find(|&x| *x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x < 0)` @@ -46,25 +36,25 @@ LL | let _ = v.iter().find(|&x| *x < 0).is_some(); = 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:209:20 + --> $DIR/methods.rs:147: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:210:20 + --> $DIR/methods.rs:148: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:211:22 + --> $DIR/methods.rs:149: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:214:13 + --> $DIR/methods.rs:152:13 | LL | let _ = v.iter().find(|&x| { | _____________^ @@ -74,13 +64,13 @@ LL | | ).is_some(); | |______________________________^ error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:220:22 + --> $DIR/methods.rs:158: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:223:13 + --> $DIR/methods.rs:161:13 | LL | let _ = v.iter().position(|&x| { | _____________^ @@ -90,13 +80,13 @@ LL | | ).is_some(); | |______________________________^ error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:229:22 + --> $DIR/methods.rs:167: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:232:13 + --> $DIR/methods.rs:170:13 | LL | let _ = v.iter().rposition(|&x| { | _____________^ @@ -105,5 +95,5 @@ LL | | } LL | | ).is_some(); | |______________________________^ -error: aborting due to 13 previous errors +error: aborting due to 12 previous errors diff --git a/tests/ui/mut_reference.stderr b/tests/ui/mut_reference.stderr index fa8c82ae0f340..062d30b262c1b 100644 --- a/tests/ui/mut_reference.stderr +++ b/tests/ui/mut_reference.stderr @@ -1,4 +1,4 @@ -error: The function/method `takes_an_immutable_reference` doesn't need a mutable reference +error: the function `takes_an_immutable_reference` doesn't need a mutable reference --> $DIR/mut_reference.rs:17:34 | LL | takes_an_immutable_reference(&mut 42); @@ -6,13 +6,13 @@ LL | takes_an_immutable_reference(&mut 42); | = note: `-D clippy::unnecessary-mut-passed` implied by `-D warnings` -error: The function/method `as_ptr` doesn't need a mutable reference +error: the function `as_ptr` doesn't need a mutable reference --> $DIR/mut_reference.rs:19:12 | LL | as_ptr(&mut 42); | ^^^^^^^ -error: The function/method `takes_an_immutable_reference` doesn't need a mutable reference +error: the method `takes_an_immutable_reference` doesn't need a mutable reference --> $DIR/mut_reference.rs:23:44 | LL | my_struct.takes_an_immutable_reference(&mut 42); diff --git a/tests/ui/mutex_atomic.stderr b/tests/ui/mutex_atomic.stderr index 7dac086585548..a3511ba708a88 100644 --- a/tests/ui/mutex_atomic.stderr +++ b/tests/ui/mutex_atomic.stderr @@ -1,4 +1,4 @@ -error: Consider using an `AtomicBool` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`. +error: consider using an `AtomicBool` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` --> $DIR/mutex_atomic.rs:6:5 | LL | Mutex::new(true); @@ -6,31 +6,31 @@ LL | Mutex::new(true); | = note: `-D clippy::mutex-atomic` implied by `-D warnings` -error: Consider using an `AtomicUsize` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`. +error: consider using an `AtomicUsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` --> $DIR/mutex_atomic.rs:7:5 | LL | Mutex::new(5usize); | ^^^^^^^^^^^^^^^^^^ -error: Consider using an `AtomicIsize` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`. +error: consider using an `AtomicIsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` --> $DIR/mutex_atomic.rs:8:5 | LL | Mutex::new(9isize); | ^^^^^^^^^^^^^^^^^^ -error: Consider using an `AtomicPtr` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`. +error: consider using an `AtomicPtr` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` --> $DIR/mutex_atomic.rs:10:5 | LL | Mutex::new(&x as *const u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: Consider using an `AtomicPtr` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`. +error: consider using an `AtomicPtr` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` --> $DIR/mutex_atomic.rs:11:5 | LL | Mutex::new(&mut x as *mut u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: Consider using an `AtomicUsize` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`. +error: consider using an `AtomicUsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` --> $DIR/mutex_atomic.rs:12:5 | LL | Mutex::new(0u32); @@ -38,7 +38,7 @@ LL | Mutex::new(0u32); | = note: `-D clippy::mutex-integer` implied by `-D warnings` -error: Consider using an `AtomicIsize` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`. +error: consider using an `AtomicIsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` --> $DIR/mutex_atomic.rs:13:5 | LL | Mutex::new(0i32); diff --git a/tests/ui/needless_doc_main.rs b/tests/ui/needless_doc_main.rs index 682d7b3c4ceb4..883683e08a2aa 100644 --- a/tests/ui/needless_doc_main.rs +++ b/tests/ui/needless_doc_main.rs @@ -9,8 +9,14 @@ /// } /// ``` /// -/// This should, too. +/// With an explicit return type it should lint too +/// ``` +/// fn main() -> () { +/// unimplemented!(); +/// } +/// ``` /// +/// This should, too. /// ```rust /// fn main() { /// unimplemented!(); @@ -18,7 +24,6 @@ /// ``` /// /// This one too. -/// /// ```no_run /// fn main() { /// unimplemented!(); @@ -33,6 +38,20 @@ fn bad_doctests() {} /// fn main(){} /// ``` /// +/// This shouldn't lint either, because main is async: +/// ``` +/// async fn main() { +/// assert_eq!(42, ANSWER); +/// } +/// ``` +/// +/// Same here, because the return type is not the unit type: +/// ``` +/// fn main() -> Result<()> { +/// Ok(()) +/// } +/// ``` +/// /// This shouldn't lint either, because there's a `static`: /// ``` /// static ANSWER: i32 = 42; @@ -42,6 +61,15 @@ fn bad_doctests() {} /// } /// ``` /// +/// This shouldn't lint either, because there's a `const`: +/// ``` +/// fn main() { +/// assert_eq!(42, ANSWER); +/// } +/// +/// const ANSWER: i32 = 42; +/// ``` +/// /// Neither should this lint because of `extern crate`: /// ``` /// #![feature(test)] @@ -51,8 +79,41 @@ fn bad_doctests() {} /// } /// ``` /// -/// We should not lint ignored examples: +/// Neither should this lint because it has an extern block: +/// ``` +/// extern {} +/// fn main() { +/// unimplemented!(); +/// } +/// ``` +/// +/// This should not lint because there is another function defined: +/// ``` +/// fn fun() {} +/// +/// fn main() { +/// unimplemented!(); +/// } +/// ``` /// +/// We should not lint inside raw strings ... +/// ``` +/// let string = r#" +/// fn main() { +/// unimplemented!(); +/// } +/// "#; +/// ``` +/// +/// ... or comments +/// ``` +/// // fn main() { +/// // let _inception = 42; +/// // } +/// let _inception = 42; +/// ``` +/// +/// We should not lint ignored examples: /// ```rust,ignore /// fn main() { /// unimplemented!(); @@ -60,7 +121,6 @@ fn bad_doctests() {} /// ``` /// /// Or even non-rust examples: -/// /// ```text /// fn main() { /// is what starts the program diff --git a/tests/ui/needless_doc_main.stderr b/tests/ui/needless_doc_main.stderr index 65d40ee6832f2..05c7f9d33a792 100644 --- a/tests/ui/needless_doc_main.stderr +++ b/tests/ui/needless_doc_main.stderr @@ -7,16 +7,22 @@ LL | /// fn main() { = note: `-D clippy::needless-doctest-main` implied by `-D warnings` error: needless `fn main` in doctest - --> $DIR/needless_doc_main.rs:15:4 + --> $DIR/needless_doc_main.rs:14:4 + | +LL | /// fn main() -> () { + | ^^^^^^^^^^^^^^^^^^ + +error: needless `fn main` in doctest + --> $DIR/needless_doc_main.rs:21:4 | LL | /// fn main() { | ^^^^^^^^^^^^ error: needless `fn main` in doctest - --> $DIR/needless_doc_main.rs:23:4 + --> $DIR/needless_doc_main.rs:28:4 | LL | /// fn main() { | ^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index ad20e2381073a..d849e093da7bb 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -69,6 +69,23 @@ fn test_void_match(x: u32) { } } +fn read_line() -> String { + use std::io::BufRead; + let stdin = ::std::io::stdin(); + return stdin.lock().lines().next().unwrap().unwrap(); +} + +fn borrows_but_not_last(value: bool) -> String { + if value { + use std::io::BufRead; + let stdin = ::std::io::stdin(); + let _a = stdin.lock().lines().next().unwrap().unwrap(); + String::from("test") + } else { + String::new() + } +} + fn main() { let _ = test_end_of_fn(); let _ = test_no_semicolon(); diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index af0cdfb207ff5..29f2bd1852af0 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -69,6 +69,23 @@ fn test_void_match(x: u32) { } } +fn read_line() -> String { + use std::io::BufRead; + let stdin = ::std::io::stdin(); + return stdin.lock().lines().next().unwrap().unwrap(); +} + +fn borrows_but_not_last(value: bool) -> String { + if value { + use std::io::BufRead; + let stdin = ::std::io::stdin(); + let _a = stdin.lock().lines().next().unwrap().unwrap(); + return String::from("test"); + } else { + return String::new(); + } +} + fn main() { let _ = test_end_of_fn(); let _ = test_no_semicolon(); diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index c34eecbcbb639..f73c833a801f3 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -72,5 +72,17 @@ error: unneeded `return` statement LL | _ => return, | ^^^^^^ help: replace `return` with an empty block: `{}` -error: aborting due to 12 previous errors +error: unneeded `return` statement + --> $DIR/needless_return.rs:83:9 + | +LL | return String::from("test"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")` + +error: unneeded `return` statement + --> $DIR/needless_return.rs:85:9 + | +LL | return String::new(); + | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()` + +error: aborting due to 14 previous errors diff --git a/tests/ui/new_ret_no_self.rs b/tests/ui/new_ret_no_self.rs index 2c2d1e275893f..e82873629a54b 100644 --- a/tests/ui/new_ret_no_self.rs +++ b/tests/ui/new_ret_no_self.rs @@ -137,9 +137,9 @@ impl MutPointerReturnerOk { } } -struct MutPointerReturnerOk2; +struct ConstPointerReturnerOk2; -impl MutPointerReturnerOk2 { +impl ConstPointerReturnerOk2 { // should not trigger lint pub fn new() -> *const Self { unimplemented!(); @@ -210,3 +210,133 @@ impl<'a> WithLifetime<'a> { unimplemented!(); } } + +mod issue5435 { + struct V; + + pub trait TraitRetSelf { + // should not trigger lint + fn new() -> Self; + } + + pub trait TraitRet { + // should trigger lint as we are in trait definition + fn new() -> String; + } + pub struct StructRet; + impl TraitRet for StructRet { + // should not trigger lint as we are in the impl block + fn new() -> String { + unimplemented!(); + } + } + + pub trait TraitRet2 { + // should trigger lint + fn new(_: String) -> String; + } + + trait TupleReturnerOk { + // should not trigger lint + fn new() -> (Self, u32) + where + Self: Sized, + { + unimplemented!(); + } + } + + trait TupleReturnerOk2 { + // should not trigger lint (it doesn't matter which element in the tuple is Self) + fn new() -> (u32, Self) + where + Self: Sized, + { + unimplemented!(); + } + } + + trait TupleReturnerOk3 { + // should not trigger lint (tuple can contain multiple Self) + fn new() -> (Self, Self) + where + Self: Sized, + { + unimplemented!(); + } + } + + trait TupleReturnerBad { + // should trigger lint + fn new() -> (u32, u32) { + unimplemented!(); + } + } + + trait MutPointerReturnerOk { + // should not trigger lint + fn new() -> *mut Self + where + Self: Sized, + { + unimplemented!(); + } + } + + trait ConstPointerReturnerOk2 { + // should not trigger lint + fn new() -> *const Self + where + Self: Sized, + { + unimplemented!(); + } + } + + trait MutPointerReturnerBad { + // should trigger lint + fn new() -> *mut V { + unimplemented!(); + } + } + + trait GenericReturnerOk { + // should not trigger lint + fn new() -> Option + where + Self: Sized, + { + unimplemented!(); + } + } + + trait NestedReturnerOk { + // should not trigger lint + fn new() -> (Option, u32) + where + Self: Sized, + { + unimplemented!(); + } + } + + trait NestedReturnerOk2 { + // should not trigger lint + fn new() -> ((Self, u32), u32) + where + Self: Sized, + { + unimplemented!(); + } + } + + trait NestedReturnerOk3 { + // should not trigger lint + fn new() -> Option<(Self, u32)> + where + Self: Sized, + { + unimplemented!(); + } + } +} diff --git a/tests/ui/new_ret_no_self.stderr b/tests/ui/new_ret_no_self.stderr index dd5a24bcbe7ae..8217bc6187f93 100644 --- a/tests/ui/new_ret_no_self.stderr +++ b/tests/ui/new_ret_no_self.stderr @@ -48,5 +48,33 @@ LL | | unimplemented!(); LL | | } | |_____^ -error: aborting due to 6 previous errors +error: methods called `new` usually return `Self` + --> $DIR/new_ret_no_self.rs:224:9 + | +LL | fn new() -> String; + | ^^^^^^^^^^^^^^^^^^^ + +error: methods called `new` usually return `Self` + --> $DIR/new_ret_no_self.rs:236:9 + | +LL | fn new(_: String) -> String; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: methods called `new` usually return `Self` + --> $DIR/new_ret_no_self.rs:271:9 + | +LL | / fn new() -> (u32, u32) { +LL | | unimplemented!(); +LL | | } + | |_________^ + +error: methods called `new` usually return `Self` + --> $DIR/new_ret_no_self.rs:298:9 + | +LL | / fn new() -> *mut V { +LL | | unimplemented!(); +LL | | } + | |_________^ + +error: aborting due to 10 previous errors diff --git a/tests/ui/option_as_ref_deref.fixed b/tests/ui/option_as_ref_deref.fixed index 076692e644517..07d7f0b45b0c2 100644 --- a/tests/ui/option_as_ref_deref.fixed +++ b/tests/ui/option_as_ref_deref.fixed @@ -38,4 +38,7 @@ fn main() { let _ = opt.as_deref(); let _ = opt.as_deref_mut(); + + // Issue #5927 + let _ = opt.as_deref(); } diff --git a/tests/ui/option_as_ref_deref.rs b/tests/ui/option_as_ref_deref.rs index 3bf5f715f8339..6ae059c9425d3 100644 --- a/tests/ui/option_as_ref_deref.rs +++ b/tests/ui/option_as_ref_deref.rs @@ -41,4 +41,7 @@ fn main() { let _ = opt.as_ref().map(|x| &**x); let _ = opt.as_mut().map(|x| &mut **x); + + // Issue #5927 + let _ = opt.as_ref().map(std::ops::Deref::deref); } diff --git a/tests/ui/option_as_ref_deref.stderr b/tests/ui/option_as_ref_deref.stderr index a106582a63323..62f2823247528 100644 --- a/tests/ui/option_as_ref_deref.stderr +++ b/tests/ui/option_as_ref_deref.stderr @@ -100,5 +100,11 @@ error: called `.as_mut().map(|x| &mut **x)` on an Option value. This can be done LL | let _ = opt.as_mut().map(|x| &mut **x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()` -error: aborting due to 16 previous errors +error: called `.as_ref().map(std::ops::Deref::deref)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead + --> $DIR/option_as_ref_deref.rs:46:13 + | +LL | let _ = opt.as_ref().map(std::ops::Deref::deref); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` + +error: aborting due to 17 previous errors diff --git a/tests/ui/precedence.fixed b/tests/ui/precedence.fixed index 4d284ae1319d3..163bd044c178e 100644 --- a/tests/ui/precedence.fixed +++ b/tests/ui/precedence.fixed @@ -48,6 +48,14 @@ fn main() { let _ = -1f64.to_degrees(); let _ = -1f64.to_radians(); + // Chains containing any non-odd function should trigger (issue #5924) + let _ = -(1.0_f64.cos().cos()); + let _ = -(1.0_f64.cos().sin()); + let _ = -(1.0_f64.sin().cos()); + + // Chains of odd functions shouldn't trigger + let _ = -1f64.sin().sin(); + let b = 3; trip!(b * 8); } diff --git a/tests/ui/precedence.rs b/tests/ui/precedence.rs index 2d08e82f349ad..8c849e3209b08 100644 --- a/tests/ui/precedence.rs +++ b/tests/ui/precedence.rs @@ -48,6 +48,14 @@ fn main() { let _ = -1f64.to_degrees(); let _ = -1f64.to_radians(); + // Chains containing any non-odd function should trigger (issue #5924) + let _ = -1.0_f64.cos().cos(); + let _ = -1.0_f64.cos().sin(); + let _ = -1.0_f64.sin().cos(); + + // Chains of odd functions shouldn't trigger + let _ = -1f64.sin().sin(); + let b = 3; trip!(b * 8); } diff --git a/tests/ui/precedence.stderr b/tests/ui/precedence.stderr index a2ed5392bfc7c..03d585b39750a 100644 --- a/tests/ui/precedence.stderr +++ b/tests/ui/precedence.stderr @@ -54,5 +54,23 @@ error: unary minus has lower precedence than method call LL | -1f32.abs(); | ^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1f32.abs())` -error: aborting due to 9 previous errors +error: unary minus has lower precedence than method call + --> $DIR/precedence.rs:52:13 + | +LL | let _ = -1.0_f64.cos().cos(); + | ^^^^^^^^^^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1.0_f64.cos().cos())` + +error: unary minus has lower precedence than method call + --> $DIR/precedence.rs:53:13 + | +LL | let _ = -1.0_f64.cos().sin(); + | ^^^^^^^^^^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1.0_f64.cos().sin())` + +error: unary minus has lower precedence than method call + --> $DIR/precedence.rs:54:13 + | +LL | let _ = -1.0_f64.sin().cos(); + | ^^^^^^^^^^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1.0_f64.sin().cos())` + +error: aborting due to 12 previous errors diff --git a/tests/ui/redundant_allocation.fixed b/tests/ui/redundant_allocation.fixed index 266358334587d..6514fd6d1ac76 100644 --- a/tests/ui/redundant_allocation.fixed +++ b/tests/ui/redundant_allocation.fixed @@ -33,7 +33,7 @@ pub fn test5(a: Rc) {} // Rc> -pub fn test6(a: Box) {} +pub fn test6(a: Rc) {} // Box<&T> diff --git a/tests/ui/redundant_allocation.stderr b/tests/ui/redundant_allocation.stderr index eaa57ce3024b6..92e4f67f5db6e 100644 --- a/tests/ui/redundant_allocation.stderr +++ b/tests/ui/redundant_allocation.stderr @@ -28,7 +28,7 @@ error: usage of `Rc>` --> $DIR/redundant_allocation.rs:36:17 | LL | pub fn test6(a: Rc>) {} - | ^^^^^^^^^^^^^ help: try: `Box` + | ^^^^^^^^^^^^^ help: try: `Rc` error: usage of `Box<&T>` --> $DIR/redundant_allocation.rs:40:22 diff --git a/tests/ui/redundant_closure_call_early.stderr b/tests/ui/redundant_closure_call_early.stderr index 79f276634619e..2735e41738f0d 100644 --- a/tests/ui/redundant_closure_call_early.stderr +++ b/tests/ui/redundant_closure_call_early.stderr @@ -1,4 +1,4 @@ -error: try not to call a closure in the expression where it is declared. +error: try not to call a closure in the expression where it is declared --> $DIR/redundant_closure_call_early.rs:9:17 | LL | let mut k = (|m| m + 1)(i); @@ -6,7 +6,7 @@ LL | let mut k = (|m| m + 1)(i); | = note: `-D clippy::redundant-closure-call` implied by `-D warnings` -error: try not to call a closure in the expression where it is declared. +error: try not to call a closure in the expression where it is declared --> $DIR/redundant_closure_call_early.rs:12:9 | LL | k = (|a, b| a * b)(1, 5); diff --git a/tests/ui/redundant_closure_call_fixable.stderr b/tests/ui/redundant_closure_call_fixable.stderr index 644161d9f5d88..afd704ef12a93 100644 --- a/tests/ui/redundant_closure_call_fixable.stderr +++ b/tests/ui/redundant_closure_call_fixable.stderr @@ -1,4 +1,4 @@ -error: try not to call a closure in the expression where it is declared. +error: try not to call a closure in the expression where it is declared --> $DIR/redundant_closure_call_fixable.rs:7:13 | LL | let a = (|| 42)(); diff --git a/tests/ui/redundant_closure_call_late.rs b/tests/ui/redundant_closure_call_late.rs index e29a1dce0c7e8..1f4864b72895b 100644 --- a/tests/ui/redundant_closure_call_late.rs +++ b/tests/ui/redundant_closure_call_late.rs @@ -24,4 +24,16 @@ fn main() { let shadowed_closure = || 2; i = shadowed_closure(); i = shadowed_closure(); + + // Fix FP in #5916 + let mut x; + let create = || 2 * 2; + x = create(); + fun(move || { + x = create(); + }) +} + +fn fun(mut f: T) { + f(); } diff --git a/tests/ui/same_item_push.rs b/tests/ui/same_item_push.rs index ff1088f86f647..bfe27e020445c 100644 --- a/tests/ui/same_item_push.rs +++ b/tests/ui/same_item_push.rs @@ -86,4 +86,12 @@ fn main() { for a in vec_a { vec12.push(2u8.pow(a.kind)); } + + // Fix #5902 + let mut vec13: Vec = Vec::new(); + let mut item = 0; + for _ in 0..10 { + vec13.push(item); + item += 10; + } } diff --git a/tests/ui/self_assignment.rs b/tests/ui/self_assignment.rs new file mode 100644 index 0000000000000..a7cbb9cd78b15 --- /dev/null +++ b/tests/ui/self_assignment.rs @@ -0,0 +1,67 @@ +#![warn(clippy::self_assignment)] + +pub struct S<'a> { + a: i32, + b: [i32; 10], + c: Vec>, + e: &'a mut i32, + f: &'a mut i32, +} + +pub fn positives(mut a: usize, b: &mut u32, mut s: S) { + a = a; + *b = *b; + s = s; + s.a = s.a; + s.b[10] = s.b[5 + 5]; + s.c[0][1] = s.c[0][1]; + s.b[a] = s.b[a]; + *s.e = *s.e; + s.b[a + 10] = s.b[10 + a]; + + let mut t = (0, 1); + t.1 = t.1; + t.0 = (t.0); +} + +pub fn negatives_not_equal(mut a: usize, b: &mut usize, mut s: S) { + dbg!(&a); + a = *b; + dbg!(&a); + s.b[1] += s.b[1]; + s.b[1] = s.b[2]; + s.c[1][0] = s.c[0][1]; + s.b[a] = s.b[*b]; + s.b[a + 10] = s.b[a + 11]; + *s.e = *s.f; + + let mut t = (0, 1); + t.0 = t.1; +} + +#[allow(clippy::eval_order_dependence)] +pub fn negatives_side_effects() { + let mut v = vec![1, 2, 3, 4, 5]; + let mut i = 0; + v[{ + i += 1; + i + }] = v[{ + i += 1; + i + }]; + + fn next(n: &mut usize) -> usize { + let v = *n; + *n += 1; + v + } + + let mut w = vec![1, 2, 3, 4, 5]; + let mut i = 0; + let i = &mut i; + w[next(i)] = w[next(i)]; + w[next(i)] = w[next(i)]; +} + +fn main() {} diff --git a/tests/ui/self_assignment.stderr b/tests/ui/self_assignment.stderr new file mode 100644 index 0000000000000..826e0d0ba888d --- /dev/null +++ b/tests/ui/self_assignment.stderr @@ -0,0 +1,70 @@ +error: self-assignment of `a` to `a` + --> $DIR/self_assignment.rs:12:5 + | +LL | a = a; + | ^^^^^ + | + = note: `-D clippy::self-assignment` implied by `-D warnings` + +error: self-assignment of `*b` to `*b` + --> $DIR/self_assignment.rs:13:5 + | +LL | *b = *b; + | ^^^^^^^ + +error: self-assignment of `s` to `s` + --> $DIR/self_assignment.rs:14:5 + | +LL | s = s; + | ^^^^^ + +error: self-assignment of `s.a` to `s.a` + --> $DIR/self_assignment.rs:15:5 + | +LL | s.a = s.a; + | ^^^^^^^^^ + +error: self-assignment of `s.b[5 + 5]` to `s.b[10]` + --> $DIR/self_assignment.rs:16:5 + | +LL | s.b[10] = s.b[5 + 5]; + | ^^^^^^^^^^^^^^^^^^^^ + +error: self-assignment of `s.c[0][1]` to `s.c[0][1]` + --> $DIR/self_assignment.rs:17:5 + | +LL | s.c[0][1] = s.c[0][1]; + | ^^^^^^^^^^^^^^^^^^^^^ + +error: self-assignment of `s.b[a]` to `s.b[a]` + --> $DIR/self_assignment.rs:18:5 + | +LL | s.b[a] = s.b[a]; + | ^^^^^^^^^^^^^^^ + +error: self-assignment of `*s.e` to `*s.e` + --> $DIR/self_assignment.rs:19:5 + | +LL | *s.e = *s.e; + | ^^^^^^^^^^^ + +error: self-assignment of `s.b[10 + a]` to `s.b[a + 10]` + --> $DIR/self_assignment.rs:20:5 + | +LL | s.b[a + 10] = s.b[10 + a]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: self-assignment of `t.1` to `t.1` + --> $DIR/self_assignment.rs:23:5 + | +LL | t.1 = t.1; + | ^^^^^^^^^ + +error: self-assignment of `(t.0)` to `t.0` + --> $DIR/self_assignment.rs:24:5 + | +LL | t.0 = (t.0); + | ^^^^^^^^^^^ + +error: aborting due to 11 previous errors + diff --git a/tests/ui/should_impl_trait/corner_cases.rs b/tests/ui/should_impl_trait/corner_cases.rs new file mode 100644 index 0000000000000..6c5ffe6aba8b7 --- /dev/null +++ b/tests/ui/should_impl_trait/corner_cases.rs @@ -0,0 +1,83 @@ +// edition:2018 + +#![warn(clippy::all, clippy::pedantic)] +#![allow( + clippy::missing_errors_doc, + clippy::needless_pass_by_value, + clippy::must_use_candidate, + clippy::unused_self, + clippy::needless_lifetimes, + clippy::missing_safety_doc, + clippy::wrong_self_convention +)] + +use std::ops::Mul; +use std::rc::{self, Rc}; +use std::sync::{self, Arc}; + +fn main() {} + +pub struct T1; +impl T1 { + // corner cases: should not lint + + // no error, not public interface + pub(crate) fn drop(&mut self) {} + + // no error, private function + fn neg(self) -> Self { + self + } + + // no error, private function + fn eq(&self, other: Self) -> bool { + true + } + + // No error; self is a ref. + fn sub(&self, other: Self) -> &Self { + self + } + + // No error; different number of arguments. + fn div(self) -> Self { + self + } + + // No error; wrong return type. + fn rem(self, other: Self) {} + + // Fine + fn into_u32(self) -> u32 { + 0 + } + + fn into_u16(&self) -> u16 { + 0 + } + + fn to_something(self) -> u32 { + 0 + } + + fn new(self) -> Self { + unimplemented!(); + } + + pub fn next<'b>(&'b mut self) -> Option<&'b mut T1> { + unimplemented!(); + } +} + +pub struct T2; +impl T2 { + // Shouldn't trigger lint as it is unsafe. + pub unsafe fn add(self, rhs: Self) -> Self { + self + } + + // Should not trigger lint since this is an async function. + pub async fn next(&mut self) -> Option { + None + } +} diff --git a/tests/ui/should_impl_trait/method_list_1.rs b/tests/ui/should_impl_trait/method_list_1.rs new file mode 100644 index 0000000000000..f8d248fc98d82 --- /dev/null +++ b/tests/ui/should_impl_trait/method_list_1.rs @@ -0,0 +1,87 @@ +// edition:2018 + +#![warn(clippy::all, clippy::pedantic)] +#![allow( + clippy::missing_errors_doc, + clippy::needless_pass_by_value, + clippy::must_use_candidate, + clippy::unused_self, + clippy::needless_lifetimes, + clippy::missing_safety_doc, + clippy::wrong_self_convention +)] + +use std::ops::Mul; +use std::rc::{self, Rc}; +use std::sync::{self, Arc}; + +fn main() {} +pub struct T; + +impl T { + // ***************************************** + // trait method list part 1, should lint all + // ***************************************** + pub fn add(self, other: T) -> T { + unimplemented!() + } + + pub fn as_mut(&mut self) -> &mut T { + unimplemented!() + } + + pub fn as_ref(&self) -> &T { + unimplemented!() + } + + pub fn bitand(self, rhs: T) -> T { + unimplemented!() + } + + pub fn bitor(self, rhs: Self) -> Self { + unimplemented!() + } + + pub fn bitxor(self, rhs: Self) -> Self { + unimplemented!() + } + + pub fn borrow(&self) -> &str { + unimplemented!() + } + + pub fn borrow_mut(&mut self) -> &mut str { + unimplemented!() + } + + pub fn clone(&self) -> Self { + unimplemented!() + } + + pub fn cmp(&self, other: &Self) -> Self { + unimplemented!() + } + + pub fn default() -> Self { + unimplemented!() + } + + pub fn deref(&self) -> &Self { + unimplemented!() + } + + pub fn deref_mut(&mut self) -> &mut Self { + unimplemented!() + } + + pub fn div(self, rhs: Self) -> Self { + unimplemented!() + } + + pub fn drop(&mut self) { + unimplemented!() + } + // ********** + // part 1 end + // ********** +} diff --git a/tests/ui/should_impl_trait/method_list_1.stderr b/tests/ui/should_impl_trait/method_list_1.stderr new file mode 100644 index 0000000000000..2b7d4628c3fa0 --- /dev/null +++ b/tests/ui/should_impl_trait/method_list_1.stderr @@ -0,0 +1,143 @@ +error: method `add` can be confused for the standard trait method `std::ops::Add::add` + --> $DIR/method_list_1.rs:25:5 + | +LL | / pub fn add(self, other: T) -> T { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = note: `-D clippy::should-implement-trait` implied by `-D warnings` + = help: consider implementing the trait `std::ops::Add` or choosing a less ambiguous method name + +error: method `as_mut` can be confused for the standard trait method `std::convert::AsMut::as_mut` + --> $DIR/method_list_1.rs:29:5 + | +LL | / pub fn as_mut(&mut self) -> &mut T { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::convert::AsMut` or choosing a less ambiguous method name + +error: method `as_ref` can be confused for the standard trait method `std::convert::AsRef::as_ref` + --> $DIR/method_list_1.rs:33:5 + | +LL | / pub fn as_ref(&self) -> &T { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::convert::AsRef` or choosing a less ambiguous method name + +error: method `bitand` can be confused for the standard trait method `std::ops::BitAnd::bitand` + --> $DIR/method_list_1.rs:37:5 + | +LL | / pub fn bitand(self, rhs: T) -> T { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::BitAnd` or choosing a less ambiguous method name + +error: method `bitor` can be confused for the standard trait method `std::ops::BitOr::bitor` + --> $DIR/method_list_1.rs:41:5 + | +LL | / pub fn bitor(self, rhs: Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::BitOr` or choosing a less ambiguous method name + +error: method `bitxor` can be confused for the standard trait method `std::ops::BitXor::bitxor` + --> $DIR/method_list_1.rs:45:5 + | +LL | / pub fn bitxor(self, rhs: Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::BitXor` or choosing a less ambiguous method name + +error: method `borrow` can be confused for the standard trait method `std::borrow::Borrow::borrow` + --> $DIR/method_list_1.rs:49:5 + | +LL | / pub fn borrow(&self) -> &str { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::borrow::Borrow` or choosing a less ambiguous method name + +error: method `borrow_mut` can be confused for the standard trait method `std::borrow::BorrowMut::borrow_mut` + --> $DIR/method_list_1.rs:53:5 + | +LL | / pub fn borrow_mut(&mut self) -> &mut str { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::borrow::BorrowMut` or choosing a less ambiguous method name + +error: method `clone` can be confused for the standard trait method `std::clone::Clone::clone` + --> $DIR/method_list_1.rs:57:5 + | +LL | / pub fn clone(&self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::clone::Clone` or choosing a less ambiguous method name + +error: method `cmp` can be confused for the standard trait method `std::cmp::Ord::cmp` + --> $DIR/method_list_1.rs:61:5 + | +LL | / pub fn cmp(&self, other: &Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::cmp::Ord` or choosing a less ambiguous method name + +error: method `deref` can be confused for the standard trait method `std::ops::Deref::deref` + --> $DIR/method_list_1.rs:69:5 + | +LL | / pub fn deref(&self) -> &Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::Deref` or choosing a less ambiguous method name + +error: method `deref_mut` can be confused for the standard trait method `std::ops::DerefMut::deref_mut` + --> $DIR/method_list_1.rs:73:5 + | +LL | / pub fn deref_mut(&mut self) -> &mut Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::DerefMut` or choosing a less ambiguous method name + +error: method `div` can be confused for the standard trait method `std::ops::Div::div` + --> $DIR/method_list_1.rs:77:5 + | +LL | / pub fn div(self, rhs: Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::Div` or choosing a less ambiguous method name + +error: method `drop` can be confused for the standard trait method `std::ops::Drop::drop` + --> $DIR/method_list_1.rs:81:5 + | +LL | / pub fn drop(&mut self) { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::Drop` or choosing a less ambiguous method name + +error: aborting due to 14 previous errors + diff --git a/tests/ui/should_impl_trait/method_list_2.rs b/tests/ui/should_impl_trait/method_list_2.rs new file mode 100644 index 0000000000000..ed5e0d384bf50 --- /dev/null +++ b/tests/ui/should_impl_trait/method_list_2.rs @@ -0,0 +1,88 @@ +// edition:2018 + +#![warn(clippy::all, clippy::pedantic)] +#![allow( + clippy::missing_errors_doc, + clippy::needless_pass_by_value, + clippy::must_use_candidate, + clippy::unused_self, + clippy::needless_lifetimes, + clippy::missing_safety_doc, + clippy::wrong_self_convention +)] + +use std::ops::Mul; +use std::rc::{self, Rc}; +use std::sync::{self, Arc}; + +fn main() {} +pub struct T; + +impl T { + // ***************************************** + // trait method list part 2, should lint all + // ***************************************** + + pub fn eq(&self, other: &Self) -> bool { + unimplemented!() + } + + pub fn from_iter(iter: T) -> Self { + unimplemented!() + } + + pub fn from_str(s: &str) -> Result { + unimplemented!() + } + + pub fn hash(&self, state: &mut T) { + unimplemented!() + } + + pub fn index(&self, index: usize) -> &Self { + unimplemented!() + } + + pub fn index_mut(&mut self, index: usize) -> &mut Self { + unimplemented!() + } + + pub fn into_iter(self) -> Self { + unimplemented!() + } + + pub fn mul(self, rhs: Self) -> Self { + unimplemented!() + } + + pub fn neg(self) -> Self { + unimplemented!() + } + + pub fn next(&mut self) -> Option { + unimplemented!() + } + + pub fn not(self) -> Self { + unimplemented!() + } + + pub fn rem(self, rhs: Self) -> Self { + unimplemented!() + } + + pub fn shl(self, rhs: Self) -> Self { + unimplemented!() + } + + pub fn shr(self, rhs: Self) -> Self { + unimplemented!() + } + + pub fn sub(self, rhs: Self) -> Self { + unimplemented!() + } + // ********** + // part 2 end + // ********** +} diff --git a/tests/ui/should_impl_trait/method_list_2.stderr b/tests/ui/should_impl_trait/method_list_2.stderr new file mode 100644 index 0000000000000..b6fd435695698 --- /dev/null +++ b/tests/ui/should_impl_trait/method_list_2.stderr @@ -0,0 +1,153 @@ +error: method `eq` can be confused for the standard trait method `std::cmp::PartialEq::eq` + --> $DIR/method_list_2.rs:26:5 + | +LL | / pub fn eq(&self, other: &Self) -> bool { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = note: `-D clippy::should-implement-trait` implied by `-D warnings` + = help: consider implementing the trait `std::cmp::PartialEq` or choosing a less ambiguous method name + +error: method `from_iter` can be confused for the standard trait method `std::iter::FromIterator::from_iter` + --> $DIR/method_list_2.rs:30:5 + | +LL | / pub fn from_iter(iter: T) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::iter::FromIterator` or choosing a less ambiguous method name + +error: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str` + --> $DIR/method_list_2.rs:34:5 + | +LL | / pub fn from_str(s: &str) -> Result { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name + +error: method `hash` can be confused for the standard trait method `std::hash::Hash::hash` + --> $DIR/method_list_2.rs:38:5 + | +LL | / pub fn hash(&self, state: &mut T) { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name + +error: method `index` can be confused for the standard trait method `std::ops::Index::index` + --> $DIR/method_list_2.rs:42:5 + | +LL | / pub fn index(&self, index: usize) -> &Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::Index` or choosing a less ambiguous method name + +error: method `index_mut` can be confused for the standard trait method `std::ops::IndexMut::index_mut` + --> $DIR/method_list_2.rs:46:5 + | +LL | / pub fn index_mut(&mut self, index: usize) -> &mut Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::IndexMut` or choosing a less ambiguous method name + +error: method `into_iter` can be confused for the standard trait method `std::iter::IntoIterator::into_iter` + --> $DIR/method_list_2.rs:50:5 + | +LL | / pub fn into_iter(self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::iter::IntoIterator` or choosing a less ambiguous method name + +error: method `mul` can be confused for the standard trait method `std::ops::Mul::mul` + --> $DIR/method_list_2.rs:54:5 + | +LL | / pub fn mul(self, rhs: Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::Mul` or choosing a less ambiguous method name + +error: method `neg` can be confused for the standard trait method `std::ops::Neg::neg` + --> $DIR/method_list_2.rs:58:5 + | +LL | / pub fn neg(self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::Neg` or choosing a less ambiguous method name + +error: method `next` can be confused for the standard trait method `std::iter::Iterator::next` + --> $DIR/method_list_2.rs:62:5 + | +LL | / pub fn next(&mut self) -> Option { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::iter::Iterator` or choosing a less ambiguous method name + +error: method `not` can be confused for the standard trait method `std::ops::Not::not` + --> $DIR/method_list_2.rs:66:5 + | +LL | / pub fn not(self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::Not` or choosing a less ambiguous method name + +error: method `rem` can be confused for the standard trait method `std::ops::Rem::rem` + --> $DIR/method_list_2.rs:70:5 + | +LL | / pub fn rem(self, rhs: Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::Rem` or choosing a less ambiguous method name + +error: method `shl` can be confused for the standard trait method `std::ops::Shl::shl` + --> $DIR/method_list_2.rs:74:5 + | +LL | / pub fn shl(self, rhs: Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::Shl` or choosing a less ambiguous method name + +error: method `shr` can be confused for the standard trait method `std::ops::Shr::shr` + --> $DIR/method_list_2.rs:78:5 + | +LL | / pub fn shr(self, rhs: Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::Shr` or choosing a less ambiguous method name + +error: method `sub` can be confused for the standard trait method `std::ops::Sub::sub` + --> $DIR/method_list_2.rs:82:5 + | +LL | / pub fn sub(self, rhs: Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::Sub` or choosing a less ambiguous method name + +error: aborting due to 15 previous errors + diff --git a/tests/ui/single_char_push_str.fixed b/tests/ui/single_char_push_str.fixed new file mode 100644 index 0000000000000..0812c026a644f --- /dev/null +++ b/tests/ui/single_char_push_str.fixed @@ -0,0 +1,15 @@ +// run-rustfix +#![warn(clippy::single_char_push_str)] + +fn main() { + let mut string = String::new(); + string.push('R'); + string.push('\''); + + string.push('u'); + string.push_str("st"); + string.push_str(""); + string.push('\x52'); + string.push('\u{0052}'); + string.push('a'); +} diff --git a/tests/ui/single_char_push_str.rs b/tests/ui/single_char_push_str.rs new file mode 100644 index 0000000000000..ab293bbe4eeb5 --- /dev/null +++ b/tests/ui/single_char_push_str.rs @@ -0,0 +1,15 @@ +// run-rustfix +#![warn(clippy::single_char_push_str)] + +fn main() { + let mut string = String::new(); + string.push_str("R"); + string.push_str("'"); + + string.push('u'); + string.push_str("st"); + string.push_str(""); + string.push_str("\x52"); + string.push_str("\u{0052}"); + string.push_str(r##"a"##); +} diff --git a/tests/ui/single_char_push_str.stderr b/tests/ui/single_char_push_str.stderr new file mode 100644 index 0000000000000..0e9bdaa23e7e8 --- /dev/null +++ b/tests/ui/single_char_push_str.stderr @@ -0,0 +1,34 @@ +error: calling `push_str()` using a single-character string literal + --> $DIR/single_char_push_str.rs:6:5 + | +LL | string.push_str("R"); + | ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('R')` + | + = note: `-D clippy::single-char-push-str` implied by `-D warnings` + +error: calling `push_str()` using a single-character string literal + --> $DIR/single_char_push_str.rs:7:5 + | +LL | string.push_str("'"); + | ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/'')` + +error: calling `push_str()` using a single-character string literal + --> $DIR/single_char_push_str.rs:12:5 + | +LL | string.push_str("/x52"); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/x52')` + +error: calling `push_str()` using a single-character string literal + --> $DIR/single_char_push_str.rs:13:5 + | +LL | string.push_str("/u{0052}"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/u{0052}')` + +error: calling `push_str()` using a single-character string literal + --> $DIR/single_char_push_str.rs:14:5 + | +LL | string.push_str(r##"a"##); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('a')` + +error: aborting due to 5 previous errors + diff --git a/tests/ui/stable_sort_primitive.stderr b/tests/ui/stable_sort_primitive.stderr index b0b729ede48e5..780389f32bc1c 100644 --- a/tests/ui/stable_sort_primitive.stderr +++ b/tests/ui/stable_sort_primitive.stderr @@ -1,4 +1,4 @@ -error: Use sort_unstable instead of sort +error: used sort instead of sort_unstable to sort primitive type `i32` --> $DIR/stable_sort_primitive.rs:7:5 | LL | vec.sort(); @@ -6,37 +6,37 @@ LL | vec.sort(); | = note: `-D clippy::stable-sort-primitive` implied by `-D warnings` -error: Use sort_unstable instead of sort +error: used sort instead of sort_unstable to sort primitive type `bool` --> $DIR/stable_sort_primitive.rs:9:5 | LL | vec.sort(); | ^^^^^^^^^^ help: try: `vec.sort_unstable()` -error: Use sort_unstable instead of sort +error: used sort instead of sort_unstable to sort primitive type `char` --> $DIR/stable_sort_primitive.rs:11:5 | LL | vec.sort(); | ^^^^^^^^^^ help: try: `vec.sort_unstable()` -error: Use sort_unstable instead of sort +error: used sort instead of sort_unstable to sort primitive type `str` --> $DIR/stable_sort_primitive.rs:13:5 | LL | vec.sort(); | ^^^^^^^^^^ help: try: `vec.sort_unstable()` -error: Use sort_unstable instead of sort +error: used sort instead of sort_unstable to sort primitive type `tuple` --> $DIR/stable_sort_primitive.rs:15:5 | LL | vec.sort(); | ^^^^^^^^^^ help: try: `vec.sort_unstable()` -error: Use sort_unstable instead of sort +error: used sort instead of sort_unstable to sort primitive type `array` --> $DIR/stable_sort_primitive.rs:17:5 | LL | vec.sort(); | ^^^^^^^^^^ help: try: `vec.sort_unstable()` -error: Use sort_unstable instead of sort +error: used sort instead of sort_unstable to sort primitive type `i32` --> $DIR/stable_sort_primitive.rs:19:5 | LL | arr.sort(); diff --git a/tests/ui/suspicious_arithmetic_impl.rs b/tests/ui/suspicious_arithmetic_impl.rs index 60c2f3ec9b652..5c280efac1a87 100644 --- a/tests/ui/suspicious_arithmetic_impl.rs +++ b/tests/ui/suspicious_arithmetic_impl.rs @@ -1,5 +1,7 @@ #![warn(clippy::suspicious_arithmetic_impl)] -use std::ops::{Add, AddAssign, BitOrAssign, Div, DivAssign, Mul, MulAssign, Sub}; +use std::ops::{ + Add, AddAssign, BitAnd, BitOr, BitOrAssign, BitXor, Div, DivAssign, Mul, MulAssign, Rem, Shl, Shr, Sub, +}; #[derive(Copy, Clone)] struct Foo(u32); @@ -61,6 +63,54 @@ impl Div for Foo { } } +impl Rem for Foo { + type Output = Foo; + + fn rem(self, other: Self) -> Self { + Foo(self.0 / other.0) + } +} + +impl BitAnd for Foo { + type Output = Foo; + + fn bitand(self, other: Self) -> Self { + Foo(self.0 | other.0) + } +} + +impl BitOr for Foo { + type Output = Foo; + + fn bitor(self, other: Self) -> Self { + Foo(self.0 ^ other.0) + } +} + +impl BitXor for Foo { + type Output = Foo; + + fn bitxor(self, other: Self) -> Self { + Foo(self.0 & other.0) + } +} + +impl Shl for Foo { + type Output = Foo; + + fn shl(self, other: Self) -> Self { + Foo(self.0 >> other.0) + } +} + +impl Shr for Foo { + type Output = Foo; + + fn shr(self, other: Self) -> Self { + Foo(self.0 << other.0) + } +} + struct Bar(i32); impl Add for Bar { diff --git a/tests/ui/suspicious_arithmetic_impl.stderr b/tests/ui/suspicious_arithmetic_impl.stderr index 23d47e3f1ff08..388fc74008209 100644 --- a/tests/ui/suspicious_arithmetic_impl.stderr +++ b/tests/ui/suspicious_arithmetic_impl.stderr @@ -1,5 +1,5 @@ error: suspicious use of binary operator in `Add` impl - --> $DIR/suspicious_arithmetic_impl.rs:11:20 + --> $DIR/suspicious_arithmetic_impl.rs:13:20 | LL | Foo(self.0 - other.0) | ^ @@ -7,7 +7,7 @@ LL | Foo(self.0 - other.0) = note: `-D clippy::suspicious-arithmetic-impl` implied by `-D warnings` error: suspicious use of binary operator in `AddAssign` impl - --> $DIR/suspicious_arithmetic_impl.rs:17:23 + --> $DIR/suspicious_arithmetic_impl.rs:19:23 | LL | *self = *self - other; | ^ @@ -15,10 +15,46 @@ LL | *self = *self - other; = note: `#[deny(clippy::suspicious_op_assign_impl)]` on by default error: suspicious use of binary operator in `MulAssign` impl - --> $DIR/suspicious_arithmetic_impl.rs:30:16 + --> $DIR/suspicious_arithmetic_impl.rs:32:16 | LL | self.0 /= other.0; | ^^ -error: aborting due to 3 previous errors +error: suspicious use of binary operator in `Rem` impl + --> $DIR/suspicious_arithmetic_impl.rs:70:20 + | +LL | Foo(self.0 / other.0) + | ^ + +error: suspicious use of binary operator in `BitAnd` impl + --> $DIR/suspicious_arithmetic_impl.rs:78:20 + | +LL | Foo(self.0 | other.0) + | ^ + +error: suspicious use of binary operator in `BitOr` impl + --> $DIR/suspicious_arithmetic_impl.rs:86:20 + | +LL | Foo(self.0 ^ other.0) + | ^ + +error: suspicious use of binary operator in `BitXor` impl + --> $DIR/suspicious_arithmetic_impl.rs:94:20 + | +LL | Foo(self.0 & other.0) + | ^ + +error: suspicious use of binary operator in `Shl` impl + --> $DIR/suspicious_arithmetic_impl.rs:102:20 + | +LL | Foo(self.0 >> other.0) + | ^^ + +error: suspicious use of binary operator in `Shr` impl + --> $DIR/suspicious_arithmetic_impl.rs:110:20 + | +LL | Foo(self.0 << other.0) + | ^^ + +error: aborting due to 9 previous errors diff --git a/tests/ui/to_string_in_display.rs b/tests/ui/to_string_in_display.rs new file mode 100644 index 0000000000000..eb8105c6b6da0 --- /dev/null +++ b/tests/ui/to_string_in_display.rs @@ -0,0 +1,69 @@ +#![warn(clippy::to_string_in_display)] +#![allow(clippy::inherent_to_string_shadow_display)] + +use std::fmt; + +struct A; +impl A { + fn fmt(&self) { + self.to_string(); + } +} + +trait B { + fn fmt(&self) {} +} + +impl B for A { + fn fmt(&self) { + self.to_string(); + } +} + +impl fmt::Display for A { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.to_string()) + } +} + +fn fmt(a: A) { + a.to_string(); +} + +struct C; + +impl C { + fn to_string(&self) -> String { + String::from("I am C") + } +} + +impl fmt::Display for C { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.to_string()) + } +} + +enum D { + E(String), + F, +} + +impl std::fmt::Display for D { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self { + Self::E(string) => write!(f, "E {}", string.to_string()), + Self::F => write!(f, "F"), + } + } +} + +fn main() { + let a = A; + a.to_string(); + a.fmt(); + fmt(a); + + let c = C; + c.to_string(); +} diff --git a/tests/ui/to_string_in_display.stderr b/tests/ui/to_string_in_display.stderr new file mode 100644 index 0000000000000..5f26ef413e239 --- /dev/null +++ b/tests/ui/to_string_in_display.stderr @@ -0,0 +1,10 @@ +error: using `to_string` in `fmt::Display` implementation might lead to infinite recursion + --> $DIR/to_string_in_display.rs:25:25 + | +LL | write!(f, "{}", self.to_string()) + | ^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::to-string-in-display` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui/transmute.rs b/tests/ui/transmute.rs index bb853d237047f..9f1948359e7d5 100644 --- a/tests/ui/transmute.rs +++ b/tests/ui/transmute.rs @@ -1,3 +1,4 @@ +#![feature(const_fn_transmute)] #![allow(dead_code)] extern crate core; @@ -81,9 +82,26 @@ fn int_to_bool() { } #[warn(clippy::transmute_int_to_float)] -fn int_to_float() { - let _: f32 = unsafe { std::mem::transmute(0_u32) }; - let _: f32 = unsafe { std::mem::transmute(0_i32) }; +mod int_to_float { + fn test() { + let _: f32 = unsafe { std::mem::transmute(0_u32) }; + let _: f32 = unsafe { std::mem::transmute(0_i32) }; + let _: f64 = unsafe { std::mem::transmute(0_u64) }; + let _: f64 = unsafe { std::mem::transmute(0_i64) }; + } + + mod issue_5747 { + const VALUE32: f32 = unsafe { std::mem::transmute(0_u32) }; + const VALUE64: f64 = unsafe { std::mem::transmute(0_i64) }; + + const fn from_bits_32(v: i32) -> f32 { + unsafe { std::mem::transmute(v) } + } + + const fn from_bits_64(v: u64) -> f64 { + unsafe { std::mem::transmute(v) } + } + } } fn bytes_to_str(b: &[u8], mb: &mut [u8]) { diff --git a/tests/ui/transmute.stderr b/tests/ui/transmute.stderr index 8582080498f3e..ad9953d12bcc6 100644 --- a/tests/ui/transmute.stderr +++ b/tests/ui/transmute.stderr @@ -1,5 +1,5 @@ error: transmute from a type (`&T`) to itself - --> $DIR/transmute.rs:19:20 + --> $DIR/transmute.rs:20:20 | LL | let _: &'a T = core::intrinsics::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,67 +7,67 @@ LL | let _: &'a T = core::intrinsics::transmute(t); = note: `-D clippy::useless-transmute` implied by `-D warnings` error: transmute from a reference to a pointer - --> $DIR/transmute.rs:23:23 + --> $DIR/transmute.rs:24:23 | LL | let _: *const T = core::intrinsics::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T` error: transmute from a reference to a pointer - --> $DIR/transmute.rs:25:21 + --> $DIR/transmute.rs:26:21 | LL | let _: *mut T = core::intrinsics::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T` error: transmute from a reference to a pointer - --> $DIR/transmute.rs:27:23 + --> $DIR/transmute.rs:28:23 | LL | let _: *const U = core::intrinsics::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U` error: transmute from a type (`std::vec::Vec`) to itself - --> $DIR/transmute.rs:33:27 + --> $DIR/transmute.rs:34:27 | LL | let _: Vec = core::intrinsics::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> $DIR/transmute.rs:35:27 + --> $DIR/transmute.rs:36:27 | LL | let _: Vec = core::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> $DIR/transmute.rs:37:27 + --> $DIR/transmute.rs:38:27 | LL | let _: Vec = std::intrinsics::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> $DIR/transmute.rs:39:27 + --> $DIR/transmute.rs:40:27 | LL | let _: Vec = std::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> $DIR/transmute.rs:41:27 + --> $DIR/transmute.rs:42:27 | LL | let _: Vec = my_transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^ error: transmute from an integer to a pointer - --> $DIR/transmute.rs:43:31 + --> $DIR/transmute.rs:44:31 | LL | let _: *const usize = std::mem::transmute(5_isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `5_isize as *const usize` error: transmute from an integer to a pointer - --> $DIR/transmute.rs:47:31 + --> $DIR/transmute.rs:48:31 | LL | let _: *const usize = std::mem::transmute(1 + 1usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(1 + 1usize) as *const usize` error: transmute from a type (`*const Usize`) to the type that it points to (`Usize`) - --> $DIR/transmute.rs:62:24 + --> $DIR/transmute.rs:63:24 | LL | let _: Usize = core::intrinsics::transmute(int_const_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -75,25 +75,25 @@ LL | let _: Usize = core::intrinsics::transmute(int_const_ptr); = note: `-D clippy::crosspointer-transmute` implied by `-D warnings` error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`) - --> $DIR/transmute.rs:64:24 + --> $DIR/transmute.rs:65:24 | LL | let _: Usize = core::intrinsics::transmute(int_mut_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`) - --> $DIR/transmute.rs:66:31 + --> $DIR/transmute.rs:67:31 | LL | let _: *const Usize = core::intrinsics::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`) - --> $DIR/transmute.rs:68:29 + --> $DIR/transmute.rs:69:29 | LL | let _: *mut Usize = core::intrinsics::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a `u32` to a `char` - --> $DIR/transmute.rs:74:28 + --> $DIR/transmute.rs:75:28 | LL | let _: char = unsafe { std::mem::transmute(0_u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_u32).unwrap()` @@ -101,13 +101,13 @@ LL | let _: char = unsafe { std::mem::transmute(0_u32) }; = note: `-D clippy::transmute-int-to-char` implied by `-D warnings` error: transmute from a `i32` to a `char` - --> $DIR/transmute.rs:75:28 + --> $DIR/transmute.rs:76:28 | LL | let _: char = unsafe { std::mem::transmute(0_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_i32 as u32).unwrap()` error: transmute from a `u8` to a `bool` - --> $DIR/transmute.rs:80:28 + --> $DIR/transmute.rs:81:28 | LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0` @@ -115,21 +115,33 @@ LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; = note: `-D clippy::transmute-int-to-bool` implied by `-D warnings` error: transmute from a `u32` to a `f32` - --> $DIR/transmute.rs:85:27 + --> $DIR/transmute.rs:87:31 | -LL | let _: f32 = unsafe { std::mem::transmute(0_u32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)` +LL | let _: f32 = unsafe { std::mem::transmute(0_u32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)` | = note: `-D clippy::transmute-int-to-float` implied by `-D warnings` error: transmute from a `i32` to a `f32` - --> $DIR/transmute.rs:86:27 + --> $DIR/transmute.rs:88:31 + | +LL | let _: f32 = unsafe { std::mem::transmute(0_i32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)` + +error: transmute from a `u64` to a `f64` + --> $DIR/transmute.rs:89:31 + | +LL | let _: f64 = unsafe { std::mem::transmute(0_u64) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_u64)` + +error: transmute from a `i64` to a `f64` + --> $DIR/transmute.rs:90:31 | -LL | let _: f32 = unsafe { std::mem::transmute(0_i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)` +LL | let _: f64 = unsafe { std::mem::transmute(0_i64) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)` error: transmute from a `&[u8]` to a `&str` - --> $DIR/transmute.rs:90:28 + --> $DIR/transmute.rs:108:28 | LL | let _: &str = unsafe { std::mem::transmute(b) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(b).unwrap()` @@ -137,10 +149,10 @@ LL | let _: &str = unsafe { std::mem::transmute(b) }; = note: `-D clippy::transmute-bytes-to-str` implied by `-D warnings` error: transmute from a `&mut [u8]` to a `&mut str` - --> $DIR/transmute.rs:91:32 + --> $DIR/transmute.rs:109:32 | LL | let _: &mut str = unsafe { std::mem::transmute(mb) }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()` -error: aborting due to 22 previous errors +error: aborting due to 24 previous errors diff --git a/tests/ui/transmute_float_to_int.rs b/tests/ui/transmute_float_to_int.rs index ce942751ada82..1040fee4b34d0 100644 --- a/tests/ui/transmute_float_to_int.rs +++ b/tests/ui/transmute_float_to_int.rs @@ -1,4 +1,5 @@ -#[warn(clippy::transmute_float_to_int)] +#![feature(const_fn_transmute)] +#![warn(clippy::transmute_float_to_int)] fn float_to_int() { let _: u32 = unsafe { std::mem::transmute(1f32) }; @@ -9,4 +10,17 @@ fn float_to_int() { let _: u64 = unsafe { std::mem::transmute(-1.0) }; } +mod issue_5747 { + const VALUE32: i32 = unsafe { std::mem::transmute(1f32) }; + const VALUE64: u64 = unsafe { std::mem::transmute(1f64) }; + + const fn to_bits_32(v: f32) -> u32 { + unsafe { std::mem::transmute(v) } + } + + const fn to_bits_64(v: f64) -> i64 { + unsafe { std::mem::transmute(v) } + } +} + fn main() {} diff --git a/tests/ui/transmute_float_to_int.stderr b/tests/ui/transmute_float_to_int.stderr index eb786bb39f95a..5a40cf381d614 100644 --- a/tests/ui/transmute_float_to_int.stderr +++ b/tests/ui/transmute_float_to_int.stderr @@ -1,5 +1,5 @@ error: transmute from a `f32` to a `u32` - --> $DIR/transmute_float_to_int.rs:4:27 + --> $DIR/transmute_float_to_int.rs:5:27 | LL | let _: u32 = unsafe { std::mem::transmute(1f32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits()` @@ -7,31 +7,31 @@ LL | let _: u32 = unsafe { std::mem::transmute(1f32) }; = note: `-D clippy::transmute-float-to-int` implied by `-D warnings` error: transmute from a `f32` to a `i32` - --> $DIR/transmute_float_to_int.rs:5:27 + --> $DIR/transmute_float_to_int.rs:6:27 | LL | let _: i32 = unsafe { std::mem::transmute(1f32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits() as i32` error: transmute from a `f64` to a `u64` - --> $DIR/transmute_float_to_int.rs:6:27 + --> $DIR/transmute_float_to_int.rs:7:27 | LL | let _: u64 = unsafe { std::mem::transmute(1f64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits()` error: transmute from a `f64` to a `i64` - --> $DIR/transmute_float_to_int.rs:7:27 + --> $DIR/transmute_float_to_int.rs:8:27 | LL | let _: i64 = unsafe { std::mem::transmute(1f64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits() as i64` error: transmute from a `f64` to a `u64` - --> $DIR/transmute_float_to_int.rs:8:27 + --> $DIR/transmute_float_to_int.rs:9:27 | LL | let _: u64 = unsafe { std::mem::transmute(1.0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.0f64.to_bits()` error: transmute from a `f64` to a `u64` - --> $DIR/transmute_float_to_int.rs:9:27 + --> $DIR/transmute_float_to_int.rs:10:27 | LL | let _: u64 = unsafe { std::mem::transmute(-1.0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-1.0f64).to_bits()` diff --git a/tests/ui/trivially_copy_pass_by_ref.rs b/tests/ui/trivially_copy_pass_by_ref.rs index 316426f1cf181..e7e0a31febc45 100644 --- a/tests/ui/trivially_copy_pass_by_ref.rs +++ b/tests/ui/trivially_copy_pass_by_ref.rs @@ -97,6 +97,24 @@ mod issue3992 { pub fn c(d: &u16) {} } +mod issue5876 { + // Don't lint here as it is always inlined + #[inline(always)] + fn foo_always(x: &i32) { + println!("{}", x); + } + + #[inline(never)] + fn foo_never(x: &i32) { + println!("{}", x); + } + + #[inline] + fn foo(x: &i32) { + println!("{}", x); + } +} + fn main() { let (mut foo, bar) = (Foo(0), Bar([0; 24])); let (mut a, b, c, x, y, z) = (0, 0, Bar([0; 24]), 0, Foo(0), 0); diff --git a/tests/ui/trivially_copy_pass_by_ref.stderr b/tests/ui/trivially_copy_pass_by_ref.stderr index be0914e4a7947..ccc3cdb2b7426 100644 --- a/tests/ui/trivially_copy_pass_by_ref.stderr +++ b/tests/ui/trivially_copy_pass_by_ref.stderr @@ -94,5 +94,17 @@ error: this argument (N byte) is passed by reference, but would be more efficien LL | fn trait_method2(&self, _color: &Color); | ^^^^^^ help: consider passing by value instead: `Color` -error: aborting due to 15 previous errors +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) + --> $DIR/trivially_copy_pass_by_ref.rs:108:21 + | +LL | fn foo_never(x: &i32) { + | ^^^^ help: consider passing by value instead: `i32` + +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) + --> $DIR/trivially_copy_pass_by_ref.rs:113:15 + | +LL | fn foo(x: &i32) { + | ^^^^ help: consider passing by value instead: `i32` + +error: aborting due to 17 previous errors diff --git a/tests/ui/unnecessary_clone.rs b/tests/ui/unnecessary_clone.rs index 2c9d4d39e6c7d..e785ac02feb32 100644 --- a/tests/ui/unnecessary_clone.rs +++ b/tests/ui/unnecessary_clone.rs @@ -90,3 +90,21 @@ mod many_derefs { let _ = &encoded.clone(); } } + +mod issue2076 { + use std::rc::Rc; + + macro_rules! try_opt { + ($expr: expr) => { + match $expr { + Some(value) => value, + None => return None, + } + }; + } + + fn func() -> Option> { + let rc = Rc::new(42); + Some(try_opt!(Some(rc)).clone()) + } +} diff --git a/tests/ui/unnecessary_clone.stderr b/tests/ui/unnecessary_clone.stderr index 113fab6900954..5ffa6c4fd0616 100644 --- a/tests/ui/unnecessary_clone.stderr +++ b/tests/ui/unnecessary_clone.stderr @@ -96,5 +96,11 @@ help: or try being explicit if you are sure, that you want to clone a reference LL | let _ = &<&[u8]>::clone(encoded); | ^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 11 previous errors +error: using `.clone()` on a ref-counted pointer + --> $DIR/unnecessary_clone.rs:108:14 + | +LL | Some(try_opt!(Some(rc)).clone()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Rc::::clone(&try_opt!(Some(rc)))` + +error: aborting due to 12 previous errors diff --git a/tests/ui/unnecessary_lazy_eval.fixed b/tests/ui/unnecessary_lazy_eval.fixed new file mode 100644 index 0000000000000..fa66e68794e4b --- /dev/null +++ b/tests/ui/unnecessary_lazy_eval.fixed @@ -0,0 +1,117 @@ +// run-rustfix +#![warn(clippy::unnecessary_lazy_evaluations)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::bind_instead_of_map)] + +struct Deep(Option); + +#[derive(Copy, Clone)] +struct SomeStruct { + some_field: usize, +} + +impl SomeStruct { + fn return_some_field(&self) -> usize { + self.some_field + } +} + +fn some_call() -> T { + T::default() +} + +fn main() { + let astronomers_pi = 10; + let ext_arr: [usize; 1] = [2]; + let ext_str = SomeStruct { some_field: 10 }; + + let mut opt = Some(42); + let ext_opt = Some(42); + let nested_opt = Some(Some(42)); + let nested_tuple_opt = Some(Some((42, 43))); + + // Should lint - Option + let _ = opt.unwrap_or(2); + let _ = opt.unwrap_or(astronomers_pi); + let _ = opt.unwrap_or(ext_str.some_field); + let _ = opt.unwrap_or(ext_arr[0]); + let _ = opt.and(ext_opt); + let _ = opt.or(ext_opt); + let _ = opt.or(None); + let _ = opt.get_or_insert(2); + let _ = opt.ok_or(2); + let _ = opt.ok_or(ext_arr[0]); + + // Cases when unwrap is not called on a simple variable + let _ = Some(10).unwrap_or(2); + let _ = Some(10).and(ext_opt); + let _: Option = None.or(ext_opt); + let _ = None.get_or_insert(2); + let _: Result = None.ok_or(2); + let _: Option = None.or(None); + + let mut deep = Deep(Some(42)); + let _ = deep.0.unwrap_or(2); + let _ = deep.0.and(ext_opt); + let _ = deep.0.or(None); + let _ = deep.0.get_or_insert(2); + let _ = deep.0.ok_or(2); + + // Should not lint - Option + let _ = opt.unwrap_or_else(|| ext_str.return_some_field()); + let _ = nested_opt.unwrap_or_else(|| Some(some_call())); + let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); + let _ = nested_tuple_opt.unwrap_or_else(|| Some((some_call(), some_call()))); + let _ = opt.or_else(some_call); + let _ = opt.or_else(|| some_call()); + let _: Result = opt.ok_or_else(|| some_call()); + let _: Result = opt.ok_or_else(some_call); + let _ = deep.0.get_or_insert_with(|| some_call()); + let _ = deep.0.or_else(some_call); + let _ = deep.0.or_else(|| some_call()); + + // These are handled by bind_instead_of_map + let _ = Some(10).and_then(|idx| Some(ext_arr[idx])); + let _ = Some(10).and_then(|idx| Some(idx)); + let _: Option = None.or_else(|| Some(3)); + let _ = deep.0.or_else(|| Some(3)); + let _ = opt.or_else(|| Some(3)); + + // Should lint - Result + let res: Result = Err(5); + let res2: Result = Err(SomeStruct { some_field: 5 }); + + let _ = res2.unwrap_or(2); + let _ = res2.unwrap_or(astronomers_pi); + let _ = res2.unwrap_or(ext_str.some_field); + + // Should not lint - Result + let _ = res.unwrap_or_else(|err| err); + let _ = res.unwrap_or_else(|err| ext_arr[err]); + let _ = res2.unwrap_or_else(|err| err.some_field); + let _ = res2.unwrap_or_else(|err| err.return_some_field()); + let _ = res2.unwrap_or_else(|_| ext_str.return_some_field()); + + let _: Result = res.and_then(|x| Ok(x)); + let _: Result = res.and_then(|x| Err(x)); + + let _: Result = res.or_else(|err| Ok(err)); + let _: Result = res.or_else(|err| Err(err)); + + // These are handled by bind_instead_of_map + let _: Result = res.and_then(|_| Ok(2)); + let _: Result = res.and_then(|_| Ok(astronomers_pi)); + let _: Result = res.and_then(|_| Ok(ext_str.some_field)); + + let _: Result = res.and_then(|_| Err(2)); + let _: Result = res.and_then(|_| Err(astronomers_pi)); + let _: Result = res.and_then(|_| Err(ext_str.some_field)); + + let _: Result = res.or_else(|_| Ok(2)); + let _: Result = res.or_else(|_| Ok(astronomers_pi)); + let _: Result = res.or_else(|_| Ok(ext_str.some_field)); + + let _: Result = res.or_else(|_| Err(2)); + let _: Result = res.or_else(|_| Err(astronomers_pi)); + let _: Result = res.or_else(|_| Err(ext_str.some_field)); +} diff --git a/tests/ui/unnecessary_lazy_eval.rs b/tests/ui/unnecessary_lazy_eval.rs new file mode 100644 index 0000000000000..04f47d1aa2978 --- /dev/null +++ b/tests/ui/unnecessary_lazy_eval.rs @@ -0,0 +1,117 @@ +// run-rustfix +#![warn(clippy::unnecessary_lazy_evaluations)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::bind_instead_of_map)] + +struct Deep(Option); + +#[derive(Copy, Clone)] +struct SomeStruct { + some_field: usize, +} + +impl SomeStruct { + fn return_some_field(&self) -> usize { + self.some_field + } +} + +fn some_call() -> T { + T::default() +} + +fn main() { + let astronomers_pi = 10; + let ext_arr: [usize; 1] = [2]; + let ext_str = SomeStruct { some_field: 10 }; + + let mut opt = Some(42); + let ext_opt = Some(42); + let nested_opt = Some(Some(42)); + let nested_tuple_opt = Some(Some((42, 43))); + + // Should lint - Option + let _ = opt.unwrap_or_else(|| 2); + let _ = opt.unwrap_or_else(|| astronomers_pi); + let _ = opt.unwrap_or_else(|| ext_str.some_field); + let _ = opt.unwrap_or_else(|| ext_arr[0]); + let _ = opt.and_then(|_| ext_opt); + let _ = opt.or_else(|| ext_opt); + let _ = opt.or_else(|| None); + let _ = opt.get_or_insert_with(|| 2); + let _ = opt.ok_or_else(|| 2); + let _ = opt.ok_or_else(|| ext_arr[0]); + + // Cases when unwrap is not called on a simple variable + let _ = Some(10).unwrap_or_else(|| 2); + let _ = Some(10).and_then(|_| ext_opt); + let _: Option = None.or_else(|| ext_opt); + let _ = None.get_or_insert_with(|| 2); + let _: Result = None.ok_or_else(|| 2); + let _: Option = None.or_else(|| None); + + let mut deep = Deep(Some(42)); + let _ = deep.0.unwrap_or_else(|| 2); + let _ = deep.0.and_then(|_| ext_opt); + let _ = deep.0.or_else(|| None); + let _ = deep.0.get_or_insert_with(|| 2); + let _ = deep.0.ok_or_else(|| 2); + + // Should not lint - Option + let _ = opt.unwrap_or_else(|| ext_str.return_some_field()); + let _ = nested_opt.unwrap_or_else(|| Some(some_call())); + let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); + let _ = nested_tuple_opt.unwrap_or_else(|| Some((some_call(), some_call()))); + let _ = opt.or_else(some_call); + let _ = opt.or_else(|| some_call()); + let _: Result = opt.ok_or_else(|| some_call()); + let _: Result = opt.ok_or_else(some_call); + let _ = deep.0.get_or_insert_with(|| some_call()); + let _ = deep.0.or_else(some_call); + let _ = deep.0.or_else(|| some_call()); + + // These are handled by bind_instead_of_map + let _ = Some(10).and_then(|idx| Some(ext_arr[idx])); + let _ = Some(10).and_then(|idx| Some(idx)); + let _: Option = None.or_else(|| Some(3)); + let _ = deep.0.or_else(|| Some(3)); + let _ = opt.or_else(|| Some(3)); + + // Should lint - Result + let res: Result = Err(5); + let res2: Result = Err(SomeStruct { some_field: 5 }); + + let _ = res2.unwrap_or_else(|_| 2); + let _ = res2.unwrap_or_else(|_| astronomers_pi); + let _ = res2.unwrap_or_else(|_| ext_str.some_field); + + // Should not lint - Result + let _ = res.unwrap_or_else(|err| err); + let _ = res.unwrap_or_else(|err| ext_arr[err]); + let _ = res2.unwrap_or_else(|err| err.some_field); + let _ = res2.unwrap_or_else(|err| err.return_some_field()); + let _ = res2.unwrap_or_else(|_| ext_str.return_some_field()); + + let _: Result = res.and_then(|x| Ok(x)); + let _: Result = res.and_then(|x| Err(x)); + + let _: Result = res.or_else(|err| Ok(err)); + let _: Result = res.or_else(|err| Err(err)); + + // These are handled by bind_instead_of_map + let _: Result = res.and_then(|_| Ok(2)); + let _: Result = res.and_then(|_| Ok(astronomers_pi)); + let _: Result = res.and_then(|_| Ok(ext_str.some_field)); + + let _: Result = res.and_then(|_| Err(2)); + let _: Result = res.and_then(|_| Err(astronomers_pi)); + let _: Result = res.and_then(|_| Err(ext_str.some_field)); + + let _: Result = res.or_else(|_| Ok(2)); + let _: Result = res.or_else(|_| Ok(astronomers_pi)); + let _: Result = res.or_else(|_| Ok(ext_str.some_field)); + + let _: Result = res.or_else(|_| Err(2)); + let _: Result = res.or_else(|_| Err(astronomers_pi)); + let _: Result = res.or_else(|_| Err(ext_str.some_field)); +} diff --git a/tests/ui/unnecessary_lazy_eval.stderr b/tests/ui/unnecessary_lazy_eval.stderr new file mode 100644 index 0000000000000..5c1b2eb1f14e8 --- /dev/null +++ b/tests/ui/unnecessary_lazy_eval.stderr @@ -0,0 +1,148 @@ +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:34:13 + | +LL | let _ = opt.unwrap_or_else(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(2)` + | + = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:35:13 + | +LL | let _ = opt.unwrap_or_else(|| astronomers_pi); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(astronomers_pi)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:36:13 + | +LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(ext_str.some_field)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:37:13 + | +LL | let _ = opt.unwrap_or_else(|| ext_arr[0]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(ext_arr[0])` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:38:13 + | +LL | let _ = opt.and_then(|_| ext_opt); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `opt.and(ext_opt)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:39:13 + | +LL | let _ = opt.or_else(|| ext_opt); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(ext_opt)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:40:13 + | +LL | let _ = opt.or_else(|| None); + | ^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(None)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:41:13 + | +LL | let _ = opt.get_or_insert_with(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `opt.get_or_insert(2)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:42:13 + | +LL | let _ = opt.ok_or_else(|| 2); + | ^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `opt.ok_or(2)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:43:13 + | +LL | let _ = opt.ok_or_else(|| ext_arr[0]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `opt.ok_or(ext_arr[0])` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:46:13 + | +LL | let _ = Some(10).unwrap_or_else(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Some(10).unwrap_or(2)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:47:13 + | +LL | let _ = Some(10).and_then(|_| ext_opt); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `Some(10).and(ext_opt)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:48:28 + | +LL | let _: Option = None.or_else(|| ext_opt); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(ext_opt)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:49:13 + | +LL | let _ = None.get_or_insert_with(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `None.get_or_insert(2)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:50:35 + | +LL | let _: Result = None.ok_or_else(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `None.ok_or(2)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:51:28 + | +LL | let _: Option = None.or_else(|| None); + | ^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(None)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:54:13 + | +LL | let _ = deep.0.unwrap_or_else(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `deep.0.unwrap_or(2)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:55:13 + | +LL | let _ = deep.0.and_then(|_| ext_opt); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `deep.0.and(ext_opt)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:56:13 + | +LL | let _ = deep.0.or_else(|| None); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `deep.0.or(None)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:57:13 + | +LL | let _ = deep.0.get_or_insert_with(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `deep.0.get_or_insert(2)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:58:13 + | +LL | let _ = deep.0.ok_or_else(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `deep.0.ok_or(2)` + +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval.rs:84:13 + | +LL | let _ = res2.unwrap_or_else(|_| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(2)` + +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval.rs:85:13 + | +LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(astronomers_pi)` + +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval.rs:86:13 + | +LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(ext_str.some_field)` + +error: aborting due to 24 previous errors + diff --git a/tests/ui/unwrap_in_result.rs b/tests/ui/unwrap_in_result.rs new file mode 100644 index 0000000000000..2aa842adc8560 --- /dev/null +++ b/tests/ui/unwrap_in_result.rs @@ -0,0 +1,44 @@ +#![warn(clippy::unwrap_in_result)] + +struct A; + +impl A { + // should not be detected + fn good_divisible_by_3(i_str: String) -> Result { + // checks whether a string represents a number divisible by 3 + let i_result = i_str.parse::(); + match i_result { + Err(_e) => Err("Not a number".to_string()), + Ok(i) => { + if i % 3 == 0 { + return Ok(true); + } + Err("Number is not divisible by 3".to_string()) + }, + } + } + + // should be detected + fn bad_divisible_by_3(i_str: String) -> Result { + // checks whether a string represents a number divisible by 3 + let i = i_str.parse::().unwrap(); + if i % 3 == 0 { + Ok(true) + } else { + Err("Number is not divisible by 3".to_string()) + } + } + + fn example_option_expect(i_str: String) -> Option { + let i = i_str.parse::().expect("not a number"); + if i % 3 == 0 { + return Some(true); + } + None + } +} + +fn main() { + A::bad_divisible_by_3("3".to_string()); + A::good_divisible_by_3("3".to_string()); +} diff --git a/tests/ui/unwrap_in_result.stderr b/tests/ui/unwrap_in_result.stderr new file mode 100644 index 0000000000000..56bc2f2d1c00e --- /dev/null +++ b/tests/ui/unwrap_in_result.stderr @@ -0,0 +1,41 @@ +error: used unwrap or expect in a function that returns result or option + --> $DIR/unwrap_in_result.rs:22:5 + | +LL | / fn bad_divisible_by_3(i_str: String) -> Result { +LL | | // checks whether a string represents a number divisible by 3 +LL | | let i = i_str.parse::().unwrap(); +LL | | if i % 3 == 0 { +... | +LL | | } +LL | | } + | |_____^ + | + = note: `-D clippy::unwrap-in-result` implied by `-D warnings` + = help: unwrap and expect should not be used in a function that returns result or option +note: potential non-recoverable error(s) + --> $DIR/unwrap_in_result.rs:24:17 + | +LL | let i = i_str.parse::().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used unwrap or expect in a function that returns result or option + --> $DIR/unwrap_in_result.rs:32:5 + | +LL | / fn example_option_expect(i_str: String) -> Option { +LL | | let i = i_str.parse::().expect("not a number"); +LL | | if i % 3 == 0 { +LL | | return Some(true); +LL | | } +LL | | None +LL | | } + | |_____^ + | + = help: unwrap and expect should not be used in a function that returns result or option +note: potential non-recoverable error(s) + --> $DIR/unwrap_in_result.rs:33:17 + | +LL | let i = i_str.parse::().expect("not a number"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/useless_conversion.fixed b/tests/ui/useless_conversion.fixed index 813cdaecaa91a..8a9b0cd3cf019 100644 --- a/tests/ui/useless_conversion.fixed +++ b/tests/ui/useless_conversion.fixed @@ -64,4 +64,9 @@ fn main() { let _ = "".lines(); let _ = vec![1, 2, 3].into_iter(); let _: String = format!("Hello {}", "world"); + + // keep parenthesis around `a + b` for suggestion (see #4750) + let a: i32 = 1; + let b: i32 = 1; + let _ = (a + b) * 3; } diff --git a/tests/ui/useless_conversion.rs b/tests/ui/useless_conversion.rs index 540fea23b36b9..4faa1572973bc 100644 --- a/tests/ui/useless_conversion.rs +++ b/tests/ui/useless_conversion.rs @@ -64,4 +64,9 @@ fn main() { let _ = "".lines().into_iter(); let _ = vec![1, 2, 3].into_iter().into_iter(); let _: String = format!("Hello {}", "world").into(); + + // keep parenthesis around `a + b` for suggestion (see #4750) + let a: i32 = 1; + let b: i32 = 1; + let _ = i32::from(a + b) * 3; } diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr index b958b03545203..f1e880d2696c4 100644 --- a/tests/ui/useless_conversion.stderr +++ b/tests/ui/useless_conversion.stderr @@ -64,5 +64,11 @@ error: useless conversion to the same type LL | let _: String = format!("Hello {}", "world").into(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")` -error: aborting due to 10 previous errors +error: useless conversion to the same type + --> $DIR/useless_conversion.rs:71:13 + | +LL | let _ = i32::from(a + b) * 3; + | ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)` + +error: aborting due to 11 previous errors diff --git a/tests/ui/vec.fixed b/tests/ui/vec.fixed index e73a791891f89..856771596202e 100644 --- a/tests/ui/vec.fixed +++ b/tests/ui/vec.fixed @@ -52,4 +52,11 @@ fn main() { for a in vec![NonCopy, NonCopy] { println!("{:?}", a); } + + on_vec(&vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack` + + // Ok + for a in vec![1; 201] { + println!("{:?}", a); + } } diff --git a/tests/ui/vec.rs b/tests/ui/vec.rs index 3eb960f53d7af..03b8ee816658c 100644 --- a/tests/ui/vec.rs +++ b/tests/ui/vec.rs @@ -52,4 +52,11 @@ fn main() { for a in vec![NonCopy, NonCopy] { println!("{:?}", a); } + + on_vec(&vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack` + + // Ok + for a in vec![1; 201] { + println!("{:?}", a); + } } diff --git a/tests/ui/wildcard_imports.fixed b/tests/ui/wildcard_imports.fixed index 67423e6ec1d19..287f8935327c5 100644 --- a/tests/ui/wildcard_imports.fixed +++ b/tests/ui/wildcard_imports.fixed @@ -20,6 +20,7 @@ use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar; use wildcard_imports_helper::{ExternA, extern_foo}; use std::io::prelude::*; +use wildcard_imports_helper::prelude::v1::*; struct ReadFoo; @@ -75,6 +76,7 @@ fn main() { let _ = A; let _ = inner_struct_mod::C; let _ = ExternA; + let _ = PreludeModAnywhere; double_struct_import_test!(); double_struct_import_test!(); diff --git a/tests/ui/wildcard_imports.rs b/tests/ui/wildcard_imports.rs index 3ad1a29aebad1..1f261159f4a94 100644 --- a/tests/ui/wildcard_imports.rs +++ b/tests/ui/wildcard_imports.rs @@ -20,6 +20,7 @@ use wildcard_imports_helper::inner::inner_for_self_import::*; use wildcard_imports_helper::*; use std::io::prelude::*; +use wildcard_imports_helper::prelude::v1::*; struct ReadFoo; @@ -75,6 +76,7 @@ fn main() { let _ = A; let _ = inner_struct_mod::C; let _ = ExternA; + let _ = PreludeModAnywhere; double_struct_import_test!(); double_struct_import_test!(); diff --git a/tests/ui/wildcard_imports.stderr b/tests/ui/wildcard_imports.stderr index fab43b738eb43..351988f31ead5 100644 --- a/tests/ui/wildcard_imports.stderr +++ b/tests/ui/wildcard_imports.stderr @@ -37,55 +37,55 @@ LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:89:13 + --> $DIR/wildcard_imports.rs:91:13 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:95:75 + --> $DIR/wildcard_imports.rs:97: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:96:13 + --> $DIR/wildcard_imports.rs:98:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:107:20 + --> $DIR/wildcard_imports.rs:109:20 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^ help: try: `inner::inner_foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:107:30 + --> $DIR/wildcard_imports.rs:109:30 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^^ help: try: `inner2::inner_bar` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:114:13 + --> $DIR/wildcard_imports.rs:116:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:143:9 + --> $DIR/wildcard_imports.rs:145: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:152:9 + --> $DIR/wildcard_imports.rs:154:9 | LL | use crate:: in_fn_test:: * ; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:153:9 + --> $DIR/wildcard_imports.rs:155:9 | LL | use crate:: fn_mod:: | _________^ @@ -93,31 +93,31 @@ LL | | *; | |_________^ help: try: `crate:: fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:164:13 + --> $DIR/wildcard_imports.rs:166:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:199:17 + --> $DIR/wildcard_imports.rs:201:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:207:13 + --> $DIR/wildcard_imports.rs:209:13 | LL | use super_imports::*; | ^^^^^^^^^^^^^^^^ help: try: `super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:216:17 + --> $DIR/wildcard_imports.rs:218:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:225:13 + --> $DIR/wildcard_imports.rs:227:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` diff --git a/tests/ui/wrong_self_convention.rs b/tests/ui/wrong_self_convention.rs index 99652ca4470c2..f44305d7e4838 100644 --- a/tests/ui/wrong_self_convention.rs +++ b/tests/ui/wrong_self_convention.rs @@ -1,3 +1,4 @@ +// edition:2018 #![warn(clippy::wrong_self_convention)] #![warn(clippy::wrong_pub_self_convention)] #![allow(dead_code)] @@ -75,3 +76,15 @@ mod issue4293 { fn into_t3(self: Arc) {} } } + +// False positive for async (see #4037) +mod issue4037 { + pub struct Foo; + pub struct Bar; + + impl Foo { + pub async fn into_bar(self) -> Bar { + Bar + } + } +} diff --git a/tests/ui/wrong_self_convention.stderr b/tests/ui/wrong_self_convention.stderr index 0d0eb19cd0723..ef3ad73ebc7c1 100644 --- a/tests/ui/wrong_self_convention.stderr +++ b/tests/ui/wrong_self_convention.stderr @@ -1,5 +1,5 @@ error: methods called `from_*` usually take no self; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:17:17 + --> $DIR/wrong_self_convention.rs:18:17 | LL | fn from_i32(self) {} | ^^^^ @@ -7,67 +7,67 @@ LL | fn from_i32(self) {} = note: `-D clippy::wrong-self-convention` implied by `-D warnings` error: methods called `from_*` usually take no self; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:23:21 + --> $DIR/wrong_self_convention.rs:24:21 | LL | pub fn from_i64(self) {} | ^^^^ error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:35:15 + --> $DIR/wrong_self_convention.rs:36:15 | LL | fn as_i32(self) {} | ^^^^ error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:37:17 + --> $DIR/wrong_self_convention.rs:38:17 | LL | fn into_i32(&self) {} | ^^^^^ error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:39:15 + --> $DIR/wrong_self_convention.rs:40:15 | LL | fn is_i32(self) {} | ^^^^ error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:41:15 + --> $DIR/wrong_self_convention.rs:42:15 | LL | fn to_i32(self) {} | ^^^^ error: methods called `from_*` usually take no self; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:43:17 + --> $DIR/wrong_self_convention.rs:44:17 | LL | fn from_i32(self) {} | ^^^^ error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:45:19 + --> $DIR/wrong_self_convention.rs:46:19 | LL | pub fn as_i64(self) {} | ^^^^ error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:46:21 + --> $DIR/wrong_self_convention.rs:47:21 | LL | pub fn into_i64(&self) {} | ^^^^^ error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:47:19 + --> $DIR/wrong_self_convention.rs:48:19 | LL | pub fn is_i64(self) {} | ^^^^ error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:48:19 + --> $DIR/wrong_self_convention.rs:49:19 | LL | pub fn to_i64(self) {} | ^^^^ error: methods called `from_*` usually take no self; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:49:21 + --> $DIR/wrong_self_convention.rs:50:21 | LL | pub fn from_i64(self) {} | ^^^^ From 7a66e6502dc3c7085b3f4078c01d4957d96175ed Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Sat, 29 Aug 2020 01:18:42 +0200 Subject: [PATCH 0030/1052] or_fn_call: ignore nullary associated const fns --- clippy_lints/src/utils/mod.rs | 2 +- tests/ui/or_fun_call.fixed | 17 +++++++++++------ tests/ui/or_fun_call.rs | 17 +++++++++++------ tests/ui/or_fun_call.stderr | 20 ++++---------------- 4 files changed, 27 insertions(+), 29 deletions(-) diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 8200525711564..fe2ee0931573b 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -899,7 +899,7 @@ pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_ return match res { def::Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true, // FIXME: check the constness of the arguments, see https://github.com/rust-lang/rust-clippy/pull/5682#issuecomment-638681210 - def::Res::Def(DefKind::Fn, def_id) if has_no_arguments(cx, def_id) => { + def::Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) if has_no_arguments(cx, def_id) => { const_eval::is_const_fn(cx.tcx, def_id) }, def::Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id), diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 67faa8bd4a0aa..5fb568672d356 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -58,12 +58,6 @@ fn or_fun_call() { let without_default = Some(Foo); without_default.unwrap_or_else(Foo::new); - let mut map = HashMap::::new(); - map.entry(42).or_insert_with(String::new); - - let mut btree = BTreeMap::::new(); - btree.entry(42).or_insert_with(String::new); - let stringy = Some(String::from("")); let _ = stringy.unwrap_or_else(|| "".to_owned()); @@ -122,6 +116,17 @@ pub fn skip_const_fn_with_no_args() { Some(42) } let _ = None.or(foo()); + + // See issue #5693. + let mut map = std::collections::HashMap::new(); + map.insert(1, vec![1]); + map.entry(1).or_insert(vec![]); + + let mut map = HashMap::::new(); + map.entry(42).or_insert(String::new()); + + let mut btree = BTreeMap::::new(); + btree.entry(42).or_insert(String::new()); } fn main() {} diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index 9867e2eedcff5..737b0f7e55bc7 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -58,12 +58,6 @@ fn or_fun_call() { let without_default = Some(Foo); without_default.unwrap_or(Foo::new()); - let mut map = HashMap::::new(); - map.entry(42).or_insert(String::new()); - - let mut btree = BTreeMap::::new(); - btree.entry(42).or_insert(String::new()); - let stringy = Some(String::from("")); let _ = stringy.unwrap_or("".to_owned()); @@ -122,6 +116,17 @@ pub fn skip_const_fn_with_no_args() { Some(42) } let _ = None.or(foo()); + + // See issue #5693. + let mut map = std::collections::HashMap::new(); + map.insert(1, vec![1]); + map.entry(1).or_insert(vec![]); + + let mut map = HashMap::::new(); + map.entry(42).or_insert(String::new()); + + let mut btree = BTreeMap::::new(); + btree.entry(42).or_insert(String::new()); } fn main() {} diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index bc5978b538f16..b8a436993f329 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -60,35 +60,23 @@ error: use of `unwrap_or` followed by a function call 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 - | -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 - | -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:62:21 | LL | let _ = stringy.unwrap_or("".to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())` error: use of `or` followed by a function call - --> $DIR/or_fun_call.rs:93:35 + --> $DIR/or_fun_call.rs:87: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:91: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 13 previous errors From 5b7590f841974255f74c64d573189aecc7a30b2e Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Sat, 29 Aug 2020 14:20:01 +0900 Subject: [PATCH 0031/1052] Downgrade applicability of `create_dir` --- clippy_lints/src/create_dir.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs index bf47c1f84a27d..1042eb455246c 100644 --- a/clippy_lints/src/create_dir.rs +++ b/clippy_lints/src/create_dir.rs @@ -42,7 +42,7 @@ impl LateLintPass<'_> for CreateDir { "calling `std::fs::create_dir` where there may be a better way", "consider calling `std::fs::create_dir_all` instead", format!("std::fs::create_dir_all({})", snippet(cx, args[0].span, "..")), - Applicability::MachineApplicable, + Applicability::MaybeIncorrect, ) } } From ba4c4988161abbe58e973b792c7e271785b4bc4d Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Sat, 29 Aug 2020 18:25:17 +0800 Subject: [PATCH 0032/1052] Add more info for Vec Drain doc See its documentation for more --- library/alloc/src/vec.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index b4ad238680f79..f6b2b3f1d23ce 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -2785,6 +2785,7 @@ unsafe impl<#[may_dangle] T> Drop for IntoIter { /// A draining iterator for `Vec`. /// /// This `struct` is created by [`Vec::drain`]. +/// See its documentation for more. #[stable(feature = "drain", since = "1.6.0")] pub struct Drain<'a, T: 'a> { /// Index of tail to preserve From 71484121001b69aefdc41fd7192b7095250517a7 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Sat, 29 Aug 2020 18:57:49 +0800 Subject: [PATCH 0033/1052] Vec slice example fix style and show type elision --- library/alloc/src/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index b4ad238680f79..d39b6b701e6d8 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -171,7 +171,7 @@ use crate::raw_vec::RawVec; /// /// // ... and that's all! /// // you can also do it like this: -/// let x : &[usize] = &v; +/// let u: &[usize] = &v; // or &[_] /// ``` /// /// In Rust, it's more common to pass slices as arguments rather than vectors From 4972989b616cbf96c015cd9fdf1f4b4464ecaace Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Fri, 14 Aug 2020 17:30:48 -0700 Subject: [PATCH 0034/1052] Add a lint for an async block/closure that yields a type that is itself awaitable. This catches bugs of the form tokio::spawn(async move { let f = some_async_thing(); f // Oh no I forgot to await f so that work will never complete. }); --- CHANGELOG.md | 1 + clippy_lints/src/async_yields_async.rs | 88 +++++++++++++++++++++++ clippy_lints/src/lib.rs | 5 ++ src/lintlist/mod.rs | 7 ++ tests/ui/async_yields_async.fixed | 61 ++++++++++++++++ tests/ui/async_yields_async.rs | 61 ++++++++++++++++ tests/ui/async_yields_async.stderr | 96 ++++++++++++++++++++++++++ 7 files changed, 319 insertions(+) create mode 100644 clippy_lints/src/async_yields_async.rs create mode 100644 tests/ui/async_yields_async.fixed create mode 100644 tests/ui/async_yields_async.rs create mode 100644 tests/ui/async_yields_async.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 34d4882102351..99a8b1a6293c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1512,6 +1512,7 @@ Released 2018-09-13 [`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants [`assign_op_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_op_pattern [`assign_ops`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_ops +[`async_yields_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#async_yields_async [`await_holding_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_lock [`bad_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#bad_bit_mask [`bind_instead_of_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#bind_instead_of_map diff --git a/clippy_lints/src/async_yields_async.rs b/clippy_lints/src/async_yields_async.rs new file mode 100644 index 0000000000000..ae347fcd3e8e4 --- /dev/null +++ b/clippy_lints/src/async_yields_async.rs @@ -0,0 +1,88 @@ +use crate::utils::{implements_trait, snippet, span_lint_and_then}; +use rustc_errors::Applicability; +use rustc_hir::{AsyncGeneratorKind, Body, BodyId, ExprKind, GeneratorKind, QPath}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** + /// Checks for async blocks that yield values of types that can themselves + /// be awaited. + /// + /// **Why is this bad?** + /// An await is likely missing. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// async fn foo() {} + /// + /// fn bar() { + /// let x = async { + /// foo() + /// }; + /// } + /// ``` + /// Use instead: + /// ```rust + /// async fn foo() {} + /// + /// fn bar() { + /// let x = async { + /// foo().await + /// }; + /// } + /// ``` + pub ASYNC_YIELDS_ASYNC, + correctness, + "async blocks that return a type that can be awaited" +} + +declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]); + +impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync { + fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) { + use AsyncGeneratorKind::{Block, Closure}; + // For functions, with explicitly defined types, don't warn. + // XXXkhuey maybe we should? + if let Some(GeneratorKind::Async(Block | Closure)) = body.generator_kind { + if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() { + let body_id = BodyId { + hir_id: body.value.hir_id, + }; + let def_id = cx.tcx.hir().body_owner_def_id(body_id); + let typeck_results = cx.tcx.typeck(def_id); + let expr_ty = typeck_results.expr_ty(&body.value); + + if implements_trait(cx, expr_ty, future_trait_def_id, &[]) { + let return_expr_span = match &body.value.kind { + // XXXkhuey there has to be a better way. + ExprKind::Block(block, _) => block.expr.map(|e| e.span), + ExprKind::Path(QPath::Resolved(_, path)) => Some(path.span), + _ => None, + }; + if let Some(return_expr_span) = return_expr_span { + span_lint_and_then( + cx, + ASYNC_YIELDS_ASYNC, + return_expr_span, + "an async construct yields a type which is itself awaitable", + |db| { + db.span_label(body.value.span, "outer async construct"); + db.span_label(return_expr_span, "awaitable value not awaited"); + db.span_suggestion( + return_expr_span, + "consider awaiting this value", + format!("{}.await", snippet(cx, return_expr_span, "..")), + Applicability::MaybeIncorrect, + ); + }, + ); + } + } + } + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 577ce6523b491..0eb1d3313660b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -154,6 +154,7 @@ mod arithmetic; mod as_conversions; mod assertions_on_constants; mod assign_ops; +mod async_yields_async; mod atomic_ordering; mod attrs; mod await_holding_lock; @@ -483,6 +484,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &assertions_on_constants::ASSERTIONS_ON_CONSTANTS, &assign_ops::ASSIGN_OP_PATTERN, &assign_ops::MISREFACTORED_ASSIGN_OP, + &async_yields_async::ASYNC_YIELDS_ASYNC, &atomic_ordering::INVALID_ATOMIC_ORDERING, &attrs::BLANKET_CLIPPY_RESTRICTION_LINTS, &attrs::DEPRECATED_CFG_ATTR, @@ -1099,6 +1101,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box unwrap_in_result::UnwrapInResult); store.register_late_pass(|| box self_assignment::SelfAssignment); store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs); + store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1232,6 +1235,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&assertions_on_constants::ASSERTIONS_ON_CONSTANTS), LintId::of(&assign_ops::ASSIGN_OP_PATTERN), LintId::of(&assign_ops::MISREFACTORED_ASSIGN_OP), + LintId::of(&async_yields_async::ASYNC_YIELDS_ASYNC), LintId::of(&atomic_ordering::INVALID_ATOMIC_ORDERING), LintId::of(&attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), LintId::of(&attrs::DEPRECATED_CFG_ATTR), @@ -1675,6 +1679,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_group(true, "clippy::correctness", Some("clippy_correctness"), vec![ LintId::of(&approx_const::APPROX_CONSTANT), + LintId::of(&async_yields_async::ASYNC_YIELDS_ASYNC), LintId::of(&atomic_ordering::INVALID_ATOMIC_ORDERING), LintId::of(&attrs::DEPRECATED_SEMVER), LintId::of(&attrs::MISMATCHED_TARGET_OS), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 687fac7baa848..dff19ef440f31 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -52,6 +52,13 @@ pub static ref ALL_LINTS: Vec = vec![ 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: "pedantic", diff --git a/tests/ui/async_yields_async.fixed b/tests/ui/async_yields_async.fixed new file mode 100644 index 0000000000000..cadc6494c7640 --- /dev/null +++ b/tests/ui/async_yields_async.fixed @@ -0,0 +1,61 @@ +// run-rustfix +// edition:2018 + +#![feature(async_closure)] +#![warn(clippy::async_yields_async)] + +use core::future::Future; +use core::pin::Pin; +use core::task::{Context, Poll}; + +struct CustomFutureType; + +impl Future for CustomFutureType { + type Output = u8; + + fn poll(self: Pin<&mut Self>, _: &mut Context) -> Poll { + Poll::Ready(3) + } +} + +fn custom_future_type_ctor() -> CustomFutureType { + CustomFutureType +} + +#[rustfmt::skip] +fn main() { + let _f = { + 3 + }; + let _g = async { + 3 + }; + let _h = async { + async { + 3 + }.await + }; + let _i = async { + CustomFutureType.await + }; + let _i = async || { + 3 + }; + let _j = async || { + async { + 3 + }.await + }; + let _k = async || { + CustomFutureType.await + }; + let _l = async || CustomFutureType.await; + let _m = async || { + println!("I'm bored"); + // Some more stuff + + // Finally something to await + CustomFutureType.await + }; + let _n = async || custom_future_type_ctor(); +} diff --git a/tests/ui/async_yields_async.rs b/tests/ui/async_yields_async.rs new file mode 100644 index 0000000000000..898fe1a95613c --- /dev/null +++ b/tests/ui/async_yields_async.rs @@ -0,0 +1,61 @@ +// run-rustfix +// edition:2018 + +#![feature(async_closure)] +#![warn(clippy::async_yields_async)] + +use core::future::Future; +use core::pin::Pin; +use core::task::{Context, Poll}; + +struct CustomFutureType; + +impl Future for CustomFutureType { + type Output = u8; + + fn poll(self: Pin<&mut Self>, _: &mut Context) -> Poll { + Poll::Ready(3) + } +} + +fn custom_future_type_ctor() -> CustomFutureType { + CustomFutureType +} + +#[rustfmt::skip] +fn main() { + let _f = { + 3 + }; + let _g = async { + 3 + }; + let _h = async { + async { + 3 + } + }; + let _i = async { + CustomFutureType + }; + let _i = async || { + 3 + }; + let _j = async || { + async { + 3 + } + }; + let _k = async || { + CustomFutureType + }; + let _l = async || CustomFutureType; + let _m = async || { + println!("I'm bored"); + // Some more stuff + + // Finally something to await + CustomFutureType + }; + let _n = async || custom_future_type_ctor(); +} diff --git a/tests/ui/async_yields_async.stderr b/tests/ui/async_yields_async.stderr new file mode 100644 index 0000000000000..112984cdccb6e --- /dev/null +++ b/tests/ui/async_yields_async.stderr @@ -0,0 +1,96 @@ +error: an async construct yields a type which is itself awaitable + --> $DIR/async_yields_async.rs:34:9 + | +LL | let _h = async { + | ____________________- +LL | | async { + | |_________^ +LL | || 3 +LL | || } + | ||_________^ awaitable value not awaited +LL | | }; + | |_____- outer async construct + | + = note: `-D clippy::async-yields-async` implied by `-D warnings` +help: consider awaiting this value + | +LL | async { +LL | 3 +LL | }.await + | + +error: an async construct yields a type which is itself awaitable + --> $DIR/async_yields_async.rs:39:9 + | +LL | let _i = async { + | ____________________- +LL | | CustomFutureType + | | ^^^^^^^^^^^^^^^^ + | | | + | | awaitable value not awaited + | | help: consider awaiting this value: `CustomFutureType.await` +LL | | }; + | |_____- outer async construct + +error: an async construct yields a type which is itself awaitable + --> $DIR/async_yields_async.rs:45:9 + | +LL | let _j = async || { + | _______________________- +LL | | async { + | |_________^ +LL | || 3 +LL | || } + | ||_________^ awaitable value not awaited +LL | | }; + | |_____- outer async construct + | +help: consider awaiting this value + | +LL | async { +LL | 3 +LL | }.await + | + +error: an async construct yields a type which is itself awaitable + --> $DIR/async_yields_async.rs:50:9 + | +LL | let _k = async || { + | _______________________- +LL | | CustomFutureType + | | ^^^^^^^^^^^^^^^^ + | | | + | | awaitable value not awaited + | | help: consider awaiting this value: `CustomFutureType.await` +LL | | }; + | |_____- outer async construct + +error: an async construct yields a type which is itself awaitable + --> $DIR/async_yields_async.rs:52:23 + | +LL | let _l = async || CustomFutureType; + | ^^^^^^^^^^^^^^^^ + | | + | outer async construct + | awaitable value not awaited + | help: consider awaiting this value: `CustomFutureType.await` + +error: an async construct yields a type which is itself awaitable + --> $DIR/async_yields_async.rs:58:9 + | +LL | let _m = async || { + | _______________________- +LL | | println!("I'm bored"); +LL | | // Some more stuff +LL | | +LL | | // Finally something to await +LL | | CustomFutureType + | | ^^^^^^^^^^^^^^^^ + | | | + | | awaitable value not awaited + | | help: consider awaiting this value: `CustomFutureType.await` +LL | | }; + | |_____- outer async construct + +error: aborting due to 6 previous errors + From c1d2b9376a6bb4fc06f845e12b9c2a93079bb2ee Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Sat, 22 Aug 2020 21:36:39 -0700 Subject: [PATCH 0035/1052] Add a test for an async function. --- tests/ui/async_yields_async.fixed | 7 +++++++ tests/ui/async_yields_async.rs | 7 +++++++ tests/ui/async_yields_async.stderr | 12 ++++++------ 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/tests/ui/async_yields_async.fixed b/tests/ui/async_yields_async.fixed index cadc6494c7640..9b1a7ac3ba9de 100644 --- a/tests/ui/async_yields_async.fixed +++ b/tests/ui/async_yields_async.fixed @@ -22,6 +22,12 @@ fn custom_future_type_ctor() -> CustomFutureType { CustomFutureType } +async fn f() -> CustomFutureType { + // Don't warn for functions since you have to explicitly declare their + // return types. + CustomFutureType +} + #[rustfmt::skip] fn main() { let _f = { @@ -58,4 +64,5 @@ fn main() { CustomFutureType.await }; let _n = async || custom_future_type_ctor(); + let _o = async || f(); } diff --git a/tests/ui/async_yields_async.rs b/tests/ui/async_yields_async.rs index 898fe1a95613c..731c094edb42b 100644 --- a/tests/ui/async_yields_async.rs +++ b/tests/ui/async_yields_async.rs @@ -22,6 +22,12 @@ fn custom_future_type_ctor() -> CustomFutureType { CustomFutureType } +async fn f() -> CustomFutureType { + // Don't warn for functions since you have to explicitly declare their + // return types. + CustomFutureType +} + #[rustfmt::skip] fn main() { let _f = { @@ -58,4 +64,5 @@ fn main() { CustomFutureType }; let _n = async || custom_future_type_ctor(); + let _o = async || f(); } diff --git a/tests/ui/async_yields_async.stderr b/tests/ui/async_yields_async.stderr index 112984cdccb6e..17d0c3751064f 100644 --- a/tests/ui/async_yields_async.stderr +++ b/tests/ui/async_yields_async.stderr @@ -1,5 +1,5 @@ error: an async construct yields a type which is itself awaitable - --> $DIR/async_yields_async.rs:34:9 + --> $DIR/async_yields_async.rs:40:9 | LL | let _h = async { | ____________________- @@ -20,7 +20,7 @@ LL | }.await | error: an async construct yields a type which is itself awaitable - --> $DIR/async_yields_async.rs:39:9 + --> $DIR/async_yields_async.rs:45:9 | LL | let _i = async { | ____________________- @@ -33,7 +33,7 @@ LL | | }; | |_____- outer async construct error: an async construct yields a type which is itself awaitable - --> $DIR/async_yields_async.rs:45:9 + --> $DIR/async_yields_async.rs:51:9 | LL | let _j = async || { | _______________________- @@ -53,7 +53,7 @@ LL | }.await | error: an async construct yields a type which is itself awaitable - --> $DIR/async_yields_async.rs:50:9 + --> $DIR/async_yields_async.rs:56:9 | LL | let _k = async || { | _______________________- @@ -66,7 +66,7 @@ LL | | }; | |_____- outer async construct error: an async construct yields a type which is itself awaitable - --> $DIR/async_yields_async.rs:52:23 + --> $DIR/async_yields_async.rs:58:23 | LL | let _l = async || CustomFutureType; | ^^^^^^^^^^^^^^^^ @@ -76,7 +76,7 @@ LL | let _l = async || CustomFutureType; | help: consider awaiting this value: `CustomFutureType.await` error: an async construct yields a type which is itself awaitable - --> $DIR/async_yields_async.rs:58:9 + --> $DIR/async_yields_async.rs:64:9 | LL | let _m = async || { | _______________________- From 04912ca115ff153a97d80b604435b10dcb155dd0 Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Sat, 22 Aug 2020 21:40:01 -0700 Subject: [PATCH 0036/1052] Formatting changes requested by ThibsG. --- clippy_lints/src/async_yields_async.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/async_yields_async.rs b/clippy_lints/src/async_yields_async.rs index ae347fcd3e8e4..88d9d3b5a263d 100644 --- a/clippy_lints/src/async_yields_async.rs +++ b/clippy_lints/src/async_yields_async.rs @@ -5,12 +5,10 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** - /// Checks for async blocks that yield values of types that can themselves - /// be awaited. + /// **What it does:** Checks for async blocks that yield values of types + /// that can themselves be awaited. /// - /// **Why is this bad?** - /// An await is likely missing. + /// **Why is this bad?** An await is likely missing. /// /// **Known problems:** None. /// From a424a2c1676a29c147252873037e8943d54941d3 Mon Sep 17 00:00:00 2001 From: Vali Schneider Date: Sat, 29 Aug 2020 16:17:53 -0700 Subject: [PATCH 0037/1052] changed check_impl_item to check_fn and added a few more test cases --- clippy_lints/src/panic_in_result.rs | 69 ++++++++++++++--------------- tests/ui/panic_in_result.rs | 20 ++++++++- tests/ui/panic_in_result.stderr | 60 +++++++++++++++++++------ 3 files changed, 99 insertions(+), 50 deletions(-) diff --git a/clippy_lints/src/panic_in_result.rs b/clippy_lints/src/panic_in_result.rs index 2901f393fc65b..11fefc12316b7 100644 --- a/clippy_lints/src/panic_in_result.rs +++ b/clippy_lints/src/panic_in_result.rs @@ -1,6 +1,8 @@ use crate::utils::{is_expn_of, is_type_diagnostic_item, return_ty, span_lint_and_then}; use if_chain::if_chain; use rustc_hir as hir; +use rustc_hir::intravisit::{self, FnKind, NestedVisitorMap, Visitor}; +use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -21,7 +23,6 @@ declare_clippy_lint! { /// panic!("error"); /// } /// ``` - pub PANIC_IN_RESULT, restriction, "functions of type `Result<..>` that contain `panic!()`, `todo!()` or `unreachable()` or `unimplemented()` " @@ -30,22 +31,26 @@ declare_clippy_lint! { declare_lint_pass!(PanicInResult => [PANIC_IN_RESULT]); impl<'tcx> LateLintPass<'tcx> for PanicInResult { - fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) { + /* + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + _: FnKind<'tcx>, + _: &'tcx hir::FnDecl<'tcx>, + body: &'tcx hir::Body<'tcx>, + span: Span, + hir_id: hir::HirId, + ) { if_chain! { - // first check if it's a method or function - if let hir::ImplItemKind::Fn(ref _signature, _) = impl_item.kind; - // checking if its return type is `result` or `option` - if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(result_type)); - then { - lint_impl_body(cx, impl_item.span, impl_item); + if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)); + then + { + lint_impl_body(cx, span, body); } } - } + }*/ } -use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_hir::{Expr, ImplItemKind}; - struct FindPanicUnimplementedUnreachable { result: Vec, } @@ -70,29 +75,21 @@ impl<'tcx> Visitor<'tcx> for FindPanicUnimplementedUnreachable { } } -fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tcx hir::ImplItem<'_>) { - if_chain! { - if let ImplItemKind::Fn(_, body_id) = impl_item.kind; - then { - let body = cx.tcx.hir().body(body_id); - let mut fpu = FindPanicUnimplementedUnreachable { - result: Vec::new(), - }; - fpu.visit_expr(&body.value); - - // if we've found one, lint - if !fpu.result.is_empty() { - span_lint_and_then( - cx, - PANIC_IN_RESULT, - impl_span, - "used unimplemented, unreachable, todo or panic in a function that returns result", - move |diag| { - diag.help( - "unimplemented, unreachable, todo or panic should not be used in a function that returns result" ); - diag.span_note(fpu.result, "will cause the application to crash."); - }); - } - } +fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir::Body<'tcx>) { + let mut panics = FindPanicUnimplementedUnreachable { result: Vec::new() }; + panics.visit_expr(&body.value); + if !panics.result.is_empty() { + span_lint_and_then( + cx, + PANIC_IN_RESULT, + impl_span, + "used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result`", + move |diag| { + diag.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", + ); + diag.span_note(panics.result, "return Err() instead of panicking"); + }, + ); } } diff --git a/tests/ui/panic_in_result.rs b/tests/ui/panic_in_result.rs index 056778995a4ca..f6fb2f1ab6120 100644 --- a/tests/ui/panic_in_result.rs +++ b/tests/ui/panic_in_result.rs @@ -49,4 +49,22 @@ impl A { } } -fn main() {} +fn function_result_with_panic() -> Result // should emit lint +{ + panic!("error"); +} + +fn todo() { + println!("something"); +} + +fn function_result_with_custom_todo() -> Result // should not emit lint +{ + todo(); + Ok(true) +} + +fn main() -> Result<(), String> { + todo!("finish main method"); + Ok(()) +} diff --git a/tests/ui/panic_in_result.stderr b/tests/ui/panic_in_result.stderr index 3b9ac69f20dd6..9faedf8298603 100644 --- a/tests/ui/panic_in_result.stderr +++ b/tests/ui/panic_in_result.stderr @@ -1,4 +1,4 @@ -error: used unimplemented, unreachable, todo or panic in a function that returns result +error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` --> $DIR/panic_in_result.rs:6:5 | LL | / fn result_with_panic() -> Result // should emit lint @@ -8,15 +8,15 @@ LL | | } | |_____^ | = note: `-D clippy::panic-in-result` implied by `-D warnings` - = help: unimplemented, unreachable, todo or panic should not be used in a function that returns result -note: will cause the application to crash. + = 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.rs:8: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 +error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` --> $DIR/panic_in_result.rs:11:5 | LL | / fn result_with_unimplemented() -> Result // should emit lint @@ -25,15 +25,15 @@ LL | | unimplemented!(); LL | | } | |_____^ | - = help: unimplemented, unreachable, todo or panic should not be used in a function that returns result -note: will cause the application to crash. + = 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.rs:13: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 +error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` --> $DIR/panic_in_result.rs:16:5 | LL | / fn result_with_unreachable() -> Result // should emit lint @@ -42,15 +42,15 @@ LL | | unreachable!(); LL | | } | |_____^ | - = help: unimplemented, unreachable, todo or panic should not be used in a function that returns result -note: will cause the application to crash. + = 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.rs:18: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 +error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` --> $DIR/panic_in_result.rs:21:5 | LL | / fn result_with_todo() -> Result // should emit lint @@ -59,13 +59,47 @@ LL | | todo!("Finish this"); LL | | } | |_____^ | - = help: unimplemented, unreachable, todo or panic should not be used in a function that returns result -note: will cause the application to crash. + = 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.rs:23:9 | LL | todo!("Finish this"); | ^^^^^^^^^^^^^^^^^^^^^ = 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 +error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` + --> $DIR/panic_in_result.rs:52:1 + | +LL | / fn function_result_with_panic() -> Result // should emit lint +LL | | { +LL | | panic!("error"); +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.rs:54: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.rs:67:1 + | +LL | / fn main() -> Result<(), String> { +LL | | todo!("finish main method"); +LL | | Ok(()) +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.rs:68:5 + | +LL | todo!("finish main method"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 6 previous errors From 73a3288282e733bfc5893e9920d29f1de5a21591 Mon Sep 17 00:00:00 2001 From: Vali Schneider Date: Sat, 29 Aug 2020 16:22:15 -0700 Subject: [PATCH 0038/1052] uncommented fn --- clippy_lints/src/panic_in_result.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clippy_lints/src/panic_in_result.rs b/clippy_lints/src/panic_in_result.rs index 11fefc12316b7..8ba365cb00c36 100644 --- a/clippy_lints/src/panic_in_result.rs +++ b/clippy_lints/src/panic_in_result.rs @@ -31,7 +31,6 @@ declare_clippy_lint! { declare_lint_pass!(PanicInResult => [PANIC_IN_RESULT]); impl<'tcx> LateLintPass<'tcx> for PanicInResult { - /* fn check_fn( &mut self, cx: &LateContext<'tcx>, @@ -48,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResult { lint_impl_body(cx, span, body); } } - }*/ + } } struct FindPanicUnimplementedUnreachable { From 27c90b881df93b53fd3f24dcbfed116379c2fc69 Mon Sep 17 00:00:00 2001 From: Federico Ponzi Date: Sun, 30 Aug 2020 16:21:41 +0200 Subject: [PATCH 0039/1052] initial implementation of OpenOptions to c_int --- library/std/src/sys/unix/fs.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index acb18e6d064e6..59dfd9f9dc424 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -692,6 +692,7 @@ impl OpenOptions { } } + impl File { pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { let path = cstr(path)?; @@ -962,6 +963,12 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> { Ok(()) } +pub fn get_openopetions_as_cint(from: OpenOptions) -> io::Result { + let access_mode = from.get_access_mode()?; + let creation_mode = from.get_creation_mode()?; + Ok(creation_mode | access_mode) +} + pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { let p = cstr(p)?; cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) })?; From eb3906be4ad375cc6b83cd6a6e0116817db22575 Mon Sep 17 00:00:00 2001 From: Federico Ponzi Date: Sun, 30 Aug 2020 17:01:20 +0200 Subject: [PATCH 0040/1052] Fix typo get openoptions function name Co-authored-by: Ivan Tham --- library/std/src/sys/unix/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 59dfd9f9dc424..338ce17b06c38 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -963,7 +963,7 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> { Ok(()) } -pub fn get_openopetions_as_cint(from: OpenOptions) -> io::Result { +pub fn get_openoptions_as_cint(from: OpenOptions) -> io::Result { let access_mode = from.get_access_mode()?; let creation_mode = from.get_creation_mode()?; Ok(creation_mode | access_mode) From 0f2bd56b29857453835e47abbe96a80b175632d1 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 3 Aug 2020 11:08:03 +0100 Subject: [PATCH 0041/1052] lint/ty: move fns to avoid abstraction violation This commit moves `transparent_newtype_field` and `is_zst` to `LateContext` where they are used, rather than being on the `VariantDef` and `TyS` types. Signed-off-by: David Wood --- compiler/rustc_lint/src/builtin.rs | 6 +++--- compiler/rustc_lint/src/types.rs | 26 +++++++++++++++++++++++--- compiler/rustc_middle/src/ty/mod.rs | 15 +-------------- compiler/rustc_middle/src/ty/sty.rs | 5 ----- 4 files changed, 27 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index ea624b9ed3003..694455171e9ec 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -21,7 +21,8 @@ //! `late_lint_methods!` invocation in `lib.rs`. use crate::{ - types::CItemKind, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext, + types::{transparent_newtype_field, CItemKind}, + EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext, }; use rustc_ast::attr::{self, HasAttrs}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; @@ -2180,8 +2181,7 @@ impl ClashingExternDeclarations { if is_transparent && !is_non_null { debug_assert!(def.variants.len() == 1); let v = &def.variants[VariantIdx::new(0)]; - ty = v - .transparent_newtype_field(tcx) + ty = transparent_newtype_field(tcx, v) .expect( "single-variant transparent structure with zero-sized field", ) diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 35c462c24c8e8..132e9286f6b3b 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -533,6 +533,26 @@ crate fn nonnull_optimization_guaranteed<'tcx>(tcx: TyCtxt<'tcx>, def: &ty::AdtD .any(|a| tcx.sess.check_name(a, sym::rustc_nonnull_optimization_guaranteed)) } +/// `repr(transparent)` structs can have a single non-ZST field, this function returns that +/// field. +pub fn transparent_newtype_field<'a, 'tcx>( + tcx: TyCtxt<'tcx>, + variant: &'a ty::VariantDef, +) -> Option<&'a ty::FieldDef> { + let param_env = tcx.param_env(variant.def_id); + for field in &variant.fields { + let field_ty = tcx.type_of(field.did); + let is_zst = + tcx.layout_of(param_env.and(field_ty)).map(|layout| layout.is_zst()).unwrap_or(false); + + if !is_zst { + return Some(field); + } + } + + None +} + /// Is type known to be non-null? crate fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool { let tcx = cx.tcx; @@ -548,7 +568,7 @@ crate fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: C } for variant in &def.variants { - if let Some(field) = variant.transparent_newtype_field(tcx) { + if let Some(field) = transparent_newtype_field(cx.tcx, variant) { if ty_is_known_nonnull(cx, field.ty(tcx, substs), mode) { return true; } @@ -569,7 +589,7 @@ fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option { let inner_field_ty = { let first_non_zst_ty = - field_def.variants.iter().filter_map(|v| v.transparent_newtype_field(tcx)); + field_def.variants.iter().filter_map(|v| transparent_newtype_field(cx.tcx, v)); debug_assert_eq!( first_non_zst_ty.clone().count(), 1, @@ -710,7 +730,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if def.repr.transparent() { // Can assume that only one field is not a ZST, so only check // that field's type for FFI-safety. - if let Some(field) = variant.transparent_newtype_field(self.cx.tcx) { + if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) { self.check_field_type_for_ffi(cache, field, substs) } else { bug!("malformed transparent type"); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index b6300a40b0d8d..8027bed2c8cf0 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2005,7 +2005,7 @@ pub struct VariantDef { flags: VariantFlags, } -impl<'tcx> VariantDef { +impl VariantDef { /// Creates a new `VariantDef`. /// /// `variant_did` is the `DefId` that identifies the enum variant (if this `VariantDef` @@ -2071,19 +2071,6 @@ impl<'tcx> VariantDef { pub fn is_recovered(&self) -> bool { self.flags.intersects(VariantFlags::IS_RECOVERED) } - - /// `repr(transparent)` structs can have a single non-ZST field, this function returns that - /// field. - pub fn transparent_newtype_field(&self, tcx: TyCtxt<'tcx>) -> Option<&FieldDef> { - for field in &self.fields { - let field_ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, self.def_id)); - if !field_ty.is_zst(tcx, self.def_id) { - return Some(field); - } - } - - None - } } #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index c1f354c7a15f3..2af3fb7f8638a 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2280,9 +2280,4 @@ impl<'tcx> TyS<'tcx> { } } } - - /// Is this a zero-sized type? - pub fn is_zst(&'tcx self, tcx: TyCtxt<'tcx>, did: DefId) -> bool { - tcx.layout_of(tcx.param_env(did).and(self)).map(|layout| layout.is_zst()).unwrap_or(false) - } } From 1c5b0fbe53f842cd5871ea02e4e48571615d5679 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 28 Aug 2020 13:26:25 -0700 Subject: [PATCH 0042/1052] Update dataflow analyses to use new interface --- clippy_lints/src/redundant_clone.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 7932be0d4b1f2..aec99cb406338 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -14,7 +14,6 @@ use rustc_middle::mir::{ visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor as _}, }; use rustc_middle::ty::{self, fold::TypeVisitor, Ty}; -use rustc_mir::dataflow::BottomValue; use rustc_mir::dataflow::{Analysis, AnalysisDomain, GenKill, GenKillAnalysis, ResultsCursor}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::{BytePos, Span}; @@ -411,14 +410,15 @@ impl<'tcx> mir::visit::Visitor<'tcx> for LocalUseVisitor { struct MaybeStorageLive; impl<'tcx> AnalysisDomain<'tcx> for MaybeStorageLive { - type Idx = mir::Local; + type Domain = BitSet; const NAME: &'static str = "maybe_storage_live"; - fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { - body.local_decls.len() + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { + // bottom = dead + BitSet::new_empty(body.local_decls.len()) } - fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet) { + fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) { for arg in body.args_iter() { state.insert(arg); } @@ -426,6 +426,8 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeStorageLive { } impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive { + type Idx = mir::Local; + fn statement_effect(&self, trans: &mut impl GenKill, stmt: &mir::Statement<'tcx>, _: mir::Location) { match stmt.kind { mir::StatementKind::StorageLive(l) => trans.gen(l), @@ -454,11 +456,6 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive { } } -impl BottomValue for MaybeStorageLive { - /// bottom = dead - const BOTTOM_VALUE: bool = false; -} - /// Collects the possible borrowers of each local. /// For example, `b = &a; c = &a;` will make `b` and (transitively) `c` /// possible borrowers of `a`. From 17b2ba5ded12f59dba63ece659b5cd714b763800 Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Sun, 30 Aug 2020 11:24:15 -0700 Subject: [PATCH 0043/1052] Syntax-highlight `single_char_push_str` lint --- clippy_lints/src/methods/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 9996df69470f0..7c4a78cbdcdb3 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1324,20 +1324,20 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Warns when using push_str with a single-character string literal, - /// and push with a char would work fine. + /// **What it does:** Warns when using `push_str` with a single-character string literal, + /// and `push` with a `char` would work fine. /// - /// **Why is this bad?** It's less clear that we are pushing a single character + /// **Why is this bad?** It's less clear that we are pushing a single character. /// /// **Known problems:** None /// /// **Example:** - /// ``` + /// ```rust /// let mut string = String::new(); /// string.push_str("R"); /// ``` /// Could be written as - /// ``` + /// ```rust /// let mut string = String::new(); /// string.push('R'); /// ``` From d3b9ece4c0028ff7e36e34df2d2b26366f9c0648 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sun, 16 Aug 2020 19:24:59 -0400 Subject: [PATCH 0044/1052] add tests related to tuple scalar layout with ZST in last field --- src/test/codegen/tuple-layout-opt.rs | 36 +++++++++++++++++++ .../dst-tuple-no-reorder.rs | 26 ++++++++++++++ .../mir/mir_const_prop_tuple_field_reorder.rs | 27 ++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 src/test/codegen/tuple-layout-opt.rs create mode 100644 src/test/ui/dynamically-sized-types/dst-tuple-no-reorder.rs create mode 100644 src/test/ui/mir/mir_const_prop_tuple_field_reorder.rs diff --git a/src/test/codegen/tuple-layout-opt.rs b/src/test/codegen/tuple-layout-opt.rs new file mode 100644 index 0000000000000..e86c75f3f4826 --- /dev/null +++ b/src/test/codegen/tuple-layout-opt.rs @@ -0,0 +1,36 @@ +// ignore-emscripten +// compile-flags: -C no-prepopulate-passes + +// Test that tuples get optimized layout, in particular with a ZST in the last field (#63244) + +#![crate_type="lib"] + +type ScalarZstLast = (u128, ()); +// CHECK: define i128 @test_ScalarZstLast(i128 %_1) +#[no_mangle] +pub fn test_ScalarZstLast(_: ScalarZstLast) -> ScalarZstLast { loop {} } + +type ScalarZstFirst = ((), u128); +// CHECK: define i128 @test_ScalarZstFirst(i128 %_1) +#[no_mangle] +pub fn test_ScalarZstFirst(_: ScalarZstFirst) -> ScalarZstFirst { loop {} } + +type ScalarPairZstLast = (u8, u128, ()); +// CHECK: define { i128, i8 } @test_ScalarPairZstLast(i128 %_1.0, i8 %_1.1) +#[no_mangle] +pub fn test_ScalarPairZstLast(_: ScalarPairZstLast) -> ScalarPairZstLast { loop {} } + +type ScalarPairZstFirst = ((), u8, u128); +// CHECK: define { i8, i128 } @test_ScalarPairZstFirst(i8 %_1.0, i128 %_1.1) +#[no_mangle] +pub fn test_ScalarPairZstFirst(_: ScalarPairZstFirst) -> ScalarPairZstFirst { loop {} } + +type ScalarPairLotsOfZsts = ((), u8, (), u128, ()); +// CHECK: define { i128, i8 } @test_ScalarPairLotsOfZsts(i128 %_1.0, i8 %_1.1) +#[no_mangle] +pub fn test_ScalarPairLotsOfZsts(_: ScalarPairLotsOfZsts) -> ScalarPairLotsOfZsts { loop {} } + +type ScalarPairLottaNesting = (((), ((), u8, (), u128, ())), ()); +// CHECK: define { i128, i8 } @test_ScalarPairLottaNesting(i128 %_1.0, i8 %_1.1) +#[no_mangle] +pub fn test_ScalarPairLottaNesting(_: ScalarPairLottaNesting) -> ScalarPairLottaNesting { loop {} } diff --git a/src/test/ui/dynamically-sized-types/dst-tuple-no-reorder.rs b/src/test/ui/dynamically-sized-types/dst-tuple-no-reorder.rs new file mode 100644 index 0000000000000..26b923f431f98 --- /dev/null +++ b/src/test/ui/dynamically-sized-types/dst-tuple-no-reorder.rs @@ -0,0 +1,26 @@ +// run-pass + +#![feature(unsized_tuple_coercion)] + +// Ensure that unsizable fields that might be accessed don't get reordered + +fn nonzero_size() { + let sized: (u8, [u32; 2]) = (123, [456, 789]); + let unsize: &(u8, [u32]) = &sized; + assert_eq!(unsize.0, 123); + assert_eq!(unsize.1.len(), 2); + assert_eq!(unsize.1[0], 456); + assert_eq!(unsize.1[1], 789); +} + +fn zst() { + let sized: (u8, [u32; 0]) = (123, []); + let unsize: &(u8, [u32]) = &sized; + assert_eq!(unsize.0, 123); + assert_eq!(unsize.1.len(), 0); +} + +pub fn main() { + nonzero_size(); + zst(); +} diff --git a/src/test/ui/mir/mir_const_prop_tuple_field_reorder.rs b/src/test/ui/mir/mir_const_prop_tuple_field_reorder.rs new file mode 100644 index 0000000000000..629b50dec65f9 --- /dev/null +++ b/src/test/ui/mir/mir_const_prop_tuple_field_reorder.rs @@ -0,0 +1,27 @@ +// compile-flags: -Z mir-opt-level=2 +// build-pass +#![crate_type="lib"] + +// This used to ICE: const-prop did not account for field reordering of scalar pairs, +// and would generate a tuple like `(0x1337, VariantBar): (FooEnum, isize)`, +// causing assertion failures in codegen when trying to read 0x1337 at the wrong type. + +pub enum FooEnum { + VariantBar, + VariantBaz, + VariantBuz, +} + +pub fn wrong_index() -> isize { + let (_, b) = id((FooEnum::VariantBar, 0x1337)); + b +} + +pub fn wrong_index_two() -> isize { + let (_, (_, b)) = id(((), (FooEnum::VariantBar, 0x1338))); + b +} + +fn id(x: T) -> T { + x +} From e5d85f917b8965a5e62513c17cbb887366b152bc Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sun, 16 Aug 2020 19:25:24 -0400 Subject: [PATCH 0045/1052] allow reordering of the last field of a MaybeUnsized struct if it's a ZST --- compiler/rustc_middle/src/ty/layout.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 08bd131565bfa..4038deb323341 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -289,25 +289,32 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let optimize = !repr.inhibit_struct_field_reordering_opt(); if optimize { - let end = - if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() }; - let optimizing = &mut inverse_memory_index[..end]; let field_align = |f: &TyAndLayout<'_>| { if let Some(pack) = pack { f.align.abi.min(pack) } else { f.align.abi } }; match kind { - StructKind::AlwaysSized | StructKind::MaybeUnsized => { - optimizing.sort_by_key(|&x| { + StructKind::AlwaysSized => { + inverse_memory_index.sort_by_key(|&x| { // Place ZSTs first to avoid "interesting offsets", // especially with only one or two non-ZST fields. let f = &fields[x as usize]; (!f.is_zst(), cmp::Reverse(field_align(f))) }); } + StructKind::MaybeUnsized => { + // Sort in descending alignment, except for the last field, + // which may be accessed through an unsized type. + inverse_memory_index[..fields.len() - 1] + .sort_by_key(|&x| cmp::Reverse(field_align(&fields[x as usize]))); + // Place ZSTs first to avoid "interesting offsets". + // This will reorder the last field if it is a ZST, which is okay because + // there's nothing in memory that could be accessed through an unsized type. + inverse_memory_index.sort_by_key(|&x| !fields[x as usize].is_zst()); + } StructKind::Prefixed(..) => { // Sort in ascending alignment so that the layout stay optimal // regardless of the prefix - optimizing.sort_by_key(|&x| field_align(&fields[x as usize])); + inverse_memory_index.sort_by_key(|&x| field_align(&fields[x as usize])); } } } From e9bc3ddb073f2261ac46832d985efe8db863ed6a Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sun, 16 Aug 2020 20:38:57 -0400 Subject: [PATCH 0046/1052] test that we do not change the offset of ZST tuple fields when unsizing --- .../dst-tuple-zst-offsets.rs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/test/ui/dynamically-sized-types/dst-tuple-zst-offsets.rs diff --git a/src/test/ui/dynamically-sized-types/dst-tuple-zst-offsets.rs b/src/test/ui/dynamically-sized-types/dst-tuple-zst-offsets.rs new file mode 100644 index 0000000000000..b0cefe77039d6 --- /dev/null +++ b/src/test/ui/dynamically-sized-types/dst-tuple-zst-offsets.rs @@ -0,0 +1,22 @@ +// run-pass + +#![feature(unsized_tuple_coercion)] + +// Check that we do not change the offsets of ZST fields when unsizing + +fn scalar_layout() { + let sized: &(u8, [(); 13]) = &(123, [(); 13]); + let unsize: &(u8, [()]) = sized; + assert_eq!(sized.1.as_ptr(), unsize.1.as_ptr()); +} + +fn scalarpair_layout() { + let sized: &(u8, u16, [(); 13]) = &(123, 456, [(); 13]); + let unsize: &(u8, u16, [()]) = sized; + assert_eq!(sized.2.as_ptr(), unsize.2.as_ptr()); +} + +pub fn main() { + scalar_layout(); + scalarpair_layout(); +} From 68217c9e0f1269d29b4c1c72d08fb1b95bf441cd Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sun, 16 Aug 2020 19:25:39 -0400 Subject: [PATCH 0047/1052] ignore zst offsets instead --- compiler/rustc_codegen_ssa/src/mir/place.rs | 32 +++-- compiler/rustc_middle/src/ty/layout.rs | 131 ++++++++------------ 2 files changed, 76 insertions(+), 87 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 05656774f0e95..7c0eddea5229b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -93,15 +93,29 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { let effective_field_align = self.align.restrict_for_offset(offset); let mut simple = || { - // Unions and newtypes only use an offset of 0. - let llval = if offset.bytes() == 0 { - self.llval - } else if let Abi::ScalarPair(ref a, ref b) = self.layout.abi { - // Offsets have to match either first or second field. - assert_eq!(offset, a.value.size(bx.cx()).align_to(b.value.align(bx.cx()).abi)); - bx.struct_gep(self.llval, 1) - } else { - bx.struct_gep(self.llval, bx.cx().backend_field_index(self.layout, ix)) + let llval = match self.layout.abi { + _ if offset.bytes() == 0 => { + // Unions and newtypes only use an offset of 0. + // Also handles the first field of Scalar and ScalarPair layouts. + self.llval + } + Abi::ScalarPair(ref a, ref b) + if offset == a.value.size(bx.cx()).align_to(b.value.align(bx.cx()).abi) => + { + // Offset matches second field. + bx.struct_gep(self.llval, 1) + } + Abi::ScalarPair(..) | Abi::Scalar(_) => { + // ZST fields are not included in Scalar and ScalarPair layouts, so manually offset the pointer. + assert!( + field.is_zst(), + "non-ZST field offset does not match layout: {:?}", + field + ); + let byte_ptr = bx.pointercast(self.llval, bx.cx().type_i8p()); + bx.gep(byte_ptr, &[bx.const_usize(offset.bytes())]) + } + _ => bx.struct_gep(self.llval, bx.cx().backend_field_index(self.layout, ix)), }; PlaceRef { // HACK(eddyb): have to bitcast pointers until LLVM removes pointee types. diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 4038deb323341..3ec0842347217 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -289,32 +289,25 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let optimize = !repr.inhibit_struct_field_reordering_opt(); if optimize { + let end = + if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() }; + let optimizing = &mut inverse_memory_index[..end]; let field_align = |f: &TyAndLayout<'_>| { if let Some(pack) = pack { f.align.abi.min(pack) } else { f.align.abi } }; match kind { - StructKind::AlwaysSized => { - inverse_memory_index.sort_by_key(|&x| { + StructKind::AlwaysSized | StructKind::MaybeUnsized => { + optimizing.sort_by_key(|&x| { // Place ZSTs first to avoid "interesting offsets", // especially with only one or two non-ZST fields. let f = &fields[x as usize]; (!f.is_zst(), cmp::Reverse(field_align(f))) }); } - StructKind::MaybeUnsized => { - // Sort in descending alignment, except for the last field, - // which may be accessed through an unsized type. - inverse_memory_index[..fields.len() - 1] - .sort_by_key(|&x| cmp::Reverse(field_align(&fields[x as usize]))); - // Place ZSTs first to avoid "interesting offsets". - // This will reorder the last field if it is a ZST, which is okay because - // there's nothing in memory that could be accessed through an unsized type. - inverse_memory_index.sort_by_key(|&x| !fields[x as usize].is_zst()); - } StructKind::Prefixed(..) => { // Sort in ascending alignment so that the layout stay optimal // regardless of the prefix - inverse_memory_index.sort_by_key(|&x| field_align(&fields[x as usize])); + optimizing.sort_by_key(|&x| field_align(&fields[x as usize])); } } } @@ -397,78 +390,60 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // Unpack newtype ABIs and find scalar pairs. if sized && size.bytes() > 0 { - // All other fields must be ZSTs, and we need them to all start at 0. - let mut zst_offsets = offsets.iter().enumerate().filter(|&(i, _)| fields[i].is_zst()); - if zst_offsets.all(|(_, o)| o.bytes() == 0) { - let mut non_zst_fields = fields.iter().enumerate().filter(|&(_, f)| !f.is_zst()); - - match (non_zst_fields.next(), non_zst_fields.next(), non_zst_fields.next()) { - // We have exactly one non-ZST field. - (Some((i, field)), None, None) => { - // Field fills the struct and it has a scalar or scalar pair ABI. - if offsets[i].bytes() == 0 - && align.abi == field.align.abi - && size == field.size - { - match field.abi { - // For plain scalars, or vectors of them, we can't unpack - // newtypes for `#[repr(C)]`, as that affects C ABIs. - Abi::Scalar(_) | Abi::Vector { .. } if optimize => { - abi = field.abi.clone(); - } - // But scalar pairs are Rust-specific and get - // treated as aggregates by C ABIs anyway. - Abi::ScalarPair(..) => { - abi = field.abi.clone(); - } - _ => {} + // All other fields must be ZSTs. + let mut non_zst_fields = fields.iter().enumerate().filter(|&(_, f)| !f.is_zst()); + + match (non_zst_fields.next(), non_zst_fields.next(), non_zst_fields.next()) { + // We have exactly one non-ZST field. + (Some((i, field)), None, None) => { + // Field fills the struct and it has a scalar or scalar pair ABI. + if offsets[i].bytes() == 0 && align.abi == field.align.abi && size == field.size + { + match field.abi { + // For plain scalars, or vectors of them, we can't unpack + // newtypes for `#[repr(C)]`, as that affects C ABIs. + Abi::Scalar(_) | Abi::Vector { .. } if optimize => { + abi = field.abi.clone(); + } + // But scalar pairs are Rust-specific and get + // treated as aggregates by C ABIs anyway. + Abi::ScalarPair(..) => { + abi = field.abi.clone(); } + _ => {} } } + } - // Two non-ZST fields, and they're both scalars. - ( - Some(( - i, - &TyAndLayout { - layout: &Layout { abi: Abi::Scalar(ref a), .. }, .. - }, - )), - Some(( - j, - &TyAndLayout { - layout: &Layout { abi: Abi::Scalar(ref b), .. }, .. - }, - )), - None, - ) => { - // Order by the memory placement, not source order. - let ((i, a), (j, b)) = if offsets[i] < offsets[j] { - ((i, a), (j, b)) - } else { - ((j, b), (i, a)) - }; - let pair = self.scalar_pair(a.clone(), b.clone()); - let pair_offsets = match pair.fields { - FieldsShape::Arbitrary { ref offsets, ref memory_index } => { - assert_eq!(memory_index, &[0, 1]); - offsets - } - _ => bug!(), - }; - if offsets[i] == pair_offsets[0] - && offsets[j] == pair_offsets[1] - && align == pair.align - && size == pair.size - { - // We can use `ScalarPair` only when it matches our - // already computed layout (including `#[repr(C)]`). - abi = pair.abi; + // Two non-ZST fields, and they're both scalars. + ( + Some((i, &TyAndLayout { layout: &Layout { abi: Abi::Scalar(ref a), .. }, .. })), + Some((j, &TyAndLayout { layout: &Layout { abi: Abi::Scalar(ref b), .. }, .. })), + None, + ) => { + // Order by the memory placement, not source order. + let ((i, a), (j, b)) = + if offsets[i] < offsets[j] { ((i, a), (j, b)) } else { ((j, b), (i, a)) }; + let pair = self.scalar_pair(a.clone(), b.clone()); + let pair_offsets = match pair.fields { + FieldsShape::Arbitrary { ref offsets, ref memory_index } => { + assert_eq!(memory_index, &[0, 1]); + offsets } + _ => bug!(), + }; + if offsets[i] == pair_offsets[0] + && offsets[j] == pair_offsets[1] + && align == pair.align + && size == pair.size + { + // We can use `ScalarPair` only when it matches our + // already computed layout (including `#[repr(C)]`). + abi = pair.abi; } - - _ => {} } + + _ => {} } } From 6fc1d8bc13124bb134d7ab54e56237821a55912e Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sun, 16 Aug 2020 22:02:18 -0400 Subject: [PATCH 0048/1052] add codegen test --- src/test/codegen/zst-offset.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 src/test/codegen/zst-offset.rs diff --git a/src/test/codegen/zst-offset.rs b/src/test/codegen/zst-offset.rs new file mode 100644 index 0000000000000..3c63cddccad64 --- /dev/null +++ b/src/test/codegen/zst-offset.rs @@ -0,0 +1,29 @@ +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +// Hack to get the correct size for the length part in slices +// CHECK: @helper([[USIZE:i[0-9]+]] %_1) +#[no_mangle] +pub fn helper(_: usize) { +} + +// Check that we correctly generate a GEP for a ZST that is not included in Scalar layout +// CHECK-LABEL: @scalar_layout +#[no_mangle] +pub fn scalar_layout(s: &(u64, ())) { +// CHECK: [[X0:%[0-9]+]] = bitcast i64* %s to i8* +// CHECK-NEXT: [[X1:%[0-9]+]] = getelementptr i8, i8* [[X0]], [[USIZE]] 8 + let x = &s.1; + &x; // keep variable in an alloca +} + +// Check that we correctly generate a GEP for a ZST that is not included in ScalarPair layout +// CHECK-LABEL: @scalarpair_layout +#[no_mangle] +pub fn scalarpair_layout(s: &(u64, u32, ())) { +// CHECK: [[X0:%[0-9]+]] = bitcast { i64, i32 }* %s to i8* +// CHECK-NEXT: [[X1:%[0-9]+]] = getelementptr i8, i8* [[X0]], [[USIZE]] 12 + let x = &s.2; + &x; // keep variable in an alloca +} From 24e0913e37cc6fc363b37d13bf519db212f175a2 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Thu, 20 Aug 2020 18:59:52 -0400 Subject: [PATCH 0049/1052] handle vector layout --- compiler/rustc_codegen_ssa/src/mir/place.rs | 20 ++++++++++++-------- src/test/codegen/zst-offset.rs | 14 ++++++++++++++ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 7c0eddea5229b..799f3b3a57570 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -96,7 +96,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { let llval = match self.layout.abi { _ if offset.bytes() == 0 => { // Unions and newtypes only use an offset of 0. - // Also handles the first field of Scalar and ScalarPair layouts. + // Also handles the first field of Scalar, ScalarPair, and Vector layouts. self.llval } Abi::ScalarPair(ref a, ref b) @@ -105,16 +105,20 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { // Offset matches second field. bx.struct_gep(self.llval, 1) } - Abi::ScalarPair(..) | Abi::Scalar(_) => { - // ZST fields are not included in Scalar and ScalarPair layouts, so manually offset the pointer. - assert!( - field.is_zst(), - "non-ZST field offset does not match layout: {:?}", - field - ); + Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } if field.is_zst() => { + // ZST fields are not included in Scalar, ScalarPair, and Vector layouts, so manually offset the pointer. let byte_ptr = bx.pointercast(self.llval, bx.cx().type_i8p()); bx.gep(byte_ptr, &[bx.const_usize(offset.bytes())]) } + Abi::Scalar(_) | Abi::ScalarPair(..) => { + // All fields of Scalar and ScalarPair layouts must have been handled by this point. + // Vector layouts have additional fields for each element of the vector, so don't panic in that case. + bug!( + "offset of non-ZST field `{:?}` does not match layout `{:#?}`", + field, + self.layout + ); + } _ => bx.struct_gep(self.llval, bx.cx().backend_field_index(self.layout, ix)), }; PlaceRef { diff --git a/src/test/codegen/zst-offset.rs b/src/test/codegen/zst-offset.rs index 3c63cddccad64..0c015fca3253a 100644 --- a/src/test/codegen/zst-offset.rs +++ b/src/test/codegen/zst-offset.rs @@ -1,6 +1,7 @@ // compile-flags: -C no-prepopulate-passes #![crate_type = "lib"] +#![feature(repr_simd)] // Hack to get the correct size for the length part in slices // CHECK: @helper([[USIZE:i[0-9]+]] %_1) @@ -27,3 +28,16 @@ pub fn scalarpair_layout(s: &(u64, u32, ())) { let x = &s.2; &x; // keep variable in an alloca } + +#[repr(simd)] +pub struct U64x4(u64, u64, u64, u64); + +// Check that we correctly generate a GEP for a ZST that is not included in Vector layout +// CHECK-LABEL: @vector_layout +#[no_mangle] +pub fn vector_layout(s: &(U64x4, ())) { +// CHECK: [[X0:%[0-9]+]] = bitcast <4 x i64>* %s to i8* +// CHECK-NEXT: [[X1:%[0-9]+]] = getelementptr i8, i8* [[X0]], [[USIZE]] 32 + let x = &s.1; + &x; // keep variable in an alloca +} From fdc48fb90c04b26b03ee7d8ae85e3175e5fc538c Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 30 Aug 2020 19:17:17 -0400 Subject: [PATCH 0050/1052] Fix clippy --- clippy_lints/src/utils/ast_utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/utils/ast_utils.rs b/clippy_lints/src/utils/ast_utils.rs index 7b419431c0f51..3c3f8b26e3ac1 100644 --- a/clippy_lints/src/utils/ast_utils.rs +++ b/clippy_lints/src/utils/ast_utils.rs @@ -191,7 +191,7 @@ pub fn eq_stmt(l: &Stmt, r: &Stmt) -> bool { (Item(l), Item(r)) => eq_item(l, r, eq_item_kind), (Expr(l), Expr(r)) | (Semi(l), Semi(r)) => eq_expr(l, r), (Empty, Empty) => true, - (MacCall(l), MacCall(r)) => l.1 == r.1 && eq_mac_call(&l.0, &r.0) && over(&l.2, &r.2, |l, r| eq_attr(l, r)), + (MacCall(l), MacCall(r)) => l.style == r.style && eq_mac_call(&l.mac, &r.mac) && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)), _ => false, } } From 518f1ccb728aa03665e51710c12973a74cc98df5 Mon Sep 17 00:00:00 2001 From: CDirkx Date: Mon, 31 Aug 2020 02:43:17 +0200 Subject: [PATCH 0051/1052] Stabilize some Result methods as const Stabilize the following methods of `Result` as const: - `is_ok` - `is_err` - `as_ref` Possible because of stabilization of #49146 (Allow if and match in constants). --- library/core/src/lib.rs | 1 - library/core/src/result.rs | 6 +++--- src/test/ui/consts/const-result.rs | 12 ++++++++++++ 3 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/consts/const-result.rs diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index aef82a5aec5d0..290540829e03c 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -87,7 +87,6 @@ #![feature(const_ptr_offset)] #![feature(const_ptr_offset_from)] #![feature(const_raw_ptr_comparison)] -#![feature(const_result)] #![feature(const_slice_from_raw_parts)] #![feature(const_slice_ptr_len)] #![feature(const_size_of_val)] diff --git a/library/core/src/result.rs b/library/core/src/result.rs index ce0fc628e1114..5cec183c237d7 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -273,7 +273,7 @@ impl Result { /// assert_eq!(x.is_ok(), false); /// ``` #[must_use = "if you intended to assert that this is ok, consider `.unwrap()` instead"] - #[rustc_const_unstable(feature = "const_result", issue = "67520")] + #[rustc_const_stable(feature = "const_result", since = "1.48.0")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub const fn is_ok(&self) -> bool { @@ -294,7 +294,7 @@ impl Result { /// assert_eq!(x.is_err(), true); /// ``` #[must_use = "if you intended to assert that this is err, consider `.unwrap_err()` instead"] - #[rustc_const_unstable(feature = "const_result", issue = "67520")] + #[rustc_const_stable(feature = "const_result", since = "1.48.0")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub const fn is_err(&self) -> bool { @@ -438,7 +438,7 @@ impl Result { /// assert_eq!(x.as_ref(), Err(&"Error")); /// ``` #[inline] - #[rustc_const_unstable(feature = "const_result", issue = "67520")] + #[rustc_const_stable(feature = "const_result", since = "1.48.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn as_ref(&self) -> Result<&T, &E> { match *self { diff --git a/src/test/ui/consts/const-result.rs b/src/test/ui/consts/const-result.rs new file mode 100644 index 0000000000000..e548d3e79ff80 --- /dev/null +++ b/src/test/ui/consts/const-result.rs @@ -0,0 +1,12 @@ +// run-pass + +fn main() { + const X: Result = Ok(32); + const Y: Result<&i32, &bool> = X.as_ref(); + + const IS_OK: bool = X.is_ok(); + assert!(IS_OK); + + const IS_ERR: bool = Y.is_err(); + assert!(!IS_ERR) +} From 3b4a346de72c3fa12b69dbcdc12116ba865ab50e Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 30 Aug 2020 22:23:53 -0400 Subject: [PATCH 0052/1052] Fix incorrect wording for `verbose-tests` This info was lost in https://github.com/rust-lang/rust/pull/74334. --- config.toml.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.toml.example b/config.toml.example index 9abb8add785a9..424ede9cd1b65 100644 --- a/config.toml.example +++ b/config.toml.example @@ -392,7 +392,7 @@ # desired in distributions, for example. #rpath = true -# Emits extra output from tests so test failures are debuggable just from logfiles. +# Emits extra output from the tests to debug issues in the test harness itself. #verbose-tests = false # Flag indicating whether tests are compiled with optimizations (the -O flag). From d983873cff7467e457bb5b3904ae7c238ffc2d38 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 30 Aug 2020 22:35:12 -0400 Subject: [PATCH 0053/1052] Document the defaults for `codegen-units` --- config.toml.example | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config.toml.example b/config.toml.example index 424ede9cd1b65..dd322c75932ca 100644 --- a/config.toml.example +++ b/config.toml.example @@ -309,6 +309,9 @@ # Number of codegen units to use for each compiler invocation. A value of 0 # means "the number of cores on this machine", and 1+ is passed through to the # compiler. +# +# Defaults: the Cargo defaults, 256 with incremental and 16 without +# https://doc.rust-lang.org/cargo/reference/profiles.html#codegen-units #codegen-units = 1 # Sets the number of codegen units to build the standard library with, From 41c13826f89665a4cf05c2e7ae470cb38fc699bc Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 30 Aug 2020 22:40:16 -0400 Subject: [PATCH 0054/1052] Mention why you'd want codegen-units = 0 (other than running out of RAM) --- config.toml.example | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config.toml.example b/config.toml.example index dd322c75932ca..2aba9445084de 100644 --- a/config.toml.example +++ b/config.toml.example @@ -306,6 +306,9 @@ # #debug = false +# This will make your build more parallel; it costs a bit of runtime +# performance perhaps (less inlining) but it's worth it. +# # Number of codegen units to use for each compiler invocation. A value of 0 # means "the number of cores on this machine", and 1+ is passed through to the # compiler. From 9f268de644df40c0ea9b323c475772d0ec2dc5b4 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 31 Aug 2020 00:37:50 -0400 Subject: [PATCH 0055/1052] Address review comments - Use prettier syntax for codegen-units defaults - Remove comment about parallelism that only made sense for specific values of codegen-units - Be more specific about what `verbose-tests` does --- config.toml.example | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/config.toml.example b/config.toml.example index 2aba9445084de..0956dd82ad93e 100644 --- a/config.toml.example +++ b/config.toml.example @@ -306,16 +306,12 @@ # #debug = false -# This will make your build more parallel; it costs a bit of runtime -# performance perhaps (less inlining) but it's worth it. -# # Number of codegen units to use for each compiler invocation. A value of 0 # means "the number of cores on this machine", and 1+ is passed through to the # compiler. # -# Defaults: the Cargo defaults, 256 with incremental and 16 without -# https://doc.rust-lang.org/cargo/reference/profiles.html#codegen-units -#codegen-units = 1 +# Uses the Cargo defaults: https://doc.rust-lang.org/cargo/reference/profiles.html#codegen-units +#codegen-units = if incremental { 256 } else { 16 } # Sets the number of codegen units to build the standard library with, # regardless of what the codegen-unit setting for the rest of the compiler is. @@ -398,7 +394,7 @@ # desired in distributions, for example. #rpath = true -# Emits extra output from the tests to debug issues in the test harness itself. +# Prints each test name as it is executed, to help debug issues in the test harness itself. #verbose-tests = false # Flag indicating whether tests are compiled with optimizations (the -O flag). From 451ef7880392f3f06088ff7a7b957e3485f4bc6c Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Mon, 31 Aug 2020 22:40:47 +0900 Subject: [PATCH 0056/1052] Use `match_def_path` instead of `match_qpath` --- clippy_lints/src/create_dir.rs | 5 +++-- tests/ui/create_dir.fixed | 6 ++++-- tests/ui/create_dir.rs | 6 ++++-- tests/ui/create_dir.stderr | 4 ++-- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs index 1042eb455246c..f80a0efa7a554 100644 --- a/clippy_lints/src/create_dir.rs +++ b/clippy_lints/src/create_dir.rs @@ -1,4 +1,4 @@ -use crate::utils::{match_qpath, paths, snippet, span_lint_and_sugg}; +use crate::utils::{match_def_path, paths, snippet, span_lint_and_sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; @@ -33,7 +33,8 @@ impl LateLintPass<'_> for CreateDir { if_chain! { if let ExprKind::Call(ref func, ref args) = expr.kind; if let ExprKind::Path(ref path) = func.kind; - if match_qpath(path, &paths::STD_FS_CREATE_DIR); + if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id(); + if match_def_path(cx, def_id, &paths::STD_FS_CREATE_DIR); then { span_lint_and_sugg( cx, diff --git a/tests/ui/create_dir.fixed b/tests/ui/create_dir.fixed index 50f31f0c9c540..0e28f87e33d4f 100644 --- a/tests/ui/create_dir.fixed +++ b/tests/ui/create_dir.fixed @@ -2,12 +2,14 @@ #![allow(unused_must_use)] #![warn(clippy::create_dir)] -fn not_create_dir() {} +fn create_dir() {} fn main() { + // Should be warned std::fs::create_dir_all("foo"); std::fs::create_dir_all("bar").unwrap(); - not_create_dir(); + // Shouldn't be warned + create_dir(); std::fs::create_dir_all("foobar"); } diff --git a/tests/ui/create_dir.rs b/tests/ui/create_dir.rs index 00ef37f413f77..1f226298c0d0d 100644 --- a/tests/ui/create_dir.rs +++ b/tests/ui/create_dir.rs @@ -2,12 +2,14 @@ #![allow(unused_must_use)] #![warn(clippy::create_dir)] -fn not_create_dir() {} +fn create_dir() {} fn main() { + // Should be warned std::fs::create_dir("foo"); std::fs::create_dir("bar").unwrap(); - not_create_dir(); + // Shouldn't be warned + create_dir(); std::fs::create_dir_all("foobar"); } diff --git a/tests/ui/create_dir.stderr b/tests/ui/create_dir.stderr index 3ae4680d9296e..0c97bdd0f7aba 100644 --- a/tests/ui/create_dir.stderr +++ b/tests/ui/create_dir.stderr @@ -1,5 +1,5 @@ error: calling `std::fs::create_dir` where there may be a better way - --> $DIR/create_dir.rs:8:5 + --> $DIR/create_dir.rs:9:5 | LL | std::fs::create_dir("foo"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `std::fs::create_dir_all` instead: `std::fs::create_dir_all("foo")` @@ -7,7 +7,7 @@ LL | std::fs::create_dir("foo"); = note: `-D clippy::create-dir` implied by `-D warnings` error: calling `std::fs::create_dir` where there may be a better way - --> $DIR/create_dir.rs:9:5 + --> $DIR/create_dir.rs:10:5 | LL | std::fs::create_dir("bar").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `std::fs::create_dir_all` instead: `std::fs::create_dir_all("bar")` From 1bc0627607262cc60a7692b16e205f30fc88b89f Mon Sep 17 00:00:00 2001 From: Federico Ponzi Date: Mon, 31 Aug 2020 15:48:28 +0200 Subject: [PATCH 0057/1052] Add as_flag function to the OpenOptionsExt struct --- library/std/src/sys/unix/ext/fs.rs | 30 ++++++++++++++++++++++++++++++ library/std/src/sys/unix/fs.rs | 12 +++++------- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/library/std/src/sys/unix/ext/fs.rs b/library/std/src/sys/unix/ext/fs.rs index b590a0280d138..0a00c64e6c545 100644 --- a/library/std/src/sys/unix/ext/fs.rs +++ b/library/std/src/sys/unix/ext/fs.rs @@ -345,6 +345,33 @@ pub trait OpenOptionsExt { /// ``` #[stable(feature = "open_options_ext", since = "1.10.0")] fn custom_flags(&mut self, flags: i32) -> &mut Self; + + /// Get the flags of this OpenOptions as libc::c_int. + /// + /// This method allows the reuse of the OpenOptions as flags argument for `libc::open()`. + /// + /// # Examples + /// + /// ```no_run + /// # #![feature(rustc_private)] + /// extern crate libc; + /// use std::ffi::CString; + /// use std::fs::OpenOptions; + /// use std::os::unix::fs::OpenOptionsExt; + /// + /// # fn main() { + /// let mut options = OpenOptions::new(); + /// options.write(true).read(true); + /// if cfg!(unix) { + /// options.custom_flags(libc::O_NOFOLLOW); + /// } + /// let file_name = CString::new("foo.txt").unwrap(); + /// let file = unsafe{ libc::open(file_name.as_c_str().as_ptr(), options.as_flags().unwrap()) }; + /// + /// # } + /// ``` + #[stable(feature = "open_options_ext_as_flags", since = "1.47.0")] + fn as_flags(&self) -> io::Result; } #[stable(feature = "fs_ext", since = "1.1.0")] @@ -358,6 +385,9 @@ impl OpenOptionsExt for OpenOptions { self.as_inner_mut().custom_flags(flags); self } + fn as_flags(&self) -> io::Result { + self.as_inner().as_flags() + } } /// Unix-specific extensions to [`fs::Metadata`]. diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 59dfd9f9dc424..f4d3ad2d2a484 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -655,7 +655,11 @@ impl OpenOptions { pub fn mode(&mut self, mode: u32) { self.mode = mode as mode_t; } - + pub fn as_flags(&self) -> io::Result { + let access_mode = self.get_access_mode()?; + let creation_mode = self.get_creation_mode()?; + Ok(creation_mode | access_mode | self.custom_flags) + } fn get_access_mode(&self) -> io::Result { match (self.read, self.write, self.append) { (true, false, false) => Ok(libc::O_RDONLY), @@ -692,7 +696,6 @@ impl OpenOptions { } } - impl File { pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { let path = cstr(path)?; @@ -963,11 +966,6 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> { Ok(()) } -pub fn get_openopetions_as_cint(from: OpenOptions) -> io::Result { - let access_mode = from.get_access_mode()?; - let creation_mode = from.get_creation_mode()?; - Ok(creation_mode | access_mode) -} pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { let p = cstr(p)?; From 001f9e45f24c5617d816e7d9dfbca4dc1a694dd9 Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Tue, 1 Sep 2020 00:05:53 +0900 Subject: [PATCH 0058/1052] Fix the wrong suggestion when using macro in `collapsible_if` --- clippy_lints/src/utils/sugg.rs | 6 +++++- tests/ui/collapsible_if.fixed | 3 +++ tests/ui/collapsible_if.rs | 5 +++++ tests/ui/collapsible_if.stderr | 10 +++++++++- 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 2955f8d8e5919..811fde388d15a 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -132,7 +132,11 @@ impl<'a> Sugg<'a> { pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self { use rustc_ast::ast::RangeLimits; - let snippet = snippet(cx, expr.span, default); + let snippet = if expr.span.from_expansion() { + snippet_with_macro_callsite(cx, expr.span, default) + } else { + snippet(cx, expr.span, default) + }; match expr.kind { ast::ExprKind::AddrOf(..) diff --git a/tests/ui/collapsible_if.fixed b/tests/ui/collapsible_if.fixed index 561283fc8e73d..efd4187947b20 100644 --- a/tests/ui/collapsible_if.fixed +++ b/tests/ui/collapsible_if.fixed @@ -135,4 +135,7 @@ fn main() { if truth() {} } } + + // Fix #5962 + if matches!(true, true) && matches!(true, true) {} } diff --git a/tests/ui/collapsible_if.rs b/tests/ui/collapsible_if.rs index dc9d9b451c0f9..657f32d38a32b 100644 --- a/tests/ui/collapsible_if.rs +++ b/tests/ui/collapsible_if.rs @@ -149,4 +149,9 @@ fn main() { if truth() {} } } + + // Fix #5962 + if matches!(true, true) { + if matches!(true, true) {} + } } diff --git a/tests/ui/collapsible_if.stderr b/tests/ui/collapsible_if.stderr index f56dd65b9dd26..acd1ec3f2caea 100644 --- a/tests/ui/collapsible_if.stderr +++ b/tests/ui/collapsible_if.stderr @@ -118,5 +118,13 @@ LL | println!("Hello world!"); LL | } | -error: aborting due to 7 previous errors +error: this `if` statement can be collapsed + --> $DIR/collapsible_if.rs:154:5 + | +LL | / if matches!(true, true) { +LL | | if matches!(true, true) {} +LL | | } + | |_____^ help: collapse nested if block: `if matches!(true, true) && matches!(true, true) {}` + +error: aborting due to 8 previous errors From 8b0aa6a00b19b8e47a72157ec8e8f9e9060cb2fb Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Tue, 1 Sep 2020 00:31:53 +0900 Subject: [PATCH 0059/1052] default_trait_access: Fix wrong suggestion --- clippy_lints/src/default_trait_access.rs | 4 +- tests/ui/default_trait_access.fixed | 106 +++++++++++++++++++++++ tests/ui/default_trait_access.rs | 5 +- tests/ui/default_trait_access.stderr | 26 +++--- 4 files changed, 127 insertions(+), 14 deletions(-) create mode 100644 tests/ui/default_trait_access.fixed diff --git a/clippy_lints/src/default_trait_access.rs b/clippy_lints/src/default_trait_access.rs index 067ea903bdd96..0b0a13078768b 100644 --- a/clippy_lints/src/default_trait_access.rs +++ b/clippy_lints/src/default_trait_access.rs @@ -55,8 +55,8 @@ impl<'tcx> LateLintPass<'tcx> for DefaultTraitAccess { // TODO: Work out a way to put "whatever the imported way of referencing // this type in this file" rather than a fully-qualified type. let expr_ty = cx.typeck_results().expr_ty(expr); - if let ty::Adt(..) = expr_ty.kind { - let replacement = format!("{}::default()", expr_ty); + if let ty::Adt(def, ..) = expr_ty.kind { + let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did)); span_lint_and_sugg( cx, DEFAULT_TRAIT_ACCESS, diff --git a/tests/ui/default_trait_access.fixed b/tests/ui/default_trait_access.fixed new file mode 100644 index 0000000000000..d05567a3f8249 --- /dev/null +++ b/tests/ui/default_trait_access.fixed @@ -0,0 +1,106 @@ +// run-rustfix + +#![allow(unused_imports)] +#![deny(clippy::default_trait_access)] + +use std::default; +use std::default::Default as D2; +use std::string; + +fn main() { + let s1: String = std::string::String::default(); + + let s2 = String::default(); + + let s3: String = std::string::String::default(); + + let s4: String = std::string::String::default(); + + let s5 = string::String::default(); + + let s6: String = std::string::String::default(); + + let s7 = std::string::String::default(); + + let s8: String = DefaultFactory::make_t_badly(); + + let s9: String = DefaultFactory::make_t_nicely(); + + let s10 = DerivedDefault::default(); + + let s11: GenericDerivedDefault = GenericDerivedDefault::default(); + + let s12 = GenericDerivedDefault::::default(); + + let s13 = TupleDerivedDefault::default(); + + let s14: TupleDerivedDefault = TupleDerivedDefault::default(); + + let s15: ArrayDerivedDefault = ArrayDerivedDefault::default(); + + let s16 = ArrayDerivedDefault::default(); + + let s17: TupleStructDerivedDefault = TupleStructDerivedDefault::default(); + + let s18 = TupleStructDerivedDefault::default(); + + let s19 = ::default(); + + println!( + "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}], [{:?}]", + s1, + s2, + s3, + s4, + s5, + s6, + s7, + s8, + s9, + s10, + s11, + s12, + s13, + s14, + s15, + s16, + s17, + s18, + s19, + ); +} + +struct DefaultFactory; + +impl DefaultFactory { + pub fn make_t_badly() -> T { + Default::default() + } + + pub fn make_t_nicely() -> T { + T::default() + } +} + +#[derive(Debug, Default)] +struct DerivedDefault { + pub s: String, +} + +#[derive(Debug, Default)] +struct GenericDerivedDefault { + pub s: T, +} + +#[derive(Debug, Default)] +struct TupleDerivedDefault { + pub s: (String, String), +} + +#[derive(Debug, Default)] +struct ArrayDerivedDefault { + pub s: [String; 10], +} + +#[derive(Debug, Default)] +struct TupleStructDerivedDefault(String); diff --git a/tests/ui/default_trait_access.rs b/tests/ui/default_trait_access.rs index 2f1490a70369e..447e70c0bbbea 100644 --- a/tests/ui/default_trait_access.rs +++ b/tests/ui/default_trait_access.rs @@ -1,4 +1,7 @@ -#![warn(clippy::default_trait_access)] +// run-rustfix + +#![allow(unused_imports)] +#![deny(clippy::default_trait_access)] use std::default; use std::default::Default as D2; diff --git a/tests/ui/default_trait_access.stderr b/tests/ui/default_trait_access.stderr index 26b2057548bd9..df8a5b94ddcf3 100644 --- a/tests/ui/default_trait_access.stderr +++ b/tests/ui/default_trait_access.stderr @@ -1,49 +1,53 @@ error: calling `std::string::String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:8:22 + --> $DIR/default_trait_access.rs:11:22 | LL | let s1: String = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` | - = note: `-D clippy::default-trait-access` implied by `-D warnings` +note: the lint level is defined here + --> $DIR/default_trait_access.rs:4:9 + | +LL | #![deny(clippy::default_trait_access)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: calling `std::string::String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:12:22 + --> $DIR/default_trait_access.rs:15:22 | LL | let s3: String = D2::default(); | ^^^^^^^^^^^^^ help: try: `std::string::String::default()` error: calling `std::string::String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:14:22 + --> $DIR/default_trait_access.rs:17:22 | LL | let s4: String = std::default::Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` error: calling `std::string::String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:18:22 + --> $DIR/default_trait_access.rs:21:22 | LL | let s6: String = default::Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` -error: calling `GenericDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:28:46 +error: calling `GenericDerivedDefault::default()` is more clear than this expression + --> $DIR/default_trait_access.rs:31:46 | LL | let s11: GenericDerivedDefault = Default::default(); - | ^^^^^^^^^^^^^^^^^^ help: try: `GenericDerivedDefault::default()` + | ^^^^^^^^^^^^^^^^^^ help: try: `GenericDerivedDefault::default()` error: calling `TupleDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:34:36 + --> $DIR/default_trait_access.rs:37:36 | LL | let s14: TupleDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `TupleDerivedDefault::default()` error: calling `ArrayDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:36:36 + --> $DIR/default_trait_access.rs:39:36 | LL | let s15: ArrayDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `ArrayDerivedDefault::default()` error: calling `TupleStructDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:40:42 + --> $DIR/default_trait_access.rs:43:42 | LL | let s17: TupleStructDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `TupleStructDerivedDefault::default()` From f9fcbbea03edb735c22311522b55d7b854bd6ac0 Mon Sep 17 00:00:00 2001 From: Vali Schneider Date: Mon, 31 Aug 2020 13:32:05 -0700 Subject: [PATCH 0060/1052] fixed bug --- clippy_lints/src/panic_in_result.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/panic_in_result.rs b/clippy_lints/src/panic_in_result.rs index 8ba365cb00c36..8b8e211cb723a 100644 --- a/clippy_lints/src/panic_in_result.rs +++ b/clippy_lints/src/panic_in_result.rs @@ -34,12 +34,15 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResult { fn check_fn( &mut self, cx: &LateContext<'tcx>, - _: FnKind<'tcx>, + fn_kind: FnKind<'tcx>, _: &'tcx hir::FnDecl<'tcx>, body: &'tcx hir::Body<'tcx>, span: Span, hir_id: hir::HirId, ) { + if let FnKind::Closure(_) = fn_kind { + return; + } if_chain! { if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)); then From 7c1e5c1dcd25c945f619eda289f639dbe2b002da Mon Sep 17 00:00:00 2001 From: Federico Ponzi Date: Mon, 31 Aug 2020 21:42:57 +0200 Subject: [PATCH 0061/1052] Update OpenOptions::as_flags docs, and minor styling --- library/std/src/sys/unix/ext/fs.rs | 17 ++++++++--------- library/std/src/sys/unix/fs.rs | 1 + 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/library/std/src/sys/unix/ext/fs.rs b/library/std/src/sys/unix/ext/fs.rs index 0a00c64e6c545..afda21d00e050 100644 --- a/library/std/src/sys/unix/ext/fs.rs +++ b/library/std/src/sys/unix/ext/fs.rs @@ -346,9 +346,13 @@ pub trait OpenOptionsExt { #[stable(feature = "open_options_ext", since = "1.10.0")] fn custom_flags(&mut self, flags: i32) -> &mut Self; - /// Get the flags of this OpenOptions as libc::c_int. + /// Get the flags of this OpenOptions as [`libc::c_int`]. + /// With: [`libc::open`] /// - /// This method allows the reuse of the OpenOptions as flags argument for `libc::open()`. + /// This method allows the reuse of the OpenOptions as flags argument for [`fs::OpenOptions`]. + /// + /// [`libc::c_int`]: https://docs.rs/libc/*/libc/type.c_int.html + /// [`libc::open`]: https://docs.rs/libc/*/libc/fn.open.html /// /// # Examples /// @@ -359,16 +363,10 @@ pub trait OpenOptionsExt { /// use std::fs::OpenOptions; /// use std::os::unix::fs::OpenOptionsExt; /// - /// # fn main() { /// let mut options = OpenOptions::new(); /// options.write(true).read(true); - /// if cfg!(unix) { - /// options.custom_flags(libc::O_NOFOLLOW); - /// } /// let file_name = CString::new("foo.txt").unwrap(); - /// let file = unsafe{ libc::open(file_name.as_c_str().as_ptr(), options.as_flags().unwrap()) }; - /// - /// # } + /// let file = unsafe { libc::open(file_name.as_c_str().as_ptr(), options.as_flags().unwrap()) }; /// ``` #[stable(feature = "open_options_ext_as_flags", since = "1.47.0")] fn as_flags(&self) -> io::Result; @@ -385,6 +383,7 @@ impl OpenOptionsExt for OpenOptions { self.as_inner_mut().custom_flags(flags); self } + fn as_flags(&self) -> io::Result { self.as_inner().as_flags() } diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 13d8d59b03457..1281fcc47bcb3 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -660,6 +660,7 @@ impl OpenOptions { let creation_mode = self.get_creation_mode()?; Ok(creation_mode | access_mode | self.custom_flags) } + fn get_access_mode(&self) -> io::Result { match (self.read, self.write, self.append) { (true, false, false) => Ok(libc::O_RDONLY), From afeb917fca7eaa5b44acd29a60f687024c0ebeac Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Tue, 1 Sep 2020 11:21:48 +1200 Subject: [PATCH 0062/1052] Fix a fp in `transmute_ptr_to_ptr` Avoid firing the lint when `transmute` in const contexts as dereferencing raw pointers in consts is unstable. cc #5959 --- clippy_lints/src/transmute.rs | 6 ++++-- tests/ui/transmute_ptr_to_ptr.rs | 8 ++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index 50d9c93f9d405..789d124eae273 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -331,8 +331,9 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::TRANSMUTE); then { - // Avoid suggesting from/to bits in const contexts. + // Avoid suggesting from/to bits and dereferencing raw pointers in const contexts. // See https://github.com/rust-lang/rust/issues/73736 for progress on making them `const fn`. + // And see https://github.com/rust-lang/rust/issues/51911 for dereferencing raw pointers. let const_context = in_constant(cx, e.hir_id); let from_ty = cx.typeck_results().expr_ty(&args[0]); @@ -486,7 +487,8 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { Applicability::Unspecified, ); } else { - if cx.tcx.erase_regions(&from_ty) != cx.tcx.erase_regions(&to_ty) { + if (cx.tcx.erase_regions(&from_ty) != cx.tcx.erase_regions(&to_ty)) + && !const_context { span_lint_and_then( cx, TRANSMUTE_PTR_TO_PTR, diff --git a/tests/ui/transmute_ptr_to_ptr.rs b/tests/ui/transmute_ptr_to_ptr.rs index 0d8a322f2b2b0..26b03bdc74055 100644 --- a/tests/ui/transmute_ptr_to_ptr.rs +++ b/tests/ui/transmute_ptr_to_ptr.rs @@ -51,4 +51,12 @@ fn transmute_ptr_to_ptr() { let _: &GenericParam<&LifetimeParam<'static>> = unsafe { std::mem::transmute(&GenericParam { t: &lp }) }; } +// dereferencing raw pointers in const contexts, should not lint as it's unstable (issue 5959) +const _: &() = { + struct ZST; + let zst = &ZST; + + unsafe { std::mem::transmute::<&'static ZST, &'static ()>(zst) } +}; + fn main() {} From 2e4b4cebbbb37efa5dc69dd2616f3b7a288b92aa Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Tue, 1 Sep 2020 12:09:32 +0900 Subject: [PATCH 0063/1052] useless_attribute: Permit wildcard_imports and enum_glob_use --- clippy_lints/src/attrs.rs | 38 ++++++++++++++++++------------- tests/ui/useless_attribute.fixed | 8 +++++++ tests/ui/useless_attribute.rs | 8 +++++++ tests/ui/useless_attribute.stderr | 2 +- 4 files changed, 39 insertions(+), 17 deletions(-) diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index cfcc1b3c5f356..c8f153e7201cb 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -71,8 +71,9 @@ declare_clippy_lint! { /// **What it does:** Checks for `extern crate` and `use` items annotated with /// lint attributes. /// - /// This lint permits `#[allow(unused_imports)]`, `#[allow(deprecated)]` and - /// `#[allow(unreachable_pub)]` on `use` items and `#[allow(unused_imports)]` on + /// This lint permits `#[allow(unused_imports)]`, `#[allow(deprecated)]`, + /// `#[allow(unreachable_pub)]`, `#[allow(clippy::wildcard_imports)]` and + /// `#[allow(clippy::enum_glob_use)]` on `use` items and `#[allow(unused_imports)]` on /// `extern crate` items with a `#[macro_use]` attribute. /// /// **Why is this bad?** Lint attributes have no effect on crate imports. Most @@ -318,7 +319,8 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { if let Some(ident) = attr.ident() { match &*ident.as_str() { "allow" | "warn" | "deny" | "forbid" => { - // permit `unused_imports`, `deprecated` and `unreachable_pub` for `use` items + // permit `unused_imports`, `deprecated`, `unreachable_pub`, + // `clippy::wildcard_imports`, and `clippy::enum_glob_use` for `use` items // and `unused_imports` for `extern crate` items with `macro_use` for lint in lint_list { match item.kind { @@ -327,6 +329,9 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { || is_word(lint, sym!(deprecated)) || is_word(lint, sym!(unreachable_pub)) || is_word(lint, sym!(unused)) + || extract_clippy_lint(lint) + .map_or(false, |s| s == "wildcard_imports") + || extract_clippy_lint(lint).map_or(false, |s| s == "enum_glob_use") { return; } @@ -387,24 +392,25 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { } } -fn check_clippy_lint_names(cx: &LateContext<'_>, ident: &str, items: &[NestedMetaItem]) { - fn extract_name(lint: &NestedMetaItem) -> Option { - if_chain! { - if let Some(meta_item) = lint.meta_item(); - if meta_item.path.segments.len() > 1; - if let tool_name = meta_item.path.segments[0].ident; - if tool_name.as_str() == "clippy"; - let lint_name = meta_item.path.segments.last().unwrap().ident.name; - then { - return Some(lint_name.as_str()); - } +/// Returns the lint name if it is clippy lint. +fn extract_clippy_lint(lint: &NestedMetaItem) -> Option { + if_chain! { + if let Some(meta_item) = lint.meta_item(); + if meta_item.path.segments.len() > 1; + if let tool_name = meta_item.path.segments[0].ident; + if tool_name.as_str() == "clippy"; + let lint_name = meta_item.path.segments.last().unwrap().ident.name; + then { + return Some(lint_name.as_str()); } - None } + None +} +fn check_clippy_lint_names(cx: &LateContext<'_>, ident: &str, items: &[NestedMetaItem]) { let lint_store = cx.lints(); for lint in items { - if let Some(lint_name) = extract_name(lint) { + if let Some(lint_name) = extract_clippy_lint(lint) { if let CheckLintNameResult::Tool(Err((None, _))) = lint_store.check_lint_name(&lint_name, Some(sym!(clippy))) { diff --git a/tests/ui/useless_attribute.fixed b/tests/ui/useless_attribute.fixed index b222e2f7976d5..a5fcde768f183 100644 --- a/tests/ui/useless_attribute.fixed +++ b/tests/ui/useless_attribute.fixed @@ -49,6 +49,14 @@ mod a { pub use self::b::C; } +// don't lint on clippy::wildcard_imports for `use` items +#[allow(clippy::wildcard_imports)] +pub use std::io::prelude::*; + +// don't lint on clippy::enum_glob_use for `use` items +#[allow(clippy::enum_glob_use)] +pub use std::cmp::Ordering::*; + fn test_indented_attr() { #![allow(clippy::almost_swapped)] use std::collections::HashSet; diff --git a/tests/ui/useless_attribute.rs b/tests/ui/useless_attribute.rs index 3422eace4ab97..0396d39e3d54e 100644 --- a/tests/ui/useless_attribute.rs +++ b/tests/ui/useless_attribute.rs @@ -49,6 +49,14 @@ mod a { pub use self::b::C; } +// don't lint on clippy::wildcard_imports for `use` items +#[allow(clippy::wildcard_imports)] +pub use std::io::prelude::*; + +// don't lint on clippy::enum_glob_use for `use` items +#[allow(clippy::enum_glob_use)] +pub use std::cmp::Ordering::*; + fn test_indented_attr() { #[allow(clippy::almost_swapped)] use std::collections::HashSet; diff --git a/tests/ui/useless_attribute.stderr b/tests/ui/useless_attribute.stderr index 57ba976730c17..d0194e4bbbe5b 100644 --- a/tests/ui/useless_attribute.stderr +++ b/tests/ui/useless_attribute.stderr @@ -13,7 +13,7 @@ LL | #[cfg_attr(feature = "cargo-clippy", allow(dead_code))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![cfg_attr(feature = "cargo-clippy", allow(dead_code)` error: useless lint attribute - --> $DIR/useless_attribute.rs:53:5 + --> $DIR/useless_attribute.rs:61:5 | LL | #[allow(clippy::almost_swapped)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![allow(clippy::almost_swapped)]` From b30422114e6bb7235398f21fe13ffa09429b7d0f Mon Sep 17 00:00:00 2001 From: Koxiaet <38139193+Koxiaet@users.noreply.github.com> Date: Tue, 1 Sep 2020 14:05:19 +0100 Subject: [PATCH 0064/1052] Allow GraphQL in doc without backticks --- clippy_lints/src/utils/conf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 292dbd7ad6b48..9c5a12ea9c8e1 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -122,7 +122,7 @@ define_Conf! { "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "NaN", "NaNs", - "OAuth", + "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "TensorFlow", From aa7ffa5257667edb284de16b529df3d4111d70ab Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Tue, 1 Sep 2020 22:39:09 +0900 Subject: [PATCH 0065/1052] Fix FP in `same_item_push` Don't emit a lint when the pushed item doesn't have Clone trait --- clippy_lints/src/loops.rs | 78 +++++++++++++++++++++----------------- tests/ui/same_item_push.rs | 6 +++ 2 files changed, 49 insertions(+), 35 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index c95e43a943044..25345f8fa316c 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1140,43 +1140,51 @@ fn detect_same_item_push<'tcx>( walk_expr(&mut same_item_push_visitor, body); if same_item_push_visitor.should_lint { if let Some((vec, pushed_item)) = same_item_push_visitor.vec_push { - // Make sure that the push does not involve possibly mutating values - if let PatKind::Wild = pat.kind { - let vec_str = snippet_with_macro_callsite(cx, vec.span, ""); - let item_str = snippet_with_macro_callsite(cx, pushed_item.span, ""); - if let ExprKind::Path(ref qpath) = pushed_item.kind { - if_chain! { - if let Res::Local(hir_id) = qpath_res(cx, qpath, pushed_item.hir_id); - let node = cx.tcx.hir().get(hir_id); - if let Node::Binding(pat) = node; - if let PatKind::Binding(bind_ann, ..) = pat.kind; - if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable); - then { - span_lint_and_help( - cx, - SAME_ITEM_PUSH, - vec.span, - "it looks like the same item is being pushed into this Vec", - None, - &format!( - "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", - item_str, vec_str, item_str - ), - ) + let ty = cx.typeck_results().expr_ty(pushed_item); + if cx + .tcx + .lang_items() + .clone_trait() + .map_or(false, |id| implements_trait(cx, ty, id, &[])) + { + // Make sure that the push does not involve possibly mutating values + if let PatKind::Wild = pat.kind { + let vec_str = snippet_with_macro_callsite(cx, vec.span, ""); + let item_str = snippet_with_macro_callsite(cx, pushed_item.span, ""); + if let ExprKind::Path(ref qpath) = pushed_item.kind { + if_chain! { + if let Res::Local(hir_id) = qpath_res(cx, qpath, pushed_item.hir_id); + let node = cx.tcx.hir().get(hir_id); + if let Node::Binding(pat) = node; + if let PatKind::Binding(bind_ann, ..) = pat.kind; + if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable); + then { + span_lint_and_help( + cx, + SAME_ITEM_PUSH, + vec.span, + "it looks like the same item is being pushed into this Vec", + None, + &format!( + "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", + item_str, vec_str, item_str + ), + ) + } } + } else if mutated_variables(pushed_item, cx).map_or(false, |mutvars| mutvars.is_empty()) { + span_lint_and_help( + cx, + SAME_ITEM_PUSH, + vec.span, + "it looks like the same item is being pushed into this Vec", + None, + &format!( + "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", + item_str, vec_str, item_str + ), + ) } - } else if mutated_variables(pushed_item, cx).map_or(false, |mutvars| mutvars.is_empty()) { - span_lint_and_help( - cx, - SAME_ITEM_PUSH, - vec.span, - "it looks like the same item is being pushed into this Vec", - None, - &format!( - "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", - item_str, vec_str, item_str - ), - ) } } } diff --git a/tests/ui/same_item_push.rs b/tests/ui/same_item_push.rs index bfe27e020445c..0903a87382651 100644 --- a/tests/ui/same_item_push.rs +++ b/tests/ui/same_item_push.rs @@ -94,4 +94,10 @@ fn main() { vec13.push(item); item += 10; } + + // Fix #5979 + let mut vec14: Vec = Vec::new(); + for _ in 0..10 { + vec14.push(std::fs::File::open("foobar").unwrap()); + } } From ea5dc0909ea1ed4135f1bdecbaa3423051be578d Mon Sep 17 00:00:00 2001 From: CDirkx Date: Tue, 1 Sep 2020 15:44:00 +0200 Subject: [PATCH 0066/1052] Make some Ordering methods const Constify the following methods of `core::cmp::Ordering`: - `reverse` - `then` Stabilizes these methods as const under the `const_ordering` feature. Also adds a test for these methods in a const context. Possible because of #49146 (Allow `if` and `match` in constants). --- library/core/src/cmp.rs | 6 ++++-- src/test/ui/consts/const-ordering.rs | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/consts/const-ordering.rs diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 3953c73319fe4..dde442aa7b52d 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -356,8 +356,9 @@ impl Ordering { /// ``` #[inline] #[must_use] + #[rustc_const_stable(feature = "const_ordering", since = "1.48.0")] #[stable(feature = "rust1", since = "1.0.0")] - pub fn reverse(self) -> Ordering { + pub const fn reverse(self) -> Ordering { match self { Less => Greater, Equal => Equal, @@ -394,8 +395,9 @@ impl Ordering { /// ``` #[inline] #[must_use] + #[rustc_const_stable(feature = "const_ordering", since = "1.48.0")] #[stable(feature = "ordering_chaining", since = "1.17.0")] - pub fn then(self, other: Ordering) -> Ordering { + pub const fn then(self, other: Ordering) -> Ordering { match self { Equal => other, _ => self, diff --git a/src/test/ui/consts/const-ordering.rs b/src/test/ui/consts/const-ordering.rs new file mode 100644 index 0000000000000..454f2da00df9e --- /dev/null +++ b/src/test/ui/consts/const-ordering.rs @@ -0,0 +1,15 @@ +// run-pass + +use std::cmp::Ordering; + +// the following methods of core::cmp::Ordering are const: +// - reverse +// - then + +fn main() { + const REVERSE : Ordering = Ordering::Greater.reverse(); + assert_eq!(REVERSE, Ordering::Less); + + const THEN : Ordering = Ordering::Equal.then(REVERSE); + assert_eq!(THEN, Ordering::Less); +} From ba664c258dd2f5516e987091a31acaa537312cf6 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 1 Sep 2020 13:37:40 -0400 Subject: [PATCH 0067/1052] Codegen defaults come from rustc, not cargo --- config.toml.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.toml.example b/config.toml.example index 0956dd82ad93e..be23efae5294b 100644 --- a/config.toml.example +++ b/config.toml.example @@ -310,7 +310,7 @@ # means "the number of cores on this machine", and 1+ is passed through to the # compiler. # -# Uses the Cargo defaults: https://doc.rust-lang.org/cargo/reference/profiles.html#codegen-units +# Uses the rustc defaults: https://doc.rust-lang.org/rustc/codegen-options/index.html#codegen-units #codegen-units = if incremental { 256 } else { 16 } # Sets the number of codegen units to build the standard library with, From 7ec1de062a1aadef0293bb65e71fbcc7cc24ebfd Mon Sep 17 00:00:00 2001 From: Kornel Date: Thu, 27 Aug 2020 13:27:14 +0100 Subject: [PATCH 0068/1052] Clarify message about unresolved use --- .../rustc_error_codes/src/error_codes/E0433.md | 16 +++++++++++++--- compiler/rustc_resolve/src/lib.rs | 9 ++++++++- .../ui/attributes/register-attr-tool-prelude.rs | 2 +- .../attributes/register-attr-tool-prelude.stderr | 4 ++-- src/test/ui/bad/bad-module.rs | 4 ++-- src/test/ui/bad/bad-module.stderr | 8 ++++---- .../coherence/conflicting-impl-with-err.stderr | 8 ++++---- src/test/ui/derived-errors/issue-31997-1.stderr | 2 +- src/test/ui/dyn-trait-compatibility.rs | 4 ++-- src/test/ui/dyn-trait-compatibility.stderr | 8 ++++---- src/test/ui/error-codes/E0433.stderr | 4 ++-- src/test/ui/export-fully-qualified.rs | 4 +++- src/test/ui/export-fully-qualified.stderr | 6 +++--- src/test/ui/export2.rs | 2 +- src/test/ui/export2.stderr | 4 ++-- src/test/ui/extern-flag/multiple-opts.stderr | 4 ++-- src/test/ui/extern-flag/noprelude.stderr | 4 ++-- .../hygiene/extern-prelude-from-opaque-fail.rs | 4 ++-- .../extern-prelude-from-opaque-fail.stderr | 8 ++++---- src/test/ui/hygiene/no_implicit_prelude.stderr | 2 +- src/test/ui/impl-trait/issue-72911.stderr | 8 ++++---- .../imports/extern-prelude-extern-crate-fail.rs | 4 +++- .../extern-prelude-extern-crate-fail.stderr | 8 ++++---- src/test/ui/issues/issue-33293.rs | 2 +- src/test/ui/issues/issue-33293.stderr | 4 ++-- .../ui/macros/builtin-prelude-no-accidents.rs | 6 +++--- .../macros/builtin-prelude-no-accidents.stderr | 12 ++++++------ src/test/ui/macros/macro-inner-attributes.rs | 2 +- src/test/ui/macros/macro-inner-attributes.stderr | 4 ++-- .../ui/macros/macro_path_as_generic_bound.stderr | 4 ++-- src/test/ui/mod/mod_file_disambig.rs | 2 +- src/test/ui/mod/mod_file_disambig.stderr | 4 ++-- src/test/ui/parser/mod_file_not_exist.rs | 2 +- src/test/ui/parser/mod_file_not_exist.stderr | 4 ++-- src/test/ui/parser/mod_file_not_exist_windows.rs | 2 +- .../ui/parser/mod_file_not_exist_windows.stderr | 4 ++-- src/test/ui/pattern/pattern-error-continue.rs | 2 +- .../ui/pattern/pattern-error-continue.stderr | 4 ++-- src/test/ui/resolve/use_suggestion.stderr | 6 +++--- .../non-existent-1.stderr | 2 +- .../type-ascription-instead-of-path.rs | 2 +- .../type-ascription-instead-of-path.stderr | 4 ++-- .../ui/type-alias/issue-62263-self-in-atb.rs | 2 +- .../ui/type-alias/issue-62263-self-in-atb.stderr | 4 ++-- .../ui/type-alias/issue-62305-self-assoc-ty.rs | 2 +- .../type-alias/issue-62305-self-assoc-ty.stderr | 4 ++-- src/test/ui/type/type-path-err-node-types.rs | 2 +- src/test/ui/type/type-path-err-node-types.stderr | 4 ++-- src/test/ui/unknown-tool-name.rs | 2 +- src/test/ui/unknown-tool-name.stderr | 4 ++-- src/test/ui/use/use-self-type.rs | 2 +- src/test/ui/use/use-self-type.stderr | 6 +++--- 52 files changed, 126 insertions(+), 105 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0433.md b/compiler/rustc_error_codes/src/error_codes/E0433.md index f9e333e8ccd00..5a64c13c9af51 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0433.md +++ b/compiler/rustc_error_codes/src/error_codes/E0433.md @@ -1,17 +1,27 @@ -An undeclared type or module was used. +An undeclared crate, module, or type was used. Erroneous code example: ```compile_fail,E0433 let map = HashMap::new(); -// error: failed to resolve: use of undeclared type or module `HashMap` +// error: failed to resolve: use of undeclared type `HashMap` ``` Please verify you didn't misspell the type/module's name or that you didn't forget to import it: - ``` use std::collections::HashMap; // HashMap has been imported. let map: HashMap = HashMap::new(); // So it can be used! ``` + +If you've expected to use a crate name: + +```compile_fail +use ferris_wheel::BigO; +// error: failed to resolve: use of undeclared crate or module `ferris_wheel` +``` + +Make sure the crate has been added as a dependency in `Cargo.toml`. + +To use a module from your current crate, add the `crate::` prefix to the path. diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 5892edf7652b7..4c06249f779c0 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -2407,7 +2407,14 @@ impl<'a> Resolver<'a> { (format!("maybe a missing crate `{}`?", ident), None) } } else if i == 0 { - (format!("use of undeclared type or module `{}`", ident), None) + if ident + .name + .with(|n| n.chars().next().map_or(false, |c| c.is_ascii_uppercase())) + { + (format!("use of undeclared type `{}`", ident), None) + } else { + (format!("use of undeclared crate or module `{}`", ident), None) + } } else { let mut msg = format!("could not find `{}` in `{}`", ident, path[i - 1].ident); diff --git a/src/test/ui/attributes/register-attr-tool-prelude.rs b/src/test/ui/attributes/register-attr-tool-prelude.rs index a491773f5eb2c..d217a8146d2ac 100644 --- a/src/test/ui/attributes/register-attr-tool-prelude.rs +++ b/src/test/ui/attributes/register-attr-tool-prelude.rs @@ -7,7 +7,7 @@ #[no_implicit_prelude] mod m { #[attr] //~ ERROR cannot find attribute `attr` in this scope - #[tool::attr] //~ ERROR failed to resolve: use of undeclared type or module `tool` + #[tool::attr] //~ ERROR failed to resolve: use of undeclared crate or module `tool` fn check() {} } diff --git a/src/test/ui/attributes/register-attr-tool-prelude.stderr b/src/test/ui/attributes/register-attr-tool-prelude.stderr index 66a4eeb6aa481..905b661206a6b 100644 --- a/src/test/ui/attributes/register-attr-tool-prelude.stderr +++ b/src/test/ui/attributes/register-attr-tool-prelude.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `tool` +error[E0433]: failed to resolve: use of undeclared crate or module `tool` --> $DIR/register-attr-tool-prelude.rs:10:7 | LL | #[tool::attr] - | ^^^^ use of undeclared type or module `tool` + | ^^^^ use of undeclared crate or module `tool` error: cannot find attribute `attr` in this scope --> $DIR/register-attr-tool-prelude.rs:9:7 diff --git a/src/test/ui/bad/bad-module.rs b/src/test/ui/bad/bad-module.rs index a496c816e94fb..b23e97c2cf6bc 100644 --- a/src/test/ui/bad/bad-module.rs +++ b/src/test/ui/bad/bad-module.rs @@ -1,7 +1,7 @@ fn main() { let foo = thing::len(Vec::new()); - //~^ ERROR failed to resolve: use of undeclared type or module `thing` + //~^ ERROR failed to resolve: use of undeclared crate or module `thing` let foo = foo::bar::baz(); - //~^ ERROR failed to resolve: use of undeclared type or module `foo` + //~^ ERROR failed to resolve: use of undeclared crate or module `foo` } diff --git a/src/test/ui/bad/bad-module.stderr b/src/test/ui/bad/bad-module.stderr index 45d4c5abd9343..581a661981460 100644 --- a/src/test/ui/bad/bad-module.stderr +++ b/src/test/ui/bad/bad-module.stderr @@ -1,14 +1,14 @@ -error[E0433]: failed to resolve: use of undeclared type or module `thing` +error[E0433]: failed to resolve: use of undeclared crate or module `thing` --> $DIR/bad-module.rs:2:15 | LL | let foo = thing::len(Vec::new()); - | ^^^^^ use of undeclared type or module `thing` + | ^^^^^ use of undeclared crate or module `thing` -error[E0433]: failed to resolve: use of undeclared type or module `foo` +error[E0433]: failed to resolve: use of undeclared crate or module `foo` --> $DIR/bad-module.rs:5:15 | LL | let foo = foo::bar::baz(); - | ^^^ use of undeclared type or module `foo` + | ^^^ use of undeclared crate or module `foo` error: aborting due to 2 previous errors diff --git a/src/test/ui/coherence/conflicting-impl-with-err.stderr b/src/test/ui/coherence/conflicting-impl-with-err.stderr index a8a5730accdd8..3009b452dc7a0 100644 --- a/src/test/ui/coherence/conflicting-impl-with-err.stderr +++ b/src/test/ui/coherence/conflicting-impl-with-err.stderr @@ -1,14 +1,14 @@ -error[E0433]: failed to resolve: use of undeclared type or module `nope` +error[E0433]: failed to resolve: use of undeclared crate or module `nope` --> $DIR/conflicting-impl-with-err.rs:4:11 | LL | impl From for Error { - | ^^^^ use of undeclared type or module `nope` + | ^^^^ use of undeclared crate or module `nope` -error[E0433]: failed to resolve: use of undeclared type or module `nope` +error[E0433]: failed to resolve: use of undeclared crate or module `nope` --> $DIR/conflicting-impl-with-err.rs:5:16 | LL | fn from(_: nope::Thing) -> Self { - | ^^^^ use of undeclared type or module `nope` + | ^^^^ use of undeclared crate or module `nope` error: aborting due to 2 previous errors diff --git a/src/test/ui/derived-errors/issue-31997-1.stderr b/src/test/ui/derived-errors/issue-31997-1.stderr index 229c5c9e80ff8..6d177666ed0fa 100644 --- a/src/test/ui/derived-errors/issue-31997-1.stderr +++ b/src/test/ui/derived-errors/issue-31997-1.stderr @@ -1,4 +1,4 @@ -error[E0433]: failed to resolve: use of undeclared type or module `HashMap` +error[E0433]: failed to resolve: use of undeclared type `HashMap` --> $DIR/issue-31997-1.rs:20:19 | LL | let mut map = HashMap::new(); diff --git a/src/test/ui/dyn-trait-compatibility.rs b/src/test/ui/dyn-trait-compatibility.rs index 2a1cea6c34870..d2b02cc2af543 100644 --- a/src/test/ui/dyn-trait-compatibility.rs +++ b/src/test/ui/dyn-trait-compatibility.rs @@ -1,7 +1,7 @@ type A0 = dyn; //~^ ERROR cannot find type `dyn` in this scope type A1 = dyn::dyn; -//~^ ERROR use of undeclared type or module `dyn` +//~^ ERROR use of undeclared crate or module `dyn` type A2 = dyn; //~^ ERROR cannot find type `dyn` in this scope //~| ERROR cannot find type `dyn` in this scope @@ -9,6 +9,6 @@ type A2 = dyn; type A3 = dyn<::dyn>; //~^ ERROR cannot find type `dyn` in this scope //~| ERROR cannot find type `dyn` in this scope -//~| ERROR use of undeclared type or module `dyn` +//~| ERROR use of undeclared crate or module `dyn` fn main() {} diff --git a/src/test/ui/dyn-trait-compatibility.stderr b/src/test/ui/dyn-trait-compatibility.stderr index 8fe8ceb4d0a60..9218ae9d5daa3 100644 --- a/src/test/ui/dyn-trait-compatibility.stderr +++ b/src/test/ui/dyn-trait-compatibility.stderr @@ -1,14 +1,14 @@ -error[E0433]: failed to resolve: use of undeclared type or module `dyn` +error[E0433]: failed to resolve: use of undeclared crate or module `dyn` --> $DIR/dyn-trait-compatibility.rs:3:11 | LL | type A1 = dyn::dyn; - | ^^^ use of undeclared type or module `dyn` + | ^^^ use of undeclared crate or module `dyn` -error[E0433]: failed to resolve: use of undeclared type or module `dyn` +error[E0433]: failed to resolve: use of undeclared crate or module `dyn` --> $DIR/dyn-trait-compatibility.rs:9:23 | LL | type A3 = dyn<::dyn>; - | ^^^ use of undeclared type or module `dyn` + | ^^^ use of undeclared crate or module `dyn` error[E0412]: cannot find type `dyn` in this scope --> $DIR/dyn-trait-compatibility.rs:1:11 diff --git a/src/test/ui/error-codes/E0433.stderr b/src/test/ui/error-codes/E0433.stderr index d9555e1fcf7a8..265d8885c8df0 100644 --- a/src/test/ui/error-codes/E0433.stderr +++ b/src/test/ui/error-codes/E0433.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `NonExistingMap` +error[E0433]: failed to resolve: use of undeclared type `NonExistingMap` --> $DIR/E0433.rs:2:15 | LL | let map = NonExistingMap::new(); - | ^^^^^^^^^^^^^^ use of undeclared type or module `NonExistingMap` + | ^^^^^^^^^^^^^^ use of undeclared type `NonExistingMap` error: aborting due to previous error diff --git a/src/test/ui/export-fully-qualified.rs b/src/test/ui/export-fully-qualified.rs index 99cb558908cb6..40f26c7095f13 100644 --- a/src/test/ui/export-fully-qualified.rs +++ b/src/test/ui/export-fully-qualified.rs @@ -1,9 +1,11 @@ +// ignore-tidy-linelength + // In this test baz isn't resolved when called as foo.baz even though // it's called from inside foo. This is somewhat surprising and may // want to change eventually. mod foo { - pub fn bar() { foo::baz(); } //~ ERROR failed to resolve: use of undeclared type or module `foo` + pub fn bar() { foo::baz(); } //~ ERROR failed to resolve: use of undeclared crate or module `foo` fn baz() { } } diff --git a/src/test/ui/export-fully-qualified.stderr b/src/test/ui/export-fully-qualified.stderr index c2ec1600868ab..a8af0c7c9b823 100644 --- a/src/test/ui/export-fully-qualified.stderr +++ b/src/test/ui/export-fully-qualified.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `foo` - --> $DIR/export-fully-qualified.rs:6:20 +error[E0433]: failed to resolve: use of undeclared crate or module `foo` + --> $DIR/export-fully-qualified.rs:8:20 | LL | pub fn bar() { foo::baz(); } - | ^^^ use of undeclared type or module `foo` + | ^^^ use of undeclared crate or module `foo` error: aborting due to previous error diff --git a/src/test/ui/export2.rs b/src/test/ui/export2.rs index 811d96f26d0cf..64ebeddffa8cf 100644 --- a/src/test/ui/export2.rs +++ b/src/test/ui/export2.rs @@ -1,5 +1,5 @@ mod foo { - pub fn x() { bar::x(); } //~ ERROR failed to resolve: use of undeclared type or module `bar` + pub fn x() { bar::x(); } //~ ERROR failed to resolve: use of undeclared crate or module `bar` } mod bar { diff --git a/src/test/ui/export2.stderr b/src/test/ui/export2.stderr index e0cd4404d3778..7cf47d0764b1e 100644 --- a/src/test/ui/export2.stderr +++ b/src/test/ui/export2.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `bar` +error[E0433]: failed to resolve: use of undeclared crate or module `bar` --> $DIR/export2.rs:2:18 | LL | pub fn x() { bar::x(); } - | ^^^ use of undeclared type or module `bar` + | ^^^ use of undeclared crate or module `bar` error: aborting due to previous error diff --git a/src/test/ui/extern-flag/multiple-opts.stderr b/src/test/ui/extern-flag/multiple-opts.stderr index 3bf73d11cfd22..5088fb1c4d2ed 100644 --- a/src/test/ui/extern-flag/multiple-opts.stderr +++ b/src/test/ui/extern-flag/multiple-opts.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `somedep` +error[E0433]: failed to resolve: use of undeclared crate or module `somedep` --> $DIR/multiple-opts.rs:19:5 | LL | somedep::somefun(); - | ^^^^^^^ use of undeclared type or module `somedep` + | ^^^^^^^ use of undeclared crate or module `somedep` error: aborting due to previous error diff --git a/src/test/ui/extern-flag/noprelude.stderr b/src/test/ui/extern-flag/noprelude.stderr index beb9200dddabc..57878721683a1 100644 --- a/src/test/ui/extern-flag/noprelude.stderr +++ b/src/test/ui/extern-flag/noprelude.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `somedep` +error[E0433]: failed to resolve: use of undeclared crate or module `somedep` --> $DIR/noprelude.rs:6:5 | LL | somedep::somefun(); - | ^^^^^^^ use of undeclared type or module `somedep` + | ^^^^^^^ use of undeclared crate or module `somedep` error: aborting due to previous error diff --git a/src/test/ui/hygiene/extern-prelude-from-opaque-fail.rs b/src/test/ui/hygiene/extern-prelude-from-opaque-fail.rs index 06d62656e957f..571017df4d7db 100644 --- a/src/test/ui/hygiene/extern-prelude-from-opaque-fail.rs +++ b/src/test/ui/hygiene/extern-prelude-from-opaque-fail.rs @@ -9,7 +9,7 @@ macro a() { mod u { // Late resolution. fn f() { my_core::mem::drop(0); } - //~^ ERROR failed to resolve: use of undeclared type or module `my_core` + //~^ ERROR failed to resolve: use of undeclared crate or module `my_core` } } @@ -22,7 +22,7 @@ mod v { mod u { // Late resolution. fn f() { my_core::mem::drop(0); } - //~^ ERROR failed to resolve: use of undeclared type or module `my_core` + //~^ ERROR failed to resolve: use of undeclared crate or module `my_core` } fn main() {} diff --git a/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr b/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr index b9e05c84a8aea..d3e6021a1ed07 100644 --- a/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr +++ b/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr @@ -18,22 +18,22 @@ LL | a!(); | = 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 or module `my_core` +error[E0433]: failed to resolve: use of undeclared crate or module `my_core` --> $DIR/extern-prelude-from-opaque-fail.rs:11:18 | LL | fn f() { my_core::mem::drop(0); } - | ^^^^^^^ use of undeclared type or module `my_core` + | ^^^^^^^ use of undeclared crate or module `my_core` ... LL | a!(); | ----- in this macro invocation | = 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 or module `my_core` +error[E0433]: failed to resolve: use of undeclared crate or module `my_core` --> $DIR/extern-prelude-from-opaque-fail.rs:24:14 | LL | fn f() { my_core::mem::drop(0); } - | ^^^^^^^ use of undeclared type or module `my_core` + | ^^^^^^^ use of undeclared crate or module `my_core` error: aborting due to 4 previous errors diff --git a/src/test/ui/hygiene/no_implicit_prelude.stderr b/src/test/ui/hygiene/no_implicit_prelude.stderr index 990210ffb6b49..3c0c0450774e9 100644 --- a/src/test/ui/hygiene/no_implicit_prelude.stderr +++ b/src/test/ui/hygiene/no_implicit_prelude.stderr @@ -6,7 +6,7 @@ LL | assert_eq!(0, 0); | = 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 or module `Vec` +error[E0433]: failed to resolve: use of undeclared type `Vec` --> $DIR/no_implicit_prelude.rs:11:9 | LL | fn f() { ::bar::m!(); } diff --git a/src/test/ui/impl-trait/issue-72911.stderr b/src/test/ui/impl-trait/issue-72911.stderr index b28142b916c77..5303a253a93b6 100644 --- a/src/test/ui/impl-trait/issue-72911.stderr +++ b/src/test/ui/impl-trait/issue-72911.stderr @@ -1,14 +1,14 @@ -error[E0433]: failed to resolve: use of undeclared type or module `foo` +error[E0433]: failed to resolve: use of undeclared crate or module `foo` --> $DIR/issue-72911.rs:12:33 | LL | fn gather_from_file(dir_entry: &foo::MissingItem) -> impl Iterator { - | ^^^ use of undeclared type or module `foo` + | ^^^ use of undeclared crate or module `foo` -error[E0433]: failed to resolve: use of undeclared type or module `foo` +error[E0433]: failed to resolve: use of undeclared crate or module `foo` --> $DIR/issue-72911.rs:17:41 | LL | fn lint_files() -> impl Iterator { - | ^^^ use of undeclared type or module `foo` + | ^^^ use of undeclared crate or module `foo` error[E0720]: cannot resolve opaque type --> $DIR/issue-72911.rs:7:24 diff --git a/src/test/ui/imports/extern-prelude-extern-crate-fail.rs b/src/test/ui/imports/extern-prelude-extern-crate-fail.rs index 6b70efe0c4486..4a0c612020194 100644 --- a/src/test/ui/imports/extern-prelude-extern-crate-fail.rs +++ b/src/test/ui/imports/extern-prelude-extern-crate-fail.rs @@ -1,3 +1,5 @@ +// ignore-tidy-linelength + // aux-build:two_macros.rs // compile-flags:--extern non_existent @@ -7,7 +9,7 @@ mod n { mod m { fn check() { - two_macros::m!(); //~ ERROR failed to resolve: use of undeclared type or module `two_macros` + two_macros::m!(); //~ ERROR failed to resolve: use of undeclared crate or module `two_macros` } } diff --git a/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr b/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr index f7544306d3434..2d7a1bf468e33 100644 --- a/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr +++ b/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr @@ -1,5 +1,5 @@ error: macro-expanded `extern crate` items cannot shadow names passed with `--extern` - --> $DIR/extern-prelude-extern-crate-fail.rs:16:9 + --> $DIR/extern-prelude-extern-crate-fail.rs:18:9 | LL | extern crate std as non_existent; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,11 +9,11 @@ LL | define_std_as_non_existent!(); | = 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 or module `two_macros` - --> $DIR/extern-prelude-extern-crate-fail.rs:10:9 +error[E0433]: failed to resolve: use of undeclared crate or module `two_macros` + --> $DIR/extern-prelude-extern-crate-fail.rs:12:9 | LL | two_macros::m!(); - | ^^^^^^^^^^ use of undeclared type or module `two_macros` + | ^^^^^^^^^^ use of undeclared crate or module `two_macros` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-33293.rs b/src/test/ui/issues/issue-33293.rs index d367037428412..a6ef007d51fb5 100644 --- a/src/test/ui/issues/issue-33293.rs +++ b/src/test/ui/issues/issue-33293.rs @@ -1,6 +1,6 @@ fn main() { match 0 { aaa::bbb(_) => () - //~^ ERROR failed to resolve: use of undeclared type or module `aaa` + //~^ ERROR failed to resolve: use of undeclared crate or module `aaa` }; } diff --git a/src/test/ui/issues/issue-33293.stderr b/src/test/ui/issues/issue-33293.stderr index 6b7333f22fe1c..c8450f400429c 100644 --- a/src/test/ui/issues/issue-33293.stderr +++ b/src/test/ui/issues/issue-33293.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `aaa` +error[E0433]: failed to resolve: use of undeclared crate or module `aaa` --> $DIR/issue-33293.rs:3:9 | LL | aaa::bbb(_) => () - | ^^^ use of undeclared type or module `aaa` + | ^^^ use of undeclared crate or module `aaa` error: aborting due to previous error diff --git a/src/test/ui/macros/builtin-prelude-no-accidents.rs b/src/test/ui/macros/builtin-prelude-no-accidents.rs index ac82f343acc02..01691a82dd772 100644 --- a/src/test/ui/macros/builtin-prelude-no-accidents.rs +++ b/src/test/ui/macros/builtin-prelude-no-accidents.rs @@ -2,7 +2,7 @@ // because macros with the same names are in prelude. fn main() { - env::current_dir; //~ ERROR use of undeclared type or module `env` - type A = panic::PanicInfo; //~ ERROR use of undeclared type or module `panic` - type B = vec::Vec; //~ ERROR use of undeclared type or module `vec` + env::current_dir; //~ ERROR use of undeclared crate or module `env` + type A = panic::PanicInfo; //~ ERROR use of undeclared crate or module `panic` + type B = vec::Vec; //~ ERROR use of undeclared crate or module `vec` } diff --git a/src/test/ui/macros/builtin-prelude-no-accidents.stderr b/src/test/ui/macros/builtin-prelude-no-accidents.stderr index 914e906df58b3..56af618d484b5 100644 --- a/src/test/ui/macros/builtin-prelude-no-accidents.stderr +++ b/src/test/ui/macros/builtin-prelude-no-accidents.stderr @@ -1,20 +1,20 @@ -error[E0433]: failed to resolve: use of undeclared type or module `env` +error[E0433]: failed to resolve: use of undeclared crate or module `env` --> $DIR/builtin-prelude-no-accidents.rs:5:5 | LL | env::current_dir; - | ^^^ use of undeclared type or module `env` + | ^^^ use of undeclared crate or module `env` -error[E0433]: failed to resolve: use of undeclared type or module `panic` +error[E0433]: failed to resolve: use of undeclared crate or module `panic` --> $DIR/builtin-prelude-no-accidents.rs:6:14 | LL | type A = panic::PanicInfo; - | ^^^^^ use of undeclared type or module `panic` + | ^^^^^ use of undeclared crate or module `panic` -error[E0433]: failed to resolve: use of undeclared type or module `vec` +error[E0433]: failed to resolve: use of undeclared crate or module `vec` --> $DIR/builtin-prelude-no-accidents.rs:7:14 | LL | type B = vec::Vec; - | ^^^ use of undeclared type or module `vec` + | ^^^ use of undeclared crate or module `vec` error: aborting due to 3 previous errors diff --git a/src/test/ui/macros/macro-inner-attributes.rs b/src/test/ui/macros/macro-inner-attributes.rs index 56a9023156612..a8cda23075b6f 100644 --- a/src/test/ui/macros/macro-inner-attributes.rs +++ b/src/test/ui/macros/macro-inner-attributes.rs @@ -15,6 +15,6 @@ test!(b, #[rustc_dummy] fn main() { a::bar(); - //~^ ERROR failed to resolve: use of undeclared type or module `a` + //~^ ERROR failed to resolve: use of undeclared crate or module `a` b::bar(); } diff --git a/src/test/ui/macros/macro-inner-attributes.stderr b/src/test/ui/macros/macro-inner-attributes.stderr index 5e20f106a955b..8223220d9a4e2 100644 --- a/src/test/ui/macros/macro-inner-attributes.stderr +++ b/src/test/ui/macros/macro-inner-attributes.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `a` +error[E0433]: failed to resolve: use of undeclared crate or module `a` --> $DIR/macro-inner-attributes.rs:17:5 | LL | a::bar(); - | ^ use of undeclared type or module `a` + | ^ use of undeclared crate or module `a` error: aborting due to previous error diff --git a/src/test/ui/macros/macro_path_as_generic_bound.stderr b/src/test/ui/macros/macro_path_as_generic_bound.stderr index 48c33575ad2a9..00d954d24f380 100644 --- a/src/test/ui/macros/macro_path_as_generic_bound.stderr +++ b/src/test/ui/macros/macro_path_as_generic_bound.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `m` +error[E0433]: failed to resolve: use of undeclared crate or module `m` --> $DIR/macro_path_as_generic_bound.rs:7:6 | LL | foo!(m::m2::A); - | ^ use of undeclared type or module `m` + | ^ use of undeclared crate or module `m` error: aborting due to previous error diff --git a/src/test/ui/mod/mod_file_disambig.rs b/src/test/ui/mod/mod_file_disambig.rs index 7b182421d34e3..e5958af173b66 100644 --- a/src/test/ui/mod/mod_file_disambig.rs +++ b/src/test/ui/mod/mod_file_disambig.rs @@ -2,5 +2,5 @@ mod mod_file_disambig_aux; //~ ERROR file for module `mod_file_disambig_aux` fou fn main() { assert_eq!(mod_file_aux::bar(), 10); - //~^ ERROR failed to resolve: use of undeclared type or module `mod_file_aux` + //~^ ERROR failed to resolve: use of undeclared crate or module `mod_file_aux` } diff --git a/src/test/ui/mod/mod_file_disambig.stderr b/src/test/ui/mod/mod_file_disambig.stderr index 2cb99b7514277..3a3d2e2ddddb3 100644 --- a/src/test/ui/mod/mod_file_disambig.stderr +++ b/src/test/ui/mod/mod_file_disambig.stderr @@ -6,11 +6,11 @@ LL | mod mod_file_disambig_aux; | = help: delete or rename one of them to remove the ambiguity -error[E0433]: failed to resolve: use of undeclared type or module `mod_file_aux` +error[E0433]: failed to resolve: use of undeclared crate or module `mod_file_aux` --> $DIR/mod_file_disambig.rs:4:16 | LL | assert_eq!(mod_file_aux::bar(), 10); - | ^^^^^^^^^^^^ use of undeclared type or module `mod_file_aux` + | ^^^^^^^^^^^^ use of undeclared crate or module `mod_file_aux` error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/mod_file_not_exist.rs b/src/test/ui/parser/mod_file_not_exist.rs index f4a27b52ec5b4..7b079eb02dcf4 100644 --- a/src/test/ui/parser/mod_file_not_exist.rs +++ b/src/test/ui/parser/mod_file_not_exist.rs @@ -5,5 +5,5 @@ mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file` fn main() { assert_eq!(mod_file_aux::bar(), 10); - //~^ ERROR failed to resolve: use of undeclared type or module `mod_file_aux` + //~^ ERROR failed to resolve: use of undeclared crate or module `mod_file_aux` } diff --git a/src/test/ui/parser/mod_file_not_exist.stderr b/src/test/ui/parser/mod_file_not_exist.stderr index 087ae9fe3e016..4e08125625f0a 100644 --- a/src/test/ui/parser/mod_file_not_exist.stderr +++ b/src/test/ui/parser/mod_file_not_exist.stderr @@ -6,11 +6,11 @@ LL | mod not_a_real_file; | = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" -error[E0433]: failed to resolve: use of undeclared type or module `mod_file_aux` +error[E0433]: failed to resolve: use of undeclared crate or module `mod_file_aux` --> $DIR/mod_file_not_exist.rs:7:16 | LL | assert_eq!(mod_file_aux::bar(), 10); - | ^^^^^^^^^^^^ use of undeclared type or module `mod_file_aux` + | ^^^^^^^^^^^^ use of undeclared crate or module `mod_file_aux` error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/mod_file_not_exist_windows.rs b/src/test/ui/parser/mod_file_not_exist_windows.rs index 4b7d7a02bbe78..5db21e2bbc78c 100644 --- a/src/test/ui/parser/mod_file_not_exist_windows.rs +++ b/src/test/ui/parser/mod_file_not_exist_windows.rs @@ -5,5 +5,5 @@ mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file` fn main() { assert_eq!(mod_file_aux::bar(), 10); - //~^ ERROR failed to resolve: use of undeclared type or module `mod_file_aux` + //~^ ERROR failed to resolve: use of undeclared crate or module `mod_file_aux` } diff --git a/src/test/ui/parser/mod_file_not_exist_windows.stderr b/src/test/ui/parser/mod_file_not_exist_windows.stderr index d67205cfdf100..73cdf098b00c9 100644 --- a/src/test/ui/parser/mod_file_not_exist_windows.stderr +++ b/src/test/ui/parser/mod_file_not_exist_windows.stderr @@ -6,11 +6,11 @@ LL | mod not_a_real_file; | = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" -error[E0433]: failed to resolve: use of undeclared type or module `mod_file_aux` +error[E0433]: failed to resolve: use of undeclared crate or module `mod_file_aux` --> $DIR/mod_file_not_exist_windows.rs:7:16 | LL | assert_eq!(mod_file_aux::bar(), 10); - | ^^^^^^^^^^^^ use of undeclared type or module `mod_file_aux` + | ^^^^^^^^^^^^ use of undeclared crate or module `mod_file_aux` error: aborting due to 2 previous errors diff --git a/src/test/ui/pattern/pattern-error-continue.rs b/src/test/ui/pattern/pattern-error-continue.rs index 8635622ab37cc..0702a9986fc1c 100644 --- a/src/test/ui/pattern/pattern-error-continue.rs +++ b/src/test/ui/pattern/pattern-error-continue.rs @@ -30,6 +30,6 @@ fn main() { //~| expected `char`, found `bool` match () { - E::V => {} //~ ERROR failed to resolve: use of undeclared type or module `E` + E::V => {} //~ ERROR failed to resolve: use of undeclared type `E` } } diff --git a/src/test/ui/pattern/pattern-error-continue.stderr b/src/test/ui/pattern/pattern-error-continue.stderr index 60f76796c0396..497c93b29497c 100644 --- a/src/test/ui/pattern/pattern-error-continue.stderr +++ b/src/test/ui/pattern/pattern-error-continue.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `E` +error[E0433]: failed to resolve: use of undeclared type `E` --> $DIR/pattern-error-continue.rs:33:9 | LL | E::V => {} - | ^ use of undeclared type or module `E` + | ^ use of undeclared type `E` error[E0532]: expected tuple struct or tuple variant, found unit variant `A::D` --> $DIR/pattern-error-continue.rs:18:9 diff --git a/src/test/ui/resolve/use_suggestion.stderr b/src/test/ui/resolve/use_suggestion.stderr index 72dda94072962..4fff179b1fecc 100644 --- a/src/test/ui/resolve/use_suggestion.stderr +++ b/src/test/ui/resolve/use_suggestion.stderr @@ -1,10 +1,10 @@ -error[E0433]: failed to resolve: use of undeclared type or module `GooMap` +error[E0433]: failed to resolve: use of undeclared type `GooMap` --> $DIR/use_suggestion.rs:3:14 | LL | let x2 = GooMap::new(); - | ^^^^^^ use of undeclared type or module `GooMap` + | ^^^^^^ use of undeclared type `GooMap` -error[E0433]: failed to resolve: use of undeclared type or module `HashMap` +error[E0433]: failed to resolve: use of undeclared type `HashMap` --> $DIR/use_suggestion.rs:2:14 | LL | let x1 = HashMap::new(); diff --git a/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-1.stderr b/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-1.stderr index 64b920e9aa7e6..81891572179b0 100644 --- a/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-1.stderr +++ b/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-1.stderr @@ -2,7 +2,7 @@ error[E0432]: unresolved import `xcrate` --> $DIR/non-existent-1.rs:3:5 | LL | use xcrate::S; - | ^^^^^^ use of undeclared type or module `xcrate` + | ^^^^^^ use of undeclared crate or module `xcrate` error: aborting due to previous error diff --git a/src/test/ui/suggestions/type-ascription-instead-of-path.rs b/src/test/ui/suggestions/type-ascription-instead-of-path.rs index e92087e2947de..ce40b55f1ee84 100644 --- a/src/test/ui/suggestions/type-ascription-instead-of-path.rs +++ b/src/test/ui/suggestions/type-ascription-instead-of-path.rs @@ -1,5 +1,5 @@ fn main() { std:io::stdin(); - //~^ ERROR failed to resolve: use of undeclared type or module `io` + //~^ ERROR failed to resolve: use of undeclared crate or module `io` //~| ERROR expected value, found crate } diff --git a/src/test/ui/suggestions/type-ascription-instead-of-path.stderr b/src/test/ui/suggestions/type-ascription-instead-of-path.stderr index fd2fedc76407c..518660cfa1686 100644 --- a/src/test/ui/suggestions/type-ascription-instead-of-path.stderr +++ b/src/test/ui/suggestions/type-ascription-instead-of-path.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `io` +error[E0433]: failed to resolve: use of undeclared crate or module `io` --> $DIR/type-ascription-instead-of-path.rs:2:9 | LL | std:io::stdin(); - | ^^ use of undeclared type or module `io` + | ^^ use of undeclared crate or module `io` error[E0423]: expected value, found crate `std` --> $DIR/type-ascription-instead-of-path.rs:2:5 diff --git a/src/test/ui/type-alias/issue-62263-self-in-atb.rs b/src/test/ui/type-alias/issue-62263-self-in-atb.rs index 5e812db4d2362..1f64b4cfe5c83 100644 --- a/src/test/ui/type-alias/issue-62263-self-in-atb.rs +++ b/src/test/ui/type-alias/issue-62263-self-in-atb.rs @@ -3,6 +3,6 @@ pub trait Trait { } pub type Alias = dyn Trait; -//~^ ERROR failed to resolve: use of undeclared type or module `Self` [E0433] +//~^ ERROR failed to resolve: use of undeclared type `Self` [E0433] fn main() {} diff --git a/src/test/ui/type-alias/issue-62263-self-in-atb.stderr b/src/test/ui/type-alias/issue-62263-self-in-atb.stderr index a642d029f93b5..d34b6ed5038bc 100644 --- a/src/test/ui/type-alias/issue-62263-self-in-atb.stderr +++ b/src/test/ui/type-alias/issue-62263-self-in-atb.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `Self` +error[E0433]: failed to resolve: use of undeclared type `Self` --> $DIR/issue-62263-self-in-atb.rs:5:32 | LL | pub type Alias = dyn Trait; - | ^^^^ use of undeclared type or module `Self` + | ^^^^ use of undeclared type `Self` error: aborting due to previous error diff --git a/src/test/ui/type-alias/issue-62305-self-assoc-ty.rs b/src/test/ui/type-alias/issue-62305-self-assoc-ty.rs index 0b95ddeb19e78..999902fb18b37 100644 --- a/src/test/ui/type-alias/issue-62305-self-assoc-ty.rs +++ b/src/test/ui/type-alias/issue-62305-self-assoc-ty.rs @@ -1,4 +1,4 @@ type Alias = Self::Target; -//~^ ERROR failed to resolve: use of undeclared type or module `Self` [E0433] +//~^ ERROR failed to resolve: use of undeclared type `Self` [E0433] fn main() {} diff --git a/src/test/ui/type-alias/issue-62305-self-assoc-ty.stderr b/src/test/ui/type-alias/issue-62305-self-assoc-ty.stderr index 6eb445e9dbcfe..823a5fa50fc6d 100644 --- a/src/test/ui/type-alias/issue-62305-self-assoc-ty.stderr +++ b/src/test/ui/type-alias/issue-62305-self-assoc-ty.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `Self` +error[E0433]: failed to resolve: use of undeclared type `Self` --> $DIR/issue-62305-self-assoc-ty.rs:1:14 | LL | type Alias = Self::Target; - | ^^^^ use of undeclared type or module `Self` + | ^^^^ use of undeclared type `Self` error: aborting due to previous error diff --git a/src/test/ui/type/type-path-err-node-types.rs b/src/test/ui/type/type-path-err-node-types.rs index 15adfebb33400..b3795772e6fe2 100644 --- a/src/test/ui/type/type-path-err-node-types.rs +++ b/src/test/ui/type/type-path-err-node-types.rs @@ -12,7 +12,7 @@ fn ufcs_trait() { } fn ufcs_item() { - NonExistent::Assoc::; //~ ERROR undeclared type or module `NonExistent` + NonExistent::Assoc::; //~ ERROR undeclared type `NonExistent` } fn method() { diff --git a/src/test/ui/type/type-path-err-node-types.stderr b/src/test/ui/type/type-path-err-node-types.stderr index ea9cca2bfaab0..baf218243c4c8 100644 --- a/src/test/ui/type/type-path-err-node-types.stderr +++ b/src/test/ui/type/type-path-err-node-types.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `NonExistent` +error[E0433]: failed to resolve: use of undeclared type `NonExistent` --> $DIR/type-path-err-node-types.rs:15:5 | LL | NonExistent::Assoc::; - | ^^^^^^^^^^^ use of undeclared type or module `NonExistent` + | ^^^^^^^^^^^ use of undeclared type `NonExistent` error[E0412]: cannot find type `Nonexistent` in this scope --> $DIR/type-path-err-node-types.rs:7:12 diff --git a/src/test/ui/unknown-tool-name.rs b/src/test/ui/unknown-tool-name.rs index 05f99ced68744..73fca61c65d1b 100644 --- a/src/test/ui/unknown-tool-name.rs +++ b/src/test/ui/unknown-tool-name.rs @@ -1,2 +1,2 @@ -#[foo::bar] //~ ERROR failed to resolve: use of undeclared type or module `foo` +#[foo::bar] //~ ERROR failed to resolve: use of undeclared crate or module `foo` fn main() {} diff --git a/src/test/ui/unknown-tool-name.stderr b/src/test/ui/unknown-tool-name.stderr index 7a6ed57bda6f3..4a1370ba80a50 100644 --- a/src/test/ui/unknown-tool-name.stderr +++ b/src/test/ui/unknown-tool-name.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `foo` +error[E0433]: failed to resolve: use of undeclared crate or module `foo` --> $DIR/unknown-tool-name.rs:1:3 | LL | #[foo::bar] - | ^^^ use of undeclared type or module `foo` + | ^^^ use of undeclared crate or module `foo` error: aborting due to previous error diff --git a/src/test/ui/use/use-self-type.rs b/src/test/ui/use/use-self-type.rs index 3e5c7bf3cca25..370593b2eb22b 100644 --- a/src/test/ui/use/use-self-type.rs +++ b/src/test/ui/use/use-self-type.rs @@ -4,7 +4,7 @@ impl S { fn f() {} fn g() { use Self::f; //~ ERROR unresolved import - pub(in Self::f) struct Z; //~ ERROR use of undeclared type or module `Self` + pub(in Self::f) struct Z; //~ ERROR use of undeclared type `Self` } } diff --git a/src/test/ui/use/use-self-type.stderr b/src/test/ui/use/use-self-type.stderr index 0dd0e04267c33..d1469fb349078 100644 --- a/src/test/ui/use/use-self-type.stderr +++ b/src/test/ui/use/use-self-type.stderr @@ -1,14 +1,14 @@ -error[E0433]: failed to resolve: use of undeclared type or module `Self` +error[E0433]: failed to resolve: use of undeclared type `Self` --> $DIR/use-self-type.rs:7:16 | LL | pub(in Self::f) struct Z; - | ^^^^ use of undeclared type or module `Self` + | ^^^^ use of undeclared type `Self` error[E0432]: unresolved import `Self` --> $DIR/use-self-type.rs:6:13 | LL | use Self::f; - | ^^^^ use of undeclared type or module `Self` + | ^^^^ use of undeclared type `Self` error: aborting due to 2 previous errors From e49a29933be3bd988ccb75b053f480d9c99a7ff5 Mon Sep 17 00:00:00 2001 From: Ricky Date: Tue, 1 Sep 2020 16:26:59 -0400 Subject: [PATCH 0069/1052] Working map_err_ignore lint --- clippy_lints/src/lib.rs | 5 ++ clippy_lints/src/map_err_ignore.rs | 108 +++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 clippy_lints/src/map_err_ignore.rs diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 0eb1d3313660b..8e80779377bcd 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -230,6 +230,7 @@ mod main_recursion; mod manual_async_fn; mod manual_non_exhaustive; mod map_clone; +mod map_err_ignore; mod map_identity; mod map_unit_fn; mod match_on_vec_items; @@ -624,6 +625,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &manual_async_fn::MANUAL_ASYNC_FN, &manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE, &map_clone::MAP_CLONE, + &map_err_ignore::MAP_ERR_IGNORE, &map_identity::MAP_IDENTITY, &map_unit_fn::OPTION_MAP_UNIT_FN, &map_unit_fn::RESULT_MAP_UNIT_FN, @@ -916,6 +918,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub); store.register_late_pass(|| box methods::Methods); store.register_late_pass(|| box map_clone::MapClone); + store.register_late_pass(|| box map_err_ignore::MapErrIgnore); store.register_late_pass(|| box shadow::Shadow); store.register_late_pass(|| box types::LetUnitValue); store.register_late_pass(|| box types::UnitCmp); @@ -1327,6 +1330,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&manual_async_fn::MANUAL_ASYNC_FN), LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), LintId::of(&map_clone::MAP_CLONE), + LintId::of(&map_err_ignore::MAP_ERR_IGNORE), LintId::of(&map_identity::MAP_IDENTITY), LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN), LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN), @@ -1534,6 +1538,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&manual_async_fn::MANUAL_ASYNC_FN), LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), LintId::of(&map_clone::MAP_CLONE), + LintId::of(&map_err_ignore::MAP_ERR_IGNORE), LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH), LintId::of(&matches::MATCH_LIKE_MATCHES_MACRO), LintId::of(&matches::MATCH_OVERLAPPING_ARM), diff --git a/clippy_lints/src/map_err_ignore.rs b/clippy_lints/src/map_err_ignore.rs new file mode 100644 index 0000000000000..c63c201a9f35a --- /dev/null +++ b/clippy_lints/src/map_err_ignore.rs @@ -0,0 +1,108 @@ +use crate::utils::span_lint_and_sugg; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, CaptureBy, PatKind, QPath}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** Checks for instances of `map_err(|_| Some::Enum)` + /// + /// **Why is this bad?** This map_err throws away the original error rather than allowing the enum to bubble the original error + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// enum Errors { + /// Ignore + ///} + ///fn main() -> Result<(), Errors> { + /// + /// let x = u32::try_from(-123_i32); + /// + /// println!("{:?}", x.map_err(|_| Errors::Ignore)); + /// + /// Ok(()) + ///} + /// ``` + /// Use instead: + /// ```rust + /// enum Errors { + /// WithContext(TryFromIntError) + ///} + ///fn main() -> Result<(), Errors> { + /// + /// let x = u32::try_from(-123_i32); + /// + /// println!("{:?}", x.map_err(|e| Errors::WithContext(e))); + /// + /// Ok(()) + ///} + /// ``` + pub MAP_ERR_IGNORE, + style, + "`map_err` should not ignore the original error" +} + +declare_lint_pass!(MapErrIgnore => [MAP_ERR_IGNORE]); + +impl<'tcx> LateLintPass<'tcx> for MapErrIgnore { + // do not try to lint if this is from a macro or desugaring + fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) { + if e.span.from_expansion() { + return; + } + + // check if this is a method call (e.g. x.foo()) + if let ExprKind::MethodCall(ref method, _t_span, ref args, _) = e.kind { + // only work if the method name is `map_err` and there are only 2 arguments (e.g. x.map_err(|_|[1] Enum::Variant[2])) + if method.ident.as_str() == "map_err" && args.len() == 2 { + // make sure the first argument is a closure, and grab the CaptureRef, body_id, and body_span fields + if let ExprKind::Closure(capture, _, body_id, body_span, _) = args[1].kind { + // check if this is by Reference (meaning there's no move statement) + if capture == CaptureBy::Ref { + // Get the closure body to check the parameters and values + let closure_body = cx.tcx.hir().body(body_id); + // make sure there's only one parameter (`|_|`) + if closure_body.params.len() == 1 { + // make sure that parameter is the wild token (`_`) + if let PatKind::Wild = closure_body.params[0].pat.kind { + // Check the value of the closure to see if we can build the enum we are throwing away the error for + // make sure this is a Path + if let ExprKind::Path(q_path) = &closure_body.value.kind { + // this should be a resolved path, only keep the path field + if let QPath::Resolved(_, path) = q_path { + // finally get the idents for each path segment collect them as a string and join them with the path separator ("::"") + let closure_fold: String = path.segments.iter().map(|x| x.ident.as_str().to_string()).collect::>().join("::"); + //Span the body of the closure (the |...| bit) and suggest the fix by taking the error and encapsulating it in the enum + span_lint_and_sugg( + cx, + MAP_ERR_IGNORE, + body_span, + "`map_err` has thrown away the original error", + "Allow the error enum to encapsulate the original error", + format!("|e| {}(e)", closure_fold), + Applicability::HasPlaceholders, + ); + } + } else { + //If we cannot build the enum in a human readable way just suggest not throwing way the error + span_lint_and_sugg( + cx, + MAP_ERR_IGNORE, + body_span, + "`map_err` has thrown away the original error", + "Allow the error enum to encapsulate the original error", + "|e|".to_string(), + Applicability::HasPlaceholders, + ); + } + } + } + } + } + } + } + } +} \ No newline at end of file From 202a80c927412a548180eca5990ee764d76ed643 Mon Sep 17 00:00:00 2001 From: Ricky Date: Tue, 1 Sep 2020 16:59:37 -0400 Subject: [PATCH 0070/1052] Added tests for map_err, ignored map_err lint on drop_ref tests --- clippy_lints/src/map_err_ignore.rs | 49 ++++++++++++++++++------------ tests/ui/drop_ref.rs | 1 + tests/ui/drop_ref.stderr | 36 +++++++++++----------- tests/ui/map_err.rs | 24 +++++++++++++++ tests/ui/map_err.stderr | 10 ++++++ 5 files changed, 82 insertions(+), 38 deletions(-) create mode 100644 tests/ui/map_err.rs create mode 100644 tests/ui/map_err.stderr diff --git a/clippy_lints/src/map_err_ignore.rs b/clippy_lints/src/map_err_ignore.rs index c63c201a9f35a..43bfcf0b8f147 100644 --- a/clippy_lints/src/map_err_ignore.rs +++ b/clippy_lints/src/map_err_ignore.rs @@ -1,6 +1,6 @@ use crate::utils::span_lint_and_sugg; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, CaptureBy, PatKind, QPath}; +use rustc_hir::{CaptureBy, Expr, ExprKind, PatKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -18,7 +18,7 @@ declare_clippy_lint! { /// Ignore ///} ///fn main() -> Result<(), Errors> { - /// + /// /// let x = u32::try_from(-123_i32); /// /// println!("{:?}", x.map_err(|_| Errors::Ignore)); @@ -32,7 +32,7 @@ declare_clippy_lint! { /// WithContext(TryFromIntError) ///} ///fn main() -> Result<(), Errors> { - /// + /// /// let x = u32::try_from(-123_i32); /// /// println!("{:?}", x.map_err(|e| Errors::WithContext(e))); @@ -48,7 +48,7 @@ declare_clippy_lint! { declare_lint_pass!(MapErrIgnore => [MAP_ERR_IGNORE]); impl<'tcx> LateLintPass<'tcx> for MapErrIgnore { - // do not try to lint if this is from a macro or desugaring + // do not try to lint if this is from a macro or desugaring fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) { if e.span.from_expansion() { return; @@ -56,26 +56,34 @@ impl<'tcx> LateLintPass<'tcx> for MapErrIgnore { // check if this is a method call (e.g. x.foo()) if let ExprKind::MethodCall(ref method, _t_span, ref args, _) = e.kind { - // only work if the method name is `map_err` and there are only 2 arguments (e.g. x.map_err(|_|[1] Enum::Variant[2])) + // only work if the method name is `map_err` and there are only 2 arguments (e.g. x.map_err(|_|[1] + // Enum::Variant[2])) if method.ident.as_str() == "map_err" && args.len() == 2 { // make sure the first argument is a closure, and grab the CaptureRef, body_id, and body_span fields - if let ExprKind::Closure(capture, _, body_id, body_span, _) = args[1].kind { + if let ExprKind::Closure(capture, _, body_id, body_span, _) = args[1].kind { // check if this is by Reference (meaning there's no move statement) - if capture == CaptureBy::Ref { - // Get the closure body to check the parameters and values + if capture == CaptureBy::Ref { + // Get the closure body to check the parameters and values let closure_body = cx.tcx.hir().body(body_id); // make sure there's only one parameter (`|_|`) - if closure_body.params.len() == 1 { - // make sure that parameter is the wild token (`_`) + if closure_body.params.len() == 1 { + // make sure that parameter is the wild token (`_`) if let PatKind::Wild = closure_body.params[0].pat.kind { - // Check the value of the closure to see if we can build the enum we are throwing away the error for - // make sure this is a Path + // Check the value of the closure to see if we can build the enum we are throwing away + // the error for make sure this is a Path if let ExprKind::Path(q_path) = &closure_body.value.kind { // this should be a resolved path, only keep the path field if let QPath::Resolved(_, path) = q_path { - // finally get the idents for each path segment collect them as a string and join them with the path separator ("::"") - let closure_fold: String = path.segments.iter().map(|x| x.ident.as_str().to_string()).collect::>().join("::"); - //Span the body of the closure (the |...| bit) and suggest the fix by taking the error and encapsulating it in the enum + // finally get the idents for each path segment collect them as a string and + // join them with the path separator ("::"") + let closure_fold: String = path + .segments + .iter() + .map(|x| x.ident.as_str().to_string()) + .collect::>() + .join("::"); + //Span the body of the closure (the |...| bit) and suggest the fix by taking + // the error and encapsulating it in the enum span_lint_and_sugg( cx, MAP_ERR_IGNORE, @@ -84,10 +92,11 @@ impl<'tcx> LateLintPass<'tcx> for MapErrIgnore { "Allow the error enum to encapsulate the original error", format!("|e| {}(e)", closure_fold), Applicability::HasPlaceholders, - ); + ); } } else { - //If we cannot build the enum in a human readable way just suggest not throwing way the error + //If we cannot build the enum in a human readable way just suggest not throwing way + // the error span_lint_and_sugg( cx, MAP_ERR_IGNORE, @@ -96,13 +105,13 @@ impl<'tcx> LateLintPass<'tcx> for MapErrIgnore { "Allow the error enum to encapsulate the original error", "|e|".to_string(), Applicability::HasPlaceholders, - ); + ); } } } - } + } } } } } -} \ No newline at end of file +} diff --git a/tests/ui/drop_ref.rs b/tests/ui/drop_ref.rs index 9181d789d4fb1..6b5bcdaa78e27 100644 --- a/tests/ui/drop_ref.rs +++ b/tests/ui/drop_ref.rs @@ -1,5 +1,6 @@ #![warn(clippy::drop_ref)] #![allow(clippy::toplevel_ref_arg)] +#![allow(clippy::map_err_ignore)] use std::mem::drop; diff --git a/tests/ui/drop_ref.stderr b/tests/ui/drop_ref.stderr index 35ae88b78a4c5..7974bf56d44cf 100644 --- a/tests/ui/drop_ref.stderr +++ b/tests/ui/drop_ref.stderr @@ -1,108 +1,108 @@ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:9:5 + --> $DIR/drop_ref.rs:10:5 | LL | drop(&SomeStruct); | ^^^^^^^^^^^^^^^^^ | = note: `-D clippy::drop-ref` implied by `-D warnings` note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:9:10 + --> $DIR/drop_ref.rs:10: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:12:5 + --> $DIR/drop_ref.rs:13:5 | LL | drop(&owned1); | ^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:12:10 + --> $DIR/drop_ref.rs:13: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: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(&mut owned1); | ^^^^^^^^^^^^^^^^^ | note: argument has type `&mut SomeStruct` - --> $DIR/drop_ref.rs:14:10 + --> $DIR/drop_ref.rs:15: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:18:5 + --> $DIR/drop_ref.rs:19:5 | LL | drop(reference1); | ^^^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:18:10 + --> $DIR/drop_ref.rs:19: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:21:5 + --> $DIR/drop_ref.rs:22:5 | LL | drop(reference2); | ^^^^^^^^^^^^^^^^ | note: argument has type `&mut SomeStruct` - --> $DIR/drop_ref.rs:21:10 + --> $DIR/drop_ref.rs:22: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:24:5 + --> $DIR/drop_ref.rs:25:5 | LL | drop(reference3); | ^^^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:24:10 + --> $DIR/drop_ref.rs:25: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:29:5 + --> $DIR/drop_ref.rs:30:5 | LL | drop(&val); | ^^^^^^^^^^ | note: argument has type `&T` - --> $DIR/drop_ref.rs:29:10 + --> $DIR/drop_ref.rs:30: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:37:5 + --> $DIR/drop_ref.rs:38:5 | LL | std::mem::drop(&SomeStruct); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:37:20 + --> $DIR/drop_ref.rs:38:20 | LL | std::mem::drop(&SomeStruct); | ^^^^^^^^^^^ diff --git a/tests/ui/map_err.rs b/tests/ui/map_err.rs new file mode 100644 index 0000000000000..f3a74ad95cd29 --- /dev/null +++ b/tests/ui/map_err.rs @@ -0,0 +1,24 @@ +use std::convert::TryFrom; +use std::error::Error; +use std::fmt; + +#[derive(Debug)] +enum Errors { + Ignored, +} + +impl Error for Errors {} + +impl fmt::Display for Errors { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Error") + } +} + +fn main() -> Result<(), Errors> { + let x = u32::try_from(-123_i32); + + println!("{:?}", x.map_err(|_| Errors::Ignored)); + + Ok(()) +} diff --git a/tests/ui/map_err.stderr b/tests/ui/map_err.stderr new file mode 100644 index 0000000000000..8cd37d8c02526 --- /dev/null +++ b/tests/ui/map_err.stderr @@ -0,0 +1,10 @@ +error: `map_err` has thrown away the original error + --> $DIR/map_err.rs:21:32 + | +LL | println!("{:?}", x.map_err(|_| Errors::Ignored)); + | ^^^ help: Allow the error enum to encapsulate the original error: `|e| Errors::Ignored(e)` + | + = note: `-D clippy::map-err-ignore` implied by `-D warnings` + +error: aborting due to previous error + From 337729137bdec31b55665653ef0cf7dc124b0eaa Mon Sep 17 00:00:00 2001 From: Ricky Date: Tue, 1 Sep 2020 17:05:40 -0400 Subject: [PATCH 0071/1052] Ran cargo dev update_lints --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 2 +- src/lintlist/mod.rs | 7 +++++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 99a8b1a6293c3..dfe45a46f0927 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1675,6 +1675,7 @@ Released 2018-09-13 [`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names [`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone [`map_entry`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_entry +[`map_err_ignore`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_err_ignore [`map_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_flatten [`map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_identity [`map_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 8e80779377bcd..3794cae091a42 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1538,7 +1538,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&manual_async_fn::MANUAL_ASYNC_FN), LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), LintId::of(&map_clone::MAP_CLONE), - LintId::of(&map_err_ignore::MAP_ERR_IGNORE), + LintId::of(&map_err_ignore::MAP_ERR_IGNORE), LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH), LintId::of(&matches::MATCH_LIKE_MATCHES_MACRO), LintId::of(&matches::MATCH_OVERLAPPING_ARM), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index dff19ef440f31..6725c97f79383 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1165,6 +1165,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "entry", }, + Lint { + name: "map_err_ignore", + group: "style", + desc: "`map_err` should not ignore the original error", + deprecation: None, + module: "map_err_ignore", + }, Lint { name: "map_flatten", group: "pedantic", From a5754a1fad6eeb765bc825dcc657134985576787 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Wed, 2 Sep 2020 08:57:00 +0200 Subject: [PATCH 0072/1052] Run cargo dev fmt --- clippy_lints/src/utils/ast_utils.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/utils/ast_utils.rs b/clippy_lints/src/utils/ast_utils.rs index 3c3f8b26e3ac1..fa8dd210ebadd 100644 --- a/clippy_lints/src/utils/ast_utils.rs +++ b/clippy_lints/src/utils/ast_utils.rs @@ -191,7 +191,9 @@ pub fn eq_stmt(l: &Stmt, r: &Stmt) -> bool { (Item(l), Item(r)) => eq_item(l, r, eq_item_kind), (Expr(l), Expr(r)) | (Semi(l), Semi(r)) => eq_expr(l, r), (Empty, Empty) => true, - (MacCall(l), MacCall(r)) => l.style == r.style && eq_mac_call(&l.mac, &r.mac) && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)), + (MacCall(l), MacCall(r)) => { + l.style == r.style && eq_mac_call(&l.mac, &r.mac) && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) + }, _ => false, } } From 321b680fe66d1be04cd67fac75ff7f148fd117fe Mon Sep 17 00:00:00 2001 From: Federico Ponzi Date: Wed, 2 Sep 2020 10:48:11 +0200 Subject: [PATCH 0073/1052] Update docs of OpenOptions::as_flags --- library/std/src/sys/unix/ext/fs.rs | 5 ++--- library/std/src/sys/unix/fs.rs | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/unix/ext/fs.rs b/library/std/src/sys/unix/ext/fs.rs index afda21d00e050..16fe316110d94 100644 --- a/library/std/src/sys/unix/ext/fs.rs +++ b/library/std/src/sys/unix/ext/fs.rs @@ -346,10 +346,9 @@ pub trait OpenOptionsExt { #[stable(feature = "open_options_ext", since = "1.10.0")] fn custom_flags(&mut self, flags: i32) -> &mut Self; - /// Get the flags of this OpenOptions as [`libc::c_int`]. - /// With: [`libc::open`] + /// Get the flags as [`libc::c_int`]. /// - /// This method allows the reuse of the OpenOptions as flags argument for [`fs::OpenOptions`]. + /// This method allows the reuse of the OpenOptions as flags argument for [`libc::open`]. /// /// [`libc::c_int`]: https://docs.rs/libc/*/libc/type.c_int.html /// [`libc::open`]: https://docs.rs/libc/*/libc/fn.open.html diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 1281fcc47bcb3..6f1db6503f1c1 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -655,6 +655,7 @@ impl OpenOptions { pub fn mode(&mut self, mode: u32) { self.mode = mode as mode_t; } + pub fn as_flags(&self) -> io::Result { let access_mode = self.get_access_mode()?; let creation_mode = self.get_creation_mode()?; From 246f1f8a8eccf4d997e85ed80097f9263624c4a4 Mon Sep 17 00:00:00 2001 From: Sasha Date: Mon, 31 Aug 2020 11:45:50 +0200 Subject: [PATCH 0074/1052] Improve recovery on malformed format call If a comma in a format call is replaced with a similar token, then we emit an error and continue parsing, instead of stopping at this point. --- tests/ui/issue-3145.rs | 2 +- tests/ui/issue-3145.stderr | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/ui/issue-3145.rs b/tests/ui/issue-3145.rs index f497d5550af5f..586d13647d15e 100644 --- a/tests/ui/issue-3145.rs +++ b/tests/ui/issue-3145.rs @@ -1,3 +1,3 @@ fn main() { - println!("{}" a); //~ERROR expected token: `,` + println!("{}" a); //~ERROR expected `,`, found `a` } diff --git a/tests/ui/issue-3145.stderr b/tests/ui/issue-3145.stderr index cb0d95f5e2643..a35032aa150dc 100644 --- a/tests/ui/issue-3145.stderr +++ b/tests/ui/issue-3145.stderr @@ -1,7 +1,7 @@ -error: expected token: `,` +error: expected `,`, found `a` --> $DIR/issue-3145.rs:2:19 | -LL | println!("{}" a); //~ERROR expected token: `,` +LL | println!("{}" a); //~ERROR expected `,`, found `a` | ^ expected `,` error: aborting due to previous error From 22c994061359aa9e0e08e44cd698dbfc6553834c Mon Sep 17 00:00:00 2001 From: Koxiaet <38139193+Koxiaet@users.noreply.github.com> Date: Wed, 2 Sep 2020 12:51:44 +0100 Subject: [PATCH 0075/1052] Add tests for allowed non-backticked identifiers in doc --- tests/ui/doc.rs | 13 +++++++++--- tests/ui/doc.stderr | 50 +++++++++++++++++++++++++-------------------- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/tests/ui/doc.rs b/tests/ui/doc.rs index 77620c857e66e..68c5d32846f19 100644 --- a/tests/ui/doc.rs +++ b/tests/ui/doc.rs @@ -49,6 +49,16 @@ fn test_emphasis() { fn test_units() { } +/// This tests allowed identifiers. +/// DirectX +/// ECMAScript +/// OAuth GraphQL +/// TeX LaTeX BibTeX BibLaTeX +/// CamelCase (see also #2395) +/// be_sure_we_got_to_the_end_of_it +fn test_allowed() { +} + /// This test has [a link_with_underscores][chunked-example] inside it. See #823. /// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues) /// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link]. @@ -168,9 +178,6 @@ fn issue_1920() {} /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels fn issue_1832() {} -/// Ok: CamelCase (It should not be surrounded by backticks) -fn issue_2395() {} - /// An iterator over mycrate::Collection's values. /// It should not lint a `'static` lifetime in ticks. fn issue_2210() {} diff --git a/tests/ui/doc.stderr b/tests/ui/doc.stderr index ae9bb394cb9ac..23fca43590b4f 100644 --- a/tests/ui/doc.stderr +++ b/tests/ui/doc.stderr @@ -54,131 +54,137 @@ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the doc LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation + --> $DIR/doc.rs:58:5 + | +LL | /// be_sure_we_got_to_the_end_of_it + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: you should put `link_with_underscores` between ticks in the documentation - --> $DIR/doc.rs:52:22 + --> $DIR/doc.rs:62:22 | LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823. | ^^^^^^^^^^^^^^^^^^^^^ error: you should put `inline_link2` between ticks in the documentation - --> $DIR/doc.rs:55:21 + --> $DIR/doc.rs:65:21 | LL | /// It can also be [inline_link2]. | ^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:65:5 + --> $DIR/doc.rs:75:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:73:8 + --> $DIR/doc.rs:83:8 | LL | /// ## CamelCaseThing | ^^^^^^^^^^^^^^ error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:76:7 + --> $DIR/doc.rs:86:7 | LL | /// # CamelCaseThing | ^^^^^^^^^^^^^^ error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:78:22 + --> $DIR/doc.rs:88:22 | LL | /// Not a title #897 CamelCaseThing | ^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:79:5 + --> $DIR/doc.rs:89:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:86:5 + --> $DIR/doc.rs:96:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:99:5 + --> $DIR/doc.rs:109:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `FooBar` between ticks in the documentation - --> $DIR/doc.rs:110:43 + --> $DIR/doc.rs:120:43 | LL | /** E.g., serialization of an empty list: FooBar | ^^^^^^ error: you should put `BarQuz` between ticks in the documentation - --> $DIR/doc.rs:115:5 + --> $DIR/doc.rs:125:5 | LL | And BarQuz too. | ^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:116:1 + --> $DIR/doc.rs:126:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `FooBar` between ticks in the documentation - --> $DIR/doc.rs:121:43 + --> $DIR/doc.rs:131:43 | LL | /** E.g., serialization of an empty list: FooBar | ^^^^^^ error: you should put `BarQuz` between ticks in the documentation - --> $DIR/doc.rs:126:5 + --> $DIR/doc.rs:136:5 | LL | And BarQuz too. | ^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:127:1 + --> $DIR/doc.rs:137:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:138:5 + --> $DIR/doc.rs:148:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:165:13 + --> $DIR/doc.rs:175:13 | LL | /// Not ok: http://www.unicode.org | ^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:166:13 + --> $DIR/doc.rs:176:13 | LL | /// Not ok: https://www.unicode.org | ^^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:167:13 + --> $DIR/doc.rs:177:13 | LL | /// Not ok: http://www.unicode.org/ | ^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:168:13 + --> $DIR/doc.rs:178:13 | LL | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `mycrate::Collection` between ticks in the documentation - --> $DIR/doc.rs:174:22 + --> $DIR/doc.rs:181:22 | LL | /// An iterator over mycrate::Collection's values. | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 30 previous errors +error: aborting due to 31 previous errors From b220ddf146f4c11011b2e1b7f37ecb8e5485555b Mon Sep 17 00:00:00 2001 From: Tim Nielens Date: Wed, 2 Sep 2020 23:30:40 +0200 Subject: [PATCH 0076/1052] unit-arg - pr remarks --- clippy_lints/src/types.rs | 82 ++++++++++++++++++------------ clippy_lints/src/utils/mod.rs | 96 ++++++++++++++++++++--------------- 2 files changed, 103 insertions(+), 75 deletions(-) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 16e48d919164f..e83d491fac3b9 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -31,8 +31,8 @@ use crate::utils::paths; use crate::utils::{ clip, comparisons, differing_macro_contexts, higher, in_constant, indent_of, int_bits, is_type_diagnostic_item, last_path_segment, match_def_path, match_path, method_chain_args, multispan_sugg, numeric_literal::NumericLiteral, - qpath_res, sext, snippet, snippet_opt, snippet_with_applicability, snippet_with_macro_callsite, span_lint, - span_lint_and_help, span_lint_and_sugg, span_lint_and_then, trim_multiline, unsext, + qpath_res, reindent_multiline, sext, snippet, snippet_opt, snippet_with_applicability, snippet_with_macro_callsite, + span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, unsext, }; declare_clippy_lint! { @@ -802,7 +802,45 @@ impl<'tcx> LateLintPass<'tcx> for UnitArg { } } -#[allow(clippy::too_many_lines)] +fn fmt_stmts_and_call( + cx: &LateContext<'_>, + call_expr: &Expr<'_>, + call_snippet: &str, + args_snippets: &[impl AsRef], + non_empty_block_args_snippets: &[impl AsRef], +) -> String { + let call_expr_indent = indent_of(cx, call_expr.span).unwrap_or(0); + let call_snippet_with_replacements = args_snippets + .iter() + .fold(call_snippet.to_owned(), |acc, arg| acc.replacen(arg.as_ref(), "()", 1)); + + let mut stmts_and_call = non_empty_block_args_snippets + .iter() + .map(|it| it.as_ref().to_owned()) + .collect::>(); + stmts_and_call.push(call_snippet_with_replacements); + stmts_and_call = stmts_and_call + .into_iter() + .map(|v| reindent_multiline(v.into(), true, Some(call_expr_indent)).into_owned()) + .collect(); + + let mut stmts_and_call_snippet = stmts_and_call.join(&format!("{}{}", ";\n", " ".repeat(call_expr_indent))); + // expr is not in a block statement or result expression position, wrap in a block + let parent_node = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(call_expr.hir_id)); + if !matches!(parent_node, Some(Node::Block(_))) && !matches!(parent_node, Some(Node::Stmt(_))) { + let block_indent = call_expr_indent + 4; + stmts_and_call_snippet = + reindent_multiline(stmts_and_call_snippet.into(), true, Some(block_indent)).into_owned(); + stmts_and_call_snippet = format!( + "{{\n{}{}\n{}}}", + " ".repeat(block_indent), + &stmts_and_call_snippet, + " ".repeat(call_expr_indent) + ); + } + stmts_and_call_snippet +} + fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Expr<'_>]) { let mut applicability = Applicability::MachineApplicable; let (singular, plural) = if args_to_recover.len() > 1 { @@ -857,37 +895,15 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp .filter(|arg| !is_empty_block(arg)) .filter_map(|arg| snippet_opt(cx, arg.span)) .collect(); - let indent = indent_of(cx, expr.span).unwrap_or(0); - - if let Some(expr_str) = snippet_opt(cx, expr.span) { - let expr_with_replacements = arg_snippets - .iter() - .fold(expr_str, |acc, arg| acc.replacen(arg, "()", 1)); - - // expr is not in a block statement or result expression position, wrap in a block - let parent_node = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(expr.hir_id)); - let wrap_in_block = - !matches!(parent_node, Some(Node::Block(_))) && !matches!(parent_node, Some(Node::Stmt(_))); - - let stmts_indent = if wrap_in_block { indent + 4 } else { indent }; - let mut stmts_and_call = arg_snippets_without_empty_blocks.clone(); - stmts_and_call.push(expr_with_replacements); - let mut stmts_and_call_str = stmts_and_call - .into_iter() - .enumerate() - .map(|(i, v)| { - let with_indent_prefix = if i > 0 { " ".repeat(stmts_indent) + &v } else { v }; - trim_multiline(with_indent_prefix.into(), true, Some(stmts_indent)).into_owned() - }) - .collect::>() - .join(";\n"); - - if wrap_in_block { - stmts_and_call_str = " ".repeat(stmts_indent) + &stmts_and_call_str; - stmts_and_call_str = format!("{{\n{}\n{}}}", &stmts_and_call_str, " ".repeat(indent)); - } - let sugg = stmts_and_call_str; + if let Some(call_snippet) = snippet_opt(cx, expr.span) { + let sugg = fmt_stmts_and_call( + cx, + expr, + &call_snippet, + &arg_snippets, + &arg_snippets_without_empty_blocks, + ); if arg_snippets_without_empty_blocks.is_empty() { db.multipart_suggestion( diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 4ce4cdeefb48f..f394b980127c4 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -19,6 +19,7 @@ pub mod paths; pub mod ptr; pub mod sugg; pub mod usage; + pub use self::attrs::*; pub use self::diagnostics::*; pub use self::hir_utils::{both, eq_expr_value, over, SpanlessEq, SpanlessHash}; @@ -108,6 +109,7 @@ pub fn in_macro(span: Span) -> bool { false } } + // If the snippet is empty, it's an attribute that was inserted during macro // expansion and we want to ignore those, because they could come from external // sources that the user has no control over. @@ -571,7 +573,7 @@ pub fn snippet_block<'a, T: LintContext>( ) -> Cow<'a, str> { let snip = snippet(cx, span, default); let indent = indent_relative_to.and_then(|s| indent_of(cx, s)); - trim_multiline(snip, true, indent) + reindent_multiline(snip, true, indent) } /// Same as `snippet_block`, but adapts the applicability level by the rules of @@ -585,7 +587,7 @@ pub fn snippet_block_with_applicability<'a, T: LintContext>( ) -> Cow<'a, str> { let snip = snippet_with_applicability(cx, span, default, applicability); let indent = indent_relative_to.and_then(|s| indent_of(cx, s)); - trim_multiline(snip, true, indent) + reindent_multiline(snip, true, indent) } /// Returns a new Span that extends the original Span to the first non-whitespace char of the first @@ -661,16 +663,16 @@ pub fn expr_block<'a, T: LintContext>( } } -/// Trim indentation from a multiline string with possibility of ignoring the -/// first line. -pub fn trim_multiline(s: Cow<'_, str>, ignore_first: bool, indent: Option) -> Cow<'_, str> { - let s_space = trim_multiline_inner(s, ignore_first, indent, ' '); - let s_tab = trim_multiline_inner(s_space, ignore_first, indent, '\t'); - trim_multiline_inner(s_tab, ignore_first, indent, ' ') +/// Reindent a multiline string with possibility of ignoring the first line. +#[allow(clippy::needless_pass_by_value)] +pub fn reindent_multiline(s: Cow<'_, str>, ignore_first: bool, indent: Option) -> Cow<'_, str> { + let s_space = reindent_multiline_inner(&s, ignore_first, indent, ' '); + let s_tab = reindent_multiline_inner(&s_space, ignore_first, indent, '\t'); + reindent_multiline_inner(&s_tab, ignore_first, indent, ' ').into() } -fn trim_multiline_inner(s: Cow<'_, str>, ignore_first: bool, indent: Option, ch: char) -> Cow<'_, str> { - let mut x = s +fn reindent_multiline_inner(s: &str, ignore_first: bool, indent: Option, ch: char) -> String { + let x = s .lines() .skip(ignore_first as usize) .filter_map(|l| { @@ -683,26 +685,20 @@ fn trim_multiline_inner(s: Cow<'_, str>, ignore_first: bool, indent: Option 0 { - Cow::Owned( - s.lines() - .enumerate() - .map(|(i, l)| { - if (ignore_first && i == 0) || l.is_empty() { - l - } else { - l.split_at(x).1 - } - }) - .collect::>() - .join("\n"), - ) - } else { - s - } + let indent = indent.unwrap_or(0); + s.lines() + .enumerate() + .map(|(i, l)| { + if (ignore_first && i == 0) || l.is_empty() { + l.to_owned() + } else if x > indent { + l.split_at(x - indent).1.to_owned() + } else { + " ".repeat(indent - x) + l + } + }) + .collect::>() + .join("\n") } /// Gets the parent expression, if any –- this is useful to constrain a lint. @@ -1475,26 +1471,26 @@ macro_rules! unwrap_cargo_metadata { #[cfg(test)] mod test { - use super::{trim_multiline, without_block_comments}; + use super::{reindent_multiline, without_block_comments}; #[test] - fn test_trim_multiline_single_line() { - assert_eq!("", trim_multiline("".into(), false, None)); - assert_eq!("...", trim_multiline("...".into(), false, None)); - assert_eq!("...", trim_multiline(" ...".into(), false, None)); - assert_eq!("...", trim_multiline("\t...".into(), false, None)); - assert_eq!("...", trim_multiline("\t\t...".into(), false, None)); + fn test_reindent_multiline_single_line() { + assert_eq!("", reindent_multiline("".into(), false, None)); + assert_eq!("...", reindent_multiline("...".into(), false, None)); + assert_eq!("...", reindent_multiline(" ...".into(), false, None)); + assert_eq!("...", reindent_multiline("\t...".into(), false, None)); + assert_eq!("...", reindent_multiline("\t\t...".into(), false, None)); } #[test] #[rustfmt::skip] - fn test_trim_multiline_block() { + fn test_reindent_multiline_block() { assert_eq!("\ if x { y } else { z - }", trim_multiline(" if x { + }", reindent_multiline(" if x { y } else { z @@ -1504,7 +1500,7 @@ mod test { \ty } else { \tz - }", trim_multiline(" if x { + }", reindent_multiline(" if x { \ty } else { \tz @@ -1513,14 +1509,14 @@ mod test { #[test] #[rustfmt::skip] - fn test_trim_multiline_empty_line() { + fn test_reindent_multiline_empty_line() { assert_eq!("\ if x { y } else { z - }", trim_multiline(" if x { + }", reindent_multiline(" if x { y } else { @@ -1528,6 +1524,22 @@ mod test { }".into(), false, None)); } + #[test] + #[rustfmt::skip] + fn test_reindent_multiline_lines_deeper() { + assert_eq!("\ + if x { + y + } else { + z + }", reindent_multiline("\ + if x { + y + } else { + z + }".into(), true, Some(8))); + } + #[test] fn test_without_block_comments_lines_without_block_comments() { let result = without_block_comments(vec!["/*", "", "*/"]); From a80d39041e2d5cd58a846c9ef9e01ee9d691a7ed Mon Sep 17 00:00:00 2001 From: Howard Su Date: Thu, 3 Sep 2020 06:31:21 +0800 Subject: [PATCH 0077/1052] Use inline(never) instead of cold inline(never) is better way to avoid optimizer to inline the function instead of cold. --- library/std/src/thread/local.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 9d8c6f1815eeb..60a05dc5d545b 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -424,10 +424,9 @@ pub mod fast { // thread_local's, or it is being recursively initialized. // // Macos: Inlining this function can cause two `tlv_get_addr` calls to - // be performed for every call to `Key::get`. The #[cold] hint makes - // that less likely. + // be performed for every call to `Key::get`. // LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722 - #[cold] + #[inline(never)] unsafe fn try_initialize T>(&self, init: F) -> Option<&'static T> { if !mem::needs_drop::() || self.try_register_dtor() { Some(self.inner.initialize(init)) From 2387f68e437bf2ff5f117f63936257ce64052cfa Mon Sep 17 00:00:00 2001 From: Ricky Date: Wed, 2 Sep 2020 19:21:34 -0400 Subject: [PATCH 0078/1052] Removed map_err suggestion in lint, and updated lint documentation example --- clippy_lints/src/map_err_ignore.rs | 117 ++++++++++++++--------------- tests/ui/map_err.stderr | 5 +- 2 files changed, 60 insertions(+), 62 deletions(-) diff --git a/clippy_lints/src/map_err_ignore.rs b/clippy_lints/src/map_err_ignore.rs index 43bfcf0b8f147..9211113ed0467 100644 --- a/clippy_lints/src/map_err_ignore.rs +++ b/clippy_lints/src/map_err_ignore.rs @@ -1,6 +1,6 @@ -use crate::utils::span_lint_and_sugg; -use rustc_errors::Applicability; -use rustc_hir::{CaptureBy, Expr, ExprKind, PatKind, QPath}; +use crate::utils::span_lint_and_help; + +use rustc_hir::{CaptureBy, Expr, ExprKind, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -12,33 +12,58 @@ declare_clippy_lint! { /// **Known problems:** None. /// /// **Example:** - /// + /// Before: /// ```rust + /// use std::convert::TryFrom; + /// + /// #[derive(Debug)] /// enum Errors { - /// Ignore - ///} - ///fn main() -> Result<(), Errors> { + /// Ignored + /// } /// - /// let x = u32::try_from(-123_i32); + /// fn divisible_by_3(inp: i32) -> Result { + /// let i = u32::try_from(inp).map_err(|_| Errors::Ignored)?; /// - /// println!("{:?}", x.map_err(|_| Errors::Ignore)); + /// Ok(i) + /// } + /// ``` /// - /// Ok(()) - ///} - /// ``` - /// Use instead: - /// ```rust - /// enum Errors { - /// WithContext(TryFromIntError) - ///} - ///fn main() -> Result<(), Errors> { + /// After: + /// ```rust + /// use std::convert::TryFrom; + /// use std::num::TryFromIntError; + /// use std::fmt; + /// use std::error::Error; + /// + /// #[derive(Debug)] + /// enum ParseError { + /// Indivisible { + /// source: TryFromIntError, + /// input: String, + /// } + /// } + /// + /// impl fmt::Display for ParseError { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// match &self { + /// ParseError::Indivisible{source: _, input} => write!(f, "Error: {}", input) + /// } + /// } + /// } + /// + /// impl Error for ParseError {} /// - /// let x = u32::try_from(-123_i32); + /// impl ParseError { + /// fn new(source: TryFromIntError, input: String) -> ParseError { + /// ParseError::Indivisible{source, input} + /// } + /// } /// - /// println!("{:?}", x.map_err(|e| Errors::WithContext(e))); + /// fn divisible_by_3(inp: i32) -> Result { + /// let i = u32::try_from(inp).map_err(|e| ParseError::new(e, e.to_string()))?; /// - /// Ok(()) - ///} + /// Ok(i) + /// } /// ``` pub MAP_ERR_IGNORE, style, @@ -69,44 +94,16 @@ impl<'tcx> LateLintPass<'tcx> for MapErrIgnore { if closure_body.params.len() == 1 { // make sure that parameter is the wild token (`_`) if let PatKind::Wild = closure_body.params[0].pat.kind { - // Check the value of the closure to see if we can build the enum we are throwing away - // the error for make sure this is a Path - if let ExprKind::Path(q_path) = &closure_body.value.kind { - // this should be a resolved path, only keep the path field - if let QPath::Resolved(_, path) = q_path { - // finally get the idents for each path segment collect them as a string and - // join them with the path separator ("::"") - let closure_fold: String = path - .segments - .iter() - .map(|x| x.ident.as_str().to_string()) - .collect::>() - .join("::"); - //Span the body of the closure (the |...| bit) and suggest the fix by taking - // the error and encapsulating it in the enum - span_lint_and_sugg( - cx, - MAP_ERR_IGNORE, - body_span, - "`map_err` has thrown away the original error", - "Allow the error enum to encapsulate the original error", - format!("|e| {}(e)", closure_fold), - Applicability::HasPlaceholders, - ); - } - } else { - //If we cannot build the enum in a human readable way just suggest not throwing way - // the error - span_lint_and_sugg( - cx, - MAP_ERR_IGNORE, - body_span, - "`map_err` has thrown away the original error", - "Allow the error enum to encapsulate the original error", - "|e|".to_string(), - Applicability::HasPlaceholders, - ); - } + // span the area of the closure capture and warn that the + // original error will be thrown away + span_lint_and_help( + cx, + MAP_ERR_IGNORE, + body_span, + "`map_else(|_|...` ignores the original error", + None, + "Consider wrapping the error in an enum variant", + ); } } } diff --git a/tests/ui/map_err.stderr b/tests/ui/map_err.stderr index 8cd37d8c02526..7a269ab95ab27 100644 --- a/tests/ui/map_err.stderr +++ b/tests/ui/map_err.stderr @@ -1,10 +1,11 @@ -error: `map_err` has thrown away the original error +error: `map_else(|_|...` ignores the original error --> $DIR/map_err.rs:21:32 | LL | println!("{:?}", x.map_err(|_| Errors::Ignored)); - | ^^^ help: Allow the error enum to encapsulate the original error: `|e| Errors::Ignored(e)` + | ^^^ | = note: `-D clippy::map-err-ignore` implied by `-D warnings` + = help: Consider wrapping the error in an enum variant error: aborting due to previous error From 93ce686b5df94f52a040a05c9434b4341efffec5 Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Thu, 3 Sep 2020 04:58:14 +0200 Subject: [PATCH 0079/1052] Update ui stderr with improved rustc output Related rust pull request: rust-lang/rust#76160 --- tests/ui/issue-3145.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/issue-3145.stderr b/tests/ui/issue-3145.stderr index cb0d95f5e2643..8f2922b022ab7 100644 --- a/tests/ui/issue-3145.stderr +++ b/tests/ui/issue-3145.stderr @@ -1,4 +1,4 @@ -error: expected token: `,` +error: expected `,`, found `a` --> $DIR/issue-3145.rs:2:19 | LL | println!("{}" a); //~ERROR expected token: `,` From 28db5214d2c48e7a58cf79b9e272097260910a33 Mon Sep 17 00:00:00 2001 From: Federico Ponzi Date: Wed, 2 Sep 2020 23:25:09 +0200 Subject: [PATCH 0080/1052] More implementations of Write for immutable refs Fixes #73836 --- library/std/src/io/stdio.rs | 54 +++++++++++++++++++++++++++++++++++++ library/std/src/io/util.rs | 24 +++++++++++++++++ library/std/src/process.rs | 19 +++++++++++++ 3 files changed, 97 insertions(+) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 3943c66aad53a..f320cf907c365 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -606,6 +606,33 @@ impl Write for Stdout { self.lock().write_fmt(args) } } + +#[stable(feature = "write_mt", since = "1.47.0")] +impl Write for &Stdout { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.lock().write(buf) + } + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + self.lock().write_vectored(bufs) + } + #[inline] + fn is_write_vectored(&self) -> bool { + self.lock().is_write_vectored() + } + fn flush(&mut self) -> io::Result<()> { + self.lock().flush() + } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + self.lock().write_all(buf) + } + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + self.lock().write_all_vectored(bufs) + } + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { + self.lock().write_fmt(args) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Write for StdoutLock<'_> { fn write(&mut self, buf: &[u8]) -> io::Result { @@ -782,6 +809,33 @@ impl Write for Stderr { self.lock().write_fmt(args) } } + +#[stable(feature = "write_mt", since = "1.47.0")] +impl Write for &Stderr { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.lock().write(buf) + } + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + self.lock().write_vectored(bufs) + } + #[inline] + fn is_write_vectored(&self) -> bool { + self.lock().is_write_vectored() + } + fn flush(&mut self) -> io::Result<()> { + self.lock().flush() + } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + self.lock().write_all(buf) + } + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + self.lock().write_all_vectored(bufs) + } + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { + self.lock().write_fmt(args) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Write for StderrLock<'_> { fn write(&mut self, buf: &[u8]) -> io::Result { diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index a093b745b0c13..ce4dd1dcd493d 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -248,6 +248,30 @@ impl Write for Sink { } } +#[stable(feature = "write_mt", since = "1.47.0")] +impl Write for &Sink { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + Ok(buf.len()) + } + + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + let total_len = bufs.iter().map(|b| b.len()).sum(); + Ok(total_len) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Sink { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/library/std/src/process.rs b/library/std/src/process.rs index c42bc1096528b..36521fdaec00f 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -262,6 +262,25 @@ impl Write for ChildStdin { } } +#[stable(feature = "write_mt", since = "1.47.0")] +impl Write for &ChildStdin { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.inner.write(buf) + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + self.inner.write_vectored(bufs) + } + + fn is_write_vectored(&self) -> bool { + self.inner.is_write_vectored() + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + impl AsInner for ChildStdin { fn as_inner(&self) -> &AnonPipe { &self.inner From 0b5e681f5af0d3989b49121969f09cf29f029263 Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Thu, 3 Sep 2020 10:13:32 +0200 Subject: [PATCH 0081/1052] Improve SGX RWLock initializer test --- library/std/src/sys/sgx/rwlock/tests.rs | 34 ++++++++----------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/library/std/src/sys/sgx/rwlock/tests.rs b/library/std/src/sys/sgx/rwlock/tests.rs index 05b36c633f861..17c9e72ee39fa 100644 --- a/library/std/src/sys/sgx/rwlock/tests.rs +++ b/library/std/src/sys/sgx/rwlock/tests.rs @@ -1,14 +1,12 @@ use super::*; -use crate::mem::{self, MaybeUninit}; -use core::array::FixedSizeArray; -// Verify that the bytes of initialized RWLock are the same as in -// libunwind. If they change, `src/UnwindRustSgx.h` in libunwind needs to -// be changed too. +// Verify that the byte pattern libunwind uses to initialize an RWLock is +// equivalent to the value of RWLock::new(). If the value changes, +// `src/UnwindRustSgx.h` in libunwind needs to be changed too. #[test] fn test_c_rwlock_initializer() { #[rustfmt::skip] - const RWLOCK_INIT: &[u8] = &[ + const C_RWLOCK_INIT: &[u8] = &[ /* 0x00 */ 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 0x10 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 0x20 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, @@ -20,24 +18,14 @@ fn test_c_rwlock_initializer() { /* 0x80 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ]; - #[inline(never)] - fn zero_stack() { - test::black_box(MaybeUninit::<[RWLock; 16]>::zeroed()); - } - - #[inline(never)] - unsafe fn rwlock_new(init: &mut MaybeUninit) { - init.write(RWLock::new()); - } + // For the test to work, we need the padding/unused bytes in RWLock to be + // initialized as 0. In practice, this is the case with statics. + static RUST_RWLOCK_INIT: RWLock = RWLock::new(); unsafe { - // try hard to make sure that the padding/unused bytes in RWLock - // get initialized as 0. If the assertion below fails, that might - // just be an issue with the test code and not with the value of - // RWLOCK_INIT. - zero_stack(); - let mut init = MaybeUninit::::zeroed(); - rwlock_new(&mut init); - assert_eq!(mem::transmute::<_, [u8; 144]>(init.assume_init()).as_slice(), RWLOCK_INIT) + // If the assertion fails, that not necessarily an issue with the value + // of C_RWLOCK_INIT. It might just be an issue with the way padding + // bytes are initialized in the test code. + assert_eq!(&crate::mem::transmute_copy::<_, [u8; 144]>(&RUST_RWLOCK_INIT), C_RWLOCK_INIT); }; } From 4231fbc0a8cb4b2b0df431d8ffcf308f837e07e3 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 3 Sep 2020 15:37:03 +0200 Subject: [PATCH 0082/1052] Condense StringReader's API to a single function --- compiler/rustc_parse/src/lexer/mod.rs | 45 +++++++------------ compiler/rustc_parse/src/lexer/tokentrees.rs | 2 +- .../rustc_parse/src/lexer/unicode_chars.rs | 2 +- compiler/rustc_parse/src/lib.rs | 9 +++- 4 files changed, 25 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 034442b798b29..8099b8a24658d 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -1,22 +1,19 @@ use rustc_ast::ast::AttrStyle; use rustc_ast::token::{self, CommentKind, Token, TokenKind}; -use rustc_ast::tokenstream::IsJoint; -use rustc_data_structures::sync::Lrc; -use rustc_errors::{error_code, Applicability, DiagnosticBuilder, FatalError}; -use rustc_lexer::Base; -use rustc_lexer::{unescape, RawStrError}; +use rustc_ast::tokenstream::{IsJoint, TokenStream}; +use rustc_errors::{error_code, Applicability, DiagnosticBuilder, FatalError, PResult}; +use rustc_lexer::unescape::{self, Mode}; +use rustc_lexer::{Base, DocStyle, RawStrError}; use rustc_session::parse::ParseSess; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{BytePos, Pos, Span}; -use std::char; use tracing::debug; mod tokentrees; mod unescape_error_reporting; mod unicode_chars; -use rustc_lexer::{unescape::Mode, DocStyle}; use unescape_error_reporting::{emit_unescape_error, push_escaped_char}; #[derive(Clone, Debug)] @@ -28,7 +25,17 @@ pub struct UnmatchedBrace { pub candidate_span: Option, } -crate struct StringReader<'a> { +crate fn parse_token_trees<'a>( + sess: &'a ParseSess, + src: &'a str, + start_pos: BytePos, + override_span: Option, +) -> (PResult<'a, TokenStream>, Vec) { + StringReader { sess, start_pos, pos: start_pos, end_src_index: src.len(), src, override_span } + .into_token_trees() +} + +struct StringReader<'a> { sess: &'a ParseSess, /// Initial position, read-only. start_pos: BytePos, @@ -37,31 +44,11 @@ crate struct StringReader<'a> { /// Stop reading src at this index. end_src_index: usize, /// Source text to tokenize. - src: Lrc, + src: &'a str, override_span: Option, } impl<'a> StringReader<'a> { - crate fn new( - sess: &'a ParseSess, - source_file: Lrc, - override_span: Option, - ) -> Self { - let src = source_file.src.clone().unwrap_or_else(|| { - sess.span_diagnostic - .bug(&format!("cannot lex `source_file` without source: {}", source_file.name)); - }); - - StringReader { - sess, - start_pos: source_file.start_pos, - pos: source_file.start_pos, - end_src_index: src.len(), - src, - override_span, - } - } - fn mk_sp(&self, lo: BytePos, hi: BytePos) -> Span { self.override_span.unwrap_or_else(|| Span::with_root_ctxt(lo, hi)) } diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index d5977ca3c7d2f..357b10ab89d41 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -12,7 +12,7 @@ use rustc_errors::PResult; use rustc_span::Span; impl<'a> StringReader<'a> { - crate fn into_token_trees(self) -> (PResult<'a, TokenStream>, Vec) { + pub(super) fn into_token_trees(self) -> (PResult<'a, TokenStream>, Vec) { let mut tt_reader = TokenTreesReader { string_reader: self, token: Token::dummy(), diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs index 8dc0db01ecb51..40e2e34aa0589 100644 --- a/compiler/rustc_parse/src/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -332,7 +332,7 @@ const ASCII_ARRAY: &[(char, &str, Option)] = &[ ('"', "Quotation Mark", None), ]; -crate fn check_for_substitution<'a>( +pub(super) fn check_for_substitution<'a>( reader: &StringReader<'a>, pos: BytePos, ch: char, diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 462279b0a9e03..b804e8a825f37 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -200,8 +200,13 @@ pub fn maybe_file_to_stream( source_file: Lrc, override_span: Option, ) -> Result<(TokenStream, Vec), Vec> { - let srdr = lexer::StringReader::new(sess, source_file, override_span); - let (token_trees, unmatched_braces) = srdr.into_token_trees(); + let src = source_file.src.as_ref().unwrap_or_else(|| { + sess.span_diagnostic + .bug(&format!("cannot lex `source_file` without source: {}", source_file.name)); + }); + + let (token_trees, unmatched_braces) = + lexer::parse_token_trees(sess, src.as_str(), source_file.start_pos, override_span); match token_trees { Ok(stream) => Ok((stream, unmatched_braces)), From 9daf8fd5b1d369cd2f91ac919dc5d17f4fd43c0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Thu, 3 Sep 2020 00:00:00 +0000 Subject: [PATCH 0083/1052] inliner: Emit storage markers for introduced arg temporaries When introducing argument temporaries during inlining, emit storage marker statements just before the assignment and in the beginning of the return block. This ensures that such temporaries will not be considered live across yield points after inlining inside a generator. --- compiler/rustc_mir/src/transform/inline.rs | 36 ++++++++++++++----- .../inline_any_operand.bar.Inline.after.mir | 4 +++ .../inline_closure.foo.Inline.after.mir | 4 +++ ...e_closure_borrows_arg.foo.Inline.after.mir | 4 +++ ...line_closure_captures.foo.Inline.after.mir | 2 ++ .../ui/mir/issue-71793-inline-args-storage.rs | 16 +++++++++ 6 files changed, 58 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/mir/issue-71793-inline-args-storage.rs diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs index 428f4e138c7f9..b451ee672f6cb 100644 --- a/compiler/rustc_mir/src/transform/inline.rs +++ b/compiler/rustc_mir/src/transform/inline.rs @@ -494,7 +494,7 @@ impl Inliner<'tcx> { let return_block = destination.1; // Copy the arguments if needed. - let args: Vec<_> = self.make_call_args(args, &callsite, caller_body); + let args: Vec<_> = self.make_call_args(args, &callsite, caller_body, return_block); let bb_len = caller_body.basic_blocks().len(); let mut integrator = Integrator { @@ -541,6 +541,7 @@ impl Inliner<'tcx> { args: Vec>, callsite: &CallSite<'tcx>, caller_body: &mut Body<'tcx>, + return_block: BasicBlock, ) -> Vec { let tcx = self.tcx; @@ -569,8 +570,18 @@ impl Inliner<'tcx> { // and the vector is `[closure_ref, tmp0, tmp1, tmp2]`. if tcx.is_closure(callsite.callee) { let mut args = args.into_iter(); - let self_ = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body); - let tuple = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body); + let self_ = self.create_temp_if_necessary( + args.next().unwrap(), + callsite, + caller_body, + return_block, + ); + let tuple = self.create_temp_if_necessary( + args.next().unwrap(), + callsite, + caller_body, + return_block, + ); assert!(args.next().is_none()); let tuple = Place::from(tuple); @@ -590,13 +601,13 @@ impl Inliner<'tcx> { Operand::Move(tcx.mk_place_field(tuple, Field::new(i), ty.expect_ty())); // Spill to a local to make e.g., `tmp0`. - self.create_temp_if_necessary(tuple_field, callsite, caller_body) + self.create_temp_if_necessary(tuple_field, callsite, caller_body, return_block) }); closure_ref_arg.chain(tuple_tmp_args).collect() } else { args.into_iter() - .map(|a| self.create_temp_if_necessary(a, callsite, caller_body)) + .map(|a| self.create_temp_if_necessary(a, callsite, caller_body, return_block)) .collect() } } @@ -608,6 +619,7 @@ impl Inliner<'tcx> { arg: Operand<'tcx>, callsite: &CallSite<'tcx>, caller_body: &mut Body<'tcx>, + return_block: BasicBlock, ) -> Local { // FIXME: Analysis of the usage of the arguments to avoid // unnecessary temporaries. @@ -630,11 +642,19 @@ impl Inliner<'tcx> { let arg_tmp = LocalDecl::new(ty, callsite.location.span); let arg_tmp = caller_body.local_decls.push(arg_tmp); - let stmt = Statement { + caller_body[callsite.bb].statements.push(Statement { + source_info: callsite.location, + kind: StatementKind::StorageLive(arg_tmp), + }); + caller_body[callsite.bb].statements.push(Statement { source_info: callsite.location, kind: StatementKind::Assign(box (Place::from(arg_tmp), arg)), - }; - caller_body[callsite.bb].statements.push(stmt); + }); + caller_body[return_block].statements.insert( + 0, + Statement { source_info: callsite.location, kind: StatementKind::StorageDead(arg_tmp) }, + ); + arg_tmp } } diff --git a/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir b/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir index 9d490f047f735..756f31315f18a 100644 --- a/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir @@ -22,9 +22,13 @@ fn bar() -> bool { // + literal: Const { ty: fn(i32, i32) -> bool {foo}, val: Value(Scalar()) } StorageLive(_2); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6 _2 = _1; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6 + StorageLive(_3); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 _3 = const 1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + StorageLive(_4); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 _4 = const -1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 _0 = Eq(move _3, move _4); // scope 2 at $DIR/inline-any-operand.rs:17:5: 17:11 + StorageDead(_4); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + StorageDead(_3); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 StorageDead(_2); // scope 1 at $DIR/inline-any-operand.rs:12:12: 12:13 StorageDead(_1); // scope 0 at $DIR/inline-any-operand.rs:13:1: 13:2 return; // scope 0 at $DIR/inline-any-operand.rs:13:2: 13:2 diff --git a/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir index b40a8047c4185..6ecbd3022e389 100644 --- a/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir @@ -30,9 +30,13 @@ fn foo(_1: T, _2: i32) -> i32 { _7 = _2; // scope 1 at $DIR/inline-closure.rs:12:10: 12:11 (_5.0: i32) = move _6; // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 (_5.1: i32) = move _7; // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 + StorageLive(_8); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 _8 = move (_5.0: i32); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 + StorageLive(_9); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 _9 = move (_5.1: i32); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 _0 = _8; // scope 2 at $DIR/inline-closure.rs:11:22: 11:24 + StorageDead(_9); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 + StorageDead(_8); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 StorageDead(_7); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12 StorageDead(_6); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12 StorageDead(_5); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12 diff --git a/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir index f6dd741364039..7475be30c0dff 100644 --- a/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir @@ -33,9 +33,13 @@ fn foo(_1: T, _2: &i32) -> i32 { _7 = &(*_2); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:10: 16:11 (_5.0: &i32) = move _6; // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 (_5.1: &i32) = move _7; // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + StorageLive(_8); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 _8 = move (_5.0: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + StorageLive(_9); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 _9 = move (_5.1: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 _0 = (*_8); // scope 3 at $DIR/inline-closure-borrows-arg.rs:14:9: 14:18 + StorageDead(_9); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + StorageDead(_8); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 StorageDead(_7); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12 StorageDead(_6); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12 StorageDead(_5); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12 diff --git a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir index e2b5d6567c299..0258e3c2e4b38 100644 --- a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir @@ -38,6 +38,7 @@ fn foo(_1: T, _2: i32) -> (i32, T) { StorageLive(_8); // scope 1 at $DIR/inline-closure-captures.rs:12:7: 12:8 _8 = _2; // scope 1 at $DIR/inline-closure-captures.rs:12:7: 12:8 (_7.0: i32) = move _8; // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 + StorageLive(_11); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 _11 = move (_7.0: i32); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 StorageLive(_9); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 _9 = (*((*_6).0: &i32)); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 @@ -47,6 +48,7 @@ fn foo(_1: T, _2: i32) -> (i32, T) { (_0.1: T) = move _10; // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24 StorageDead(_10); // scope 2 at $DIR/inline-closure-captures.rs:11:23: 11:24 StorageDead(_9); // scope 2 at $DIR/inline-closure-captures.rs:11:23: 11:24 + StorageDead(_11); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 StorageDead(_8); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9 StorageDead(_7); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9 StorageDead(_6); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9 diff --git a/src/test/ui/mir/issue-71793-inline-args-storage.rs b/src/test/ui/mir/issue-71793-inline-args-storage.rs new file mode 100644 index 0000000000000..87b2806d4e208 --- /dev/null +++ b/src/test/ui/mir/issue-71793-inline-args-storage.rs @@ -0,0 +1,16 @@ +// Verifies that inliner emits StorageLive & StorageDead when introducing +// temporaries for arguments, so that they don't become part of the generator. +// Regression test for #71793. +// +// check-pass +// edition:2018 +// compile-args: -Zmir-opt-level=2 + +#![crate_type = "lib"] + +pub async fn connect() {} + +pub async fn connect_many() { + Vec::::new().first().ok_or("").unwrap(); + connect().await; +} From ccf41dd5eb42730b1de6a4bc9d95c03dca0a8143 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 3 Sep 2020 17:21:53 +0200 Subject: [PATCH 0084/1052] Rename IsJoint -> Spacing To match better naming from proc-macro --- compiler/rustc_ast/src/attr/mod.rs | 16 ++++---- compiler/rustc_ast/src/tokenstream.rs | 41 +++++++++---------- compiler/rustc_expand/src/mbe/transcribe.rs | 4 +- .../rustc_expand/src/proc_macro_server.rs | 12 +++--- compiler/rustc_parse/src/lexer/mod.rs | 14 +++---- compiler/rustc_parse/src/lexer/tokentrees.rs | 22 +++++----- compiler/rustc_parse/src/lib.rs | 4 +- compiler/rustc_parse/src/parser/mod.rs | 10 ++--- .../ast-json/ast-json-noexpand-output.stdout | 2 +- src/test/ui/ast-json/ast-json-output.stdout | 2 +- 10 files changed, 62 insertions(+), 65 deletions(-) diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 12d6f7cc33ddc..d819e3cb8152e 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -8,7 +8,7 @@ use crate::ast::{Path, PathSegment}; use crate::mut_visit::visit_clobber; use crate::ptr::P; use crate::token::{self, CommentKind, Token}; -use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; +use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndSpacing}; use rustc_index::bit_set::GrowableBitSet; use rustc_span::source_map::{BytePos, Spanned}; @@ -361,7 +361,7 @@ pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool { } impl MetaItem { - fn token_trees_and_joints(&self) -> Vec { + fn token_trees_and_spacings(&self) -> Vec { let mut idents = vec![]; let mut last_pos = BytePos(0 as u32); for (i, segment) in self.path.segments.iter().enumerate() { @@ -374,7 +374,7 @@ impl MetaItem { idents.push(TokenTree::Token(Token::from_ast_ident(segment.ident)).into()); last_pos = segment.ident.span.hi(); } - idents.extend(self.kind.token_trees_and_joints(self.span)); + idents.extend(self.kind.token_trees_and_spacings(self.span)); idents } @@ -447,7 +447,7 @@ impl MetaItemKind { if i > 0 { tts.push(TokenTree::token(token::Comma, span).into()); } - tts.extend(item.token_trees_and_joints()) + tts.extend(item.token_trees_and_spacings()) } MacArgs::Delimited( DelimSpan::from_single(span), @@ -458,7 +458,7 @@ impl MetaItemKind { } } - fn token_trees_and_joints(&self, span: Span) -> Vec { + fn token_trees_and_spacings(&self, span: Span) -> Vec { match *self { MetaItemKind::Word => vec![], MetaItemKind::NameValue(ref lit) => { @@ -470,7 +470,7 @@ impl MetaItemKind { if i > 0 { tokens.push(TokenTree::token(token::Comma, span).into()); } - tokens.extend(item.token_trees_and_joints()) + tokens.extend(item.token_trees_and_spacings()) } vec![ TokenTree::Delimited( @@ -553,9 +553,9 @@ impl NestedMetaItem { } } - fn token_trees_and_joints(&self) -> Vec { + fn token_trees_and_spacings(&self) -> Vec { match *self { - NestedMetaItem::MetaItem(ref item) => item.token_trees_and_joints(), + NestedMetaItem::MetaItem(ref item) => item.token_trees_and_spacings(), NestedMetaItem::Literal(ref lit) => vec![lit.token_tree().into()], } } diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 151acddae840e..f201f0b5c6643 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -83,7 +83,7 @@ impl TokenTree { } pub fn joint(self) -> TokenStream { - TokenStream::new(vec![(self, Joint)]) + TokenStream::new(vec![(self, Spacing::Joint)]) } pub fn token(kind: TokenKind, span: Span) -> TokenTree { @@ -125,22 +125,20 @@ where /// instead of a representation of the abstract syntax tree. /// Today's `TokenTree`s can still contain AST via `token::Interpolated` for back-compat. #[derive(Clone, Debug, Default, Encodable, Decodable)] -pub struct TokenStream(pub Lrc>); +pub struct TokenStream(pub Lrc>); -pub type TreeAndJoint = (TokenTree, IsJoint); +pub type TreeAndSpacing = (TokenTree, Spacing); // `TokenStream` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] rustc_data_structures::static_assert_size!(TokenStream, 8); #[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable)] -pub enum IsJoint { +pub enum Spacing { + Alone, Joint, - NonJoint, } -use IsJoint::*; - impl TokenStream { /// Given a `TokenStream` with a `Stream` of only two arguments, return a new `TokenStream` /// separating the two arguments with a comma for diagnostic suggestions. @@ -153,7 +151,7 @@ impl TokenStream { let sp = match (&ts, &next) { (_, (TokenTree::Token(Token { kind: token::Comma, .. }), _)) => continue, ( - (TokenTree::Token(token_left), NonJoint), + (TokenTree::Token(token_left), Spacing::Alone), (TokenTree::Token(token_right), _), ) if ((token_left.is_ident() && !token_left.is_reserved_ident()) || token_left.is_lit()) @@ -162,11 +160,11 @@ impl TokenStream { { token_left.span } - ((TokenTree::Delimited(sp, ..), NonJoint), _) => sp.entire(), + ((TokenTree::Delimited(sp, ..), Spacing::Alone), _) => sp.entire(), _ => continue, }; let sp = sp.shrink_to_hi(); - let comma = (TokenTree::token(token::Comma, sp), NonJoint); + let comma = (TokenTree::token(token::Comma, sp), Spacing::Alone); suggestion = Some((pos, comma, sp)); } } @@ -184,19 +182,19 @@ impl TokenStream { impl From for TokenStream { fn from(tree: TokenTree) -> TokenStream { - TokenStream::new(vec![(tree, NonJoint)]) + TokenStream::new(vec![(tree, Spacing::Alone)]) } } -impl From for TreeAndJoint { - fn from(tree: TokenTree) -> TreeAndJoint { - (tree, NonJoint) +impl From for TreeAndSpacing { + fn from(tree: TokenTree) -> TreeAndSpacing { + (tree, Spacing::Alone) } } impl iter::FromIterator for TokenStream { fn from_iter>(iter: I) -> Self { - TokenStream::new(iter.into_iter().map(Into::into).collect::>()) + TokenStream::new(iter.into_iter().map(Into::into).collect::>()) } } @@ -209,7 +207,7 @@ impl PartialEq for TokenStream { } impl TokenStream { - pub fn new(streams: Vec) -> TokenStream { + pub fn new(streams: Vec) -> TokenStream { TokenStream(Lrc::new(streams)) } @@ -320,11 +318,11 @@ impl TokenStreamBuilder { // If `self` is not empty and the last tree within the last stream is a // token tree marked with `Joint`... if let Some(TokenStream(ref mut last_stream_lrc)) = self.0.last_mut() { - if let Some((TokenTree::Token(last_token), Joint)) = last_stream_lrc.last() { + if let Some((TokenTree::Token(last_token), Spacing::Joint)) = last_stream_lrc.last() { // ...and `stream` is not empty and the first tree within it is // a token tree... let TokenStream(ref mut stream_lrc) = stream; - if let Some((TokenTree::Token(token), is_joint)) = stream_lrc.first() { + if let Some((TokenTree::Token(token), spacing)) = stream_lrc.first() { // ...and the two tokens can be glued together... if let Some(glued_tok) = last_token.glue(&token) { // ...then do so, by overwriting the last token @@ -337,8 +335,7 @@ impl TokenStreamBuilder { // Overwrite the last token tree with the merged // token. let last_vec_mut = Lrc::make_mut(last_stream_lrc); - *last_vec_mut.last_mut().unwrap() = - (TokenTree::Token(glued_tok), *is_joint); + *last_vec_mut.last_mut().unwrap() = (TokenTree::Token(glued_tok), *spacing); // Remove the first token tree from `stream`. (This // is almost always the only tree in `stream`.) @@ -375,7 +372,7 @@ impl Iterator for Cursor { type Item = TokenTree; fn next(&mut self) -> Option { - self.next_with_joint().map(|(tree, _)| tree) + self.next_with_spacing().map(|(tree, _)| tree) } } @@ -384,7 +381,7 @@ impl Cursor { Cursor { stream, index: 0 } } - pub fn next_with_joint(&mut self) -> Option { + pub fn next_with_spacing(&mut self) -> Option { if self.index < self.stream.len() { self.index += 1; Some(self.stream.0[self.index - 1].clone()) diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index b908a12c1fc9e..0e5c5fe4d4473 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -4,7 +4,7 @@ use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch}; use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::token::{self, NtTT, Token}; -use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; +use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndSpacing}; use rustc_ast::MacCall; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; @@ -111,7 +111,7 @@ pub(super) fn transcribe<'a>( // // Thus, if we try to pop the `result_stack` and it is empty, we have reached the top-level // again, and we are done transcribing. - let mut result: Vec = Vec::new(); + let mut result: Vec = Vec::new(); let mut result_stack = Vec::new(); let mut marker = Marker(cx.current_expansion.id, transparency); diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 39c82f97e0a39..ec41fd7a3eebe 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -2,7 +2,7 @@ use crate::base::ExtCtxt; use rustc_ast as ast; use rustc_ast::token; -use rustc_ast::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint}; +use rustc_ast::tokenstream::{self, DelimSpan, Spacing::*, TokenStream, TreeAndSpacing}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; use rustc_errors::Diagnostic; @@ -47,15 +47,15 @@ impl ToInternal for Delimiter { } } -impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec)> +impl FromInternal<(TreeAndSpacing, &'_ ParseSess, &'_ mut Vec)> for TokenTree { fn from_internal( - ((tree, is_joint), sess, stack): (TreeAndJoint, &ParseSess, &mut Vec), + ((tree, spacing), sess, stack): (TreeAndSpacing, &ParseSess, &mut Vec), ) -> Self { use rustc_ast::token::*; - let joint = is_joint == Joint; + let joint = spacing == Joint; let Token { kind, span } = match tree { tokenstream::TokenTree::Delimited(span, delim, tts) => { let delimiter = Delimiter::from_internal(delim); @@ -261,7 +261,7 @@ impl ToInternal for TokenTree { }; let tree = tokenstream::TokenTree::token(kind, span); - TokenStream::new(vec![(tree, if joint { Joint } else { NonJoint })]) + TokenStream::new(vec![(tree, if joint { Joint } else { Alone })]) } } @@ -444,7 +444,7 @@ impl server::TokenStreamIter for Rustc<'_> { ) -> Option> { loop { let tree = iter.stack.pop().or_else(|| { - let next = iter.cursor.next_with_joint()?; + let next = iter.cursor.next_with_spacing()?; Some(TokenTree::from_internal((next, self.sess, &mut iter.stack))) })?; // A hack used to pass AST fragments to attribute and derive macros diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 8099b8a24658d..32b124970cf7c 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -1,6 +1,6 @@ use rustc_ast::ast::AttrStyle; use rustc_ast::token::{self, CommentKind, Token, TokenKind}; -use rustc_ast::tokenstream::{IsJoint, TokenStream}; +use rustc_ast::tokenstream::{Spacing, TokenStream}; use rustc_errors::{error_code, Applicability, DiagnosticBuilder, FatalError, PResult}; use rustc_lexer::unescape::{self, Mode}; use rustc_lexer::{Base, DocStyle, RawStrError}; @@ -54,8 +54,8 @@ impl<'a> StringReader<'a> { } /// Returns the next token, and info about preceding whitespace, if any. - fn next_token(&mut self) -> (IsJoint, Token) { - let mut is_joint = IsJoint::Joint; + fn next_token(&mut self) -> (Spacing, Token) { + let mut spacing = Spacing::Joint; // Skip `#!` at the start of the file let start_src_index = self.src_index(self.pos); @@ -64,7 +64,7 @@ impl<'a> StringReader<'a> { if is_beginning_of_file { if let Some(shebang_len) = rustc_lexer::strip_shebang(text) { self.pos = self.pos + BytePos::from_usize(shebang_len); - is_joint = IsJoint::NonJoint; + spacing = Spacing::Alone; } } @@ -75,7 +75,7 @@ impl<'a> StringReader<'a> { if text.is_empty() { let span = self.mk_sp(self.pos, self.pos); - return (is_joint, Token::new(token::Eof, span)); + return (spacing, Token::new(token::Eof, span)); } let token = rustc_lexer::first_token(text); @@ -88,9 +88,9 @@ impl<'a> StringReader<'a> { match self.cook_lexer_token(token.kind, start) { Some(kind) => { let span = self.mk_sp(start, self.pos); - return (is_joint, Token::new(kind, span)); + return (spacing, Token::new(kind, span)); } - None => is_joint = IsJoint::NonJoint, + None => spacing = Spacing::Alone, } } } diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index 357b10ab89d41..0f364bffb134e 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -3,8 +3,8 @@ use super::{StringReader, UnmatchedBrace}; use rustc_ast::token::{self, DelimToken, Token}; use rustc_ast::tokenstream::{ DelimSpan, - IsJoint::{self, *}, - TokenStream, TokenTree, TreeAndJoint, + Spacing::{self, *}, + TokenStream, TokenTree, TreeAndSpacing, }; use rustc_ast_pretty::pprust::token_to_string; use rustc_data_structures::fx::FxHashMap; @@ -77,7 +77,7 @@ impl<'a> TokenTreesReader<'a> { } } - fn parse_token_tree(&mut self) -> PResult<'a, TreeAndJoint> { + fn parse_token_tree(&mut self) -> PResult<'a, TreeAndSpacing> { let sm = self.string_reader.sess.source_map(); match self.token.kind { @@ -262,29 +262,29 @@ impl<'a> TokenTreesReader<'a> { } _ => { let tt = TokenTree::Token(self.token.take()); - let mut is_joint = self.bump(); + let mut spacing = self.bump(); if !self.token.is_op() { - is_joint = NonJoint; + spacing = Alone; } - Ok((tt, is_joint)) + Ok((tt, spacing)) } } } - fn bump(&mut self) -> IsJoint { - let (joint_to_prev, token) = self.string_reader.next_token(); + fn bump(&mut self) -> Spacing { + let (spacing, token) = self.string_reader.next_token(); self.token = token; - joint_to_prev + spacing } } #[derive(Default)] struct TokenStreamBuilder { - buf: Vec, + buf: Vec, } impl TokenStreamBuilder { - fn push(&mut self, (tree, joint): TreeAndJoint) { + fn push(&mut self, (tree, joint): TreeAndSpacing) { if let Some((TokenTree::Token(prev_token), Joint)) = self.buf.last() { if let TokenTree::Token(token) = &tree { if let Some(glued) = prev_token.glue(token) { diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index b804e8a825f37..e7fd74f551aaa 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -8,7 +8,7 @@ use rustc_ast as ast; use rustc_ast::token::{self, DelimToken, Nonterminal, Token, TokenKind}; -use rustc_ast::tokenstream::{self, IsJoint, TokenStream, TokenTree}; +use rustc_ast::tokenstream::{self, Spacing, TokenStream, TokenTree}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; use rustc_errors::{Diagnostic, FatalError, Level, PResult}; @@ -437,7 +437,7 @@ pub fn tokenstream_probably_equal_for_proc_macro( // issue #75734 tracks resolving this. nt_to_tokenstream(nt, sess, *span).into_trees() } else { - TokenStream::new(vec![(tree, IsJoint::NonJoint)]).into_trees() + TokenStream::new(vec![(tree, Spacing::Alone)]).into_trees() } }; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 84edfecad192f..d22d08cd14438 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -15,7 +15,7 @@ pub use path::PathStyle; use rustc_ast::ptr::P; use rustc_ast::token::{self, DelimToken, Token, TokenKind}; -use rustc_ast::tokenstream::{self, DelimSpan, TokenStream, TokenTree, TreeAndJoint}; +use rustc_ast::tokenstream::{self, DelimSpan, TokenStream, TokenTree, TreeAndSpacing}; use rustc_ast::DUMMY_NODE_ID; use rustc_ast::{self as ast, AttrStyle, AttrVec, Const, CrateSugar, Extern, Unsafe}; use rustc_ast::{Async, MacArgs, MacDelimiter, Mutability, StrLit, Visibility, VisibilityKind}; @@ -118,7 +118,7 @@ impl<'a> Drop for Parser<'a> { struct TokenCursor { frame: TokenCursorFrame, stack: Vec, - cur_token: Option, + cur_token: Option, collecting: Option, } @@ -136,7 +136,7 @@ struct TokenCursorFrame { struct Collecting { /// Holds the current tokens captured during the most /// recent call to `collect_tokens` - buf: Vec, + buf: Vec, /// The depth of the `TokenCursor` stack at the time /// collection was started. When we encounter a `TokenTree::Delimited`, /// we want to record the `TokenTree::Delimited` itself, @@ -167,7 +167,7 @@ impl TokenCursor { let tree = if !self.frame.open_delim { self.frame.open_delim = true; TokenTree::open_tt(self.frame.span, self.frame.delim).into() - } else if let Some(tree) = self.frame.tree_cursor.next_with_joint() { + } else if let Some(tree) = self.frame.tree_cursor.next_with_spacing() { tree } else if !self.frame.close_delim { self.frame.close_delim = true; @@ -1154,7 +1154,7 @@ impl<'a> Parser<'a> { f: impl FnOnce(&mut Self) -> PResult<'a, R>, ) -> PResult<'a, (R, TokenStream)> { // Record all tokens we parse when parsing this item. - let tokens: Vec = self.token_cursor.cur_token.clone().into_iter().collect(); + let tokens: Vec = self.token_cursor.cur_token.clone().into_iter().collect(); debug!("collect_tokens: starting with {:?}", tokens); // We need special handling for the case where `collect_tokens` is called diff --git a/src/test/ui/ast-json/ast-json-noexpand-output.stdout b/src/test/ui/ast-json/ast-json-noexpand-output.stdout index d0942f78bb86c..031c0d0cae51c 100644 --- a/src/test/ui/ast-json/ast-json-noexpand-output.stdout +++ b/src/test/ui/ast-json/ast-json-noexpand-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"NonJoint"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} +{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout index dc06fd74a4bb5..9b3b6870cbe7e 100644 --- a/src/test/ui/ast-json/ast-json-output.stdout +++ b/src/test/ui/ast-json/ast-json-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"NonJoint"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} +{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} From 4b132eefb48880a7a3781efe844d13845b070c07 Mon Sep 17 00:00:00 2001 From: kadmin Date: Sat, 22 Aug 2020 03:32:07 +0000 Subject: [PATCH 0085/1052] Initial commit --- compiler/rustc_typeck/src/astconv/generics.rs | 58 ++++++++++++++----- src/test/ui/const-generics/invalid-enum.rs | 17 ++++++ .../ui/const-generics/invalid-enum.stderr | 27 +++++++++ .../const-generics/issues/issue-62878.stderr | 2 + 4 files changed, 90 insertions(+), 14 deletions(-) create mode 100644 src/test/ui/const-generics/invalid-enum.rs create mode 100644 src/test/ui/const-generics/invalid-enum.stderr diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index 84dab6de95819..43c7b30b78887 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -367,7 +367,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } if position != GenericArgPosition::Type && !args.bindings.is_empty() { - Self::prohibit_assoc_ty_binding(tcx, args.bindings[0].span); + AstConv::prohibit_assoc_ty_binding(tcx, args.bindings[0].span); } let explicit_late_bound = @@ -392,7 +392,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } if silent { - return Err(true); + return Err((0i32, None)); } // Unfortunately lifetime and type parameter mismatches are typically styled @@ -441,16 +441,25 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { for span in spans { err.span_label(span, label.as_str()); } - err.emit(); - Err(true) + assert_ne!(bound, provided); + Err((bound as i32 - provided as i32, Some(err))) }; + let emit_correct = + |correct: Result<(), (_, Option>)>| match correct { + Ok(()) => Ok(()), + Err((v, None)) => Err(v == 0), + Err((v, Some(mut err))) => { + err.emit(); + Err(v == 0) + } + }; - let mut arg_count_correct = Ok(()); let mut unexpected_spans = vec![]; + let mut lifetime_count_correct = Ok(()); if !infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes { - arg_count_correct = check_kind_count( + lifetime_count_correct = check_kind_count( "lifetime", param_counts.lifetimes, param_counts.lifetimes, @@ -458,12 +467,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { 0, &mut unexpected_spans, explicit_late_bound == ExplicitLateBound::Yes, - ) - .and(arg_count_correct); + ); } + // FIXME(const_generics:defaults) + let mut const_count_correct = Ok(()); if !infer_args || arg_counts.consts > param_counts.consts { - arg_count_correct = check_kind_count( + const_count_correct = check_kind_count( "const", param_counts.consts, param_counts.consts, @@ -471,13 +481,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { arg_counts.lifetimes + arg_counts.types, &mut unexpected_spans, false, - ) - .and(arg_count_correct); + ); } + // Note that type errors are currently be emitted *after* const errors. + let mut type_count_correct = Ok(()); if !infer_args || arg_counts.types > param_counts.types - defaults.types - has_self as usize { - arg_count_correct = check_kind_count( + type_count_correct = check_kind_count( "type", param_counts.types - defaults.types - has_self as usize, param_counts.types - has_self as usize, @@ -485,10 +496,29 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { arg_counts.lifetimes, &mut unexpected_spans, false, - ) - .and(arg_count_correct); + ); } + // Emit a help message if it's possible that a type could be surrounded in braces + if let Err((c_mismatch, Some(ref mut _const_err))) = &mut const_count_correct { + if let Err((t_mismatch, Some(ref mut type_err))) = &mut type_count_correct { + if *c_mismatch == -*t_mismatch && *t_mismatch < 0 { + for i in 0..*c_mismatch as usize { + // let t_span = unexpected_type_spans[i].clone(); + let ident = args.args[arg_counts.lifetimes + i].id(); + type_err.help(&format!( + "For more complex types, surround with braces: `{{ {} }}`", + ident, + )); + } + } + } + } + + let arg_count_correct = emit_correct(lifetime_count_correct) + .and(emit_correct(const_count_correct)) + .and(emit_correct(type_count_correct)); + GenericArgCountResult { explicit_late_bound, correct: arg_count_correct.map_err(|reported_err| GenericArgCountMismatch { diff --git a/src/test/ui/const-generics/invalid-enum.rs b/src/test/ui/const-generics/invalid-enum.rs new file mode 100644 index 0000000000000..05c13e8fe0c88 --- /dev/null +++ b/src/test/ui/const-generics/invalid-enum.rs @@ -0,0 +1,17 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +#[derive(PartialEq, Eq)] +enum CompileFlag { + A, + B, +} + +pub fn test() {} + +pub fn main() { + test::(); + //~^ ERROR: expected type, found variant + //~| ERROR: wrong number of const arguments + //~| ERROR: wrong number of type arguments +} diff --git a/src/test/ui/const-generics/invalid-enum.stderr b/src/test/ui/const-generics/invalid-enum.stderr new file mode 100644 index 0000000000000..096e478d4abb0 --- /dev/null +++ b/src/test/ui/const-generics/invalid-enum.stderr @@ -0,0 +1,27 @@ +error[E0573]: expected type, found variant `CompileFlag::A` + --> $DIR/invalid-enum.rs:13:10 + | +LL | test::(); + | ^^^^^^^^^^^^^^ + | | + | not a type + | help: try using the variant's enum: `CompileFlag` + +error[E0107]: wrong number of const arguments: expected 1, found 0 + --> $DIR/invalid-enum.rs:13:3 + | +LL | test::(); + | ^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument + +error[E0107]: wrong number of type arguments: expected 0, found 1 + --> $DIR/invalid-enum.rs:13:10 + | +LL | test::(); + | ^^^^^^^^^^^^^^ unexpected type argument + | + = help: For more complex types, surround with braces: `{ HirId { owner: DefId(0:5 ~ invalid_enum[317d]::main[0]), local_id: 1 } }` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0107, E0573. +For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/const-generics/issues/issue-62878.stderr b/src/test/ui/const-generics/issues/issue-62878.stderr index fe0990d8241fa..702fbfe84de62 100644 --- a/src/test/ui/const-generics/issues/issue-62878.stderr +++ b/src/test/ui/const-generics/issues/issue-62878.stderr @@ -24,6 +24,8 @@ error[E0107]: wrong number of type arguments: expected 0, found 1 | LL | foo::<_, {[1]}>(); | ^ unexpected type argument + | + = help: For more complex types, surround with braces: `{ HirId { owner: DefId(0:7 ~ issue_62878[317d]::main[0]), local_id: 1 } }` error[E0308]: mismatched types --> $DIR/issue-62878.rs:7:15 From 8d9187597a5e8ebcf17acba6b234884252b1a543 Mon Sep 17 00:00:00 2001 From: kadmin Date: Fri, 21 Aug 2020 06:55:14 +0000 Subject: [PATCH 0086/1052] Update to use multipart suggestion Nice. --- compiler/rustc_typeck/src/astconv/generics.rs | 43 ++++++++++++------- .../ui/const-generics/invalid-enum.stderr | 5 ++- .../const-generics/issues/issue-62878.stderr | 2 - 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index 43c7b30b78887..b7336fcd36991 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -2,7 +2,7 @@ use crate::astconv::{ AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgPosition, }; use rustc_ast::ast::ParamKindOrd; -use rustc_errors::{pluralize, struct_span_err, DiagnosticId, ErrorReported}; +use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorReported}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{GenericArg, GenericArgs}; @@ -448,10 +448,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let emit_correct = |correct: Result<(), (_, Option>)>| match correct { Ok(()) => Ok(()), - Err((v, None)) => Err(v == 0), - Err((v, Some(mut err))) => { + Err((_, None)) => Err(()), + Err((_, Some(mut err))) => { err.emit(); - Err(v == 0) + Err(()) } }; @@ -500,16 +500,27 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } // Emit a help message if it's possible that a type could be surrounded in braces - if let Err((c_mismatch, Some(ref mut _const_err))) = &mut const_count_correct { - if let Err((t_mismatch, Some(ref mut type_err))) = &mut type_count_correct { - if *c_mismatch == -*t_mismatch && *t_mismatch < 0 { - for i in 0..*c_mismatch as usize { - // let t_span = unexpected_type_spans[i].clone(); - let ident = args.args[arg_counts.lifetimes + i].id(); - type_err.help(&format!( - "For more complex types, surround with braces: `{{ {} }}`", - ident, - )); + if let Err((c_mismatch, Some(ref mut _const_err))) = const_count_correct { + if let Err((t_mismatch, Some(ref mut type_err))) = type_count_correct { + if c_mismatch == -t_mismatch && t_mismatch < 0 { + for i in 0..c_mismatch as usize { + let arg = &args.args[arg_counts.lifetimes + i]; + match arg { + GenericArg::Type(hir::Ty { + kind: hir::TyKind::Path { .. }, .. + }) => {} + _ => continue, + } + let suggestions = vec![ + (arg.span().shrink_to_lo(), String::from("{ ")), + (arg.span().shrink_to_hi(), String::from(" }")), + ]; + type_err.multipart_suggestion( + "If this generic argument was intended as a const parameter, \ + try surrounding it with braces:", + suggestions, + Applicability::MaybeIncorrect, + ); } } } @@ -521,8 +532,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { GenericArgCountResult { explicit_late_bound, - correct: arg_count_correct.map_err(|reported_err| GenericArgCountMismatch { - reported: if reported_err { Some(ErrorReported) } else { None }, + correct: arg_count_correct.map_err(|()| GenericArgCountMismatch { + reported: Some(ErrorReported), invalid_args: unexpected_spans, }), } diff --git a/src/test/ui/const-generics/invalid-enum.stderr b/src/test/ui/const-generics/invalid-enum.stderr index 096e478d4abb0..3291b62ea9fbb 100644 --- a/src/test/ui/const-generics/invalid-enum.stderr +++ b/src/test/ui/const-generics/invalid-enum.stderr @@ -19,7 +19,10 @@ error[E0107]: wrong number of type arguments: expected 0, found 1 LL | test::(); | ^^^^^^^^^^^^^^ unexpected type argument | - = help: For more complex types, surround with braces: `{ HirId { owner: DefId(0:5 ~ invalid_enum[317d]::main[0]), local_id: 1 } }` +help: If this generic argument was intended as a const parameter, try surrounding it with braces: + | +LL | test::<{ CompileFlag::A }>(); + | ^ ^ error: aborting due to 3 previous errors diff --git a/src/test/ui/const-generics/issues/issue-62878.stderr b/src/test/ui/const-generics/issues/issue-62878.stderr index 702fbfe84de62..fe0990d8241fa 100644 --- a/src/test/ui/const-generics/issues/issue-62878.stderr +++ b/src/test/ui/const-generics/issues/issue-62878.stderr @@ -24,8 +24,6 @@ error[E0107]: wrong number of type arguments: expected 0, found 1 | LL | foo::<_, {[1]}>(); | ^ unexpected type argument - | - = help: For more complex types, surround with braces: `{ HirId { owner: DefId(0:7 ~ issue_62878[317d]::main[0]), local_id: 1 } }` error[E0308]: mismatched types --> $DIR/issue-62878.rs:7:15 From 96bb2c86f2cfe03ad870d12b3b838e8b75eb1978 Mon Sep 17 00:00:00 2001 From: kadmin Date: Mon, 31 Aug 2020 17:12:53 +0000 Subject: [PATCH 0087/1052] Add further tests and liberalize type checking --- compiler/rustc_typeck/src/astconv/generics.rs | 61 ++++++------ src/test/ui/const-generics/invalid-enum.rs | 26 ++++- .../ui/const-generics/invalid-enum.stderr | 99 ++++++++++++++++--- 3 files changed, 139 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index b7336fcd36991..eb2207a0d675d 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -445,15 +445,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assert_ne!(bound, provided); Err((bound as i32 - provided as i32, Some(err))) }; - let emit_correct = - |correct: Result<(), (_, Option>)>| match correct { - Ok(()) => Ok(()), - Err((_, None)) => Err(()), - Err((_, Some(mut err))) => { - err.emit(); - Err(()) - } - }; let mut unexpected_spans = vec![]; @@ -501,31 +492,41 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Emit a help message if it's possible that a type could be surrounded in braces if let Err((c_mismatch, Some(ref mut _const_err))) = const_count_correct { - if let Err((t_mismatch, Some(ref mut type_err))) = type_count_correct { - if c_mismatch == -t_mismatch && t_mismatch < 0 { - for i in 0..c_mismatch as usize { - let arg = &args.args[arg_counts.lifetimes + i]; - match arg { - GenericArg::Type(hir::Ty { - kind: hir::TyKind::Path { .. }, .. - }) => {} - _ => continue, - } - let suggestions = vec![ - (arg.span().shrink_to_lo(), String::from("{ ")), - (arg.span().shrink_to_hi(), String::from(" }")), - ]; - type_err.multipart_suggestion( - "If this generic argument was intended as a const parameter, \ - try surrounding it with braces:", - suggestions, - Applicability::MaybeIncorrect, - ); - } + if let Err((_, Some(ref mut type_err))) = type_count_correct { + let possible_matches = args.args[arg_counts.lifetimes..] + .iter() + .filter(|arg| { + matches!( + arg, + GenericArg::Type(hir::Ty { kind: hir::TyKind::Path { .. }, .. }) + ) + }) + .take(c_mismatch.max(0) as usize); + for arg in possible_matches { + let suggestions = vec![ + (arg.span().shrink_to_lo(), String::from("{ ")), + (arg.span().shrink_to_hi(), String::from(" }")), + ]; + type_err.multipart_suggestion( + "If this generic argument was intended as a const parameter, \ + try surrounding it with braces:", + suggestions, + Applicability::MaybeIncorrect, + ); } } } + let emit_correct = + |correct: Result<(), (_, Option>)>| match correct { + Ok(()) => Ok(()), + Err((_, None)) => Err(()), + Err((_, Some(mut err))) => { + err.emit(); + Err(()) + } + }; + let arg_count_correct = emit_correct(lifetime_count_correct) .and(emit_correct(const_count_correct)) .and(emit_correct(type_count_correct)); diff --git a/src/test/ui/const-generics/invalid-enum.rs b/src/test/ui/const-generics/invalid-enum.rs index 05c13e8fe0c88..ceb188a0d3d34 100644 --- a/src/test/ui/const-generics/invalid-enum.rs +++ b/src/test/ui/const-generics/invalid-enum.rs @@ -7,11 +7,33 @@ enum CompileFlag { B, } -pub fn test() {} +pub fn test_1() {} +pub fn test_2(x: T) {} +pub struct Example{ + x: T, +} + +impl Example { + const ASSOC_FLAG: CompileFlag = CompileFlag::A; +} pub fn main() { - test::(); + test_1::(); + //~^ ERROR: expected type, found variant + //~| ERROR: wrong number of const arguments + //~| ERROR: wrong number of type arguments + + test_2::<_, CompileFlag::A>(0); //~^ ERROR: expected type, found variant //~| ERROR: wrong number of const arguments //~| ERROR: wrong number of type arguments + + let _: Example = Example { x: 0 }; + //~^ ERROR: expected type, found variant + //~| ERROR: wrong number of const arguments + //~| ERROR: wrong number of type arguments + + let _: Example = Example { x: 0 }; + //~^ ERROR: wrong number of const arguments + //~| ERROR: wrong number of type arguments } diff --git a/src/test/ui/const-generics/invalid-enum.stderr b/src/test/ui/const-generics/invalid-enum.stderr index 3291b62ea9fbb..965abbc9cb7b8 100644 --- a/src/test/ui/const-generics/invalid-enum.stderr +++ b/src/test/ui/const-generics/invalid-enum.stderr @@ -1,30 +1,99 @@ error[E0573]: expected type, found variant `CompileFlag::A` - --> $DIR/invalid-enum.rs:13:10 + --> $DIR/invalid-enum.rs:21:12 | -LL | test::(); - | ^^^^^^^^^^^^^^ - | | - | not a type - | help: try using the variant's enum: `CompileFlag` +LL | test_1::(); + | ^^^^^^^^^^^^^^ + | | + | not a type + | help: try using the variant's enum: `CompileFlag` + +error[E0573]: expected type, found variant `CompileFlag::A` + --> $DIR/invalid-enum.rs:26:15 + | +LL | test_2::<_, CompileFlag::A>(0); + | ^^^^^^^^^^^^^^ + | | + | not a type + | help: try using the variant's enum: `CompileFlag` + +error[E0573]: expected type, found variant `CompileFlag::A` + --> $DIR/invalid-enum.rs:31:18 + | +LL | let _: Example = Example { x: 0 }; + | ^^^^^^^^^^^^^^ + | | + | not a type + | help: try using the variant's enum: `CompileFlag` + +error[E0107]: wrong number of const arguments: expected 1, found 0 + --> $DIR/invalid-enum.rs:31:10 + | +LL | let _: Example = Example { x: 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument + +error[E0107]: wrong number of type arguments: expected at most 1, found 2 + --> $DIR/invalid-enum.rs:31:10 + | +LL | let _: Example = Example { x: 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected at most 1 type argument + | +help: If this generic argument was intended as a const parameter, try surrounding it with braces: + | +LL | let _: Example<{ CompileFlag::A }, _> = Example { x: 0 }; + | ^ ^ + +error[E0107]: wrong number of const arguments: expected 1, found 0 + --> $DIR/invalid-enum.rs:36:10 + | +LL | let _: Example = Example { x: 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument + +error[E0107]: wrong number of type arguments: expected at most 1, found 2 + --> $DIR/invalid-enum.rs:36:10 + | +LL | let _: Example = Example { x: 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected at most 1 type argument + | +help: If this generic argument was intended as a const parameter, try surrounding it with braces: + | +LL | let _: Example<{ Example::ASSOC_FLAG }, _> = Example { x: 0 }; + | ^ ^ error[E0107]: wrong number of const arguments: expected 1, found 0 - --> $DIR/invalid-enum.rs:13:3 + --> $DIR/invalid-enum.rs:21:3 | -LL | test::(); - | ^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument +LL | test_1::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument error[E0107]: wrong number of type arguments: expected 0, found 1 - --> $DIR/invalid-enum.rs:13:10 + --> $DIR/invalid-enum.rs:21:12 + | +LL | test_1::(); + | ^^^^^^^^^^^^^^ unexpected type argument + | +help: If this generic argument was intended as a const parameter, try surrounding it with braces: + | +LL | test_1::<{ CompileFlag::A }>(); + | ^ ^ + +error[E0107]: wrong number of const arguments: expected 1, found 0 + --> $DIR/invalid-enum.rs:26:3 + | +LL | test_2::<_, CompileFlag::A>(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument + +error[E0107]: wrong number of type arguments: expected 1, found 2 + --> $DIR/invalid-enum.rs:26:15 | -LL | test::(); - | ^^^^^^^^^^^^^^ unexpected type argument +LL | test_2::<_, CompileFlag::A>(0); + | ^^^^^^^^^^^^^^ unexpected type argument | help: If this generic argument was intended as a const parameter, try surrounding it with braces: | -LL | test::<{ CompileFlag::A }>(); - | ^ ^ +LL | test_2::<_, { CompileFlag::A }>(0); + | ^ ^ -error: aborting due to 3 previous errors +error: aborting due to 11 previous errors Some errors have detailed explanations: E0107, E0573. For more information about an error, try `rustc --explain E0107`. From ccf1f580812b25eda231d4f2ac2e20c445fe7b62 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 3 Sep 2020 21:34:39 +0200 Subject: [PATCH 0088/1052] rustdoc: fix min_const_generics with ty::Param --- src/librustdoc/clean/mod.rs | 20 +++++++++---------- src/test/rustdoc/const-generics/type-alias.rs | 6 ++++++ 2 files changed, 16 insertions(+), 10 deletions(-) create mode 100644 src/test/rustdoc/const-generics/type-alias.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 14e0fa7eabb00..fc38c6b14b54b 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1364,16 +1364,16 @@ impl Clean for hir::Ty<'_> { TyKind::Slice(ref ty) => Slice(box ty.clean(cx)), TyKind::Array(ref ty, ref length) => { let def_id = cx.tcx.hir().local_def_id(length.hir_id); - let length = match cx.tcx.const_eval_poly(def_id.to_def_id()) { - Ok(length) => { - print_const(cx, ty::Const::from_value(cx.tcx, length, cx.tcx.types.usize)) - } - Err(_) => cx - .sess() - .source_map() - .span_to_snippet(cx.tcx.def_span(def_id)) - .unwrap_or_else(|_| "_".to_string()), - }; + // NOTE(min_const_generics): We can't use `const_eval_poly` for constants + // as we currently do not supply the parent generics to anonymous constants + // but do allow `ConstKind::Param`. + // + // `const_eval_poly` tries to to first substitute generic parameters which + // results in an ICE while manually constructing the constant and using `eval` + // does nothing for `ConstKind::Param`. + let ct = ty::Const::from_anon_const(cx.tcx, def_id); + let param_env = cx.tcx.param_env(def_id); + let length = print_const(cx, ct.eval(cx.tcx, param_env)); Array(box ty.clean(cx), length) } TyKind::Tup(ref tys) => Tuple(tys.clean(cx)), diff --git a/src/test/rustdoc/const-generics/type-alias.rs b/src/test/rustdoc/const-generics/type-alias.rs new file mode 100644 index 0000000000000..3064d0701e300 --- /dev/null +++ b/src/test/rustdoc/const-generics/type-alias.rs @@ -0,0 +1,6 @@ +// ignore-tidy-linelength +#![feature(min_const_generics)] +#![crate_name = "foo"] + +// @has foo/type.CellIndex.html '//pre[@class="rust typedef"]' 'type CellIndex = [i64; D];' +pub type CellIndex = [i64; D]; From 787b2707a77fa1a98f512a4905662a1a16daf13c Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Fri, 4 Sep 2020 00:24:34 +0200 Subject: [PATCH 0089/1052] Move const tests for `Result` to `library\core` Part of #76268 --- library/core/tests/result.rs | 16 ++++++++++++++++ src/test/ui/consts/const-result.rs | 12 ------------ 2 files changed, 16 insertions(+), 12 deletions(-) delete mode 100644 src/test/ui/consts/const-result.rs diff --git a/library/core/tests/result.rs b/library/core/tests/result.rs index caa2d916cd7a8..d3c650669dab3 100644 --- a/library/core/tests/result.rs +++ b/library/core/tests/result.rs @@ -305,3 +305,19 @@ fn test_result_as_deref_mut() { let expected_result = Result::Err::<&mut u32, &mut Vec>(&mut expected_vec); assert_eq!(mut_err.as_deref_mut(), expected_result); } + +#[test] +fn result_const() { + // test that the methods of `Result` are usable in a const context + + const RESULT: Result = Ok(32); + + const REF: Result<&usize, &bool> = RESULT.as_ref(); + assert_eq!(REF, Ok(&32)); + + const IS_OK: bool = RESULT.is_ok(); + assert!(IS_OK); + + const IS_ERR: bool = RESULT.is_err(); + assert!(!IS_ERR) +} diff --git a/src/test/ui/consts/const-result.rs b/src/test/ui/consts/const-result.rs deleted file mode 100644 index e548d3e79ff80..0000000000000 --- a/src/test/ui/consts/const-result.rs +++ /dev/null @@ -1,12 +0,0 @@ -// run-pass - -fn main() { - const X: Result = Ok(32); - const Y: Result<&i32, &bool> = X.as_ref(); - - const IS_OK: bool = X.is_ok(); - assert!(IS_OK); - - const IS_ERR: bool = Y.is_err(); - assert!(!IS_ERR) -} From 79d563c819483eaf6e67b6aaaef9d0ca6030337d Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Fri, 4 Sep 2020 00:40:11 +0200 Subject: [PATCH 0090/1052] Move const tests for `Ordering` to `library\core` Part of #76268 --- library/core/tests/cmp.rs | 18 +++++++++++++++++- src/test/ui/consts/const-ordering.rs | 15 --------------- 2 files changed, 17 insertions(+), 16 deletions(-) delete mode 100644 src/test/ui/consts/const-ordering.rs diff --git a/library/core/tests/cmp.rs b/library/core/tests/cmp.rs index 4086917780fa4..835289daf715a 100644 --- a/library/core/tests/cmp.rs +++ b/library/core/tests/cmp.rs @@ -1,4 +1,7 @@ -use core::cmp::{self, Ordering::*}; +use core::cmp::{ + self, + Ordering::{self, *}, +}; #[test] fn test_int_totalord() { @@ -116,3 +119,16 @@ fn test_user_defined_eq() { assert!(SketchyNum { num: 37 } == SketchyNum { num: 34 }); assert!(SketchyNum { num: 25 } != SketchyNum { num: 57 }); } + +#[test] +fn ordering_const() { + // test that the methods of `Ordering` are usable in a const context + + const ORDERING: Ordering = Greater; + + const REVERSE: Ordering = ORDERING.reverse(); + assert_eq!(REVERSE, Less); + + const THEN: Ordering = Equal.then(ORDERING); + assert_eq!(THEN, Greater); +} diff --git a/src/test/ui/consts/const-ordering.rs b/src/test/ui/consts/const-ordering.rs deleted file mode 100644 index 454f2da00df9e..0000000000000 --- a/src/test/ui/consts/const-ordering.rs +++ /dev/null @@ -1,15 +0,0 @@ -// run-pass - -use std::cmp::Ordering; - -// the following methods of core::cmp::Ordering are const: -// - reverse -// - then - -fn main() { - const REVERSE : Ordering = Ordering::Greater.reverse(); - assert_eq!(REVERSE, Ordering::Less); - - const THEN : Ordering = Ordering::Equal.then(REVERSE); - assert_eq!(THEN, Ordering::Less); -} From b54386ab7a9da8a4f22db3a35a9ec7b0f2b98b6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Tue, 4 Aug 2020 00:00:00 +0000 Subject: [PATCH 0091/1052] Detect overflow in proc_macro_server subspan --- compiler/rustc_expand/src/proc_macro_server.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 39c82f97e0a39..5a728bbda96c5 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -584,12 +584,12 @@ impl server::Literal for Rustc<'_> { let start = match start { Bound::Included(lo) => lo, - Bound::Excluded(lo) => lo + 1, + Bound::Excluded(lo) => lo.checked_add(1)?, Bound::Unbounded => 0, }; let end = match end { - Bound::Included(hi) => hi + 1, + Bound::Included(hi) => hi.checked_add(1)?, Bound::Excluded(hi) => hi, Bound::Unbounded => length, }; From d98bac4e4e3cc87ec9b848c173d570ebe2aa30b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Tue, 4 Aug 2020 00:00:00 +0000 Subject: [PATCH 0092/1052] Add tests for overflow in Vec::drain --- library/alloc/tests/vec.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 8e66c8a22cec5..8abebd940d20f 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -3,6 +3,7 @@ use std::collections::TryReserveError::*; use std::fmt::Debug; use std::iter::InPlaceIterable; use std::mem::size_of; +use std::ops::Bound::*; use std::panic::{catch_unwind, AssertUnwindSafe}; use std::rc::Rc; use std::vec::{Drain, IntoIter}; @@ -566,6 +567,16 @@ fn test_drain_max_vec_size() { assert_eq!(v.len(), usize::MAX - 1); } +#[test] +#[should_panic] +fn test_drain_index_overflow() { + let mut v = Vec::<()>::with_capacity(usize::MAX); + unsafe { + v.set_len(usize::MAX); + } + v.drain(0..=usize::MAX); +} + #[test] #[should_panic] fn test_drain_inclusive_out_of_bounds() { @@ -573,6 +584,20 @@ fn test_drain_inclusive_out_of_bounds() { v.drain(5..=5); } +#[test] +#[should_panic] +fn test_drain_start_overflow() { + let mut v = vec![1, 2, 3]; + v.drain((Excluded(usize::MAX), Included(0))); +} + +#[test] +#[should_panic] +fn test_drain_end_overflow() { + let mut v = vec![1, 2, 3]; + v.drain((Included(0), Included(usize::MAX))); +} + #[test] fn test_drain_leak() { static mut DROPS: i32 = 0; From f8cfb2f5ad847b871399dfef9b8b8ff4e84a75cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Fri, 4 Sep 2020 00:00:00 +0000 Subject: [PATCH 0093/1052] Add tests for overflow in String / VecDeque operations using ranges --- library/alloc/tests/lib.rs | 1 + library/alloc/tests/string.rs | 29 +++++++++++++++++++++++++++++ library/alloc/tests/vec_deque.rs | 15 +++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index b1513d1b05655..a6912d3f5bcc3 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -14,6 +14,7 @@ #![feature(slice_ptr_get)] #![feature(split_inclusive)] #![feature(binary_heap_retain)] +#![feature(deque_range)] #![feature(inplace_iteration)] #![feature(iter_map_while)] diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs index d38655af78cb7..e2eb042f79172 100644 --- a/library/alloc/tests/string.rs +++ b/library/alloc/tests/string.rs @@ -1,6 +1,7 @@ use std::borrow::Cow; use std::collections::TryReserveError::*; use std::mem::size_of; +use std::ops::Bound::*; pub trait IntoCow<'a, B: ?Sized> where @@ -463,6 +464,20 @@ fn test_drain() { assert_eq!(t, ""); } +#[test] +#[should_panic] +fn test_drain_start_overflow() { + let mut s = String::from("abc"); + s.drain((Excluded(usize::MAX), Included(0))); +} + +#[test] +#[should_panic] +fn test_drain_end_overflow() { + let mut s = String::from("abc"); + s.drain((Included(0), Included(usize::MAX))); +} + #[test] fn test_replace_range() { let mut s = "Hello, world!".to_owned(); @@ -500,6 +515,20 @@ fn test_replace_range_inclusive_out_of_bounds() { s.replace_range(5..=5, "789"); } +#[test] +#[should_panic] +fn test_replace_range_start_overflow() { + let mut s = String::from("123"); + s.replace_range((Excluded(usize::MAX), Included(0)), ""); +} + +#[test] +#[should_panic] +fn test_replace_range_end_overflow() { + let mut s = String::from("456"); + s.replace_range((Included(0), Included(usize::MAX)), ""); +} + #[test] fn test_replace_range_empty() { let mut s = String::from("12345"); diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs index 762dc4be44d62..46d8a3c4cb493 100644 --- a/library/alloc/tests/vec_deque.rs +++ b/library/alloc/tests/vec_deque.rs @@ -2,6 +2,7 @@ use std::collections::TryReserveError::*; use std::collections::{vec_deque::Drain, VecDeque}; use std::fmt::Debug; use std::mem::size_of; +use std::ops::Bound::*; use std::panic::{catch_unwind, AssertUnwindSafe}; use crate::hash; @@ -115,6 +116,20 @@ fn test_index_out_of_bounds() { deq[3]; } +#[test] +#[should_panic] +fn test_range_start_overflow() { + let deq = VecDeque::from(vec![1, 2, 3]); + deq.range((Included(0), Included(usize::MAX))); +} + +#[test] +#[should_panic] +fn test_range_end_overflow() { + let deq = VecDeque::from(vec![1, 2, 3]); + deq.range((Excluded(usize::MAX), Included(0))); +} + #[derive(Clone, PartialEq, Debug)] enum Taggy { One(i32), From 01510612ee20d14a3397427891a4042a34d53956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Thu, 3 Sep 2020 00:00:00 +0000 Subject: [PATCH 0094/1052] NRVO: Allow occurrences of the return place in var debug info The non-use occurrence of the return place in var debug info does not currently inhibit NRVO optimization, but it will fail assertion in `visit_place` when optimization is performed. Relax assertion check to allow the return place in var debug info. This case might be impossible to hit in optimization pipelines as of now, but can be encountered in customized mir-opt-level=2 pipeline with copy propagation disabled. For example in: ``` pub fn b(s: String) -> String { a(s) } #[inline] pub fn a(s: String) -> String { let x = s; let y = x; y } ``` --- compiler/rustc_mir/src/transform/nrvo.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir/src/transform/nrvo.rs b/compiler/rustc_mir/src/transform/nrvo.rs index 1f3d7bb7cc6f4..3673b6a4aa223 100644 --- a/compiler/rustc_mir/src/transform/nrvo.rs +++ b/compiler/rustc_mir/src/transform/nrvo.rs @@ -1,6 +1,6 @@ use rustc_hir::Mutability; use rustc_index::bit_set::HybridBitSet; -use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; +use rustc_middle::mir::visit::{MutVisitor, NonUseContext, PlaceContext, Visitor}; use rustc_middle::mir::{self, BasicBlock, Local, Location}; use rustc_middle::ty::TyCtxt; @@ -196,9 +196,10 @@ impl MutVisitor<'tcx> for RenameToReturnPlace<'tcx> { self.super_terminator(terminator, loc); } - fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) { - assert_ne!(*l, mir::RETURN_PLACE); - if *l == self.to_rename { + fn visit_local(&mut self, l: &mut Local, ctxt: PlaceContext, _: Location) { + if *l == mir::RETURN_PLACE { + assert_eq!(ctxt, PlaceContext::NonUse(NonUseContext::VarDebugInfo)); + } else if *l == self.to_rename { *l = mir::RETURN_PLACE; } } From cf1cc7c449e881f0ac5d8474209222bc269df250 Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Fri, 4 Sep 2020 05:15:31 +0200 Subject: [PATCH 0095/1052] Simplify `clippy::default_trait_access` Remove repeated matching on the same QPath. --- clippy_lints/src/default_trait_access.rs | 46 +++++++++--------------- 1 file changed, 16 insertions(+), 30 deletions(-) diff --git a/clippy_lints/src/default_trait_access.rs b/clippy_lints/src/default_trait_access.rs index 0b0a13078768b..320a2a257bd09 100644 --- a/clippy_lints/src/default_trait_access.rs +++ b/clippy_lints/src/default_trait_access.rs @@ -38,37 +38,23 @@ impl<'tcx> LateLintPass<'tcx> for DefaultTraitAccess { if let ExprKind::Path(ref qpath) = path.kind; if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD); + // Detect and ignore ::default() because these calls do explicitly name the type. + if let QPath::Resolved(None, _path) = qpath; then { - match qpath { - QPath::Resolved(..) => { - if_chain! { - // Detect and ignore ::default() because these calls do - // explicitly name the type. - if let ExprKind::Call(ref method, ref _args) = expr.kind; - if let ExprKind::Path(ref p) = method.kind; - if let QPath::Resolved(Some(_ty), _path) = p; - then { - return; - } - } - - // TODO: Work out a way to put "whatever the imported way of referencing - // this type in this file" rather than a fully-qualified type. - let expr_ty = cx.typeck_results().expr_ty(expr); - if let ty::Adt(def, ..) = expr_ty.kind { - let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did)); - span_lint_and_sugg( - cx, - DEFAULT_TRAIT_ACCESS, - expr.span, - &format!("calling `{}` is more clear than this expression", replacement), - "try", - replacement, - Applicability::Unspecified, // First resolve the TODO above - ); - } - }, - QPath::TypeRelative(..) | QPath::LangItem(..) => {}, + let expr_ty = cx.typeck_results().expr_ty(expr); + if let ty::Adt(def, ..) = expr_ty.kind { + // TODO: Work out a way to put "whatever the imported way of referencing + // this type in this file" rather than a fully-qualified type. + let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did)); + span_lint_and_sugg( + cx, + DEFAULT_TRAIT_ACCESS, + expr.span, + &format!("calling `{}` is more clear than this expression", replacement), + "try", + replacement, + Applicability::Unspecified, // First resolve the TODO above + ); } } } From 6092828d1f432bb313818e7cfab961c0e494f69e Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 3 Sep 2020 19:59:51 -0700 Subject: [PATCH 0096/1052] Add `[T; N]: TryFrom>` This is very similar to the existing `Box<[T; N]>: TryFrom>`, but allows avoiding the `shrink_to_fit` if you have a vector and not a boxed slice. --- library/alloc/src/vec.rs | 52 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 9013e3fc16ab9..b6d923daaf2ab 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -55,6 +55,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use core::cmp::{self, Ordering}; +use core::convert::TryFrom; use core::fmt; use core::hash::{Hash, Hasher}; use core::intrinsics::{arith_offset, assume}; @@ -2771,6 +2772,57 @@ impl From<&str> for Vec { } } +#[stable(feature = "array_try_from_vec", since = "1.47.0")] +impl TryFrom> for [T; N] { + type Error = Vec; + + /// Gets the entire contents of the `Vec` as an array, + /// if its size exactly matches that of the requested array. + /// + /// # Examples + /// + /// ``` + /// use std::convert::TryInto; + /// assert_eq!(vec![1, 2, 3].try_into(), Ok([1, 2, 3])); + /// assert_eq!(>::new().try_into(), Ok([])); + /// ``` + /// + /// If the length doesn't match, the input comes back in `Err`: + /// ``` + /// use std::convert::TryInto; + /// let r: Result<[i32; 4], _> = (0..10).collect::>().try_into(); + /// assert_eq!(r, Err(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); + /// ``` + /// + /// If you're fine with just getting a prefix of the `Vec`, + /// you can call [`.truncate(N)`](Vec::truncate) first. + /// ``` + /// use std::convert::TryInto; + /// let mut v = String::from("hello world").into_bytes(); + /// v.sort(); + /// v.truncate(2); + /// let [a, b]: [_; 2] = v.try_into().unwrap(); + /// assert_eq!(a, b' '); + /// assert_eq!(b, b'd'); + /// ``` + fn try_from(mut vec: Vec) -> Result<[T; N], Vec> { + if vec.len() != N { + return Err(vec); + } + + // SAFETY: `.set_len(0)` is always sound. + unsafe { vec.set_len(0) }; + + // SAFETY: A `Vec`'s pointer is always aligned property, and + // the alignment the array needs is the same as the items. + // We checked earlier that we have sufficient items. + // The items will not double-drop as the `set_len` + // tells the `Vec` not to also drop them. + let array = unsafe { ptr::read(vec.as_ptr() as *const [T; N]) }; + Ok(array) + } +} + //////////////////////////////////////////////////////////////////////////////// // Clone-on-write //////////////////////////////////////////////////////////////////////////////// From f8376b59d1391a5191a561c44067355f1a99c7c0 Mon Sep 17 00:00:00 2001 From: David Wood Date: Sun, 9 Aug 2020 20:08:45 +0100 Subject: [PATCH 0097/1052] shim: monomorphic `FnPtrShim`s during construction This commit adjusts MIR shim construction so that substitutions are applied to function pointer shims during construction, rather than during codegen (as determined by `substs_for_mir_body`) - as substitutions will no longer occur during codegen, function pointer shims can now be polymorphic without incurring double substitutions. Signed-off-by: David Wood --- compiler/rustc_middle/src/ty/instance.rs | 53 ++++++++-------- compiler/rustc_mir/src/shim.rs | 60 ++++++++++--------- ...-Fn-call.AddMovesForPackedDrops.before.mir | 4 +- 3 files changed, 58 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index c8b6705b35f36..a6b62097d5b18 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -62,10 +62,6 @@ pub enum InstanceDef<'tcx> { /// `::call_*` (generated `FnTrait` implementation for `fn()` pointers). /// /// `DefId` is `FnTrait::call_*`. - /// - /// NB: the (`fn` pointer) type must currently be monomorphic to avoid double substitution - /// problems with the MIR shim bodies. `Instance::resolve` enforces this. - // FIXME(#69925) support polymorphic MIR shim bodies properly instead. FnPtrShim(DefId, Ty<'tcx>), /// Dynamic dispatch to `::fn`. @@ -87,10 +83,6 @@ pub enum InstanceDef<'tcx> { /// The `DefId` is for `core::ptr::drop_in_place`. /// The `Option>` is either `Some(T)`, or `None` for empty drop /// glue. - /// - /// NB: the type must currently be monomorphic to avoid double substitution - /// problems with the MIR shim bodies. `Instance::resolve` enforces this. - // FIXME(#69925) support polymorphic MIR shim bodies properly instead. DropGlue(DefId, Option>), /// Compiler-generated `::clone` implementation. @@ -99,10 +91,6 @@ pub enum InstanceDef<'tcx> { /// Additionally, arrays, tuples, and closures get a `Clone` shim even if they aren't `Copy`. /// /// The `DefId` is for `Clone::clone`, the `Ty` is the type `T` with the builtin `Clone` impl. - /// - /// NB: the type must currently be monomorphic to avoid double substitution - /// problems with the MIR shim bodies. `Instance::resolve` enforces this. - // FIXME(#69925) support polymorphic MIR shim bodies properly instead. CloneShim(DefId, Ty<'tcx>), } @@ -243,6 +231,27 @@ impl<'tcx> InstanceDef<'tcx> { _ => false, } } + + /// Returns `true` when the MIR body associated with this instance should be monomorphized + /// by its users (e.g. codegen or miri) by substituting the `substs` from `Instance` (see + /// `Instance::substs_for_mir_body`). + /// + /// Otherwise, returns `false` only for some kinds of shims where the construction of the MIR + /// body should perform necessary substitutions. + pub fn has_polymorphic_mir_body(&self) -> bool { + match *self { + InstanceDef::CloneShim(..) + | InstanceDef::FnPtrShim(..) + | InstanceDef::DropGlue(_, Some(_)) => false, + InstanceDef::ClosureOnceShim { .. } + | InstanceDef::DropGlue(..) + | InstanceDef::Item(_) + | InstanceDef::Intrinsic(..) + | InstanceDef::ReifyShim(..) + | InstanceDef::Virtual(..) + | InstanceDef::VtableShim(..) => true, + } + } } impl<'tcx> fmt::Display for Instance<'tcx> { @@ -440,30 +449,18 @@ impl<'tcx> Instance<'tcx> { Instance { def, substs } } - /// FIXME(#69925) Depending on the kind of `InstanceDef`, the MIR body associated with an + /// Depending on the kind of `InstanceDef`, the MIR body associated with an /// instance is expressed in terms of the generic parameters of `self.def_id()`, and in other /// cases the MIR body is expressed in terms of the types found in the substitution array. /// In the former case, we want to substitute those generic types and replace them with the /// values from the substs when monomorphizing the function body. But in the latter case, we /// don't want to do that substitution, since it has already been done effectively. /// - /// This function returns `Some(substs)` in the former case and None otherwise -- i.e., if + /// This function returns `Some(substs)` in the former case and `None` otherwise -- i.e., if /// this function returns `None`, then the MIR body does not require substitution during - /// monomorphization. + /// codegen. pub fn substs_for_mir_body(&self) -> Option> { - match self.def { - InstanceDef::CloneShim(..) - | InstanceDef::DropGlue(_, Some(_)) => None, - InstanceDef::ClosureOnceShim { .. } - | InstanceDef::DropGlue(..) - // FIXME(#69925): `FnPtrShim` should be in the other branch. - | InstanceDef::FnPtrShim(..) - | InstanceDef::Item(_) - | InstanceDef::Intrinsic(..) - | InstanceDef::ReifyShim(..) - | InstanceDef::Virtual(..) - | InstanceDef::VtableShim(..) => Some(self.substs), - } + if self.def.has_polymorphic_mir_body() { Some(self.substs) } else { None } } /// Returns a new `Instance` where generic parameters in `instance.substs` are replaced by diff --git a/compiler/rustc_mir/src/shim.rs b/compiler/rustc_mir/src/shim.rs index 479b6c2a6ca9f..a99302e952155 100644 --- a/compiler/rustc_mir/src/shim.rs +++ b/compiler/rustc_mir/src/shim.rs @@ -33,7 +33,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' let mut result = match instance { ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance), ty::InstanceDef::VtableShim(def_id) => { - build_call_shim(tcx, instance, Some(Adjustment::Deref), CallKind::Direct(def_id), None) + build_call_shim(tcx, instance, Some(Adjustment::Deref), CallKind::Direct(def_id)) } ty::InstanceDef::FnPtrShim(def_id, ty) => { let trait_ = tcx.trait_of_item(def_id).unwrap(); @@ -42,16 +42,8 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' Some(ty::ClosureKind::FnMut | ty::ClosureKind::Fn) => Adjustment::Deref, None => bug!("fn pointer {:?} is not an fn", ty), }; - // HACK: we need the "real" argument types for the MIR, - // but because our substs are (Self, Args), where Args - // is a tuple, we must include the *concrete* argument - // types in the MIR. They will be substituted again with - // the param-substs, but because they are concrete, this - // will not do any harm. - let sig = tcx.erase_late_bound_regions(&ty.fn_sig(tcx)); - let arg_tys = sig.inputs(); - - build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect(ty), Some(arg_tys)) + + build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect(ty)) } // We are generating a call back to our def-id, which the // codegen backend knows to turn to an actual call, be it @@ -59,7 +51,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' // indirect calls must be codegen'd differently than direct ones // (such as `#[track_caller]`). ty::InstanceDef::ReifyShim(def_id) => { - build_call_shim(tcx, instance, None, CallKind::Direct(def_id), None) + build_call_shim(tcx, instance, None, CallKind::Direct(def_id)) } ty::InstanceDef::ClosureOnceShim { call_once: _ } => { let fn_mut = tcx.require_lang_item(LangItem::FnMut, None); @@ -70,13 +62,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' .unwrap() .def_id; - build_call_shim( - tcx, - instance, - Some(Adjustment::RefMut), - CallKind::Direct(call_mut), - None, - ) + build_call_shim(tcx, instance, Some(Adjustment::RefMut), CallKind::Direct(call_mut)) } ty::InstanceDef::DropGlue(def_id, ty) => build_drop_shim(tcx, def_id, ty), ty::InstanceDef::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty), @@ -641,29 +627,45 @@ impl CloneShimBuilder<'tcx> { } } -/// Builds a "call" shim for `instance`. The shim calls the -/// function specified by `call_kind`, first adjusting its first -/// argument according to `rcvr_adjustment`. -/// -/// If `untuple_args` is a vec of types, the second argument of the -/// function will be untupled as these types. +/// Builds a "call" shim for `instance`. The shim calls the function specified by `call_kind`, +/// first adjusting its first argument according to `rcvr_adjustment`. fn build_call_shim<'tcx>( tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>, rcvr_adjustment: Option, call_kind: CallKind<'tcx>, - untuple_args: Option<&[Ty<'tcx>]>, ) -> Body<'tcx> { debug!( - "build_call_shim(instance={:?}, rcvr_adjustment={:?}, \ - call_kind={:?}, untuple_args={:?})", - instance, rcvr_adjustment, call_kind, untuple_args + "build_call_shim(instance={:?}, rcvr_adjustment={:?}, call_kind={:?})", + instance, rcvr_adjustment, call_kind ); + // `FnPtrShim` contains the fn pointer type that a call shim is being built for - this is used + // to substitute into the signature of the shim. It is not necessary for users of this + // MIR body to perform further substitutions (see `InstanceDef::has_polymorphic_mir_body`). + let (sig_substs, untuple_args) = if let ty::InstanceDef::FnPtrShim(_, ty) = instance { + let sig = tcx.erase_late_bound_regions(&ty.fn_sig(tcx)); + + let untuple_args = sig.inputs(); + + // Create substitutions for the `Self` and `Args` generic parameters of the shim body. + let arg_tup = tcx.mk_tup(untuple_args.iter()); + let sig_substs = tcx.mk_substs_trait(ty, &[ty::subst::GenericArg::from(arg_tup)]); + + (Some(sig_substs), Some(untuple_args)) + } else { + (None, None) + }; + let def_id = instance.def_id(); let sig = tcx.fn_sig(def_id); let mut sig = tcx.erase_late_bound_regions(&sig); + assert_eq!(sig_substs.is_some(), !instance.has_polymorphic_mir_body()); + if let Some(sig_substs) = sig_substs { + sig = sig.subst(tcx, sig_substs); + } + if let CallKind::Indirect(fnty) = call_kind { // `sig` determines our local decls, and thus the callee type in the `Call` terminator. This // can only be an `FnDef` or `FnPtr`, but currently will be `Self` since the types come from diff --git a/src/test/mir-opt/fn_ptr_shim.core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir b/src/test/mir-opt/fn_ptr_shim.core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir index d3f92d389f5b2..bcc6042f2fb62 100644 --- a/src/test/mir-opt/fn_ptr_shim.core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir +++ b/src/test/mir-opt/fn_ptr_shim.core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir @@ -1,7 +1,7 @@ // MIR for `std::ops::Fn::call` before AddMovesForPackedDrops -fn std::ops::Fn::call(_1: *const fn(), _2: Args) -> >::Output { - let mut _0: >::Output; // return place in scope 0 at $SRC_DIR/core/src/ops/function.rs:LL:COL +fn std::ops::Fn::call(_1: *const fn(), _2: ()) -> >::Output { + let mut _0: >::Output; // return place in scope 0 at $SRC_DIR/core/src/ops/function.rs:LL:COL bb0: { _0 = move (*_1)() -> bb1; // scope 0 at $SRC_DIR/core/src/ops/function.rs:LL:COL From 28f9b84042b7d0ffd1f913e8ba82348ebe23dd1b Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Tue, 4 Aug 2020 00:18:29 +0200 Subject: [PATCH 0098/1052] `ty.kind` -> `ty.kind()` in rustdoc and clippy --- clippy_lints/src/atomic_ordering.rs | 2 +- clippy_lints/src/await_holding_lock.rs | 2 +- clippy_lints/src/bytecount.rs | 2 +- clippy_lints/src/consts.rs | 24 ++++----- clippy_lints/src/default_trait_access.rs | 2 +- clippy_lints/src/derive.rs | 8 +-- clippy_lints/src/doc.rs | 4 +- clippy_lints/src/drop_forget_ref.rs | 2 +- clippy_lints/src/enum_clike.rs | 4 +- clippy_lints/src/eta_reduction.rs | 8 +-- clippy_lints/src/eval_order_dependence.rs | 4 +- .../src/float_equality_without_abs.rs | 4 +- clippy_lints/src/float_literal.rs | 2 +- clippy_lints/src/floating_point_arithmetic.rs | 2 +- clippy_lints/src/format.rs | 2 +- clippy_lints/src/functions.rs | 2 +- clippy_lints/src/future_not_send.rs | 2 +- clippy_lints/src/identity_op.rs | 2 +- clippy_lints/src/indexing_slicing.rs | 4 +- clippy_lints/src/large_const_arrays.rs | 2 +- clippy_lints/src/large_stack_arrays.rs | 2 +- clippy_lints/src/len_zero.rs | 2 +- clippy_lints/src/loops.rs | 12 ++--- clippy_lints/src/map_clone.rs | 4 +- clippy_lints/src/map_unit_fn.rs | 4 +- clippy_lints/src/matches.rs | 16 +++--- .../src/methods/inefficient_to_string.rs | 4 +- clippy_lints/src/methods/mod.rs | 54 +++++++++---------- clippy_lints/src/misc.rs | 6 +-- clippy_lints/src/modulo_arithmetic.rs | 2 +- clippy_lints/src/mut_key.rs | 4 +- clippy_lints/src/mut_mut.rs | 2 +- clippy_lints/src/mut_reference.rs | 4 +- clippy_lints/src/mutable_debug_assertion.rs | 2 +- clippy_lints/src/mutex_atomic.rs | 6 +-- clippy_lints/src/needless_borrow.rs | 6 +-- clippy_lints/src/needless_pass_by_value.rs | 2 +- clippy_lints/src/needless_update.rs | 2 +- clippy_lints/src/pattern_type_mismatch.rs | 10 ++-- clippy_lints/src/ptr.rs | 2 +- clippy_lints/src/ranges.rs | 2 +- clippy_lints/src/redundant_clone.rs | 4 +- clippy_lints/src/shadow.rs | 2 +- clippy_lints/src/swap.rs | 4 +- clippy_lints/src/to_digit_is_some.rs | 2 +- clippy_lints/src/transmute.rs | 12 ++--- .../src/trivially_copy_pass_by_ref.rs | 4 +- clippy_lints/src/try_err.rs | 12 ++--- clippy_lints/src/types.rs | 40 +++++++------- clippy_lints/src/unit_return_expecting_ord.rs | 2 +- clippy_lints/src/unnamed_address.rs | 4 +- clippy_lints/src/unnecessary_sort_by.rs | 2 +- clippy_lints/src/useless_conversion.rs | 4 +- clippy_lints/src/utils/mod.rs | 45 ++++++++-------- clippy_lints/src/vec.rs | 6 +-- 55 files changed, 187 insertions(+), 188 deletions(-) diff --git a/clippy_lints/src/atomic_ordering.rs b/clippy_lints/src/atomic_ordering.rs index 277fe350055ec..2d964ac2b9f64 100644 --- a/clippy_lints/src/atomic_ordering.rs +++ b/clippy_lints/src/atomic_ordering.rs @@ -53,7 +53,7 @@ const ATOMIC_TYPES: [&str; 12] = [ ]; fn type_is_atomic(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - if let ty::Adt(&ty::AdtDef { did, .. }, _) = cx.typeck_results().expr_ty(expr).kind { + if let ty::Adt(&ty::AdtDef { did, .. }, _) = cx.typeck_results().expr_ty(expr).kind() { ATOMIC_TYPES .iter() .any(|ty| match_def_path(cx, did, &["core", "sync", "atomic", ty])) diff --git a/clippy_lints/src/await_holding_lock.rs b/clippy_lints/src/await_holding_lock.rs index b10b1e0a65ab9..f18e7e5d99755 100644 --- a/clippy_lints/src/await_holding_lock.rs +++ b/clippy_lints/src/await_holding_lock.rs @@ -67,7 +67,7 @@ impl LateLintPass<'_> for AwaitHoldingLock { fn check_interior_types(cx: &LateContext<'_>, ty_causes: &[GeneratorInteriorTypeCause<'_>], span: Span) { for ty_cause in ty_causes { - if let rustc_middle::ty::Adt(adt, _) = ty_cause.ty.kind { + if let rustc_middle::ty::Adt(adt, _) = ty_cause.ty.kind() { if is_mutex_guard(cx, adt.did) { span_lint_and_note( cx, diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index cdb49d777d8da..189c07427ae99 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -63,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for ByteCount { _ => { return; } } }; - if ty::Uint(UintTy::U8) != walk_ptrs_ty(cx.typeck_results().expr_ty(needle)).kind { + if ty::Uint(UintTy::U8) != *walk_ptrs_ty(cx.typeck_results().expr_ty(needle)).kind() { return; } let haystack = if let ExprKind::MethodCall(ref path, _, ref args, _) = diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index c77b80bc23733..3ee022e4e68a0 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -123,7 +123,7 @@ impl Constant { (&Self::Str(ref ls), &Self::Str(ref rs)) => Some(ls.cmp(rs)), (&Self::Char(ref l), &Self::Char(ref r)) => Some(l.cmp(r)), (&Self::Int(l), &Self::Int(r)) => { - if let ty::Int(int_ty) = cmp_type.kind { + if let ty::Int(int_ty) = *cmp_type.kind() { Some(sext(tcx, l, int_ty).cmp(&sext(tcx, r, int_ty))) } else { Some(l.cmp(&r)) @@ -162,7 +162,7 @@ pub fn lit_to_constant(lit: &LitKind, ty: Option>) -> Constant { FloatTy::F32 => Constant::F32(is.as_str().parse().unwrap()), FloatTy::F64 => Constant::F64(is.as_str().parse().unwrap()), }, - LitKind::Float(ref is, LitFloatType::Unsuffixed) => match ty.expect("type of float is known").kind { + LitKind::Float(ref is, LitFloatType::Unsuffixed) => match ty.expect("type of float is known").kind() { ty::Float(FloatTy::F32) => Constant::F32(is.as_str().parse().unwrap()), ty::Float(FloatTy::F64) => Constant::F64(is.as_str().parse().unwrap()), _ => bug!(), @@ -230,7 +230,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { ExprKind::Array(ref vec) => self.multi(vec).map(Constant::Vec), ExprKind::Tup(ref tup) => self.multi(tup).map(Constant::Tuple), ExprKind::Repeat(ref value, _) => { - let n = match self.typeck_results.expr_ty(e).kind { + let n = match self.typeck_results.expr_ty(e).kind() { ty::Array(_, n) => n.try_eval_usize(self.lcx.tcx, self.lcx.param_env)?, _ => span_bug!(e.span, "typeck error"), }; @@ -281,7 +281,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { Bool(b) => Some(Bool(!b)), Int(value) => { let value = !value; - match ty.kind { + match *ty.kind() { ty::Int(ity) => Some(Int(unsext(self.lcx.tcx, value as i128, ity))), ty::Uint(ity) => Some(Int(clip(self.lcx.tcx, value, ity))), _ => None, @@ -295,7 +295,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { use self::Constant::{Int, F32, F64}; match *o { Int(value) => { - let ity = match ty.kind { + let ity = match *ty.kind() { ty::Int(ity) => ity, _ => return None, }; @@ -402,7 +402,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { let l = self.expr(left)?; let r = self.expr(right); match (l, r) { - (Constant::Int(l), Some(Constant::Int(r))) => match self.typeck_results.expr_ty_opt(left)?.kind { + (Constant::Int(l), Some(Constant::Int(r))) => match *self.typeck_results.expr_ty_opt(left)?.kind() { ty::Int(ity) => { let l = sext(self.lcx.tcx, l, ity); let r = sext(self.lcx.tcx, r, ity); @@ -495,7 +495,7 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option { use rustc_middle::mir::interpret::{ConstValue, Scalar}; match result.val { ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data: d, .. })) => { - match result.ty.kind { + match result.ty.kind() { ty::Bool => Some(Constant::Bool(d == 1)), ty::Uint(_) | ty::Int(_) => Some(Constant::Int(d)), ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits( @@ -505,7 +505,7 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option { d.try_into().expect("invalid f64 bit representation"), ))), ty::RawPtr(type_and_mut) => { - if let ty::Uint(_) = type_and_mut.ty.kind { + if let ty::Uint(_) = type_and_mut.ty.kind() { return Some(Constant::RawPtr(d)); } None @@ -514,8 +514,8 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option { _ => None, } }, - ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => match result.ty.kind { - ty::Ref(_, tam, _) => match tam.kind { + ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => match result.ty.kind() { + ty::Ref(_, tam, _) => match tam.kind() { ty::Str => String::from_utf8( data.inspect_with_uninit_and_ptr_outside_interpreter(start..end) .to_owned(), @@ -526,8 +526,8 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option { }, _ => None, }, - ty::ConstKind::Value(ConstValue::ByRef { alloc, offset: _ }) => match result.ty.kind { - ty::Array(sub_type, len) => match sub_type.kind { + ty::ConstKind::Value(ConstValue::ByRef { alloc, offset: _ }) => match result.ty.kind() { + ty::Array(sub_type, len) => match sub_type.kind() { ty::Float(FloatTy::F32) => match miri_to_const(len) { Some(Constant::Int(len)) => alloc .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * len as usize)) diff --git a/clippy_lints/src/default_trait_access.rs b/clippy_lints/src/default_trait_access.rs index 067ea903bdd96..1654df56a9a5b 100644 --- a/clippy_lints/src/default_trait_access.rs +++ b/clippy_lints/src/default_trait_access.rs @@ -55,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultTraitAccess { // TODO: Work out a way to put "whatever the imported way of referencing // this type in this file" rather than a fully-qualified type. let expr_ty = cx.typeck_results().expr_ty(expr); - if let ty::Adt(..) = expr_ty.kind { + if let ty::Adt(..) = expr_ty.kind() { let replacement = format!("{}::default()", expr_ty); span_lint_and_sugg( cx, diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 58b0704294b56..bf8e030cc294b 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -299,20 +299,20 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &T return; } - match ty.kind { + match *ty.kind() { ty::Adt(def, _) if def.is_union() => return, // Some types are not Clone by default but could be cloned “by hand” if necessary ty::Adt(def, substs) => { for variant in &def.variants { for field in &variant.fields { - if let ty::FnDef(..) = field.ty(cx.tcx, substs).kind { + if let ty::FnDef(..) = field.ty(cx.tcx, substs).kind() { return; } } for subst in substs { if let ty::subst::GenericArgKind::Type(subst) = subst.unpack() { - if let ty::Param(_) = subst.kind { + if let ty::Param(_) = subst.kind() { return; } } @@ -353,7 +353,7 @@ fn check_unsafe_derive_deserialize<'tcx>( if_chain! { if match_path(&trait_ref.path, &paths::SERDE_DESERIALIZE); - if let ty::Adt(def, _) = ty.kind; + if let ty::Adt(def, _) = ty.kind(); if let Some(local_def_id) = def.did.as_local(); let adt_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id); if !is_allowed(cx, UNSAFE_DERIVE_DESERIALIZE, adt_hir_id); diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 9555459e240e9..50121a054c798 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -239,9 +239,9 @@ fn lint_for_missing_headers<'tcx>( let mir = cx.tcx.optimized_mir(def_id.to_def_id()); let ret_ty = mir.return_ty(); if implements_trait(cx, ret_ty, future, &[]); - if let ty::Opaque(_, subs) = ret_ty.kind; + if let ty::Opaque(_, subs) = ret_ty.kind(); if let Some(gen) = subs.types().next(); - if let ty::Generator(_, subs, _) = gen.kind; + if let ty::Generator(_, subs, _) = gen.kind(); if is_type_diagnostic_item(cx, subs.as_generator().return_ty(), sym!(result_type)); then { span_lint( diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index 57ff569f14b0f..cf528d189b4b1 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -121,7 +121,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { let arg = &args[0]; let arg_ty = cx.typeck_results().expr_ty(arg); - if let ty::Ref(..) = arg_ty.kind { + if let ty::Ref(..) = arg_ty.kind() { if match_def_path(cx, def_id, &paths::DROP) { lint = DROP_REF; msg = DROP_REF_SUMMARY.to_string(); diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index 48caf48dbdb2c..fb80f48a9ccf3 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -53,12 +53,12 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant { .ok() .map(|val| rustc_middle::ty::Const::from_value(cx.tcx, val, ty)); if let Some(Constant::Int(val)) = constant.and_then(miri_to_const) { - if let ty::Adt(adt, _) = ty.kind { + if let ty::Adt(adt, _) = ty.kind() { if adt.is_enum() { ty = adt.repr.discr_type().to_ty(cx.tcx); } } - match ty.kind { + match ty.kind() { ty::Int(IntTy::Isize) => { let val = ((val as i128) << 64) >> 64; if i32::try_from(val).is_ok() { diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 87254c1dbc490..53df3abbf5437 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -99,7 +99,7 @@ fn check_closure(cx: &LateContext<'_>, expr: &Expr<'_>) { let fn_ty = cx.typeck_results().expr_ty(caller); - if matches!(fn_ty.kind, ty::FnDef(_, _) | ty::FnPtr(_) | ty::Closure(_, _)); + if matches!(fn_ty.kind(), ty::FnDef(_, _) | ty::FnPtr(_) | ty::Closure(_, _)); if !type_is_unsafe_function(cx, fn_ty); @@ -173,14 +173,14 @@ fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: def_id::DefId, self_a } fn match_borrow_depth(lhs: Ty<'_>, rhs: Ty<'_>) -> bool { - match (&lhs.kind, &rhs.kind) { + match (&lhs.kind(), &rhs.kind()) { (ty::Ref(_, t1, mut1), ty::Ref(_, t2, mut2)) => mut1 == mut2 && match_borrow_depth(&t1, &t2), (l, r) => !matches!((l, r), (ty::Ref(_, _, _), _) | (_, ty::Ref(_, _, _))), } } fn match_types(lhs: Ty<'_>, rhs: Ty<'_>) -> bool { - match (&lhs.kind, &rhs.kind) { + match (&lhs.kind(), &rhs.kind()) { (ty::Bool, ty::Bool) | (ty::Char, ty::Char) | (ty::Int(_), ty::Int(_)) @@ -194,7 +194,7 @@ fn match_types(lhs: Ty<'_>, rhs: Ty<'_>) -> bool { } fn get_type_name(cx: &LateContext<'_>, ty: Ty<'_>) -> String { - match ty.kind { + match ty.kind() { ty::Adt(t, _) => cx.tcx.def_path_str(t.did), ty::Ref(_, r, _) => get_type_name(cx, &r), _ => ty.to_string(), diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index c00638ecc0c1d..4240147f498db 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -138,10 +138,10 @@ impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> { ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => self.report_diverging_sub_expr(e), ExprKind::Call(ref func, _) => { let typ = self.cx.typeck_results().expr_ty(func); - match typ.kind { + match typ.kind() { ty::FnDef(..) | ty::FnPtr(_) => { let sig = typ.fn_sig(self.cx.tcx); - if let ty::Never = self.cx.tcx.erase_late_bound_regions(&sig).output().kind { + if let ty::Never = self.cx.tcx.erase_late_bound_regions(&sig).output().kind() { self.report_diverging_sub_expr(e); } }, diff --git a/clippy_lints/src/float_equality_without_abs.rs b/clippy_lints/src/float_equality_without_abs.rs index 9ac5a45eb4590..69818b4d3c642 100644 --- a/clippy_lints/src/float_equality_without_abs.rs +++ b/clippy_lints/src/float_equality_without_abs.rs @@ -81,8 +81,8 @@ impl<'tcx> LateLintPass<'tcx> for FloatEqualityWithoutAbs { // values of the substractions on the left hand side are of the type float let t_val_l = cx.typeck_results().expr_ty(val_l); let t_val_r = cx.typeck_results().expr_ty(val_r); - if let ty::Float(_) = t_val_l.kind; - if let ty::Float(_) = t_val_r.kind; + if let ty::Float(_) = t_val_l.kind(); + if let ty::Float(_) = t_val_r.kind(); then { let sug_l = sugg::Sugg::hir(cx, &val_l, ".."); diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 358b9f6dcd0a5..1fe4461533b36 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { if_chain! { let ty = cx.typeck_results().expr_ty(expr); - if let ty::Float(fty) = ty.kind; + if let ty::Float(fty) = *ty.kind(); if let hir::ExprKind::Lit(ref lit) = expr.kind; if let LitKind::Float(sym, lit_float_ty) = lit.node; then { diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 1b02cee126d03..18fea8b34bfd4 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -136,7 +136,7 @@ fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Su if_chain! { // if the expression is a float literal and it is unsuffixed then // add a suffix so the suggestion is valid and unambiguous - if let ty::Float(float_ty) = cx.typeck_results().expr_ty(expr).kind; + if let ty::Float(float_ty) = cx.typeck_results().expr_ty(expr).kind(); if let ExprKind::Lit(lit) = &expr.kind; if let ast::LitKind::Float(sym, ast::LitFloatType::Unsuffixed) = lit.node; then { diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 572c839502f4f..8bd85af87682a 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -91,7 +91,7 @@ fn on_argumentv1_new<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arms: & if pats.len() == 1; then { let ty = walk_ptrs_ty(cx.typeck_results().pat_ty(&pats[0])); - if ty.kind != rustc_middle::ty::Str && !is_type_diagnostic_item(cx, ty, sym!(string_type)) { + if *ty.kind() != rustc_middle::ty::Str && !is_type_diagnostic_item(cx, ty, sym!(string_type)) { return None; } if let ExprKind::Lit(ref lit) = format_args.kind { diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index ac1c7aa9bbbe9..89fde1d509d30 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -505,7 +505,7 @@ fn is_mutable_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, tys: &mut FxHashSet< static KNOWN_WRAPPER_TYS: &[&[&str]] = &[&["alloc", "rc", "Rc"], &["std", "sync", "Arc"]]; fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, tys: &mut FxHashSet) -> bool { - match ty.kind { + match *ty.kind() { // primitive types are never mutable ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false, ty::Adt(ref adt, ref substs) => { diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index 0fdb5b8c2a48e..2ab257ca88e3b 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { return; } let ret_ty = utils::return_ty(cx, hir_id); - if let Opaque(id, subst) = ret_ty.kind { + if let Opaque(id, subst) = *ret_ty.kind() { let preds = cx.tcx.predicates_of(id).instantiate(cx.tcx, subst); let mut is_future = false; for p in preds.predicates { diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index 4c62637858cde..8501d34770201 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -75,7 +75,7 @@ fn is_allowed(cx: &LateContext<'_>, cmp: BinOp, left: &Expr<'_>, right: &Expr<'_ #[allow(clippy::cast_possible_wrap)] fn check(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span) { if let Some(Constant::Int(v)) = constant_simple(cx, cx.typeck_results(), e) { - let check = match cx.typeck_results().expr_ty(e).kind { + let check = match *cx.typeck_results().expr_ty(e).kind() { ty::Int(ity) => unsext(cx.tcx, -1_i128, ity), ty::Uint(uty) => clip(cx.tcx, !0, uty), _ => return, diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index 90b1a529be79d..a28eda8be15a4 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -91,7 +91,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { let ty = cx.typeck_results().expr_ty(array); if let Some(range) = higher::range(index) { // Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..] - if let ty::Array(_, s) = ty.kind { + if let ty::Array(_, s) = ty.kind() { let size: u128 = if let Some(size) = s.try_eval_usize(cx.tcx, cx.param_env) { size.into() } else { @@ -141,7 +141,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { span_lint_and_help(cx, INDEXING_SLICING, expr.span, "slicing may panic.", None, help_msg); } else { // Catchall non-range index, i.e., [n] or [n << m] - if let ty::Array(..) = ty.kind { + if let ty::Array(..) = ty.kind() { // Index is a constant uint. if let Some(..) = constant(cx, cx.typeck_results(), index) { // Let rustc's `const_err` lint handle constant `usize` indexing on arrays. diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs index c6cc174a8c97b..025ff86da39d8 100644 --- a/clippy_lints/src/large_const_arrays.rs +++ b/clippy_lints/src/large_const_arrays.rs @@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { if !item.span.from_expansion(); if let ItemKind::Const(hir_ty, _) = &item.kind; let ty = hir_ty_to_ty(cx.tcx, hir_ty); - if let ty::Array(element_type, cst) = ty.kind; + if let ty::Array(element_type, cst) = ty.kind(); if let ConstKind::Value(val) = cst.val; if let ConstValue::Scalar(element_count) = val; if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx); diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index a7c715879232b..9fd3780e14e04 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -42,7 +42,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { if let ExprKind::Repeat(_, _) = expr.kind; - if let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind; + if let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind(); if let ConstKind::Value(val) = cst.val; if let ConstValue::Scalar(element_count) = val; if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx); diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index b691d363d2f21..42a98dc963d20 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -286,7 +286,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } let ty = &walk_ptrs_ty(cx.typeck_results().expr_ty(expr)); - match ty.kind { + match ty.kind() { ty::Dynamic(ref tt, ..) => tt.principal().map_or(false, |principal| { cx.tcx .associated_items(principal.def_id()) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index c95e43a943044..604a97e3c0835 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -826,7 +826,7 @@ struct FixedOffsetVar<'hir> { } fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'_>) -> bool { - let is_slice = match ty.kind { + let is_slice = match ty.kind() { ty::Ref(_, subty, _) => is_slice_like(cx, subty), ty::Slice(..) | ty::Array(..) => true, _ => false, @@ -1375,7 +1375,7 @@ fn is_end_eq_array_len<'tcx>( if_chain! { if let ExprKind::Lit(ref lit) = end.kind; if let ast::LitKind::Int(end_int, _) = lit.node; - if let ty::Array(_, arr_len_const) = indexed_ty.kind; + if let ty::Array(_, arr_len_const) = indexed_ty.kind(); if let Some(arr_len) = arr_len_const.try_eval_usize(cx.tcx, cx.param_env); then { return match limits { @@ -1612,7 +1612,7 @@ fn check_for_loop_over_map_kv<'tcx>( if let PatKind::Tuple(ref pat, _) = pat.kind { if pat.len() == 2 { let arg_span = arg.span; - let (new_pat_span, kind, ty, mutbl) = match cx.typeck_results().expr_ty(arg).kind { + let (new_pat_span, kind, ty, mutbl) = match *cx.typeck_results().expr_ty(arg).kind() { ty::Ref(_, ty, mutbl) => match (&pat[0].kind, &pat[1].kind) { (key, _) if pat_is_wild(key, body) => (pat[1].span, "value", ty, mutbl), (_, value) if pat_is_wild(value, body) => (pat[0].span, "key", ty, Mutability::Not), @@ -1940,7 +1940,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { for expr in args { let ty = self.cx.typeck_results().expr_ty_adjusted(expr); self.prefer_mutable = false; - if let ty::Ref(_, _, mutbl) = ty.kind { + if let ty::Ref(_, _, mutbl) = *ty.kind() { if mutbl == Mutability::Mut { self.prefer_mutable = true; } @@ -1952,7 +1952,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap(); for (ty, expr) in self.cx.tcx.fn_sig(def_id).inputs().skip_binder().iter().zip(args) { self.prefer_mutable = false; - if let ty::Ref(_, _, mutbl) = ty.kind { + if let ty::Ref(_, _, mutbl) = *ty.kind() { if mutbl == Mutability::Mut { self.prefer_mutable = true; } @@ -2050,7 +2050,7 @@ fn is_ref_iterable_type(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { fn is_iterable_array<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool { // IntoIterator is currently only implemented for array sizes <= 32 in rustc - match ty.kind { + match ty.kind() { ty::Array(_, n) => n .try_eval_usize(cx.tcx, cx.param_env) .map_or(false, |val| (0..=32).contains(&val)), diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 1cd5b2012922f..6d1c2ffbfbdd2 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { match closure_expr.kind { hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner) => { if ident_eq(name, inner) { - if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind { + if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() { lint(cx, e.span, args[0].span, true); } } @@ -80,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { && 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 { + if let ty::Ref(_, ty, _) = obj_ty.kind() { let copy = is_copy(cx, ty); lint(cx, e.span, args[0].span, copy); } else { diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 198251c58ddc5..1f9ae8c931a1e 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -93,7 +93,7 @@ declare_clippy_lint! { declare_lint_pass!(MapUnit => [OPTION_MAP_UNIT_FN, RESULT_MAP_UNIT_FN]); fn is_unit_type(ty: Ty<'_>) -> bool { - match ty.kind { + match ty.kind() { ty::Tuple(slice) => slice.is_empty(), ty::Never => true, _ => false, @@ -103,7 +103,7 @@ fn is_unit_type(ty: Ty<'_>) -> bool { fn is_unit_function(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { let ty = cx.typeck_results().expr_ty(expr); - if let ty::FnDef(id, _) = ty.kind { + if let ty::FnDef(id, _) = *ty.kind() { if let Some(fn_type) = cx.tcx.fn_sig(id).no_bound_vars() { return is_unit_type(fn_type.output()); } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index be879dfe28d70..7ba7397c29cb6 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -573,7 +573,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { if let QPath::Resolved(_, ref path) = qpath; if let Some(def_id) = path.res.opt_def_id(); let ty = cx.tcx.type_of(def_id); - if let ty::Adt(def, _) = ty.kind; + if let ty::Adt(def, _) = ty.kind(); if def.is_struct() || def.is_union(); if fields.len() == def.non_enum_variant().fields.len(); @@ -621,7 +621,7 @@ fn check_single_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp }; let ty = cx.typeck_results().expr_ty(ex); - if ty.kind != ty::Bool || is_allowed(cx, MATCH_BOOL, ex.hir_id) { + if *ty.kind() != ty::Bool || is_allowed(cx, MATCH_BOOL, ex.hir_id) { check_single_match_single_pattern(cx, ex, arms, expr, els); check_single_match_opt_like(cx, ex, arms, expr, ty, els); } @@ -712,7 +712,7 @@ fn check_single_match_opt_like( fn check_match_bool(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) { // Type of expression is `bool`. - if cx.typeck_results().expr_ty(ex).kind == ty::Bool { + if *cx.typeck_results().expr_ty(ex).kind() == ty::Bool { span_lint_and_then( cx, MATCH_BOOL, @@ -860,7 +860,7 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) // already covered. let mut missing_variants = vec![]; - if let ty::Adt(def, _) = ty.kind { + if let ty::Adt(def, _) = ty.kind() { for variant in &def.variants { missing_variants.push(variant); } @@ -914,7 +914,7 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) let mut message = "wildcard match will miss any future added variants"; - if let ty::Adt(def, _) = ty.kind { + if let ty::Adt(def, _) = ty.kind() { if def.is_variant_list_non_exhaustive() { message = "match on non-exhaustive enum doesn't explicitly match all known variants"; suggestion.push(String::from("_")); @@ -1014,11 +1014,11 @@ fn check_match_as_ref(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp let input_ty = cx.typeck_results().expr_ty(ex); let cast = if_chain! { - if let ty::Adt(_, substs) = input_ty.kind; + if let ty::Adt(_, substs) = input_ty.kind(); let input_ty = substs.type_at(0); - if let ty::Adt(_, substs) = output_ty.kind; + if let ty::Adt(_, substs) = output_ty.kind(); let output_ty = substs.type_at(0); - if let ty::Ref(_, output_ty, _) = output_ty.kind; + if let ty::Ref(_, output_ty, _) = *output_ty.kind(); if input_ty != output_ty; then { ".map(|x| x as _)" diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index e5f815772eba9..5dae7efad9763 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -46,7 +46,7 @@ pub fn lint<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &hir::Expr< /// Returns whether `ty` specializes `ToString`. /// Currently, these are `str`, `String`, and `Cow<'_, str>`. fn specializes_tostring(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { - if let ty::Str = ty.kind { + if let ty::Str = ty.kind() { return true; } @@ -54,7 +54,7 @@ fn specializes_tostring(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { return true; } - if let ty::Adt(adt, substs) = ty.kind { + if let ty::Adt(adt, substs) = ty.kind() { match_def_path(cx, adt.did, &paths::COW) && substs.type_at(1).is_str() } else { false diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 9996df69470f0..a7a3d67515678 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1534,8 +1534,8 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } } - match self_ty.kind { - ty::Ref(_, ty, _) if ty.kind == ty::Str => { + match self_ty.kind() { + ty::Ref(_, ty, _) if *ty.kind() == ty::Str => { for &(method, pos) in &PATTERN_METHODS { if method_call.ident.name.as_str() == method && args.len() > pos { lint_single_char_pattern(cx, expr, &args[pos]); @@ -1661,7 +1661,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } // if return type is impl trait, check the associated types - if let ty::Opaque(def_id, _) = ret_ty.kind { + if let ty::Opaque(def_id, _) = *ret_ty.kind() { // one of the associated types must be Self for &(predicate, _span) in cx.tcx.predicates_of(def_id).predicates { if let ty::PredicateAtom::Projection(projection_predicate) = predicate.skip_binders() { @@ -1803,7 +1803,7 @@ fn lint_or_fun_call<'tcx>( if path.ident.as_str() == "len" { let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0])); - match ty.kind { + match ty.kind() { ty::Slice(_) | ty::Array(_, _) => return, _ => (), } @@ -1910,7 +1910,7 @@ fn lint_expect_fun_call( && { let arg_type = cx.typeck_results().expr_ty(&call_args[0]); let base_type = walk_ptrs_ty(arg_type); - base_type.kind == ty::Str || is_type_diagnostic_item(cx, base_type, sym!(string_type)) + *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym!(string_type)) } { &call_args[0] @@ -1931,8 +1931,8 @@ fn lint_expect_fun_call( if is_type_diagnostic_item(cx, arg_ty, sym!(string_type)) { return false; } - if let ty::Ref(_, ty, ..) = arg_ty.kind { - if ty.kind == ty::Str && can_be_static_str(cx, arg) { + if let ty::Ref(_, ty, ..) = arg_ty.kind() { + if *ty.kind() == ty::Str && can_be_static_str(cx, arg) { return false; } }; @@ -1948,7 +1948,7 @@ fn lint_expect_fun_call( if let hir::ExprKind::Path(ref p) = fun.kind { match cx.qpath_res(p, fun.hir_id) { hir::def::Res::Def(hir::def::DefKind::Fn | hir::def::DefKind::AssocFn, def_id) => matches!( - cx.tcx.fn_sig(def_id).output().skip_binder().kind, + cx.tcx.fn_sig(def_id).output().skip_binder().kind(), ty::Ref(ty::ReStatic, ..) ), _ => false, @@ -1962,7 +1962,7 @@ fn lint_expect_fun_call( .type_dependent_def_id(arg.hir_id) .map_or(false, |method_id| { matches!( - cx.tcx.fn_sig(method_id).output().skip_binder().kind, + cx.tcx.fn_sig(method_id).output().skip_binder().kind(), ty::Ref(ty::ReStatic, ..) ) }) @@ -2081,8 +2081,8 @@ fn lint_expect_fun_call( /// Checks for the `CLONE_ON_COPY` lint. fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'_>) { let ty = cx.typeck_results().expr_ty(expr); - if let ty::Ref(_, inner, _) = arg_ty.kind { - if let ty::Ref(_, innermost, _) = inner.kind { + if let ty::Ref(_, inner, _) = arg_ty.kind() { + if let ty::Ref(_, innermost, _) = inner.kind() { span_lint_and_then( cx, CLONE_DOUBLE_REF, @@ -2093,7 +2093,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Exp if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) { let mut ty = innermost; let mut n = 0; - while let ty::Ref(_, inner, _) = ty.kind { + while let ty::Ref(_, inner, _) = ty.kind() { ty = inner; n += 1; } @@ -2172,7 +2172,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Exp fn lint_clone_on_ref_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) { let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(arg)); - if let ty::Adt(_, subst) = obj_ty.kind { + if let ty::Adt(_, subst) = obj_ty.kind() { let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) { "Rc" } else if is_type_diagnostic_item(cx, obj_ty, sym::Arc) { @@ -2202,7 +2202,7 @@ fn lint_string_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::E if let Some(arglists) = method_chain_args(arg, &["chars"]) { let target = &arglists[0][0]; let self_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(target)); - let ref_str = if self_ty.kind == ty::Str { + let ref_str = if *self_ty.kind() == ty::Str { "" } else if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) { "&" @@ -2238,7 +2238,7 @@ fn lint_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_> fn lint_cstring_as_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, source: &hir::Expr<'_>, unwrap: &hir::Expr<'_>) { if_chain! { let source_type = cx.typeck_results().expr_ty(source); - if let ty::Adt(def, substs) = source_type.kind; + if let ty::Adt(def, substs) = source_type.kind(); if cx.tcx.is_diagnostic_item(sym!(result_type), def.did); if match_type(cx, substs.type_at(0), &paths::CSTRING); then { @@ -2412,7 +2412,7 @@ fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_ } } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(caller_expr), sym!(vec_type)) || matches!( - &walk_ptrs_ty(cx.typeck_results().expr_ty(caller_expr)).kind, + &walk_ptrs_ty(cx.typeck_results().expr_ty(caller_expr)).kind(), ty::Array(_, _) ) { @@ -2579,7 +2579,7 @@ fn derefs_to_slice<'tcx>( ty: Ty<'tcx>, ) -> Option<&'tcx hir::Expr<'tcx>> { fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool { - match ty.kind { + match ty.kind() { ty::Slice(_) => true, ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()), ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym!(vec_type)), @@ -2598,7 +2598,7 @@ fn derefs_to_slice<'tcx>( None } } else { - match ty.kind { + match ty.kind() { ty::Slice(_) => Some(expr), ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => Some(expr), ty::Ref(_, inner, _) => { @@ -2692,9 +2692,9 @@ fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map // lint if caller of `.map().flatten()` is an Iterator if match_trait_method(cx, expr, &paths::ITERATOR) { let map_closure_ty = cx.typeck_results().expr_ty(&map_args[1]); - let is_map_to_option = match map_closure_ty.kind { + let is_map_to_option = match map_closure_ty.kind() { ty::Closure(_, _) | ty::FnDef(_, _) | ty::FnPtr(_) => { - let map_closure_sig = match map_closure_ty.kind { + let map_closure_sig = match map_closure_ty.kind() { ty::Closure(_, substs) => substs.as_closure().sig(), _ => map_closure_ty.fn_sig(cx.tcx), }; @@ -3164,7 +3164,7 @@ fn lint_chars_cmp( let mut applicability = Applicability::MachineApplicable; let self_ty = walk_ptrs_ty(cx.typeck_results().expr_ty_adjusted(&args[0][0])); - if self_ty.kind != ty::Str { + if *self_ty.kind() != ty::Str { return false; } @@ -3352,7 +3352,7 @@ fn lint_asref(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_re fn ty_has_iter_method(cx: &LateContext<'_>, self_ref_ty: Ty<'_>) -> Option<(&'static str, &'static str)> { has_iter_method(cx, self_ref_ty).map(|ty_name| { - let mutbl = match self_ref_ty.kind { + let mutbl = match self_ref_ty.kind() { ty::Ref(_, _, mutbl) => mutbl, _ => unreachable!(), }; @@ -3404,7 +3404,7 @@ fn lint_maybe_uninit(cx: &LateContext<'_>, expr: &hir::Expr<'_>, outer: &hir::Ex } fn is_maybe_uninit_ty_valid(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { - match ty.kind { + match ty.kind() { ty::Array(ref component, _) => is_maybe_uninit_ty_valid(cx, component), ty::Tuple(ref types) => types.types().all(|ty| is_maybe_uninit_ty_valid(cx, ty)), ty::Adt(ref adt, _) => match_def_path(cx, adt.did, &paths::MEM_MAYBEUNINIT), @@ -3531,7 +3531,7 @@ fn lint_option_as_ref_deref<'tcx>( /// Given a `Result` type, return its error type (`E`). fn get_error_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option> { - match ty.kind { + match ty.kind() { ty::Adt(_, substs) if is_type_diagnostic_item(cx, ty, sym!(result_type)) => substs.types().nth(1), _ => None, } @@ -3685,7 +3685,7 @@ impl SelfKind { } else if ty.is_box() { ty.boxed_ty() == parent_ty } else if is_type_diagnostic_item(cx, ty, sym::Rc) || is_type_diagnostic_item(cx, ty, sym::Arc) { - if let ty::Adt(_, substs) = ty.kind { + if let ty::Adt(_, substs) = ty.kind() { substs.types().next().map_or(false, |t| t == parent_ty) } else { false @@ -3696,7 +3696,7 @@ impl SelfKind { } fn matches_ref<'a>(cx: &LateContext<'a>, mutability: hir::Mutability, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool { - if let ty::Ref(_, t, m) = ty.kind { + if let ty::Ref(_, t, m) = *ty.kind() { return m == mutability && t == parent_ty; } @@ -3813,7 +3813,7 @@ fn contains_return(expr: &hir::Expr<'_>) -> bool { fn check_pointer_offset(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { if_chain! { if args.len() == 2; - if let ty::RawPtr(ty::TypeAndMut { ref ty, .. }) = cx.typeck_results().expr_ty(&args[0]).kind; + if let ty::RawPtr(ty::TypeAndMut { ref ty, .. }) = cx.typeck_results().expr_ty(&args[0]).kind(); if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)); if layout.is_zst(); then { diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 06f367a8b775f..d4a50dd9013f0 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -561,17 +561,17 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } fn is_float(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - let value = &walk_ptrs_ty(cx.typeck_results().expr_ty(expr)).kind; + let value = &walk_ptrs_ty(cx.typeck_results().expr_ty(expr)).kind(); if let ty::Array(arr_ty, _) = value { - return matches!(arr_ty.kind, ty::Float(_)); + return matches!(arr_ty.kind(), ty::Float(_)); }; matches!(value, ty::Float(_)) } fn is_array(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - matches!(&walk_ptrs_ty(cx.typeck_results().expr_ty(expr)).kind, ty::Array(_, _)) + matches!(&walk_ptrs_ty(cx.typeck_results().expr_ty(expr)).kind(), ty::Array(_, _)) } fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) { diff --git a/clippy_lints/src/modulo_arithmetic.rs b/clippy_lints/src/modulo_arithmetic.rs index b1d788b5c683f..da3ae1d652f6c 100644 --- a/clippy_lints/src/modulo_arithmetic.rs +++ b/clippy_lints/src/modulo_arithmetic.rs @@ -38,7 +38,7 @@ struct OperandInfo { fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { match constant(cx, cx.typeck_results(), operand) { - Some((Constant::Int(v), _)) => match cx.typeck_results().expr_ty(expr).kind { + Some((Constant::Int(v), _)) => match *cx.typeck_results().expr_ty(expr).kind() { ty::Int(ity) => { let value = sext(cx.tcx, v, ity); return Some(OperandInfo { diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 9f8f401cc0f67..7423107e8f945 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -97,7 +97,7 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, item_hir_id: hir::HirId, decl: &hir:: // generics (because the compiler cannot ensure immutability for unknown types). fn check_ty<'tcx>(cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) { let ty = walk_ptrs_ty(ty); - if let Adt(def, substs) = ty.kind { + if let Adt(def, substs) = ty.kind() { if [&paths::HASHMAP, &paths::BTREEMAP, &paths::HASHSET, &paths::BTREESET] .iter() .any(|path| match_def_path(cx, def.did, &**path)) @@ -109,7 +109,7 @@ fn check_ty<'tcx>(cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) { } fn is_mutable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span) -> bool { - match ty.kind { + match *ty.kind() { RawPtr(TypeAndMut { ty: inner_ty, mutbl }) | Ref(_, inner_ty, mutbl) => { mutbl == hir::Mutability::Mut || is_mutable_type(cx, inner_ty, span) }, diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index b02e86bca2719..2f3cdb894f01c 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -69,7 +69,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> { expr.span, "generally you want to avoid `&mut &mut _` if possible", ); - } else if let ty::Ref(_, _, hir::Mutability::Mut) = self.cx.typeck_results().expr_ty(e).kind { + } else if let ty::Ref(_, _, hir::Mutability::Mut) = self.cx.typeck_results().expr_ty(e).kind() { span_lint( self.cx, MUT_MUT, diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index c506440ed7987..3f0b765df1561 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -61,11 +61,11 @@ fn check_arguments<'tcx>( name: &str, fn_kind: &str, ) { - match type_definition.kind { + match type_definition.kind() { ty::FnDef(..) | ty::FnPtr(_) => { let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs(); for (argument, parameter) in arguments.iter().zip(parameters.iter()) { - match parameter.kind { + match parameter.kind() { ty::Ref(_, _, Mutability::Not) | ty::RawPtr(ty::TypeAndMut { mutbl: Mutability::Not, .. diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index 7f529f0404c00..cc635c2a202f6 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -138,7 +138,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> { if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id) { if adj .iter() - .any(|a| matches!(a.target.kind, ty::Ref(_, _, Mutability::Mut))) + .any(|a| matches!(a.target.kind(), ty::Ref(_, _, Mutability::Mut))) { self.found = true; return; diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 21efee7126986..ea986874291e0 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -67,7 +67,7 @@ declare_lint_pass!(Mutex => [MUTEX_ATOMIC, MUTEX_INTEGER]); impl<'tcx> LateLintPass<'tcx> for Mutex { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let ty = cx.typeck_results().expr_ty(expr); - if let ty::Adt(_, subst) = ty.kind { + if let ty::Adt(_, subst) = ty.kind() { if is_type_diagnostic_item(cx, ty, sym!(mutex_type)) { let mutex_param = subst.type_at(0); if let Some(atomic_name) = get_atomic_name(mutex_param) { @@ -76,7 +76,7 @@ impl<'tcx> LateLintPass<'tcx> for Mutex { behavior and not the internal type, consider using `Mutex<()>`", atomic_name ); - match mutex_param.kind { + match *mutex_param.kind() { ty::Uint(t) if t != ast::UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg), ty::Int(t) if t != ast::IntTy::Isize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg), _ => span_lint(cx, MUTEX_ATOMIC, expr.span, &msg), @@ -88,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for Mutex { } fn get_atomic_name(ty: Ty<'_>) -> Option<&'static str> { - match ty.kind { + match ty.kind() { ty::Bool => Some("AtomicBool"), ty::Uint(_) => Some("AtomicUsize"), ty::Int(_) => Some("AtomicIsize"), diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index 9391049c6e8f9..b71d5496a37a3 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -46,7 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow { return; } if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, ref inner) = e.kind { - if let ty::Ref(..) = cx.typeck_results().expr_ty(inner).kind { + if let ty::Ref(..) = cx.typeck_results().expr_ty(inner).kind() { for adj3 in cx.typeck_results().expr_adjustments(e).windows(3) { if let [Adjustment { kind: Adjust::Deref(_), .. @@ -85,9 +85,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow { } if_chain! { if let PatKind::Binding(BindingAnnotation::Ref, .., name, _) = pat.kind; - if let ty::Ref(_, tam, mutbl) = cx.typeck_results().pat_ty(pat).kind; + if let ty::Ref(_, tam, mutbl) = *cx.typeck_results().pat_ty(pat).kind(); if mutbl == Mutability::Not; - if let ty::Ref(_, _, mutbl) = tam.kind; + if let ty::Ref(_, _, mutbl) = *tam.kind(); // only lint immutable refs, because borrowed `&mut T` cannot be moved out if mutbl == Mutability::Not; then { diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 047a78b087841..7e933c674dd78 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -194,7 +194,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { // Dereference suggestion let sugg = |diag: &mut DiagnosticBuilder<'_>| { - if let ty::Adt(def, ..) = ty.kind { + if let ty::Adt(def, ..) = ty.kind() { if let Some(span) = cx.tcx.hir().span_if_local(def.did) { if can_type_implement_copy(cx.tcx, cx.param_env, ty).is_ok() { diag.span_help(span, "consider marking this type as `Copy`"); diff --git a/clippy_lints/src/needless_update.rs b/clippy_lints/src/needless_update.rs index ce3f066eff5e7..98e9078094a22 100644 --- a/clippy_lints/src/needless_update.rs +++ b/clippy_lints/src/needless_update.rs @@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessUpdate { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::Struct(_, ref fields, Some(ref base)) = expr.kind { let ty = cx.typeck_results().expr_ty(expr); - if let ty::Adt(def, _) = ty.kind { + if let ty::Adt(def, _) = ty.kind() { if fields.len() == def.non_enum_variant().fields.len() { span_lint( cx, diff --git a/clippy_lints/src/pattern_type_mismatch.rs b/clippy_lints/src/pattern_type_mismatch.rs index ef26fc667b225..5539331d0460b 100644 --- a/clippy_lints/src/pattern_type_mismatch.rs +++ b/clippy_lints/src/pattern_type_mismatch.rs @@ -187,19 +187,19 @@ fn find_first_mismatch<'tcx>( level: Level, ) -> Option<(Span, Mutability, Level)> { if let PatKind::Ref(ref sub_pat, _) = pat.kind { - if let TyKind::Ref(_, sub_ty, _) = ty.kind { + if let TyKind::Ref(_, sub_ty, _) = ty.kind() { return find_first_mismatch(cx, sub_pat, sub_ty, Level::Lower); } } - if let TyKind::Ref(_, _, mutability) = ty.kind { + if let TyKind::Ref(_, _, mutability) = *ty.kind() { if is_non_ref_pattern(&pat.kind) { return Some((pat.span, mutability, level)); } } if let PatKind::Struct(ref qpath, ref field_pats, _) = pat.kind { - if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind { + if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind() { if let Some(variant) = get_variant(adt_def, qpath) { let field_defs = &variant.fields; return find_first_mismatch_in_struct(cx, field_pats, field_defs, substs_ref); @@ -208,7 +208,7 @@ fn find_first_mismatch<'tcx>( } if let PatKind::TupleStruct(ref qpath, ref pats, _) = pat.kind { - if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind { + if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind() { if let Some(variant) = get_variant(adt_def, qpath) { let field_defs = &variant.fields; let ty_iter = field_defs.iter().map(|field_def| field_def.ty(cx.tcx, substs_ref)); @@ -218,7 +218,7 @@ fn find_first_mismatch<'tcx>( } if let PatKind::Tuple(ref pats, _) = pat.kind { - if let TyKind::Tuple(..) = ty.kind { + if let TyKind::Tuple(..) = ty.kind() { return find_first_mismatch_in_tuple(cx, pats, ty.tuple_fields()); } } diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 7dafb1555dc6e..6b1c848a9467b 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -180,7 +180,7 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: } } - if let ty::Ref(_, ty, Mutability::Not) = ty.kind { + if let ty::Ref(_, ty, Mutability::Not) = ty.kind() { if is_type_diagnostic_item(cx, ty, sym!(vec_type)) { let mut ty_snippet = None; if_chain! { diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 7a75fc125d0ad..cc492917b9daf 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -281,7 +281,7 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::range(expr); let ty = cx.typeck_results().expr_ty(start); - if let ty::Int(_) | ty::Uint(_) = ty.kind; + if let ty::Int(_) | ty::Uint(_) = ty.kind(); if let Some((start_idx, _)) = constant(cx, cx.typeck_results(), start); if let Some((end_idx, _)) = constant(cx, cx.typeck_results(), end); if let Some(ordering) = Constant::partial_cmp(cx.tcx, ty, &start_idx, &end_idx); diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 7932be0d4b1f2..4773731e3272f 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -124,7 +124,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { continue; } - if let ty::Adt(ref def, _) = arg_ty.kind { + if let ty::Adt(ref def, _) = arg_ty.kind() { if match_def_path(cx, def.did, &paths::MEM_MANUALLY_DROP) { continue; } @@ -287,7 +287,7 @@ fn is_call_with_ref_arg<'tcx>( if let mir::TerminatorKind::Call { func, args, destination, .. } = kind; if args.len() == 1; if let mir::Operand::Move(mir::Place { local, .. }) = &args[0]; - if let ty::FnDef(def_id, _) = func.ty(&*mir, cx.tcx).kind; + if let ty::FnDef(def_id, _) = *func.ty(&*mir, cx.tcx).kind(); if let (inner_ty, 1) = walk_ptrs_ty_depth(args[0].ty(&*mir, cx.tcx)); if !is_copy(cx, inner_ty); then { diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 2610157763a8b..087d50c90e671 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -165,7 +165,7 @@ fn check_local<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>, bindings: & fn is_binding(cx: &LateContext<'_>, pat_id: HirId) -> bool { let var_ty = cx.typeck_results().node_type_opt(pat_id); - var_ty.map_or(false, |var_ty| !matches!(var_ty.kind, ty::Adt(..))) + var_ty.map_or(false, |var_ty| !matches!(var_ty.kind(), ty::Adt(..))) } fn check_pat<'tcx>( diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index cc39f060fc7f3..47a73ca9a24cf 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -196,8 +196,8 @@ fn check_for_slice<'a>(cx: &LateContext<'_>, lhs1: &'a Expr<'_>, lhs2: &'a Expr< if eq_expr_value(cx, lhs1, lhs2) { let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(lhs1)); - if matches!(ty.kind, ty::Slice(_)) - || matches!(ty.kind, ty::Array(_, _)) + if matches!(ty.kind(), ty::Slice(_)) + || matches!(ty.kind(), ty::Array(_, _)) || is_type_diagnostic_item(cx, ty, sym!(vec_type)) || is_type_diagnostic_item(cx, ty, sym!(vecdeque_type)) { diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs index 6750452941f28..eeda39bfa2087 100644 --- a/clippy_lints/src/to_digit_is_some.rs +++ b/clippy_lints/src/to_digit_is_some.rs @@ -44,7 +44,7 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome { if let [char_arg, radix_arg] = &**to_digit_args; if to_digits_path.ident.name.as_str() == "to_digit"; let char_arg_ty = cx.typeck_results().expr_ty_adjusted(char_arg); - if char_arg_ty.kind == ty::Char; + if *char_arg_ty.kind() == ty::Char; then { Some((true, char_arg, radix_arg)) } else { diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index 50d9c93f9d405..87c5408c78588 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -338,7 +338,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { let from_ty = cx.typeck_results().expr_ty(&args[0]); let to_ty = cx.typeck_results().expr_ty(e); - match (&from_ty.kind, &to_ty.kind) { + match (&from_ty.kind(), &to_ty.kind()) { _ if from_ty == to_ty => span_lint( cx, USELESS_TRANSMUTE, @@ -446,7 +446,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { &format!("transmute from a `{}` to a `char`", from_ty), |diag| { let arg = sugg::Sugg::hir(cx, &args[0], ".."); - let arg = if let ty::Int(_) = from_ty.kind { + let arg = if let ty::Int(_) = from_ty.kind() { arg.as_ty(ast::UintTy::U32.name_str()) } else { arg @@ -462,8 +462,8 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { }, (ty::Ref(_, ty_from, from_mutbl), ty::Ref(_, ty_to, to_mutbl)) => { if_chain! { - if let (&ty::Slice(slice_ty), &ty::Str) = (&ty_from.kind, &ty_to.kind); - if let ty::Uint(ast::UintTy::U8) = slice_ty.kind; + if let (&ty::Slice(slice_ty), &ty::Str) = (&ty_from.kind(), &ty_to.kind()); + if let ty::Uint(ast::UintTy::U8) = slice_ty.kind(); if from_mutbl == to_mutbl; then { let postfix = if *from_mutbl == Mutability::Mut { @@ -555,7 +555,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { &format!("transmute from a `{}` to a `{}`", from_ty, to_ty), |diag| { let arg = sugg::Sugg::hir(cx, &args[0], ".."); - let arg = if let ty::Int(int_ty) = from_ty.kind { + let arg = if let ty::Int(int_ty) = from_ty.kind() { arg.as_ty(format!( "u{}", int_ty.bit_width().map_or_else(|| "size".to_string(), |v| v.to_string()) @@ -601,7 +601,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { arg = sugg::Sugg::NonParen(format!("{}.to_bits()", arg.maybe_par()).into()); // cast the result of `to_bits` if `to_ty` is signed - arg = if let ty::Int(int_ty) = to_ty.kind { + arg = if let ty::Int(int_ty) = to_ty.kind() { arg.as_ty(int_ty.name_str().to_string()) } else { arg diff --git a/clippy_lints/src/trivially_copy_pass_by_ref.rs b/clippy_lints/src/trivially_copy_pass_by_ref.rs index 92f42168a1eab..1f06d2dbe9144 100644 --- a/clippy_lints/src/trivially_copy_pass_by_ref.rs +++ b/clippy_lints/src/trivially_copy_pass_by_ref.rs @@ -83,7 +83,7 @@ impl<'tcx> TriviallyCopyPassByRef { // Use lifetimes to determine if we're returning a reference to the // argument. In that case we can't switch to pass-by-value as the // argument will not live long enough. - let output_lts = match fn_sig.output().kind { + let output_lts = match *fn_sig.output().kind() { ty::Ref(output_lt, _, _) => vec![output_lt], ty::Adt(_, substs) => substs.regions().collect(), _ => vec![], @@ -97,7 +97,7 @@ impl<'tcx> TriviallyCopyPassByRef { } if_chain! { - if let ty::Ref(input_lt, ty, Mutability::Not) = ty.kind; + if let ty::Ref(input_lt, ty, Mutability::Not) = ty.kind(); if !output_lts.contains(&input_lt); if is_copy(cx, ty); if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes()); diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index a4676e505b6f3..3e747ec4ad9e2 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -132,7 +132,7 @@ fn find_return_type<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx ExprKind<'_>) -> O /// Extracts the error type from Result. fn result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { if_chain! { - if let ty::Adt(_, subst) = ty.kind; + if let ty::Adt(_, subst) = ty.kind(); if is_type_diagnostic_item(cx, ty, sym!(result_type)); let err_ty = subst.type_at(1); then { @@ -146,11 +146,11 @@ fn result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option>. fn poll_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { if_chain! { - if let ty::Adt(def, subst) = ty.kind; + if let ty::Adt(def, subst) = ty.kind(); if match_def_path(cx, def.did, &paths::POLL); let ready_ty = subst.type_at(0); - if let ty::Adt(ready_def, ready_subst) = ready_ty.kind; + if let ty::Adt(ready_def, ready_subst) = ready_ty.kind(); if cx.tcx.is_diagnostic_item(sym!(result_type), ready_def.did); let err_ty = ready_subst.type_at(1); @@ -165,15 +165,15 @@ fn poll_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option< /// Extracts the error type from Poll>>. fn poll_option_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { if_chain! { - if let ty::Adt(def, subst) = ty.kind; + if let ty::Adt(def, subst) = ty.kind(); if match_def_path(cx, def.did, &paths::POLL); let ready_ty = subst.type_at(0); - if let ty::Adt(ready_def, ready_subst) = ready_ty.kind; + if let ty::Adt(ready_def, ready_subst) = ready_ty.kind(); if cx.tcx.is_diagnostic_item(sym!(option_type), ready_def.did); let some_ty = ready_subst.type_at(0); - if let ty::Adt(some_def, some_subst) = some_ty.kind; + if let ty::Adt(some_def, some_subst) = some_ty.kind(); if cx.tcx.is_diagnostic_item(sym!(result_type), some_def.did); let err_ty = some_subst.type_at(1); diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 7e9190bef5e78..c82deaa43b266 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -907,7 +907,7 @@ fn is_questionmark_desugar_marked_call(expr: &Expr<'_>) -> bool { } fn is_unit(ty: Ty<'_>) -> bool { - matches!(ty.kind, ty::Tuple(slice) if slice.is_empty()) + matches!(ty.kind(), ty::Tuple(slice) if slice.is_empty()) } fn is_unit_literal(expr: &Expr<'_>) -> bool { @@ -1134,7 +1134,7 @@ declare_clippy_lint! { /// Returns the size in bits of an integral type. /// Will return 0 if the type is not an int or uint variant fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_>) -> u64 { - match typ.kind { + match typ.kind() { ty::Int(i) => match i { IntTy::Isize => tcx.data_layout.pointer_size.bits(), IntTy::I8 => 8, @@ -1156,7 +1156,7 @@ fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_>) -> u64 { } fn is_isize_or_usize(typ: Ty<'_>) -> bool { - matches!(typ.kind, ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize)) + matches!(typ.kind(), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize)) } fn span_precision_loss_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to_f64: bool) { @@ -1248,7 +1248,7 @@ fn check_loss_of_sign(cx: &LateContext<'_>, expr: &Expr<'_>, op: &Expr<'_>, cast if_chain! { if let Some((const_val, _)) = const_val; if let Constant::Int(n) = const_val; - if let ty::Int(ity) = cast_from.kind; + if let ty::Int(ity) = *cast_from.kind(); if sext(cx.tcx, n, ity) >= 0; then { return @@ -1381,7 +1381,7 @@ declare_lint_pass!(Casts => [ // Check if the given type is either `core::ffi::c_void` or // one of the platform specific `libc::::c_void` of libc. fn is_c_void(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { - if let ty::Adt(adt, _) = ty.kind { + if let ty::Adt(adt, _) = ty.kind() { let names = cx.get_def_path(adt.did); if names.is_empty() { @@ -1397,7 +1397,7 @@ fn is_c_void(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { /// Returns the mantissa bits wide of a fp type. /// Will return 0 if the type is not a fp fn fp_ty_mantissa_nbits(typ: Ty<'_>) -> u32 { - match typ.kind { + match typ.kind() { ty::Float(FloatTy::F32) => 23, ty::Float(FloatTy::F64) | ty::Infer(InferTy::FloatVar(_)) => 52, _ => 0, @@ -1437,7 +1437,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts { match lit.node { LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed) => {}, _ => { - if cast_from.kind == cast_to.kind && !in_external_macro(cx.sess(), expr.span) { + if cast_from.kind() == cast_to.kind() && !in_external_macro(cx.sess(), expr.span) { span_lint( cx, UNNECESSARY_CAST, @@ -1470,7 +1470,7 @@ fn lint_numeric_casts<'tcx>( match (cast_from.is_integral(), cast_to.is_integral()) { (true, false) => { let from_nbits = int_ty_to_nbits(cast_from, cx.tcx); - let to_nbits = if let ty::Float(FloatTy::F32) = cast_to.kind { + let to_nbits = if let ty::Float(FloatTy::F32) = cast_to.kind() { 32 } else { 64 @@ -1507,7 +1507,7 @@ fn lint_numeric_casts<'tcx>( check_lossless(cx, expr, cast_expr, cast_from, cast_to); }, (false, false) => { - if let (&ty::Float(FloatTy::F64), &ty::Float(FloatTy::F32)) = (&cast_from.kind, &cast_to.kind) { + if let (&ty::Float(FloatTy::F64), &ty::Float(FloatTy::F32)) = (&cast_from.kind(), &cast_to.kind()) { span_lint( cx, CAST_POSSIBLE_TRUNCATION, @@ -1515,7 +1515,7 @@ fn lint_numeric_casts<'tcx>( "casting `f64` to `f32` may truncate the value", ); } - if let (&ty::Float(FloatTy::F32), &ty::Float(FloatTy::F64)) = (&cast_from.kind, &cast_to.kind) { + if let (&ty::Float(FloatTy::F32), &ty::Float(FloatTy::F64)) = (&cast_from.kind(), &cast_to.kind()) { span_lossless_lint(cx, expr, cast_expr, cast_from, cast_to); } }, @@ -1524,8 +1524,8 @@ fn lint_numeric_casts<'tcx>( fn lint_cast_ptr_alignment<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, cast_from: Ty<'tcx>, cast_to: Ty<'tcx>) { if_chain! { - if let ty::RawPtr(from_ptr_ty) = &cast_from.kind; - if let ty::RawPtr(to_ptr_ty) = &cast_to.kind; + if let ty::RawPtr(from_ptr_ty) = &cast_from.kind(); + if let ty::RawPtr(to_ptr_ty) = &cast_to.kind(); if let Ok(from_layout) = cx.layout_of(from_ptr_ty.ty); if let Ok(to_layout) = cx.layout_of(to_ptr_ty.ty); if from_layout.align.abi < to_layout.align.abi; @@ -1558,11 +1558,11 @@ fn lint_fn_to_numeric_cast( cast_to: Ty<'_>, ) { // We only want to check casts to `ty::Uint` or `ty::Int` - match cast_to.kind { + match cast_to.kind() { ty::Uint(_) | ty::Int(..) => { /* continue on */ }, _ => return, } - match cast_from.kind { + match cast_from.kind() { ty::FnDef(..) | ty::FnPtr(_) => { let mut applicability = Applicability::MaybeIncorrect; let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability); @@ -1581,7 +1581,7 @@ fn lint_fn_to_numeric_cast( format!("{} as usize", from_snippet), applicability, ); - } else if cast_to.kind != ty::Uint(UintTy::Usize) { + } else if *cast_to.kind() != ty::Uint(UintTy::Usize) { span_lint_and_sugg( cx, FN_TO_NUMERIC_CAST, @@ -1798,7 +1798,7 @@ impl<'tcx> LateLintPass<'tcx> for CharLitAsU8 { if let ExprKind::Cast(e, _) = &expr.kind; if let ExprKind::Lit(l) = &e.kind; if let LitKind::Char(c) = l.node; - if ty::Uint(UintTy::U8) == cx.typeck_results().expr_ty(expr).kind; + if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(expr).kind(); then { let mut applicability = Applicability::MachineApplicable; let snippet = snippet_with_applicability(cx, e.span, "'x'", &mut applicability); @@ -1937,7 +1937,7 @@ fn detect_extreme_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Op let cv = constant(cx, cx.typeck_results(), expr)?.0; - let which = match (&ty.kind, cv) { + let which = match (ty.kind(), cv) { (&ty::Bool, Constant::Bool(false)) | (&ty::Uint(_), Constant::Int(0)) => Minimum, (&ty::Int(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::MIN >> (128 - int_bits(cx.tcx, ity)), ity) => { Minimum @@ -2071,7 +2071,7 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> if cx.layout_of(pre_cast_ty).ok().map(|l| l.size) == cx.layout_of(cast_ty).ok().map(|l| l.size) { return None; } - match pre_cast_ty.kind { + match pre_cast_ty.kind() { ty::Int(int_ty) => Some(match int_ty { IntTy::I8 => (FullInt::S(i128::from(i8::MIN)), FullInt::S(i128::from(i8::MAX))), IntTy::I16 => (FullInt::S(i128::from(i16::MIN)), FullInt::S(i128::from(i16::MAX))), @@ -2098,7 +2098,7 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> fn node_as_const_fullint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option { let val = constant(cx, cx.typeck_results(), expr)?.0; if let Constant::Int(const_int) = val { - match cx.typeck_results().expr_ty(expr).kind { + match *cx.typeck_results().expr_ty(expr).kind() { ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))), ty::Uint(_) => Some(FullInt::U(const_int)), _ => None, @@ -2601,7 +2601,7 @@ impl<'tcx> LateLintPass<'tcx> for RefToMut { if let TyKind::Ptr(MutTy { mutbl: Mutability::Mut, .. }) = t.kind; if let ExprKind::Cast(e, t) = &e.kind; if let TyKind::Ptr(MutTy { mutbl: Mutability::Not, .. }) = t.kind; - if let ty::Ref(..) = cx.typeck_results().node_type(e.hir_id).kind; + if let ty::Ref(..) = cx.typeck_results().node_type(e.hir_id).kind(); then { span_lint( cx, diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index 679aaec9fcd6c..0d5a5017331b7 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -110,7 +110,7 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Span, Option)> { if_chain! { if let ExprKind::Closure(_, _fn_decl, body_id, span, _) = arg.kind; - if let ty::Closure(_def_id, substs) = &cx.typeck_results().node_type(arg.hir_id).kind; + if let ty::Closure(_def_id, substs) = &cx.typeck_results().node_type(arg.hir_id).kind(); let ret_ty = substs.as_closure().sig().output(); let ty = cx.tcx.erase_late_bound_regions(&ret_ty); if ty.is_unit(); diff --git a/clippy_lints/src/unnamed_address.rs b/clippy_lints/src/unnamed_address.rs index 28b393b9f11f0..9582c162e77b2 100644 --- a/clippy_lints/src/unnamed_address.rs +++ b/clippy_lints/src/unnamed_address.rs @@ -65,14 +65,14 @@ impl LateLintPass<'_> for UnnamedAddress { } fn is_trait_ptr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - match cx.typeck_results().expr_ty_adjusted(expr).kind { + match cx.typeck_results().expr_ty_adjusted(expr).kind() { ty::RawPtr(ty::TypeAndMut { ty, .. }) => ty.is_trait(), _ => false, } } fn is_fn_def(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - matches!(cx.typeck_results().expr_ty(expr).kind, ty::FnDef(..)) + matches!(cx.typeck_results().expr_ty(expr).kind(), ty::FnDef(..)) } if_chain! { diff --git a/clippy_lints/src/unnecessary_sort_by.rs b/clippy_lints/src/unnecessary_sort_by.rs index 59993d25bb470..8b00d29acb52c 100644 --- a/clippy_lints/src/unnecessary_sort_by.rs +++ b/clippy_lints/src/unnecessary_sort_by.rs @@ -230,7 +230,7 @@ fn key_returns_borrow(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { if let Some(def_id) = utils::fn_def_id(cx, expr) { let output = cx.tcx.fn_sig(def_id).output(); let ty = output.skip_binder(); - return matches!(ty.kind, ty::Ref(..)) + return matches!(ty.kind(), ty::Ref(..)) || ty.walk().any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_))); } diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 4ab2b5e796deb..615440e15f384 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -107,7 +107,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(&args[0]); if is_type_diagnostic_item(cx, a, sym!(result_type)); - if let ty::Adt(_, substs) = a.kind; + if let ty::Adt(_, substs) = a.kind(); if let Some(a_type) = substs.types().next(); if TyS::same_type(a_type, b); @@ -137,7 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if_chain! { if match_def_path(cx, def_id, &paths::TRY_FROM); if is_type_diagnostic_item(cx, a, sym!(result_type)); - if let ty::Adt(_, substs) = a.kind; + if let ty::Adt(_, substs) = a.kind(); if let Some(a_type) = substs.types().next(); if TyS::same_type(a_type, b); diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 8200525711564..45add9ab284d2 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -129,7 +129,7 @@ pub fn is_wild<'tcx>(pat: &impl std::ops::Deref>) -> bool { /// Checks if type is struct, enum or union type with the given def path. pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool { - match ty.kind { + match ty.kind() { ty::Adt(adt, _) => match_def_path(cx, adt.did, path), _ => false, } @@ -137,7 +137,7 @@ pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool { /// Checks if the type is equal to a diagnostic item pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symbol) -> bool { - match ty.kind { + match ty.kind() { ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did), _ => false, } @@ -145,7 +145,7 @@ pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symb /// Checks if the type is equal to a lang item pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangItem) -> bool { - match ty.kind { + match ty.kind() { ty::Adt(adt, _) => cx.tcx.lang_items().require(lang_item).unwrap() == adt.did, _ => false, } @@ -754,7 +754,7 @@ pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> { /// Returns the base type for references and raw pointers. pub fn walk_ptrs_ty(ty: Ty<'_>) -> Ty<'_> { - match ty.kind { + match ty.kind() { ty::Ref(_, ty, _) => walk_ptrs_ty(ty), _ => ty, } @@ -764,7 +764,7 @@ pub fn walk_ptrs_ty(ty: Ty<'_>) -> Ty<'_> { /// depth. pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) { fn inner(ty: Ty<'_>, depth: usize) -> (Ty<'_>, usize) { - match ty.kind { + match ty.kind() { ty::Ref(_, ty, _) => inner(ty, depth + 1), _ => (ty, depth), } @@ -877,7 +877,7 @@ pub fn contains_ty(ty: Ty<'_>, other_ty: Ty<'_>) -> bool { /// Returns `true` if the given type is an `unsafe` function. pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - match ty.kind { + match ty.kind() { ty::FnDef(..) | ty::FnPtr(_) => ty.fn_sig(cx.tcx).unsafety() == Unsafety::Unsafe, _ => false, } @@ -942,7 +942,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, pats.iter().map(|pat| &**pat)) }, PatKind::Slice(ref head, ref middle, ref tail) => { - match &cx.typeck_results().node_type(pat.hir_id).kind { + match &cx.typeck_results().node_type(pat.hir_id).kind() { ty::Slice(..) => { // [..] is the only irrefutable slice pattern. !head.is_empty() || middle.is_none() || !tail.is_empty() @@ -1156,12 +1156,12 @@ pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option< &paths::RECEIVER, ]; - let ty_to_check = match probably_ref_ty.kind { + let ty_to_check = match probably_ref_ty.kind() { ty::Ref(_, ty_to_check, _) => ty_to_check, _ => probably_ref_ty, }; - let def_id = match ty_to_check.kind { + let def_id = match ty_to_check.kind() { ty::Array(..) => return Some("array"), ty::Slice(..) => return Some("slice"), ty::Adt(adt, _) => adt.did, @@ -1277,7 +1277,7 @@ pub fn must_use_attr(attrs: &[Attribute]) -> Option<&Attribute> { // Returns whether the type has #[must_use] attribute pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - match ty.kind { + match ty.kind() { ty::Adt(ref adt, _) => must_use_attr(&cx.tcx.get_attrs(adt.did)).is_some(), ty::Foreign(ref did) => must_use_attr(&cx.tcx.get_attrs(*did)).is_some(), ty::Slice(ref ty) @@ -1409,9 +1409,9 @@ pub fn run_lints(cx: &LateContext<'_>, lints: &[&'static Lint], id: HirId) -> bo /// Returns true iff the given type is a primitive (a bool or char, any integer or floating-point /// number type, a str, or an array, slice, or tuple of those types). pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool { - match ty.kind { + match ty.kind() { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true, - ty::Ref(_, inner, _) if inner.kind == ty::Str => true, + ty::Ref(_, inner, _) if *inner.kind() == ty::Str => true, ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(inner_type), ty::Tuple(inner_types) => inner_types.types().all(is_recursively_primitive_type), _ => false, @@ -1423,24 +1423,23 @@ pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool { /// `is_recursively_primitive_type` function) and None otherwise. pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { let expr_type = cx.typeck_results().expr_ty_adjusted(expr); - let expr_kind = &expr_type.kind; + let expr_kind = expr_type.kind(); let is_primitive = match expr_kind { - ty::Slice(ref element_type) - | ty::Ref( - _, - ty::TyS { - kind: ty::Slice(ref element_type), - .. - }, - _, - ) => is_recursively_primitive_type(element_type), + ty::Slice(element_type) => is_recursively_primitive_type(element_type), + ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), &ty::Slice(_)) => { + if let ty::Slice(element_type) = inner_ty.kind() { + is_recursively_primitive_type(element_type) + } else { + unreachable!() + } + } _ => false, }; if is_primitive { // if we have wrappers like Array, Slice or Tuple, print these // and get the type enclosed in the slice ref - match expr_type.peel_refs().walk().nth(1).unwrap().expect_ty().kind { + match expr_type.peel_refs().walk().nth(1).unwrap().expect_ty().kind() { ty::Slice(..) => return Some("slice".into()), ty::Array(..) => return Some("array".into()), ty::Tuple(..) => return Some("tuple".into()), diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 84e907d7125de..149cceb39dd99 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -44,8 +44,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { // search for `&vec![_]` expressions where the adjusted type is `&[_]` if_chain! { - if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(expr).kind; - if let ty::Slice(..) = ty.kind; + if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(expr).kind(); + if let ty::Slice(..) = ty.kind(); if let ExprKind::AddrOf(BorrowKind::Ref, _, ref addressee) = expr.kind; if let Some(vec_args) = higher::vec_macro(cx, addressee); then { @@ -127,7 +127,7 @@ fn size_of(cx: &LateContext<'_>, expr: &Expr<'_>) -> u64 { /// Returns the item type of the vector (i.e., the `T` in `Vec`). fn vec_type(ty: Ty<'_>) -> Ty<'_> { - if let ty::Adt(_, substs) = ty.kind { + if let ty::Adt(_, substs) = ty.kind() { substs.type_at(0) } else { panic!("The type of `vec!` is a not a struct?"); From 4286d9c87af269e46203fc1ca8108669d00e7c63 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Thu, 6 Aug 2020 17:49:46 +0200 Subject: [PATCH 0099/1052] ty.flags -> ty.flags() --- clippy_lints/src/non_copy_const.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index f1df634701dd2..73eabd4207e77 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -128,7 +128,7 @@ fn verify_ty_bound<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, source: Source) { diag.span_label(const_kw_span, "make this a static item (maybe with lazy_static)"); }, Source::Assoc { ty: ty_span, .. } => { - if ty.flags.intersects(TypeFlags::HAS_FREE_LOCAL_NAMES) { + if ty.flags().intersects(TypeFlags::HAS_FREE_LOCAL_NAMES) { diag.span_label(ty_span, &format!("consider requiring `{}` to be `Copy`", ty)); } }, From 6cb671628393e292d5e68e6367f80488ace46532 Mon Sep 17 00:00:00 2001 From: kadmin Date: Sun, 16 Aug 2020 03:01:38 +0000 Subject: [PATCH 0100/1052] Add test for checking if-let or-patterns --- src/test/mir-opt/issues/issue-75439.rs | 21 +++++ ...e_75439.foo.MatchBranchSimplification.diff | 87 +++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 src/test/mir-opt/issues/issue-75439.rs create mode 100644 src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff diff --git a/src/test/mir-opt/issues/issue-75439.rs b/src/test/mir-opt/issues/issue-75439.rs new file mode 100644 index 0000000000000..44d6bc619d3bb --- /dev/null +++ b/src/test/mir-opt/issues/issue-75439.rs @@ -0,0 +1,21 @@ +// EMIT_MIR issue_75439.foo.MatchBranchSimplification.diff + +#![feature(const_fn_transmute)] +#![feature(or_patterns)] + +use std::mem::transmute; + +pub fn foo(bytes: [u8; 16]) -> Option<[u8; 4]> { + // big endian `u32`s + let dwords: [u32; 4] = unsafe { transmute(bytes) }; + const FF: u32 = 0x0000_ffff_u32.to_be(); + if let [0, 0, 0 | FF, ip] = dwords { + Some(unsafe { transmute(ip) }) + } else { + None + } +} + +fn main() { + let _ = foo([0; 16]); +} diff --git a/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff b/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff new file mode 100644 index 0000000000000..43422b36e1e52 --- /dev/null +++ b/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff @@ -0,0 +1,87 @@ +- // MIR for `foo` before MatchBranchSimplification ++ // MIR for `foo` after MatchBranchSimplification + + fn foo(_1: [u8; 16]) -> Option<[u8; 4]> { + debug bytes => _1; // in scope 0 at $DIR/issue-75439.rs:8:12: 8:17 + let mut _0: std::option::Option<[u8; 4]>; // return place in scope 0 at $DIR/issue-75439.rs:8:32: 8:47 + let _2: [u32; 4]; // in scope 0 at $DIR/issue-75439.rs:10:9: 10:15 + let mut _3: [u8; 16]; // in scope 0 at $DIR/issue-75439.rs:10:47: 10:52 + let mut _5: [u8; 4]; // in scope 0 at $DIR/issue-75439.rs:13:14: 13:38 + let mut _6: u32; // in scope 0 at $DIR/issue-75439.rs:13:33: 13:35 + scope 1 { + debug dwords => _2; // in scope 1 at $DIR/issue-75439.rs:10:9: 10:15 + let _4: u32; // in scope 1 at $DIR/issue-75439.rs:12:27: 12:29 + scope 3 { + debug ip => _4; // in scope 3 at $DIR/issue-75439.rs:12:27: 12:29 + scope 4 { + } + } + } + scope 2 { + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/issue-75439.rs:10:9: 10:15 + StorageLive(_3); // scope 2 at $DIR/issue-75439.rs:10:47: 10:52 + _3 = _1; // scope 2 at $DIR/issue-75439.rs:10:47: 10:52 + _2 = transmute::<[u8; 16], [u32; 4]>(move _3) -> bb1; // scope 2 at $DIR/issue-75439.rs:10:37: 10:53 + // mir::Constant + // + span: $DIR/issue-75439.rs:10:37: 10:46 + // + literal: Const { ty: unsafe extern "rust-intrinsic" fn([u8; 16]) -> [u32; 4] {std::intrinsics::transmute::<[u8; 16], [u32; 4]>}, val: Value(Scalar()) } + } + + bb1: { + StorageDead(_3); // scope 2 at $DIR/issue-75439.rs:10:52: 10:53 + switchInt(_2[0 of 4]) -> [0_u32: bb2, otherwise: bb4]; // scope 1 at $DIR/issue-75439.rs:12:13: 12:14 + } + + bb2: { + switchInt(_2[1 of 4]) -> [0_u32: bb3, otherwise: bb4]; // scope 1 at $DIR/issue-75439.rs:12:16: 12:17 + } + + bb3: { + switchInt(_2[2 of 4]) -> [0_u32: bb6, 4294901760_u32: bb7, otherwise: bb4]; // scope 1 at $DIR/issue-75439.rs:12:19: 12:20 + } + + bb4: { + discriminant(_0) = 0; // scope 1 at $DIR/issue-75439.rs:15:9: 15:13 + goto -> bb9; // scope 1 at $DIR/issue-75439.rs:12:5: 16:6 + } + + bb5: { + StorageLive(_5); // scope 3 at $DIR/issue-75439.rs:13:14: 13:38 + StorageLive(_6); // scope 4 at $DIR/issue-75439.rs:13:33: 13:35 + _6 = _4; // scope 4 at $DIR/issue-75439.rs:13:33: 13:35 + _5 = transmute::(move _6) -> bb8; // scope 4 at $DIR/issue-75439.rs:13:23: 13:36 + // mir::Constant + // + span: $DIR/issue-75439.rs:13:23: 13:32 + // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) -> [u8; 4] {std::intrinsics::transmute::}, val: Value(Scalar()) } + } + + bb6: { + StorageLive(_4); // scope 1 at $DIR/issue-75439.rs:12:27: 12:29 + _4 = _2[3 of 4]; // scope 1 at $DIR/issue-75439.rs:12:27: 12:29 + goto -> bb5; // scope 1 at $DIR/issue-75439.rs:12:5: 16:6 + } + + bb7: { + StorageLive(_4); // scope 1 at $DIR/issue-75439.rs:12:27: 12:29 + _4 = _2[3 of 4]; // scope 1 at $DIR/issue-75439.rs:12:27: 12:29 + goto -> bb5; // scope 1 at $DIR/issue-75439.rs:12:5: 16:6 + } + + bb8: { + StorageDead(_6); // scope 4 at $DIR/issue-75439.rs:13:35: 13:36 + ((_0 as Some).0: [u8; 4]) = move _5; // scope 3 at $DIR/issue-75439.rs:13:9: 13:39 + discriminant(_0) = 1; // scope 3 at $DIR/issue-75439.rs:13:9: 13:39 + StorageDead(_5); // scope 3 at $DIR/issue-75439.rs:13:38: 13:39 + StorageDead(_4); // scope 1 at $DIR/issue-75439.rs:14:5: 14:6 + goto -> bb9; // scope 1 at $DIR/issue-75439.rs:12:5: 16:6 + } + + bb9: { + StorageDead(_2); // scope 0 at $DIR/issue-75439.rs:17:1: 17:2 + return; // scope 0 at $DIR/issue-75439.rs:17:2: 17:2 + } + } + From 7bcf40a13d90952d9a59ed547832155439e3bcf7 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Fri, 4 Sep 2020 23:30:06 +0200 Subject: [PATCH 0101/1052] Fix fallout from rustup --- clippy_lints/src/default_trait_access.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/default_trait_access.rs b/clippy_lints/src/default_trait_access.rs index 320a2a257bd09..3048436d9a7b5 100644 --- a/clippy_lints/src/default_trait_access.rs +++ b/clippy_lints/src/default_trait_access.rs @@ -42,7 +42,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultTraitAccess { if let QPath::Resolved(None, _path) = qpath; then { let expr_ty = cx.typeck_results().expr_ty(expr); - if let ty::Adt(def, ..) = expr_ty.kind { + if let ty::Adt(def, ..) = expr_ty.kind() { // TODO: Work out a way to put "whatever the imported way of referencing // this type in this file" rather than a fully-qualified type. let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did)); From 2905fff93659d17f1c6b1cf270b5731e04ebe46d Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Fri, 4 Sep 2020 23:30:55 +0200 Subject: [PATCH 0102/1052] Run cargo dev fmt --- clippy_lints/src/utils/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 96e9d0f32f8e3..bea0a4d24593c 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -1432,7 +1432,7 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option false, }; From c31d4730b0d40c62934839405d0c25e2ffa3fad1 Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Fri, 4 Sep 2020 15:55:13 -0700 Subject: [PATCH 0103/1052] update example to be more idiomatic --- clippy_lints/src/map_err_ignore.rs | 87 ++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 27 deletions(-) diff --git a/clippy_lints/src/map_err_ignore.rs b/clippy_lints/src/map_err_ignore.rs index 9211113ed0467..649de4133e067 100644 --- a/clippy_lints/src/map_err_ignore.rs +++ b/clippy_lints/src/map_err_ignore.rs @@ -14,55 +14,88 @@ declare_clippy_lint! { /// **Example:** /// Before: /// ```rust - /// use std::convert::TryFrom; + /// use std::fmt; /// /// #[derive(Debug)] - /// enum Errors { - /// Ignored + /// enum Error { + /// Indivisible, + /// Remainder(u8), + /// } + /// + /// impl fmt::Display for Error { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// match self { + /// Error::Indivisible => write!(f, "could not divide input by three"), + /// Error::Remainder(remainder) => write!( + /// f, + /// "input is not divisible by three, remainder = {}", + /// remainder + /// ), + /// } + /// } /// } /// - /// fn divisible_by_3(inp: i32) -> Result { - /// let i = u32::try_from(inp).map_err(|_| Errors::Ignored)?; + /// impl std::error::Error for Error {} /// - /// Ok(i) + /// fn divisible_by_3(input: &str) -> Result<(), Error> { + /// input + /// .parse::() + /// .map_err(|_| Error::Indivisible) + /// .map(|v| v % 3) + /// .and_then(|remainder| { + /// if remainder == 0 { + /// Ok(()) + /// } else { + /// Err(Error::Remainder(remainder as u8)) + /// } + /// }) /// } /// ``` /// /// After: /// ```rust - /// use std::convert::TryFrom; - /// use std::num::TryFromIntError; - /// use std::fmt; - /// use std::error::Error; + /// use std::{fmt, num::ParseIntError}; /// /// #[derive(Debug)] - /// enum ParseError { - /// Indivisible { - /// source: TryFromIntError, - /// input: String, - /// } + /// enum Error { + /// Indivisible(ParseIntError), + /// Remainder(u8), /// } /// - /// impl fmt::Display for ParseError { + /// impl fmt::Display for Error { /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - /// match &self { - /// ParseError::Indivisible{source: _, input} => write!(f, "Error: {}", input) + /// match self { + /// Error::Indivisible(_) => write!(f, "could not divide input by three"), + /// Error::Remainder(remainder) => write!( + /// f, + /// "input is not divisible by three, remainder = {}", + /// remainder + /// ), /// } /// } /// } /// - /// impl Error for ParseError {} - /// - /// impl ParseError { - /// fn new(source: TryFromIntError, input: String) -> ParseError { - /// ParseError::Indivisible{source, input} + /// impl std::error::Error for Error { + /// fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + /// match self { + /// Error::Indivisible(source) => Some(source), + /// _ => None, + /// } /// } /// } /// - /// fn divisible_by_3(inp: i32) -> Result { - /// let i = u32::try_from(inp).map_err(|e| ParseError::new(e, e.to_string()))?; - /// - /// Ok(i) + /// fn divisible_by_3(input: &str) -> Result<(), Error> { + /// input + /// .parse::() + /// .map_err(Error::Indivisible) + /// .map(|v| v % 3) + /// .and_then(|remainder| { + /// if remainder == 0 { + /// Ok(()) + /// } else { + /// Err(Error::Remainder(remainder as u8)) + /// } + /// }) /// } /// ``` pub MAP_ERR_IGNORE, From 04ba07bdc3c82aa17297e3e91fdc884983be7cad Mon Sep 17 00:00:00 2001 From: Ryan1729 Date: Fri, 4 Sep 2020 19:26:35 -0600 Subject: [PATCH 0104/1052] add line_count and max_lines to too_many_lines lint message --- clippy_lints/src/functions.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 89fde1d509d30..50b39cf4ea7c0 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -374,7 +374,12 @@ impl<'tcx> Functions { } if line_count > self.max_lines { - span_lint(cx, TOO_MANY_LINES, span, "this function has a large number of lines") + span_lint( + cx, + TOO_MANY_LINES, + span, + &format!("this function has too many lines ({}/{})", line_count, self.max_lines), + ) } } From db16fa26cef82fff84751dcad7940fd9b819a169 Mon Sep 17 00:00:00 2001 From: Ryan1729 Date: Fri, 4 Sep 2020 20:16:02 -0600 Subject: [PATCH 0105/1052] run tests/ui/update-all-references.sh --- tests/ui/functions_maxlines.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/functions_maxlines.stderr b/tests/ui/functions_maxlines.stderr index c640c82d6d7c9..dc6c8ba2f154d 100644 --- a/tests/ui/functions_maxlines.stderr +++ b/tests/ui/functions_maxlines.stderr @@ -1,4 +1,4 @@ -error: this function has a large number of lines +error: this function has too many lines (102/100) --> $DIR/functions_maxlines.rs:58:1 | LL | / fn bad_lines() { From f6a6d2fef6c090806e961acb89817be8329f8208 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Sat, 1 Aug 2020 11:07:12 -0700 Subject: [PATCH 0106/1052] Add slice::array_chunks_mut --- library/core/src/slice/mod.rs | 151 ++++++++++++++++++++++++++++++++-- 1 file changed, 146 insertions(+), 5 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 68977a983aa37..18ff50b8dbd41 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -997,9 +997,9 @@ impl [T] { /// Returns an iterator over `N` elements of the slice at a time, starting at the /// beginning of the slice. /// - /// The chunks are slices and do not overlap. If `N` does not divide the length of the - /// slice, then the last up to `N-1` elements will be omitted and can be retrieved - /// from the `remainder` function of the iterator. + /// The chunks are array references and do not overlap. If `N` does not divide the + /// length of the slice, then the last up to `N-1` elements will be omitted and can be + /// retrieved from the `remainder` function of the iterator. /// /// This method is the const generic equivalent of [`chunks_exact`]. /// @@ -1033,6 +1033,51 @@ impl [T] { ArrayChunks { iter: array_slice.iter(), rem: snd } } + /// Returns an iterator over `N` elements of the slice at a time, starting at the + /// beginning of the slice. + /// + /// The chunks are mutable array references and do not overlap. If `N` does not divide + /// the length of the slice, then the last up to `N-1` elements will be omitted and + /// can be retrieved from the `into_remainder` function of the iterator. + /// + /// This method is the const generic equivalent of [`chunks_exact_mut`]. + /// + /// # Panics + /// + /// Panics if `N` is 0. This check will most probably get changed to a compile time + /// error before this method gets stabilized. + /// + /// # Examples + /// + /// ``` + /// #![feature(array_chunks)] + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.array_chunks_mut() { + /// *chunk = [count; 2]; + /// count += 1; + /// } + /// assert_eq!(v, &[1, 1, 2, 2, 0]); + /// ``` + /// + /// [`chunks_exact_mut`]: #method.chunks_exact_mut + #[unstable(feature = "array_chunks", issue = "74985")] + #[inline] + pub fn array_chunks_mut(&mut self) -> ArrayChunksMut<'_, T, N> { + assert_ne!(N, 0); + let len = self.len() / N; + let (fst_ptr, snd) = { + // Scope the first slice into a pointer to avoid aliasing the new slice below. + let (fst, snd) = self.split_at_mut(len * N); + (fst.as_mut_ptr(), snd) + }; + // SAFETY: We cast a slice of `len * N` elements into + // a slice of `len` many `N` elements chunks. + let array_slice: &mut [[T; N]] = unsafe { from_raw_parts_mut(fst_ptr.cast(), len) }; + ArrayChunksMut { iter: array_slice.iter_mut(), rem: snd } + } + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end /// of the slice. /// @@ -5826,7 +5871,7 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> { /// time), starting at the beginning of the slice. /// /// When the slice len is not evenly divided by the chunk size, the last -/// up to `chunk_size-1` elements will be omitted but can be retrieved from +/// up to `N-1` elements will be omitted but can be retrieved from /// the [`remainder`] function from the iterator. /// /// This struct is created by the [`array_chunks`] method on [slices]. @@ -5843,7 +5888,7 @@ pub struct ArrayChunks<'a, T: 'a, const N: usize> { impl<'a, T, const N: usize> ArrayChunks<'a, T, N> { /// Returns the remainder of the original slice that is not going to be - /// returned by the iterator. The returned slice has at most `chunk_size-1` + /// returned by the iterator. The returned slice has at most `N-1` /// elements. #[unstable(feature = "array_chunks", issue = "74985")] pub fn remainder(&self) -> &'a [T] { @@ -5929,6 +5974,102 @@ unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> } } +/// An iterator over a slice in (non-overlapping) mutable chunks (`N` elements +/// at a time), starting at the beginning of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last +/// up to `N-1` elements will be omitted but can be retrieved from +/// the [`into_remainder`] function from the iterator. +/// +/// This struct is created by the [`array_chunks_mut`] method on [slices]. +/// +/// [`array_chunks_mut`]: ../../std/primitive.slice.html#method.array_chunks_mut +/// [`into_remainder`]: ../../std/slice/struct.ArrayChunksMut.html#method.into_remainder +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[unstable(feature = "array_chunks", issue = "74985")] +pub struct ArrayChunksMut<'a, T: 'a, const N: usize> { + iter: IterMut<'a, [T; N]>, + rem: &'a mut [T], +} + +impl<'a, T, const N: usize> ArrayChunksMut<'a, T, N> { + /// Returns the remainder of the original slice that is not going to be + /// returned by the iterator. The returned slice has at most `N-1` + /// elements. + #[unstable(feature = "array_chunks", issue = "74985")] + pub fn into_remainder(self) -> &'a mut [T] { + self.rem + } +} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl<'a, T, const N: usize> Iterator for ArrayChunksMut<'a, T, N> { + type Item = &'a mut [T; N]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T; N]> { + self.iter.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[inline] + fn count(self) -> usize { + self.iter.count() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + self.iter.nth(n) + } + + #[inline] + fn last(self) -> Option { + self.iter.last() + } +} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunksMut<'a, T, N> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T; N]> { + self.iter.next_back() + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + self.iter.nth_back(n) + } +} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl ExactSizeIterator for ArrayChunksMut<'_, T, N> { + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for ArrayChunksMut<'_, T, N> {} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl FusedIterator for ArrayChunksMut<'_, T, N> {} + +#[doc(hidden)] +#[unstable(feature = "array_chunks", issue = "74985")] +unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunksMut<'a, T, N> { + unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T; N] { + unsafe { self.iter.get_unchecked(i) } + } + fn may_have_side_effect() -> bool { + false + } +} + /// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a /// time), starting at the end of the slice. /// From b9fd6734e8ce315f0825157c0bf3aad67521e664 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Sat, 1 Aug 2020 11:07:28 -0700 Subject: [PATCH 0107/1052] Add tests for array_chunks_mut --- library/core/tests/slice.rs | 93 +++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index 743df68699c28..9b31e532a6a9f 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -564,6 +564,99 @@ fn test_array_chunks_zip() { assert_eq!(res, vec![14, 22]); } +#[test] +fn test_array_chunks_mut_infer() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6]; + for a in v.array_chunks_mut() { + let sum = a.iter().sum::(); + *a = [sum; 3]; + } + assert_eq!(v, &[3, 3, 3, 12, 12, 12, 6]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6]; + v2.array_chunks_mut().for_each(|[a, b]| core::mem::swap(a, b)); + assert_eq!(v2, &[1, 0, 3, 2, 5, 4, 6]); +} + +#[test] +fn test_array_chunks_mut_count() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let c = v.array_chunks_mut::<3>(); + assert_eq!(c.count(), 2); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c2 = v2.array_chunks_mut::<2>(); + assert_eq!(c2.count(), 2); + + let v3: &mut [i32] = &mut []; + let c3 = v3.array_chunks_mut::<2>(); + assert_eq!(c3.count(), 0); +} + +#[test] +fn test_array_chunks_mut_nth() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let mut c = v.array_chunks_mut::<2>(); + assert_eq!(c.nth(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[4, 5]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6]; + let mut c2 = v2.array_chunks_mut::<3>(); + assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]); + assert_eq!(c2.next(), None); +} + +#[test] +fn test_array_chunks_mut_nth_back() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let mut c = v.array_chunks_mut::<2>(); + assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[0, 1]); + assert_eq!(c.next(), None); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let mut c2 = v2.array_chunks_mut::<3>(); + assert_eq!(c2.nth_back(0).unwrap(), &[0, 1, 2]); + assert_eq!(c2.next(), None); + assert_eq!(c2.next_back(), None); + + let v3: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let mut c3 = v3.array_chunks_mut::<10>(); + assert_eq!(c3.nth_back(0), None); +} + +#[test] +fn test_array_chunks_mut_last() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let c = v.array_chunks_mut::<2>(); + assert_eq!(c.last().unwrap(), &[4, 5]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c2 = v2.array_chunks_mut::<2>(); + assert_eq!(c2.last().unwrap(), &[2, 3]); +} + +#[test] +fn test_array_chunks_mut_remainder() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c = v.array_chunks_mut::<2>(); + assert_eq!(c.into_remainder(), &[4]); +} + +#[test] +fn test_array_chunks_mut_zip() { + let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + for (a, b) in v1.array_chunks_mut::<2>().zip(v2.array_chunks::<2>()) { + let sum = b.iter().sum::(); + for v in a { + *v += sum; + } + } + assert_eq!(v1, [13, 14, 19, 20, 4]); +} + #[test] fn test_rchunks_count() { let v: &[i32] = &[0, 1, 2, 3, 4, 5]; From 864a28e01d70cd73ef7f0b64f6793697f638b8b0 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Sat, 1 Aug 2020 11:48:34 -0700 Subject: [PATCH 0108/1052] Re-export ArrayChunksMut in alloc --- library/alloc/src/slice.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 8ea2c6dc859b2..677bfdd2349ec 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -93,6 +93,8 @@ use crate::vec::Vec; #[unstable(feature = "array_chunks", issue = "74985")] pub use core::slice::ArrayChunks; +#[unstable(feature = "array_chunks", issue = "74985")] +pub use core::slice::ArrayChunksMut; #[stable(feature = "slice_get_slice", since = "1.28.0")] pub use core::slice::SliceIndex; #[stable(feature = "from_ref", since = "1.28.0")] From 21903532eee96a5311d08b8a9e9cc9f9231bc478 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Sun, 2 Aug 2020 10:35:57 -0700 Subject: [PATCH 0109/1052] Build the slice directly in array_chunks_mut Review discussion found that the concern about aliasing was overblown, so we can simplify this to cast from one slice to another directly. --- library/core/src/slice/mod.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 18ff50b8dbd41..a32ea062de494 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1067,14 +1067,11 @@ impl [T] { pub fn array_chunks_mut(&mut self) -> ArrayChunksMut<'_, T, N> { assert_ne!(N, 0); let len = self.len() / N; - let (fst_ptr, snd) = { - // Scope the first slice into a pointer to avoid aliasing the new slice below. - let (fst, snd) = self.split_at_mut(len * N); - (fst.as_mut_ptr(), snd) - }; + let (fst, snd) = self.split_at_mut(len * N); // SAFETY: We cast a slice of `len * N` elements into // a slice of `len` many `N` elements chunks. - let array_slice: &mut [[T; N]] = unsafe { from_raw_parts_mut(fst_ptr.cast(), len) }; + let array_slice: &mut [[T; N]] = + unsafe { from_raw_parts_mut(fst.as_mut_ptr().cast(), len) }; ArrayChunksMut { iter: array_slice.iter_mut(), rem: snd } } From 86b9f710d0c90068866e736bbbb7b89ac93ff2e6 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 4 Sep 2020 20:08:12 -0700 Subject: [PATCH 0110/1052] Move ArrayChunksMut::get_unchecked per #73565 --- library/core/src/slice/mod.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index a32ea062de494..609fdbd599274 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1070,9 +1070,10 @@ impl [T] { let (fst, snd) = self.split_at_mut(len * N); // SAFETY: We cast a slice of `len * N` elements into // a slice of `len` many `N` elements chunks. - let array_slice: &mut [[T; N]] = - unsafe { from_raw_parts_mut(fst.as_mut_ptr().cast(), len) }; - ArrayChunksMut { iter: array_slice.iter_mut(), rem: snd } + unsafe { + let array_slice: &mut [[T; N]] = from_raw_parts_mut(fst.as_mut_ptr().cast(), len); + ArrayChunksMut { iter: array_slice.iter_mut(), rem: snd } + } } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end @@ -6028,6 +6029,12 @@ impl<'a, T, const N: usize> Iterator for ArrayChunksMut<'a, T, N> { fn last(self) -> Option { self.iter.last() } + + unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T; N] { + // SAFETY: The safety guarantees of `get_unchecked` are transferred to + // the caller. + unsafe { self.iter.get_unchecked(i) } + } } #[unstable(feature = "array_chunks", issue = "74985")] @@ -6059,9 +6066,6 @@ impl FusedIterator for ArrayChunksMut<'_, T, N> {} #[doc(hidden)] #[unstable(feature = "array_chunks", issue = "74985")] unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunksMut<'a, T, N> { - unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T; N] { - unsafe { self.iter.get_unchecked(i) } - } fn may_have_side_effect() -> bool { false } From 9e7ce9d3851426f59ec98eabee7f113e4fd18198 Mon Sep 17 00:00:00 2001 From: Ryan1729 Date: Fri, 4 Sep 2020 21:12:16 -0600 Subject: [PATCH 0111/1052] run the specific script suggested by the error message ``` ./tests/ui-toml/update-references.sh './target/debug/test_build_base' 'functions_maxlines/test.rs' ``` --- tests/ui-toml/functions_maxlines/test.stderr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui-toml/functions_maxlines/test.stderr b/tests/ui-toml/functions_maxlines/test.stderr index fb12257021a1e..a27ce945ca584 100644 --- a/tests/ui-toml/functions_maxlines/test.stderr +++ b/tests/ui-toml/functions_maxlines/test.stderr @@ -1,4 +1,4 @@ -error: this function has a large number of lines +error: this function has too many lines (2/1) --> $DIR/test.rs:18:1 | LL | / fn too_many_lines() { @@ -9,7 +9,7 @@ LL | | } | = note: `-D clippy::too-many-lines` implied by `-D warnings` -error: this function has a large number of lines +error: this function has too many lines (2/1) --> $DIR/test.rs:38:1 | LL | / fn comment_before_code() { From 941dca8ed238a04a55741127165e9ad80671ed8a Mon Sep 17 00:00:00 2001 From: Ayush Kumar Mishra Date: Sat, 5 Sep 2020 16:52:52 +0530 Subject: [PATCH 0112/1052] Add Arith Tests in Library --- library/core/tests/num/i32.rs | 27 +++++++++++++++++++++++ src/test/ui/numbers-arithmetic/arith-0.rs | 8 ------- src/test/ui/numbers-arithmetic/arith-1.rs | 24 -------------------- src/test/ui/numbers-arithmetic/arith-2.rs | 9 -------- 4 files changed, 27 insertions(+), 41 deletions(-) delete mode 100644 src/test/ui/numbers-arithmetic/arith-0.rs delete mode 100644 src/test/ui/numbers-arithmetic/arith-1.rs delete mode 100644 src/test/ui/numbers-arithmetic/arith-2.rs diff --git a/library/core/tests/num/i32.rs b/library/core/tests/num/i32.rs index 39250ee84bce6..71a40e14ebceb 100644 --- a/library/core/tests/num/i32.rs +++ b/library/core/tests/num/i32.rs @@ -1 +1,28 @@ int_module!(i32, i32); + +#[test] +fn test_arith_operation() { + let a: isize = 10; + assert_eq!(a * (a - 1), 90); + let i32_a: isize = 10; + assert_eq!(i32_a, 10); + assert_eq!(i32_a - 10, 0); + assert_eq!(i32_a / 10, 1); + assert_eq!(i32_a - 20, -10); + assert_eq!(i32_a << 10, 10240); + assert_eq!(i32_a << 16, 655360); + assert_eq!(i32_a * 16, 160); + assert_eq!(i32_a * i32_a * i32_a, 1000); + assert_eq!(i32_a * i32_a * i32_a * i32_a, 10000); + assert_eq!(i32_a * i32_a / i32_a * i32_a, 100); + assert_eq!(i32_a * (i32_a - 1) << (2 + i32_a as usize), 368640); + let i32_b: isize = 0x10101010; + assert_eq!(i32_b + 1 - 1, i32_b); + assert_eq!(i32_b << 1, i32_b << 1); + assert_eq!(i32_b >> 1, i32_b >> 1); + assert_eq!(i32_b & i32_b << 1, 0); + assert_eq!(i32_b | i32_b << 1, 0x30303030); + let i32_c: isize = 0x10101010; + assert_eq!(i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3), + i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3)); +} diff --git a/src/test/ui/numbers-arithmetic/arith-0.rs b/src/test/ui/numbers-arithmetic/arith-0.rs deleted file mode 100644 index 7943cb908d1f1..0000000000000 --- a/src/test/ui/numbers-arithmetic/arith-0.rs +++ /dev/null @@ -1,8 +0,0 @@ -// run-pass - - -pub fn main() { - let a: isize = 10; - println!("{}", a); - assert_eq!(a * (a - 1), 90); -} diff --git a/src/test/ui/numbers-arithmetic/arith-1.rs b/src/test/ui/numbers-arithmetic/arith-1.rs deleted file mode 100644 index c13c8d8b7659d..0000000000000 --- a/src/test/ui/numbers-arithmetic/arith-1.rs +++ /dev/null @@ -1,24 +0,0 @@ -// run-pass - - -pub fn main() { - let i32_a: isize = 10; - assert_eq!(i32_a, 10); - assert_eq!(i32_a - 10, 0); - assert_eq!(i32_a / 10, 1); - assert_eq!(i32_a - 20, -10); - assert_eq!(i32_a << 10, 10240); - assert_eq!(i32_a << 16, 655360); - assert_eq!(i32_a * 16, 160); - assert_eq!(i32_a * i32_a * i32_a, 1000); - assert_eq!(i32_a * i32_a * i32_a * i32_a, 10000); - assert_eq!(i32_a * i32_a / i32_a * i32_a, 100); - assert_eq!(i32_a * (i32_a - 1) << (2 + i32_a as usize), 368640); - let i32_b: isize = 0x10101010; - assert_eq!(i32_b + 1 - 1, i32_b); - assert_eq!(i32_b << 1, i32_b << 1); - assert_eq!(i32_b >> 1, i32_b >> 1); - assert_eq!(i32_b & i32_b << 1, 0); - println!("{}", i32_b | i32_b << 1); - assert_eq!(i32_b | i32_b << 1, 0x30303030); -} diff --git a/src/test/ui/numbers-arithmetic/arith-2.rs b/src/test/ui/numbers-arithmetic/arith-2.rs deleted file mode 100644 index 46c280677ce84..0000000000000 --- a/src/test/ui/numbers-arithmetic/arith-2.rs +++ /dev/null @@ -1,9 +0,0 @@ -// run-pass - - - -pub fn main() { - let i32_c: isize = 0x10101010; - assert_eq!(i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3), - i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3)); -} From dc37b553accd4fb2f8d0c59f69c701b524361cc2 Mon Sep 17 00:00:00 2001 From: Ayush Kumar Mishra Date: Sat, 5 Sep 2020 17:07:53 +0530 Subject: [PATCH 0113/1052] Minor refactoring --- library/core/tests/num/i32.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/core/tests/num/i32.rs b/library/core/tests/num/i32.rs index 71a40e14ebceb..4acc760ffac99 100644 --- a/library/core/tests/num/i32.rs +++ b/library/core/tests/num/i32.rs @@ -23,6 +23,8 @@ fn test_arith_operation() { assert_eq!(i32_b & i32_b << 1, 0); assert_eq!(i32_b | i32_b << 1, 0x30303030); let i32_c: isize = 0x10101010; - assert_eq!(i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3), - i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3)); + assert_eq!( + i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3), + i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3) + ); } From 7d834c87d2ebb3d8dd4895bc5fabc4d44a1d2b52 Mon Sep 17 00:00:00 2001 From: Ayush Kumar Mishra Date: Sat, 5 Sep 2020 17:24:06 +0530 Subject: [PATCH 0114/1052] Move Various str tests in library --- library/alloc/tests/str.rs | 21 +++++++++++++++++++++ src/test/ui/str-multiline.rs | 13 ------------- src/test/ui/string-escapes.rs | 7 ------- 3 files changed, 21 insertions(+), 20 deletions(-) delete mode 100644 src/test/ui/str-multiline.rs delete mode 100644 src/test/ui/string-escapes.rs diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index b20cf076aca3c..ed8ee2d8823c0 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1921,3 +1921,24 @@ fn different_str_pattern_forwarding_lifetimes() { foo::<&str>("x"); } + +#[test] +fn test_str_multiline() { + let a: String = "this \ +is a test" + .to_string(); + let b: String = "this \ + is \ + another \ + test" + .to_string(); + assert_eq!(a, "this is a test".to_string()); + assert_eq!(b, "this is another test".to_string()); +} + +#[test] +fn test_str_escapes() { + let x = "\\\\\ + "; + assert_eq!(x, r"\\"); // extraneous whitespace stripped +} diff --git a/src/test/ui/str-multiline.rs b/src/test/ui/str-multiline.rs deleted file mode 100644 index 2b2e001d8bb7f..0000000000000 --- a/src/test/ui/str-multiline.rs +++ /dev/null @@ -1,13 +0,0 @@ -// run-pass - -pub fn main() { - let a: String = "this \ -is a test".to_string(); - let b: String = - "this \ - is \ - another \ - test".to_string(); - assert_eq!(a, "this is a test".to_string()); - assert_eq!(b, "this is another test".to_string()); -} diff --git a/src/test/ui/string-escapes.rs b/src/test/ui/string-escapes.rs deleted file mode 100644 index cee5e27786cae..0000000000000 --- a/src/test/ui/string-escapes.rs +++ /dev/null @@ -1,7 +0,0 @@ -// run-pass - -fn main() { - let x = "\\\\\ - "; - assert_eq!(x, r"\\"); // extraneous whitespace stripped -} From 96b31a5b36ed06b6781804d3384a3a84a52b8ce6 Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Sun, 6 Sep 2020 00:02:35 +0900 Subject: [PATCH 0115/1052] Fix FP when coercion kicks in --- clippy_lints/src/loops.rs | 3 ++- tests/ui/same_item_push.rs | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 25345f8fa316c..b65ae15edcd99 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1140,7 +1140,8 @@ fn detect_same_item_push<'tcx>( walk_expr(&mut same_item_push_visitor, body); if same_item_push_visitor.should_lint { if let Some((vec, pushed_item)) = same_item_push_visitor.vec_push { - let ty = cx.typeck_results().expr_ty(pushed_item); + let vec_ty = cx.typeck_results().expr_ty(vec); + let ty = vec_ty.walk().nth(1).unwrap().expect_ty(); if cx .tcx .lang_items() diff --git a/tests/ui/same_item_push.rs b/tests/ui/same_item_push.rs index 0903a87382651..0928820892b13 100644 --- a/tests/ui/same_item_push.rs +++ b/tests/ui/same_item_push.rs @@ -100,4 +100,15 @@ fn main() { for _ in 0..10 { vec14.push(std::fs::File::open("foobar").unwrap()); } + // Fix #5979 + #[derive(Clone)] + struct S {} + + trait T {} + impl T for S {} + + let mut vec15: Vec> = Vec::new(); + for _ in 0..10 { + vec15.push(Box::new(S {})); + } } From 3797f29aadb51ed038e8b9eaf1b2098cfa26d547 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Thu, 20 Aug 2020 11:41:18 -0400 Subject: [PATCH 0116/1052] [WIP] give better errors for broken intra doc links --- compiler/rustc_hir/src/def.rs | 9 + compiler/rustc_hir/src/lib.rs | 1 + .../passes/collect_intra_doc_links.rs | 361 ++++++++++++++---- .../deny-intra-link-resolution-failure.stderr | 3 +- .../rustdoc-ui/intra-doc-alias-ice.stderr | 5 +- src/test/rustdoc-ui/intra-link-errors.rs | 59 +++ src/test/rustdoc-ui/intra-link-errors.stderr | 68 ++++ .../intra-link-span-ice-55723.stderr | 3 +- .../intra-links-warning-crlf.stderr | 12 +- .../rustdoc-ui/intra-links-warning.stderr | 49 ++- 10 files changed, 476 insertions(+), 94 deletions(-) create mode 100644 src/test/rustdoc-ui/intra-link-errors.rs create mode 100644 src/test/rustdoc-ui/intra-link-errors.stderr diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 0d61dc037c65a..b019e518d0c54 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -6,6 +6,7 @@ use rustc_ast::NodeId; use rustc_macros::HashStable_Generic; use rustc_span::hygiene::MacroKind; +use std::array::IntoIter; use std::fmt::Debug; /// Encodes if a `DefKind::Ctor` is the constructor of an enum variant or a struct. @@ -291,6 +292,14 @@ impl PerNS { pub fn map U>(self, mut f: F) -> PerNS { PerNS { value_ns: f(self.value_ns), type_ns: f(self.type_ns), macro_ns: f(self.macro_ns) } } + + pub fn into_iter(self) -> IntoIter { + IntoIter::new([self.value_ns, self.type_ns, self.macro_ns]) + } + + pub fn iter(&self) -> IntoIter<&T, 3> { + IntoIter::new([&self.value_ns, &self.type_ns, &self.macro_ns]) + } } impl ::std::ops::Index for PerNS { diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index c69a9b063aeca..9d931b3a9e1e5 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -2,6 +2,7 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html +#![feature(array_value_iter)] #![feature(crate_visibility_modifier)] #![feature(const_fn)] // For the unsizing cast on `&[]` #![feature(const_panic)] diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 5d10e2e149b32..f6f01028ee2e2 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -17,7 +17,7 @@ use rustc_span::hygiene::MacroKind; use rustc_span::symbol::Ident; use rustc_span::symbol::Symbol; use rustc_span::DUMMY_SP; -use smallvec::SmallVec; +use smallvec::{smallvec, SmallVec}; use std::cell::Cell; use std::ops::Range; @@ -47,10 +47,53 @@ pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_>) -> Crate { } enum ErrorKind { - ResolutionFailure, + Resolve(ResolutionFailure), AnchorFailure(AnchorFailure), } +#[derive(Debug)] +enum ResolutionFailure { + /// This resolved, but with the wrong namespace. + /// `Namespace` is the expected namespace (as opposed to the actual). + WrongNamespace(Res, Namespace), + /// `String` is the base name of the path (not necessarily the whole link) + NotInScope(String), + /// this is a primitive type without an impls (no associated methods) + /// when will this actually happen? + /// the `Res` is the primitive it resolved to + NoPrimitiveImpl(Res, String), + /// `[u8::not_found]` + /// the `Res` is the primitive it resolved to + NoPrimitiveAssocItem { res: Res, prim_name: String, assoc_item: String }, + /// `[S::not_found]` + /// the `String` is the associated item that wasn't found + NoAssocItem(Res, String), + /// should not ever happen + NoParentItem, + /// the root of this path resolved, but it was not an enum. + NotAnEnum(Res), + /// this could be an enum variant, but the last path fragment wasn't resolved. + /// the `String` is the variant that didn't exist + NotAVariant(Res, String), + /// used to communicate that this should be ignored, but shouldn't be reported to the user + Dummy, +} + +impl ResolutionFailure { + fn res(&self) -> Option { + use ResolutionFailure::*; + match self { + NoPrimitiveAssocItem { res, .. } + | NoAssocItem(res, _) + | NoPrimitiveImpl(res, _) + | NotAnEnum(res) + | NotAVariant(res, _) + | WrongNamespace(res, _) => Some(*res), + NotInScope(_) | NoParentItem | Dummy => None, + } + } +} + enum AnchorFailure { MultipleAnchors, Primitive, @@ -85,10 +128,14 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { let cx = self.cx; let mut split = path_str.rsplitn(3, "::"); - let variant_field_name = - split.next().map(|f| Symbol::intern(f)).ok_or(ErrorKind::ResolutionFailure)?; + let variant_field_name = split + .next() + .map(|f| Symbol::intern(f)) + .expect("fold_item should ensure link is non-empty"); let variant_name = - split.next().map(|f| Symbol::intern(f)).ok_or(ErrorKind::ResolutionFailure)?; + // we're not sure this is a variant at all, so use the full string + split.next().map(|f| Symbol::intern(f)).ok_or(ErrorKind::Resolve(ResolutionFailure::NotInScope(path_str.to_string())))?; + // TODO: this looks very wrong, why are we requiring 3 fields? let path = split .next() .map(|f| { @@ -99,14 +146,15 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } f.to_owned() }) - .ok_or(ErrorKind::ResolutionFailure)?; + // TODO: is this right? + .ok_or(ErrorKind::Resolve(ResolutionFailure::NotInScope(variant_name.to_string())))?; let (_, ty_res) = cx .enter_resolver(|resolver| { resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) }) - .map_err(|_| ErrorKind::ResolutionFailure)?; + .map_err(|_| ErrorKind::Resolve(ResolutionFailure::NotInScope(path.to_string())))?; if let Res::Err = ty_res { - return Err(ErrorKind::ResolutionFailure); + return Err(ErrorKind::Resolve(ResolutionFailure::NotInScope(path.to_string()))); } let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); match ty_res { @@ -118,7 +166,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .flat_map(|imp| cx.tcx.associated_items(*imp).in_definition_order()) .any(|item| item.ident.name == variant_name) { - return Err(ErrorKind::ResolutionFailure); + // This is just to let `fold_item` know that this shouldn't be considered; + // it's a bug for the error to make it to the user + return Err(ErrorKind::Resolve(ResolutionFailure::Dummy)); } match cx.tcx.type_of(did).kind() { ty::Adt(def, _) if def.is_enum() => { @@ -131,18 +181,25 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { )), )) } else { - Err(ErrorKind::ResolutionFailure) + Err(ErrorKind::Resolve(ResolutionFailure::NotAVariant( + ty_res, + variant_field_name.to_string(), + ))) } } - _ => Err(ErrorKind::ResolutionFailure), + _ => unreachable!(), } } - _ => Err(ErrorKind::ResolutionFailure), + _ => Err(ErrorKind::Resolve(ResolutionFailure::NotAnEnum(ty_res))), } } /// Resolves a string as a macro. - fn macro_resolve(&self, path_str: &str, parent_id: Option) -> Option { + fn macro_resolve( + &self, + path_str: &str, + parent_id: Option, + ) -> Result { let cx = self.cx; let path = ast::Path::from_ident(Ident::from_str(path_str)); cx.enter_resolver(|resolver| { @@ -154,11 +211,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { false, ) { if let SyntaxExtensionKind::LegacyBang { .. } = ext.kind { - return Some(res.map_id(|_| panic!("unexpected id"))); + return Ok(res.map_id(|_| panic!("unexpected id"))); } } if let Some(res) = resolver.all_macros().get(&Symbol::intern(path_str)) { - return Some(res.map_id(|_| panic!("unexpected id"))); + return Ok(res.map_id(|_| panic!("unexpected id"))); } if let Some(module_id) = parent_id { debug!("resolving {} as a macro in the module {:?}", path_str, module_id); @@ -168,13 +225,14 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // don't resolve builtins like `#[derive]` if let Res::Def(..) = res { let res = res.map_id(|_| panic!("unexpected node_id")); - return Some(res); + return Ok(res); } } } else { debug!("attempting to resolve item without parent module: {}", path_str); + return Err(ResolutionFailure::NoParentItem); } - None + return Err(ResolutionFailure::NotInScope(path_str.to_string())); }) } /// Resolves a string as a path within a particular namespace. Also returns an optional @@ -196,8 +254,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }); debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns); let result = match result { - Ok((_, Res::Err)) => Err(ErrorKind::ResolutionFailure), - _ => result.map_err(|_| ErrorKind::ResolutionFailure), + Ok((_, Res::Err)) => Err(()), + _ => result.map_err(|_| ()), }; if let Ok((_, res)) = result { @@ -226,7 +284,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }; if value != (ns == ValueNS) { - return Err(ErrorKind::ResolutionFailure); + return Err(ErrorKind::Resolve(ResolutionFailure::WrongNamespace(res, ns))); } } else if let Some((path, prim)) = is_primitive(path_str, ns) { if extra_fragment.is_some() { @@ -237,9 +295,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // Try looking for methods and associated items. let mut split = path_str.rsplitn(2, "::"); - let item_name = - split.next().map(|f| Symbol::intern(f)).ok_or(ErrorKind::ResolutionFailure)?; - let path = split + // this can be an `unwrap()` because we ensure the link is never empty + let item_name = Symbol::intern(split.next().unwrap()); + let path_root = split .next() .map(|f| { if f == "self" || f == "Self" { @@ -249,10 +307,15 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } f.to_owned() }) - .ok_or(ErrorKind::ResolutionFailure)?; - - if let Some((path, prim)) = is_primitive(&path, TypeNS) { - for &impl_ in primitive_impl(cx, &path).ok_or(ErrorKind::ResolutionFailure)? { + // If there's no `::`, it's not an associated item. + // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved. + .ok_or(ErrorKind::Resolve(ResolutionFailure::NotInScope(item_name.to_string())))?; + + if let Some((path, prim)) = is_primitive(&path_root, ns) { + let impls = primitive_impl(cx, &path).ok_or_else(|| { + ErrorKind::Resolve(ResolutionFailure::NoPrimitiveImpl(prim, path_root)) + })?; + for &impl_ in impls { let link = cx .tcx .associated_items(impl_) @@ -272,19 +335,25 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { return Ok(link); } } - return Err(ErrorKind::ResolutionFailure); + return Err(ErrorKind::Resolve(ResolutionFailure::NoPrimitiveAssocItem { + res: prim, + prim_name: path.to_string(), + assoc_item: item_name.to_string(), + })); } let (_, ty_res) = cx .enter_resolver(|resolver| { - resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) + resolver.resolve_str_path_error(DUMMY_SP, &path_root, TypeNS, module_id) }) - .map_err(|_| ErrorKind::ResolutionFailure)?; + .map_err(|_| { + ErrorKind::Resolve(ResolutionFailure::NotInScope(path_root.clone())) + })?; if let Res::Err = ty_res { return if ns == Namespace::ValueNS { self.variant_field(path_str, current_item, module_id) } else { - Err(ErrorKind::ResolutionFailure) + Err(ErrorKind::Resolve(ResolutionFailure::NotInScope(path_root))) }; } let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); @@ -380,7 +449,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } } else { // We already know this isn't in ValueNS, so no need to check variant_field - return Err(ErrorKind::ResolutionFailure); + return Err(ErrorKind::Resolve(ResolutionFailure::NoAssocItem( + ty_res, + item_name.to_string(), + ))); } } Res::Def(DefKind::Trait, did) => cx @@ -419,12 +491,16 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { if ns == Namespace::ValueNS { self.variant_field(path_str, current_item, module_id) } else { - Err(ErrorKind::ResolutionFailure) + Err(ErrorKind::Resolve(ResolutionFailure::NoAssocItem( + ty_res, + item_name.to_string(), + ))) } }) } else { debug!("attempting to resolve item without parent module: {}", path_str); - Err(ErrorKind::ResolutionFailure) + // TODO: maybe this should just be an ICE? + Err(ErrorKind::Resolve(ResolutionFailure::NoParentItem)) } } } @@ -562,10 +638,10 @@ fn traits_implemented_by(cx: &DocContext<'_>, type_: DefId, module: DefId) -> Fx /// Check for resolve collisions between a trait and its derive /// /// These are common and we should just resolve to the trait in that case -fn is_derive_trait_collision(ns: &PerNS>) -> bool { +fn is_derive_trait_collision(ns: &PerNS>) -> bool { if let PerNS { - type_ns: Some((Res::Def(DefKind::Trait, _), _)), - macro_ns: Some((Res::Def(DefKind::Macro(MacroKind::Derive), _), _)), + type_ns: Ok((Res::Def(DefKind::Trait, _), _)), + macro_ns: Ok((Res::Def(DefKind::Macro(MacroKind::Derive), _), _)), .. } = *ns { @@ -764,8 +840,15 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { match self.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment) { Ok(res) => res, - Err(ErrorKind::ResolutionFailure) => { - resolution_failure(cx, &item, path_str, &dox, link_range); + Err(ErrorKind::Resolve(kind)) => { + resolution_failure( + cx, + &item, + path_str, + &dox, + link_range, + smallvec![kind], + ); // This could just be a normal link or a broken link // we could potentially check if something is // "intra-doc-link-like" and warn in that case. @@ -792,13 +875,13 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { ) { Ok(res) => { debug!("got res in TypeNS: {:?}", res); - Some(res) + Ok(res) } Err(ErrorKind::AnchorFailure(msg)) => { anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); continue; } - Err(ErrorKind::ResolutionFailure) => None, + Err(ErrorKind::Resolve(kind)) => Err(kind), }, value_ns: match self.resolve( path_str, @@ -807,48 +890,62 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { base_node, &extra_fragment, ) { - Ok(res) => Some(res), + Ok(res) => Ok(res), Err(ErrorKind::AnchorFailure(msg)) => { anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); continue; } - Err(ErrorKind::ResolutionFailure) => None, + Err(ErrorKind::Resolve(kind)) => Err(kind), } .and_then(|(res, fragment)| { // Constructors are picked up in the type namespace. match res { - Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) => None, + Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) => { + Err(ResolutionFailure::WrongNamespace(res, TypeNS)) + } _ => match (fragment, extra_fragment) { (Some(fragment), Some(_)) => { // Shouldn't happen but who knows? - Some((res, Some(fragment))) - } - (fragment, None) | (None, fragment) => { - Some((res, fragment)) + Ok((res, Some(fragment))) } + (fragment, None) | (None, fragment) => Ok((res, fragment)), }, } }), }; - if candidates.is_empty() { - resolution_failure(cx, &item, path_str, &dox, link_range); + let mut candidates_iter = + candidates.iter().filter_map(|res| res.as_ref().ok()); + let len = candidates_iter.clone().count(); + + if len == 0 { + drop(candidates_iter); + resolution_failure( + cx, + &item, + path_str, + &dox, + link_range, + candidates.into_iter().filter_map(|res| res.err()).collect(), + ); // this could just be a normal link continue; } - let len = candidates.clone().present_items().count(); - if len == 1 { - candidates.present_items().next().unwrap() + candidates_iter.next().unwrap().clone() } else if len == 2 && is_derive_trait_collision(&candidates) { + drop(candidates_iter); candidates.type_ns.unwrap() } else { + drop(candidates_iter); if is_derive_trait_collision(&candidates) { - candidates.macro_ns = None; + candidates.macro_ns = + Err(ResolutionFailure::NotInScope(path_str.to_string())); } + // If we're reporting an ambiguity, don't mention the namespaces that failed let candidates = - candidates.map(|candidate| candidate.map(|(res, _)| res)); + candidates.map(|candidate| candidate.ok().map(|(res, _)| res)); ambiguity_error( cx, &item, @@ -861,11 +958,44 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } } Some(MacroNS) => { - if let Some(res) = self.macro_resolve(path_str, base_node) { - (res, extra_fragment) - } else { - resolution_failure(cx, &item, path_str, &dox, link_range); - continue; + match self.macro_resolve(path_str, base_node) { + Ok(res) => (res, extra_fragment), + Err(mut kind) => { + // `macro_resolve` only looks in the macro namespace. Try to give a better error if possible. + for &ns in &[TypeNS, ValueNS] { + match self.resolve( + path_str, + ns, + ¤t_item, + base_node, + &extra_fragment, + ) { + Ok(res) => { + kind = ResolutionFailure::WrongNamespace(res.0, MacroNS) + } + // This will show up in the other namespace, no need to handle it here + Err(ErrorKind::Resolve( + ResolutionFailure::WrongNamespace(..), + )) => {} + Err(ErrorKind::AnchorFailure(_)) => {} + Err(ErrorKind::Resolve(inner_kind)) => { + if let Some(res) = inner_kind.res() { + kind = + ResolutionFailure::WrongNamespace(res, MacroNS); + } + } + } + } + resolution_failure( + cx, + &item, + path_str, + &dox, + link_range, + smallvec![kind], + ); + continue; + } } } } @@ -907,7 +1037,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { let report_mismatch = |specified: Disambiguator, resolved: Disambiguator| { // The resolved item did not match the disambiguator; give a better error than 'not found' let msg = format!("incompatible link kind for `{}`", path_str); - report_diagnostic(cx, &msg, &item, &dox, link_range.clone(), |diag, sp| { + report_diagnostic(cx, &msg, &item, &dox, &link_range, |diag, sp| { let note = format!( "this link resolved to {} {}, which is not {} {}", resolved.article(), @@ -1161,7 +1291,7 @@ fn report_diagnostic( msg: &str, item: &Item, dox: &str, - link_range: Option>, + link_range: &Option>, decorate: impl FnOnce(&mut DiagnosticBuilder<'_>, Option), ) { let hir_id = match cx.as_local_hir_id(item.def_id) { @@ -1218,19 +1348,107 @@ fn resolution_failure( path_str: &str, dox: &str, link_range: Option>, + kinds: SmallVec<[ResolutionFailure; 3]>, ) { report_diagnostic( cx, &format!("unresolved link to `{}`", path_str), item, dox, - link_range, + &link_range, |diag, sp| { - if let Some(sp) = sp { - diag.span_label(sp, "unresolved link"); + let in_scope = kinds.iter().any(|kind| kind.res().is_some()); + let mut reported_not_in_scope = false; + let item = |res: Res| { + if let Some(id) = res.opt_def_id() { + (format!("the {} `{}`", res.descr(), cx.tcx.item_name(id).to_string()), ",") + } else { + (format!("{} {}", res.article(), res.descr()), "") + } + }; + for failure in kinds { + match failure { + // already handled above + ResolutionFailure::NotInScope(base) => { + if in_scope || reported_not_in_scope { + continue; + } + reported_not_in_scope = true; + diag.note(&format!("no item named `{}` is in scope", base)); + diag.help(r#"to escape `[` and `]` characters, add '\' before them like `\[` or `\]`"#); + } + ResolutionFailure::Dummy => continue, + ResolutionFailure::WrongNamespace(res, expected_ns) => { + let (item, comma) = item(res); + let note = format!( + "this link resolves to {}{} which is not in the {} namespace", + item, + comma, + expected_ns.descr() + ); + diag.note(¬e); + + if let Res::Def(kind, _) = res { + let disambiguator = Disambiguator::Kind(kind); + suggest_disambiguator( + disambiguator, + diag, + path_str, + dox, + sp, + &link_range, + ) + } + } + ResolutionFailure::NoParentItem => { + panic!("all intra doc links should have a parent item") + } + ResolutionFailure::NoPrimitiveImpl(res, _) => { + let (item, comma) = item(res); + let note = format!( + "this link partially resolves to {}{} which does not have any associated items", + item, comma, + ); + diag.note(¬e); + } + ResolutionFailure::NoPrimitiveAssocItem { prim_name, assoc_item, .. } => { + let note = format!( + "the builtin type `{}` does not have an associated item named `{}`", + prim_name, assoc_item + ); + diag.note(¬e); + } + ResolutionFailure::NoAssocItem(res, assoc_item) => { + let (item, _) = item(res); + diag.note(&format!("this link partially resolves to {}", item)); + // FIXME: when are items neither a primitive nor a Def? + if let Res::Def(_, def_id) = res { + let name = cx.tcx.item_name(def_id); + let note = format!( + "`{}` has no field, variant, or associated item named `{}`", + name, assoc_item + ); + diag.note(¬e); + } + } + // TODO: is there ever a case where this happens? + ResolutionFailure::NotAnEnum(res) => { + let (item, comma) = item(res); + let note = + format!("this link resolves to {}{} which is not an enum", item, comma); + diag.note(¬e); + diag.note("if this were an enum, it might have a variant which resolved"); + } + ResolutionFailure::NotAVariant(res, variant) => { + let note = format!( + "this link partially resolves to {}, but there is no variant named {}", + item(res).0, + variant + ); + diag.note(¬e); + } + } } - - diag.help(r#"to escape `[` and `]` characters, add '\' before them like `\[` or `\]`"#); }, ); } @@ -1269,7 +1487,7 @@ fn anchor_failure( } }; - report_diagnostic(cx, &msg, item, dox, link_range, |diag, sp| { + report_diagnostic(cx, &msg, item, dox, &link_range, |diag, sp| { if let Some(sp) = sp { diag.span_label(sp, "contains invalid anchor"); } @@ -1308,7 +1526,7 @@ fn ambiguity_error( } } - report_diagnostic(cx, &msg, item, dox, link_range.clone(), |diag, sp| { + report_diagnostic(cx, &msg, item, dox, &link_range, |diag, sp| { if let Some(sp) = sp { diag.span_label(sp, "ambiguous link"); } else { @@ -1356,7 +1574,7 @@ fn privacy_error( let msg = format!("public documentation for `{}` links to private item `{}`", item_name, path_str); - report_diagnostic(cx, &msg, item, dox, link_range, |diag, sp| { + report_diagnostic(cx, &msg, item, dox, &link_range, |diag, sp| { if let Some(sp) = sp { diag.span_label(sp, "this item is private"); } @@ -1384,7 +1602,8 @@ fn handle_variant( let parent = if let Some(parent) = cx.tcx.parent(res.def_id()) { parent } else { - return Err(ErrorKind::ResolutionFailure); + // TODO: this should just be an unwrap, there should never be `Variant`s without a parent + return Err(ErrorKind::Resolve(ResolutionFailure::NoParentItem)); }; let parent_def = Res::Def(DefKind::Enum, parent); let variant = cx.tcx.expect_variant_res(res); diff --git a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr index 7530e3ad0f551..4ae53e83613e0 100644 --- a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr +++ b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr @@ -2,13 +2,14 @@ error: unresolved link to `v2` --> $DIR/deny-intra-link-resolution-failure.rs:3:6 | LL | /// [v2] - | ^^ unresolved link + | ^^ | note: the lint level is defined here --> $DIR/deny-intra-link-resolution-failure.rs:1:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ + = note: no item named `v2` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr index f1c07e31cd753..f5eb3a15abcc7 100644 --- a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr +++ b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr @@ -2,14 +2,15 @@ error: unresolved link to `TypeAlias::hoge` --> $DIR/intra-doc-alias-ice.rs:5:30 | LL | /// [broken cross-reference](TypeAlias::hoge) - | ^^^^^^^^^^^^^^^ unresolved link + | ^^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/intra-doc-alias-ice.rs:1:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + = note: this link partially resolves to the type alias `TypeAlias`, + = note: `TypeAlias` has no field, variant, or associated item named `hoge` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-link-errors.rs b/src/test/rustdoc-ui/intra-link-errors.rs new file mode 100644 index 0000000000000..7a53a6f079334 --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-errors.rs @@ -0,0 +1,59 @@ +#![deny(broken_intra_doc_links)] +//~^ NOTE lint level is defined + +//! [std::io::oops] +//! [std::io::oops::not::here] + +// FIXME: this should say that it was skipped (maybe an allowed by default lint?) +/// [] + +// FIXME: this could say which path was the first to not be found (in this case, `path`) +/// [path::to::nonexistent::module] +//~^ ERROR unresolved link +//~| NOTE no item named `path::to::nonexistent` is in scope +//~| HELP to escape + +// TODO: why does this say `f` and not `f::A`?? +/// [f::A] +//~^ ERROR unresolved link +//~| NOTE no item named `f` is in scope +//~| HELP to escape + +/// [S::A] +//~^ ERROR unresolved link +//~| NOTE this link partially resolves +//~| NOTE `S` has no field + +/// [S::fmt] +//~^ ERROR unresolved link +//~| NOTE this link partially resolves +//~| NOTE `S` has no field + +/// [E::D] +//~^ ERROR unresolved link +//~| NOTE this link partially resolves +//~| NOTE `E` has no field + +/// [u8::not_found] +//~^ ERROR unresolved link +//~| NOTE the builtin type `u8` does not have an associated item named `not_found` + +/// [S!] +//~^ ERROR unresolved link +//~| HELP to link to the unit struct, use its disambiguator +//~| NOTE this link resolves to the unit struct `S` +pub fn f() {} +#[derive(Debug)] +pub struct S; + +pub enum E { A, B, C } + +/// [type@S::h] +impl S { + pub fn h() {} +} + +/// [type@T::g] +pub trait T { + fn g() {} +} diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr new file mode 100644 index 0000000000000..249b27cd87894 --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-errors.stderr @@ -0,0 +1,68 @@ +error: unresolved link to `path::to::nonexistent::module` + --> $DIR/intra-link-errors.rs:8:6 + | +LL | /// [path::to::nonexistent::module] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/intra-link-errors.rs:1:9 + | +LL | #![deny(broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: no item named `path::to::nonexistent` is in scope + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `f::A` + --> $DIR/intra-link-errors.rs:14:6 + | +LL | /// [f::A] + | ^^^^ + | + = note: no item named `f` is in scope + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `S::A` + --> $DIR/intra-link-errors.rs:19:6 + | +LL | /// [S::A] + | ^^^^ + | + = note: this link partially resolves to the struct `S`, + = note: `S` has no field, variant, or associated item named `A` + +error: unresolved link to `S::fmt` + --> $DIR/intra-link-errors.rs:24:6 + | +LL | /// [S::fmt] + | ^^^^^^ + | + = note: this link partially resolves to the struct `S`, + = note: `S` has no field, variant, or associated item named `fmt` + +error: unresolved link to `E::D` + --> $DIR/intra-link-errors.rs:29:6 + | +LL | /// [E::D] + | ^^^^ + | + = note: this link partially resolves to the enum `E`, + = note: `E` has no field, variant, or associated item named `D` + +error: unresolved link to `u8::not_found` + --> $DIR/intra-link-errors.rs:34:6 + | +LL | /// [u8::not_found] + | ^^^^^^^^^^^^^ + | + = note: the builtin type `u8` does not have an associated item named `not_found` + +error: unresolved link to `S` + --> $DIR/intra-link-errors.rs:38:6 + | +LL | /// [S!] + | ^^ help: to link to the unit struct, use its disambiguator: `value@S` + | + = note: this link resolves to the unit struct `S`, which is not in the value namespace + +error: aborting due to 7 previous errors + diff --git a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr index 6b0ff8f116295..47b6a08baf37d 100644 --- a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr +++ b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr @@ -2,13 +2,14 @@ error: unresolved link to `i` --> $DIR/intra-link-span-ice-55723.rs:9:10 | LL | /// (arr[i]) - | ^ unresolved link + | ^ | note: the lint level is defined here --> $DIR/intra-link-span-ice-55723.rs:1:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ + = note: no item named `i` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr b/src/test/rustdoc-ui/intra-links-warning-crlf.stderr index 1e3a26fadfa9f..1da27b786180f 100644 --- a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr +++ b/src/test/rustdoc-ui/intra-links-warning-crlf.stderr @@ -2,33 +2,37 @@ warning: unresolved link to `error` --> $DIR/intra-links-warning-crlf.rs:7:6 | LL | /// [error] - | ^^^^^ unresolved link + | ^^^^^ | = note: `#[warn(broken_intra_doc_links)]` on by default + = note: no item named `error` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error1` --> $DIR/intra-links-warning-crlf.rs:12:11 | LL | /// docs [error1] - | ^^^^^^ unresolved link + | ^^^^^^ | + = note: no item named `error1` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error2` --> $DIR/intra-links-warning-crlf.rs:15:11 | LL | /// docs [error2] - | ^^^^^^ unresolved link + | ^^^^^^ | + = note: no item named `error2` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` --> $DIR/intra-links-warning-crlf.rs:23:20 | LL | * It also has an [error]. - | ^^^^^ unresolved link + | ^^^^^ | + = note: no item named `error` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: 4 warnings emitted diff --git a/src/test/rustdoc-ui/intra-links-warning.stderr b/src/test/rustdoc-ui/intra-links-warning.stderr index 53f2476295ebb..f728d3919e670 100644 --- a/src/test/rustdoc-ui/intra-links-warning.stderr +++ b/src/test/rustdoc-ui/intra-links-warning.stderr @@ -2,73 +2,82 @@ warning: unresolved link to `Foo::baz` --> $DIR/intra-links-warning.rs:3:23 | LL | //! Test with [Foo::baz], [Bar::foo], ... - | ^^^^^^^^ unresolved link + | ^^^^^^^^ | = note: `#[warn(broken_intra_doc_links)]` on by default - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + = note: this link partially resolves to the struct `Foo`, + = note: `Foo` has no field, variant, or associated item named `baz` warning: unresolved link to `Bar::foo` --> $DIR/intra-links-warning.rs:3:35 | LL | //! Test with [Foo::baz], [Bar::foo], ... - | ^^^^^^^^ unresolved link + | ^^^^^^^^ | + = note: no item named `Bar` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `Uniooon::X` --> $DIR/intra-links-warning.rs:6:13 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^^^^^ unresolved link + | ^^^^^^^^^^ | + = note: no item named `Uniooon` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `Qux::Z` --> $DIR/intra-links-warning.rs:6:30 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^ unresolved link + | ^^^^^^ | + = note: no item named `Qux` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `Uniooon::X` --> $DIR/intra-links-warning.rs:10:14 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^^^^^ unresolved link + | ^^^^^^^^^^ | + = note: no item named `Uniooon` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `Qux::Z` --> $DIR/intra-links-warning.rs:10:31 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^ unresolved link + | ^^^^^^ | + = note: no item named `Qux` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `Qux:Y` --> $DIR/intra-links-warning.rs:14:13 | LL | /// [Qux:Y] - | ^^^^^ unresolved link + | ^^^^^ | + = note: no item named `Qux:Y` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` --> $DIR/intra-links-warning.rs:58:30 | LL | * time to introduce a link [error]*/ - | ^^^^^ unresolved link + | ^^^^^ | + = note: no item named `error` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` --> $DIR/intra-links-warning.rs:64:30 | LL | * time to introduce a link [error] - | ^^^^^ unresolved link + | ^^^^^ | + = note: no item named `error` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` @@ -81,6 +90,7 @@ LL | #[doc = "single line [error]"] single line [error] ^^^^^ + = note: no item named `error` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` @@ -93,6 +103,7 @@ LL | #[doc = "single line with \"escaping\" [error]"] single line with "escaping" [error] ^^^^^ + = note: no item named `error` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` @@ -107,46 +118,52 @@ LL | | /// [error] [error] ^^^^^ + = note: no item named `error` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error1` --> $DIR/intra-links-warning.rs:80:11 | LL | /// docs [error1] - | ^^^^^^ unresolved link + | ^^^^^^ | + = note: no item named `error1` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error2` --> $DIR/intra-links-warning.rs:82:11 | LL | /// docs [error2] - | ^^^^^^ unresolved link + | ^^^^^^ | + = note: no item named `error2` is in scope = 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 - | ^^^^ unresolved link + | ^^^^ | + = note: no item named `BarA` is 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 - | ^^^^ unresolved link + | ^^^^ | + = note: no item named `BarB` is 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 - | ^^^^ unresolved link + | ^^^^ | + = note: no item named `BarC` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `BarD` @@ -159,6 +176,7 @@ LL | #[doc = "Foo\nbar [BarD] bar\nbaz"] bar [BarD] bar ^^^^ + = note: no item named `BarD` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `BarF` @@ -174,6 +192,7 @@ LL | f!("Foo\nbar [BarF] bar\nbaz"); bar [BarF] bar ^^^^ + = note: no item named `BarF` is 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) From f45e7b586259b795babf49231cd7de4a4534a2e7 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Thu, 20 Aug 2020 21:15:32 -0400 Subject: [PATCH 0117/1052] Update .stderr --- .../rustdoc-ui/intra-doc-alias-ice.stderr | 2 +- src/test/rustdoc-ui/intra-link-errors.stderr | 68 +++++++++++++++---- .../rustdoc-ui/intra-links-warning.stderr | 2 +- 3 files changed, 55 insertions(+), 17 deletions(-) diff --git a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr index f5eb3a15abcc7..cc1343eb7b95e 100644 --- a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr +++ b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr @@ -9,7 +9,7 @@ note: the lint level is defined here | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ - = note: this link partially resolves to the type alias `TypeAlias`, + = note: this link partially resolves to the type alias `TypeAlias` = note: `TypeAlias` has no field, variant, or associated item named `hoge` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr index 249b27cd87894..baf4ab7a9bc46 100644 --- a/src/test/rustdoc-ui/intra-link-errors.stderr +++ b/src/test/rustdoc-ui/intra-link-errors.stderr @@ -1,19 +1,39 @@ -error: unresolved link to `path::to::nonexistent::module` - --> $DIR/intra-link-errors.rs:8:6 +error: unresolved link to `std::io::oops` + --> $DIR/intra-link-errors.rs:4:6 | -LL | /// [path::to::nonexistent::module] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | //! [std::io::oops] + | ^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/intra-link-errors.rs:1:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ + = note: this link resolves to the crate `std`, which is not an enum + = note: if this were an enum, it might have a variant which resolved + = note: this link partially resolves to the module `io` + = note: `io` has no field, variant, or associated item named `oops` + +error: unresolved link to `std::io::oops::not::here` + --> $DIR/intra-link-errors.rs:5:6 + | +LL | //! [std::io::oops::not::here] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: no item named `std::io::oops::not` is in scope + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `path::to::nonexistent::module` + --> $DIR/intra-link-errors.rs:11:6 + | +LL | /// [path::to::nonexistent::module] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | = note: no item named `path::to::nonexistent` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: unresolved link to `f::A` - --> $DIR/intra-link-errors.rs:14:6 + --> $DIR/intra-link-errors.rs:17:6 | LL | /// [f::A] | ^^^^ @@ -22,34 +42,34 @@ LL | /// [f::A] = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: unresolved link to `S::A` - --> $DIR/intra-link-errors.rs:19:6 + --> $DIR/intra-link-errors.rs:22:6 | LL | /// [S::A] | ^^^^ | - = note: this link partially resolves to the struct `S`, + = note: this link partially resolves to the struct `S` = note: `S` has no field, variant, or associated item named `A` error: unresolved link to `S::fmt` - --> $DIR/intra-link-errors.rs:24:6 + --> $DIR/intra-link-errors.rs:27:6 | LL | /// [S::fmt] | ^^^^^^ | - = note: this link partially resolves to the struct `S`, + = note: this link partially resolves to the struct `S` = note: `S` has no field, variant, or associated item named `fmt` error: unresolved link to `E::D` - --> $DIR/intra-link-errors.rs:29:6 + --> $DIR/intra-link-errors.rs:32:6 | LL | /// [E::D] | ^^^^ | - = note: this link partially resolves to the enum `E`, + = note: this link partially resolves to the enum `E` = note: `E` has no field, variant, or associated item named `D` error: unresolved link to `u8::not_found` - --> $DIR/intra-link-errors.rs:34:6 + --> $DIR/intra-link-errors.rs:37:6 | LL | /// [u8::not_found] | ^^^^^^^^^^^^^ @@ -57,12 +77,30 @@ LL | /// [u8::not_found] = note: the builtin type `u8` does not have an associated item named `not_found` error: unresolved link to `S` - --> $DIR/intra-link-errors.rs:38:6 + --> $DIR/intra-link-errors.rs:41:6 | LL | /// [S!] | ^^ help: to link to the unit struct, use its disambiguator: `value@S` | - = note: this link resolves to the unit struct `S`, which is not in the value namespace + = note: this link resolves to the unit struct `S`, which is not in the macro namespace + +error: unresolved link to `T::g` + --> $DIR/intra-link-errors.rs:56:6 + | +LL | /// [type@T::g] + | ^^^^^^^^^ + | + = note: this link partially resolves to the trait `T` + = note: `T` has no field, variant, or associated item named `g` + +error: unresolved link to `S::h` + --> $DIR/intra-link-errors.rs:51:6 + | +LL | /// [type@S::h] + | ^^^^^^^^^ + | + = note: this link partially resolves to the struct `S` + = note: `S` has no field, variant, or associated item named `h` -error: aborting due to 7 previous errors +error: aborting due to 11 previous errors diff --git a/src/test/rustdoc-ui/intra-links-warning.stderr b/src/test/rustdoc-ui/intra-links-warning.stderr index f728d3919e670..3737cad1cb187 100644 --- a/src/test/rustdoc-ui/intra-links-warning.stderr +++ b/src/test/rustdoc-ui/intra-links-warning.stderr @@ -5,7 +5,7 @@ LL | //! Test with [Foo::baz], [Bar::foo], ... | ^^^^^^^^ | = note: `#[warn(broken_intra_doc_links)]` on by default - = note: this link partially resolves to the struct `Foo`, + = note: this link partially resolves to the struct `Foo` = note: `Foo` has no field, variant, or associated item named `baz` warning: unresolved link to `Bar::foo` From 4ace4e75201d5bfc187bd40cf918cd2df6009419 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Thu, 20 Aug 2020 21:29:14 -0400 Subject: [PATCH 0118/1052] Use fewer `.to_string()`s --- .../passes/collect_intra_doc_links.rs | 81 ++++++++++--------- 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index f6f01028ee2e2..9bf30c71892aa 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -19,6 +19,7 @@ use rustc_span::symbol::Symbol; use rustc_span::DUMMY_SP; use smallvec::{smallvec, SmallVec}; +use std::borrow::Cow; use std::cell::Cell; use std::ops::Range; @@ -46,40 +47,40 @@ pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_>) -> Crate { } } -enum ErrorKind { - Resolve(ResolutionFailure), +enum ErrorKind<'a> { + Resolve(ResolutionFailure<'a>), AnchorFailure(AnchorFailure), } #[derive(Debug)] -enum ResolutionFailure { +enum ResolutionFailure<'a> { /// This resolved, but with the wrong namespace. /// `Namespace` is the expected namespace (as opposed to the actual). WrongNamespace(Res, Namespace), /// `String` is the base name of the path (not necessarily the whole link) - NotInScope(String), + NotInScope(Cow<'a, str>), /// this is a primitive type without an impls (no associated methods) /// when will this actually happen? /// the `Res` is the primitive it resolved to NoPrimitiveImpl(Res, String), /// `[u8::not_found]` /// the `Res` is the primitive it resolved to - NoPrimitiveAssocItem { res: Res, prim_name: String, assoc_item: String }, + NoPrimitiveAssocItem { res: Res, prim_name: &'a str, assoc_item: Symbol }, /// `[S::not_found]` /// the `String` is the associated item that wasn't found - NoAssocItem(Res, String), + NoAssocItem(Res, Symbol), /// should not ever happen NoParentItem, /// the root of this path resolved, but it was not an enum. NotAnEnum(Res), /// this could be an enum variant, but the last path fragment wasn't resolved. /// the `String` is the variant that didn't exist - NotAVariant(Res, String), + NotAVariant(Res, Symbol), /// used to communicate that this should be ignored, but shouldn't be reported to the user Dummy, } -impl ResolutionFailure { +impl ResolutionFailure<'a> { fn res(&self) -> Option { use ResolutionFailure::*; match self { @@ -121,10 +122,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { fn variant_field( &self, - path_str: &str, + path_str: &'path str, current_item: &Option, module_id: DefId, - ) -> Result<(Res, Option), ErrorKind> { + ) -> Result<(Res, Option), ErrorKind<'path>> { let cx = self.cx; let mut split = path_str.rsplitn(3, "::"); @@ -134,7 +135,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .expect("fold_item should ensure link is non-empty"); let variant_name = // we're not sure this is a variant at all, so use the full string - split.next().map(|f| Symbol::intern(f)).ok_or(ErrorKind::Resolve(ResolutionFailure::NotInScope(path_str.to_string())))?; + split.next().map(|f| Symbol::intern(f)).ok_or(ErrorKind::Resolve(ResolutionFailure::NotInScope(path_str.into())))?; // TODO: this looks very wrong, why are we requiring 3 fields? let path = split .next() @@ -147,14 +148,18 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { f.to_owned() }) // TODO: is this right? - .ok_or(ErrorKind::Resolve(ResolutionFailure::NotInScope(variant_name.to_string())))?; + .ok_or(ErrorKind::Resolve(ResolutionFailure::NotInScope( + variant_name.to_string().into(), + )))?; let (_, ty_res) = cx .enter_resolver(|resolver| { resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) }) - .map_err(|_| ErrorKind::Resolve(ResolutionFailure::NotInScope(path.to_string())))?; + .map_err(|_| { + ErrorKind::Resolve(ResolutionFailure::NotInScope(path.to_string().into())) + })?; if let Res::Err = ty_res { - return Err(ErrorKind::Resolve(ResolutionFailure::NotInScope(path.to_string()))); + return Err(ErrorKind::Resolve(ResolutionFailure::NotInScope(path.to_string().into()))); } let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); match ty_res { @@ -183,7 +188,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } else { Err(ErrorKind::Resolve(ResolutionFailure::NotAVariant( ty_res, - variant_field_name.to_string(), + variant_field_name, ))) } } @@ -197,9 +202,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { /// Resolves a string as a macro. fn macro_resolve( &self, - path_str: &str, + path_str: &'a str, parent_id: Option, - ) -> Result { + ) -> Result> { let cx = self.cx; let path = ast::Path::from_ident(Ident::from_str(path_str)); cx.enter_resolver(|resolver| { @@ -232,19 +237,19 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { debug!("attempting to resolve item without parent module: {}", path_str); return Err(ResolutionFailure::NoParentItem); } - return Err(ResolutionFailure::NotInScope(path_str.to_string())); + return Err(ResolutionFailure::NotInScope(path_str.into())); }) } /// Resolves a string as a path within a particular namespace. Also returns an optional /// URL fragment in the case of variants and methods. - fn resolve( + fn resolve<'path>( &self, - path_str: &str, + path_str: &'path str, ns: Namespace, current_item: &Option, parent_id: Option, extra_fragment: &Option, - ) -> Result<(Res, Option), ErrorKind> { + ) -> Result<(Res, Option), ErrorKind<'path>> { let cx = self.cx; // In case we're in a module, try to resolve the relative path. @@ -309,11 +314,13 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }) // If there's no `::`, it's not an associated item. // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved. - .ok_or(ErrorKind::Resolve(ResolutionFailure::NotInScope(item_name.to_string())))?; + .ok_or(ErrorKind::Resolve(ResolutionFailure::NotInScope( + item_name.to_string().into(), + )))?; if let Some((path, prim)) = is_primitive(&path_root, ns) { let impls = primitive_impl(cx, &path).ok_or_else(|| { - ErrorKind::Resolve(ResolutionFailure::NoPrimitiveImpl(prim, path_root)) + ErrorKind::Resolve(ResolutionFailure::NoPrimitiveImpl(prim, path_root.into())) })?; for &impl_ in impls { let link = cx @@ -337,8 +344,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } return Err(ErrorKind::Resolve(ResolutionFailure::NoPrimitiveAssocItem { res: prim, - prim_name: path.to_string(), - assoc_item: item_name.to_string(), + prim_name: path, + assoc_item: item_name, })); } @@ -347,13 +354,13 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { resolver.resolve_str_path_error(DUMMY_SP, &path_root, TypeNS, module_id) }) .map_err(|_| { - ErrorKind::Resolve(ResolutionFailure::NotInScope(path_root.clone())) + ErrorKind::Resolve(ResolutionFailure::NotInScope(path_root.clone().into())) })?; if let Res::Err = ty_res { return if ns == Namespace::ValueNS { self.variant_field(path_str, current_item, module_id) } else { - Err(ErrorKind::Resolve(ResolutionFailure::NotInScope(path_root))) + Err(ErrorKind::Resolve(ResolutionFailure::NotInScope(path_root.into()))) }; } let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); @@ -450,8 +457,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } else { // We already know this isn't in ValueNS, so no need to check variant_field return Err(ErrorKind::Resolve(ResolutionFailure::NoAssocItem( - ty_res, - item_name.to_string(), + ty_res, item_name, ))); } } @@ -491,10 +497,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { if ns == Namespace::ValueNS { self.variant_field(path_str, current_item, module_id) } else { - Err(ErrorKind::Resolve(ResolutionFailure::NoAssocItem( - ty_res, - item_name.to_string(), - ))) + Err(ErrorKind::Resolve(ResolutionFailure::NoAssocItem(ty_res, item_name))) } }) } else { @@ -638,7 +641,7 @@ fn traits_implemented_by(cx: &DocContext<'_>, type_: DefId, module: DefId) -> Fx /// Check for resolve collisions between a trait and its derive /// /// These are common and we should just resolve to the trait in that case -fn is_derive_trait_collision(ns: &PerNS>) -> bool { +fn is_derive_trait_collision(ns: &PerNS>>) -> bool { if let PerNS { type_ns: Ok((Res::Def(DefKind::Trait, _), _)), macro_ns: Ok((Res::Def(DefKind::Macro(MacroKind::Derive), _), _)), @@ -941,7 +944,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { drop(candidates_iter); if is_derive_trait_collision(&candidates) { candidates.macro_ns = - Err(ResolutionFailure::NotInScope(path_str.to_string())); + Err(ResolutionFailure::NotInScope(path_str.into())); } // If we're reporting an ambiguity, don't mention the namespaces that failed let candidates = @@ -1348,7 +1351,7 @@ fn resolution_failure( path_str: &str, dox: &str, link_range: Option>, - kinds: SmallVec<[ResolutionFailure; 3]>, + kinds: SmallVec<[ResolutionFailure<'_>; 3]>, ) { report_diagnostic( cx, @@ -1494,10 +1497,10 @@ fn anchor_failure( }); } -fn ambiguity_error( +fn ambiguity_error<'a>( cx: &DocContext<'_>, item: &Item, - path_str: &str, + path_str: &'a str, dox: &str, link_range: Option>, candidates: Vec, @@ -1593,7 +1596,7 @@ fn handle_variant( cx: &DocContext<'_>, res: Res, extra_fragment: &Option, -) -> Result<(Res, Option), ErrorKind> { +) -> Result<(Res, Option), ErrorKind<'static>> { use rustc_middle::ty::DefIdTree; if extra_fragment.is_some() { From fcb21999a7989792c9405a89e9c788ac143e0574 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Thu, 20 Aug 2020 22:31:44 -0400 Subject: [PATCH 0119/1052] Report if the thing exists in another namespace --- .../passes/collect_intra_doc_links.rs | 65 ++++++++++++------- src/test/rustdoc-ui/intra-link-errors.rs | 1 + 2 files changed, 43 insertions(+), 23 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 9bf30c71892aa..5013257736719 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -81,6 +81,7 @@ enum ResolutionFailure<'a> { } impl ResolutionFailure<'a> { + // A partial or full resolution fn res(&self) -> Option { use ResolutionFailure::*; match self { @@ -93,6 +94,14 @@ impl ResolutionFailure<'a> { NotInScope(_) | NoParentItem | Dummy => None, } } + + // This resolved fully (not just partially) but is erroneous for some other reason + fn full_res(&self) -> Option { + match self { + Self::WrongNamespace(res, _) => Some(*res), + _ => None, + } + } } enum AnchorFailure { @@ -128,6 +137,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { ) -> Result<(Res, Option), ErrorKind<'path>> { let cx = self.cx; + debug!("looking for enum variant {}", path_str); let mut split = path_str.rsplitn(3, "::"); let variant_field_name = split .next() @@ -260,7 +270,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns); let result = match result { Ok((_, Res::Err)) => Err(()), - _ => result.map_err(|_| ()), + x => x, }; if let Ok((_, res)) = result { @@ -419,6 +429,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { Ok((ty_res, Some(format!("{}.{}", out, item_name)))) }) } else if ns == Namespace::ValueNS { + debug!("looking for variants or fields named {} for {:?}", item_name, did); match cx.tcx.type_of(did).kind() { ty::Adt(def, _) => { let field = if def.is_enum() { @@ -838,12 +849,36 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } } + // used for reporting better errors + let check_full_res = |this: &mut Self, ns| { + match this.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment) { + Ok(res) => { + debug!( + "check_full_res: saw res for {} in {:?} ns: {:?}", + path_str, ns, res.0 + ); + Some(res.0) + } + Err(ErrorKind::Resolve(kind)) => kind.full_res(), + // TODO: add `Res` to AnchorFailure + Err(ErrorKind::AnchorFailure(_)) => None, + } + }; + match disambiguator.map(Disambiguator::ns) { Some(ns @ (ValueNS | TypeNS)) => { match self.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment) { Ok(res) => res, - Err(ErrorKind::Resolve(kind)) => { + Err(ErrorKind::Resolve(mut kind)) => { + // We only looked in one namespace. Try to give a better error if possible. + // TODO: handle MacroNS too + if kind.full_res().is_none() { + let other_ns = if ns == ValueNS { TypeNS } else { ValueNS }; + if let Some(res) = check_full_res(self, other_ns) { + kind = ResolutionFailure::WrongNamespace(res, other_ns); + } + } resolution_failure( cx, &item, @@ -965,30 +1000,14 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { Ok(res) => (res, extra_fragment), Err(mut kind) => { // `macro_resolve` only looks in the macro namespace. Try to give a better error if possible. + //if kind.res().is_none() { for &ns in &[TypeNS, ValueNS] { - match self.resolve( - path_str, - ns, - ¤t_item, - base_node, - &extra_fragment, - ) { - Ok(res) => { - kind = ResolutionFailure::WrongNamespace(res.0, MacroNS) - } - // This will show up in the other namespace, no need to handle it here - Err(ErrorKind::Resolve( - ResolutionFailure::WrongNamespace(..), - )) => {} - Err(ErrorKind::AnchorFailure(_)) => {} - Err(ErrorKind::Resolve(inner_kind)) => { - if let Some(res) = inner_kind.res() { - kind = - ResolutionFailure::WrongNamespace(res, MacroNS); - } - } + if let Some(res) = check_full_res(self, ns) { + kind = ResolutionFailure::WrongNamespace(res, MacroNS); + break; } } + //} resolution_failure( cx, &item, diff --git a/src/test/rustdoc-ui/intra-link-errors.rs b/src/test/rustdoc-ui/intra-link-errors.rs index 7a53a6f079334..99d080fb324e3 100644 --- a/src/test/rustdoc-ui/intra-link-errors.rs +++ b/src/test/rustdoc-ui/intra-link-errors.rs @@ -54,6 +54,7 @@ impl S { } /// [type@T::g] +/// [T::h!] pub trait T { fn g() {} } From 42bed035001b9a0bd6282326a243a926ea3d0424 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Thu, 20 Aug 2020 23:05:47 -0400 Subject: [PATCH 0120/1052] Pass on the DefId so rustdoc can name it in suggestions Look at this beauty: ```rust error: unresolved link to `S::h` --> intra-link-errors.rs:51:6 | 51 | /// [type@S::h] | ^^^^^^^^^ help: to link to the associated function, use its disambiguator: `S::h()` | = note: this link resolves to the associated function `h`, which is not in the type namespace ``` --- .../passes/collect_intra_doc_links.rs | 52 ++++++++++--------- src/test/rustdoc-ui/intra-link-errors.rs | 7 +++ src/test/rustdoc-ui/intra-link-errors.stderr | 27 ++++++---- 3 files changed, 52 insertions(+), 34 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 5013257736719..287f5fcf805ef 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -121,7 +121,7 @@ struct LinkCollector<'a, 'tcx> { /// This is used to store the kind of associated items, /// because `clean` and the disambiguator code expect them to be different. /// See the code for associated items on inherent impls for details. - kind_side_channel: Cell>, + kind_side_channel: Cell>, } impl<'a, 'tcx> LinkCollector<'a, 'tcx> { @@ -381,7 +381,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { ) => { debug!("looking for associated item named {} for item {:?}", item_name, did); // Checks if item_name belongs to `impl SomeItem` - let kind = cx + let assoc_item = cx .tcx .inherent_impls(did) .iter() @@ -393,7 +393,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { imp, ) }) - .map(|item| item.kind) + .map(|item| (item.kind, item.def_id)) // There should only ever be one associated item that matches from any inherent impl .next() // Check if item_name belongs to `impl SomeTrait for SomeItem` @@ -409,7 +409,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { kind }); - if let Some(kind) = kind { + if let Some((kind, id)) = assoc_item { let out = match kind { ty::AssocKind::Fn => "method", ty::AssocKind::Const => "associatedconstant", @@ -425,7 +425,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // HACK(jynelson): `clean` expects the type, not the associated item. // but the disambiguator logic expects the associated item. // Store the kind in a side channel so that only the disambiguator logic looks at it. - self.kind_side_channel.set(Some(kind.as_def_kind())); + self.kind_side_channel.set(Some((kind.as_def_kind(), id))); Ok((ty_res, Some(format!("{}.{}", out, item_name)))) }) } else if ns == Namespace::ValueNS { @@ -525,7 +525,7 @@ fn resolve_associated_trait_item( item_name: Symbol, ns: Namespace, cx: &DocContext<'_>, -) -> Option { +) -> Option<(ty::AssocKind, DefId)> { let ty = cx.tcx.type_of(did); // First consider automatic impls: `impl From for T` let implicit_impls = crate::clean::get_auto_trait_and_blanket_impls(cx, ty, did); @@ -553,7 +553,7 @@ fn resolve_associated_trait_item( // but provided methods come directly from `tcx`. // Fortunately, we don't need the whole method, we just need to know // what kind of associated item it is. - Some((assoc.def_id, kind)) + Some((kind, assoc.def_id)) }); let assoc = items.next(); debug_assert_eq!(items.count(), 0); @@ -575,7 +575,7 @@ fn resolve_associated_trait_item( ns, trait_, ) - .map(|assoc| (assoc.def_id, assoc.kind)) + .map(|assoc| (assoc.kind, assoc.def_id)) } } _ => panic!("get_impls returned something that wasn't an impl"), @@ -592,12 +592,12 @@ fn resolve_associated_trait_item( cx.tcx .associated_items(trait_) .find_by_name_and_namespace(cx.tcx, Ident::with_dummy_span(item_name), ns, trait_) - .map(|assoc| (assoc.def_id, assoc.kind)) + .map(|assoc| (assoc.kind, assoc.def_id)) })); } // FIXME: warn about ambiguity debug!("the candidates were {:?}", candidates); - candidates.pop().map(|(_, kind)| kind) + candidates.pop() } /// Given a type, return all traits in scope in `module` implemented by that type. @@ -851,18 +851,21 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { // used for reporting better errors let check_full_res = |this: &mut Self, ns| { - match this.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment) { - Ok(res) => { - debug!( - "check_full_res: saw res for {} in {:?} ns: {:?}", - path_str, ns, res.0 - ); - Some(res.0) - } - Err(ErrorKind::Resolve(kind)) => kind.full_res(), - // TODO: add `Res` to AnchorFailure - Err(ErrorKind::AnchorFailure(_)) => None, - } + let res = + match this.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment) + { + Ok(res) => { + debug!( + "check_full_res: saw res for {} in {:?} ns: {:?}", + path_str, ns, res.0 + ); + Some(res.0) + } + Err(ErrorKind::Resolve(kind)) => kind.full_res(), + // TODO: add `Res` to AnchorFailure + Err(ErrorKind::AnchorFailure(_)) => None, + }; + this.kind_side_channel.take().map(|(kind, id)| Res::Def(kind, id)).or(res) }; match disambiguator.map(Disambiguator::ns) { @@ -876,7 +879,8 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { if kind.full_res().is_none() { let other_ns = if ns == ValueNS { TypeNS } else { ValueNS }; if let Some(res) = check_full_res(self, other_ns) { - kind = ResolutionFailure::WrongNamespace(res, other_ns); + // recall that this stores the _expected_ namespace + kind = ResolutionFailure::WrongNamespace(res, ns); } } resolution_failure( @@ -1092,7 +1096,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { // Disallow e.g. linking to enums with `struct@` if let Res::Def(kind, _) = res { debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator); - match (self.kind_side_channel.take().unwrap_or(kind), disambiguator) { + match (self.kind_side_channel.take().map(|(kind, _)| kind).unwrap_or(kind), disambiguator) { | (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const))) // NOTE: this allows 'method' to mean both normal functions and associated functions // This can't cause ambiguity because both are in the same namespace. diff --git a/src/test/rustdoc-ui/intra-link-errors.rs b/src/test/rustdoc-ui/intra-link-errors.rs index 99d080fb324e3..8c42a38ff4eb0 100644 --- a/src/test/rustdoc-ui/intra-link-errors.rs +++ b/src/test/rustdoc-ui/intra-link-errors.rs @@ -49,11 +49,18 @@ pub struct S; pub enum E { A, B, C } /// [type@S::h] +//~^ ERROR unresolved link +//~| HELP to link to the associated function +//~| NOTE not in the type namespace impl S { pub fn h() {} } /// [type@T::g] +//~^ ERROR unresolved link +//~| HELP to link to the associated function +//~| NOTE not in the type namespace + /// [T::h!] pub trait T { fn g() {} diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr index baf4ab7a9bc46..bb9db68e0d5e1 100644 --- a/src/test/rustdoc-ui/intra-link-errors.stderr +++ b/src/test/rustdoc-ui/intra-link-errors.stderr @@ -80,27 +80,34 @@ error: unresolved link to `S` --> $DIR/intra-link-errors.rs:41:6 | LL | /// [S!] - | ^^ help: to link to the unit struct, use its disambiguator: `value@S` + | ^^ help: to link to the struct, use its disambiguator: `struct@S` | - = note: this link resolves to the unit struct `S`, which is not in the macro namespace + = note: this link resolves to the struct `S`, which is not in the macro namespace error: unresolved link to `T::g` - --> $DIR/intra-link-errors.rs:56:6 + --> $DIR/intra-link-errors.rs:59:6 | LL | /// [type@T::g] - | ^^^^^^^^^ + | ^^^^^^^^^ help: to link to the associated function, use its disambiguator: `T::g()` | - = note: this link partially resolves to the trait `T` - = note: `T` has no field, variant, or associated item named `g` + = note: this link resolves to the associated function `g`, which is not in the type namespace + +error: unresolved link to `T::h` + --> $DIR/intra-link-errors.rs:64:6 + | +LL | /// [T::h!] + | ^^^^^ + | + = note: no item named `T::h` is in scope + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: unresolved link to `S::h` --> $DIR/intra-link-errors.rs:51:6 | LL | /// [type@S::h] - | ^^^^^^^^^ + | ^^^^^^^^^ help: to link to the associated function, use its disambiguator: `S::h()` | - = note: this link partially resolves to the struct `S` - = note: `S` has no field, variant, or associated item named `h` + = note: this link resolves to the associated function `h`, which is not in the type namespace -error: aborting due to 11 previous errors +error: aborting due to 12 previous errors From f4e6ebd11aaea9fc412d78371fd3060468625056 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Thu, 20 Aug 2020 23:14:41 -0400 Subject: [PATCH 0121/1052] Fix tests and improve error message if `::` isn't found --- .../passes/collect_intra_doc_links.rs | 13 +++-- .../rustdoc-ui/intra-doc-alias-ice.stderr | 2 +- src/test/rustdoc-ui/intra-link-errors.rs | 16 +++--- src/test/rustdoc-ui/intra-link-errors.stderr | 54 ++++++------------- .../rustdoc-ui/intra-links-warning.stderr | 2 +- 5 files changed, 33 insertions(+), 54 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 287f5fcf805ef..ea3ec1b6685cc 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -324,9 +324,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }) // If there's no `::`, it's not an associated item. // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved. - .ok_or(ErrorKind::Resolve(ResolutionFailure::NotInScope( - item_name.to_string().into(), - )))?; + .ok_or_else(|| { + debug!("found no `::`, assumming {} was correctly not in scope", item_name); + ErrorKind::Resolve(ResolutionFailure::NotInScope(item_name.to_string().into())) + })?; if let Some((path, prim)) = is_primitive(&path_root, ns) { let impls = primitive_impl(cx, &path).ok_or_else(|| { @@ -361,6 +362,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { let (_, ty_res) = cx .enter_resolver(|resolver| { + // only types can have associated items resolver.resolve_str_path_error(DUMMY_SP, &path_root, TypeNS, module_id) }) .map_err(|_| { @@ -1450,10 +1452,7 @@ fn resolution_failure( // FIXME: when are items neither a primitive nor a Def? if let Res::Def(_, def_id) = res { let name = cx.tcx.item_name(def_id); - let note = format!( - "`{}` has no field, variant, or associated item named `{}`", - name, assoc_item - ); + let note = format!("no `{}` in `{}`", assoc_item, name,); diag.note(¬e); } } diff --git a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr index cc1343eb7b95e..58abe4406a85d 100644 --- a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr +++ b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr @@ -10,7 +10,7 @@ note: the lint level is defined here LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ = note: this link partially resolves to the type alias `TypeAlias` - = note: `TypeAlias` has no field, variant, or associated item named `hoge` + = note: no `hoge` in `TypeAlias` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-link-errors.rs b/src/test/rustdoc-ui/intra-link-errors.rs index 8c42a38ff4eb0..79ce57c22676f 100644 --- a/src/test/rustdoc-ui/intra-link-errors.rs +++ b/src/test/rustdoc-ui/intra-link-errors.rs @@ -1,9 +1,6 @@ #![deny(broken_intra_doc_links)] //~^ NOTE lint level is defined -//! [std::io::oops] -//! [std::io::oops::not::here] - // FIXME: this should say that it was skipped (maybe an allowed by default lint?) /// [] @@ -22,17 +19,17 @@ /// [S::A] //~^ ERROR unresolved link //~| NOTE this link partially resolves -//~| NOTE `S` has no field +//~| NOTE no `A` in `S` /// [S::fmt] //~^ ERROR unresolved link //~| NOTE this link partially resolves -//~| NOTE `S` has no field +//~| NOTE no `fmt` in `S` /// [E::D] //~^ ERROR unresolved link //~| NOTE this link partially resolves -//~| NOTE `E` has no field +//~| NOTE no `D` in `E` /// [u8::not_found] //~^ ERROR unresolved link @@ -40,8 +37,8 @@ /// [S!] //~^ ERROR unresolved link -//~| HELP to link to the unit struct, use its disambiguator -//~| NOTE this link resolves to the unit struct `S` +//~| HELP to link to the struct, use its disambiguator +//~| NOTE this link resolves to the struct `S` pub fn f() {} #[derive(Debug)] pub struct S; @@ -62,6 +59,9 @@ impl S { //~| NOTE not in the type namespace /// [T::h!] +//~^ ERROR unresolved link +//~| NOTE no item named `T::h` +//~| HELP to escape pub trait T { fn g() {} } diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr index bb9db68e0d5e1..4044c7fde66f2 100644 --- a/src/test/rustdoc-ui/intra-link-errors.stderr +++ b/src/test/rustdoc-ui/intra-link-errors.stderr @@ -1,39 +1,19 @@ -error: unresolved link to `std::io::oops` - --> $DIR/intra-link-errors.rs:4:6 +error: unresolved link to `path::to::nonexistent::module` + --> $DIR/intra-link-errors.rs:8:6 | -LL | //! [std::io::oops] - | ^^^^^^^^^^^^^ +LL | /// [path::to::nonexistent::module] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/intra-link-errors.rs:1:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ - = note: this link resolves to the crate `std`, which is not an enum - = note: if this were an enum, it might have a variant which resolved - = note: this link partially resolves to the module `io` - = note: `io` has no field, variant, or associated item named `oops` - -error: unresolved link to `std::io::oops::not::here` - --> $DIR/intra-link-errors.rs:5:6 - | -LL | //! [std::io::oops::not::here] - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: no item named `std::io::oops::not` is in scope - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` - -error: unresolved link to `path::to::nonexistent::module` - --> $DIR/intra-link-errors.rs:11:6 - | -LL | /// [path::to::nonexistent::module] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | = note: no item named `path::to::nonexistent` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: unresolved link to `f::A` - --> $DIR/intra-link-errors.rs:17:6 + --> $DIR/intra-link-errors.rs:14:6 | LL | /// [f::A] | ^^^^ @@ -42,34 +22,34 @@ LL | /// [f::A] = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: unresolved link to `S::A` - --> $DIR/intra-link-errors.rs:22:6 + --> $DIR/intra-link-errors.rs:19:6 | LL | /// [S::A] | ^^^^ | = note: this link partially resolves to the struct `S` - = note: `S` has no field, variant, or associated item named `A` + = note: no `A` in `S` error: unresolved link to `S::fmt` - --> $DIR/intra-link-errors.rs:27:6 + --> $DIR/intra-link-errors.rs:24:6 | LL | /// [S::fmt] | ^^^^^^ | = note: this link partially resolves to the struct `S` - = note: `S` has no field, variant, or associated item named `fmt` + = note: no `fmt` in `S` error: unresolved link to `E::D` - --> $DIR/intra-link-errors.rs:32:6 + --> $DIR/intra-link-errors.rs:29:6 | LL | /// [E::D] | ^^^^ | = note: this link partially resolves to the enum `E` - = note: `E` has no field, variant, or associated item named `D` + = note: no `D` in `E` error: unresolved link to `u8::not_found` - --> $DIR/intra-link-errors.rs:37:6 + --> $DIR/intra-link-errors.rs:34:6 | LL | /// [u8::not_found] | ^^^^^^^^^^^^^ @@ -77,7 +57,7 @@ LL | /// [u8::not_found] = note: the builtin type `u8` does not have an associated item named `not_found` error: unresolved link to `S` - --> $DIR/intra-link-errors.rs:41:6 + --> $DIR/intra-link-errors.rs:38:6 | LL | /// [S!] | ^^ help: to link to the struct, use its disambiguator: `struct@S` @@ -85,7 +65,7 @@ LL | /// [S!] = note: this link resolves to the struct `S`, which is not in the macro namespace error: unresolved link to `T::g` - --> $DIR/intra-link-errors.rs:59:6 + --> $DIR/intra-link-errors.rs:56:6 | LL | /// [type@T::g] | ^^^^^^^^^ help: to link to the associated function, use its disambiguator: `T::g()` @@ -93,7 +73,7 @@ LL | /// [type@T::g] = note: this link resolves to the associated function `g`, which is not in the type namespace error: unresolved link to `T::h` - --> $DIR/intra-link-errors.rs:64:6 + --> $DIR/intra-link-errors.rs:61:6 | LL | /// [T::h!] | ^^^^^ @@ -102,12 +82,12 @@ LL | /// [T::h!] = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: unresolved link to `S::h` - --> $DIR/intra-link-errors.rs:51:6 + --> $DIR/intra-link-errors.rs:48:6 | LL | /// [type@S::h] | ^^^^^^^^^ help: to link to the associated function, use its disambiguator: `S::h()` | = note: this link resolves to the associated function `h`, which is not in the type namespace -error: aborting due to 12 previous errors +error: aborting due to 10 previous errors diff --git a/src/test/rustdoc-ui/intra-links-warning.stderr b/src/test/rustdoc-ui/intra-links-warning.stderr index 3737cad1cb187..b51c8e89600b0 100644 --- a/src/test/rustdoc-ui/intra-links-warning.stderr +++ b/src/test/rustdoc-ui/intra-links-warning.stderr @@ -6,7 +6,7 @@ LL | //! Test with [Foo::baz], [Bar::foo], ... | = note: `#[warn(broken_intra_doc_links)]` on by default = note: this link partially resolves to the struct `Foo` - = note: `Foo` has no field, variant, or associated item named `baz` + = note: no `baz` in `Foo` warning: unresolved link to `Bar::foo` --> $DIR/intra-links-warning.rs:3:35 From 002d3a922c06c11a45e001d2737951a00e40687a Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 21 Aug 2020 00:23:23 -0400 Subject: [PATCH 0122/1052] Don't give misleading errors for `f::A`, where f is in the value namespace --- .../passes/collect_intra_doc_links.rs | 62 ++++++++++++++----- src/test/rustdoc-ui/intra-link-errors.rs | 6 +- src/test/rustdoc-ui/intra-link-errors.stderr | 6 +- 3 files changed, 54 insertions(+), 20 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index ea3ec1b6685cc..ed411bf2b8dab 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -57,6 +57,9 @@ enum ResolutionFailure<'a> { /// This resolved, but with the wrong namespace. /// `Namespace` is the expected namespace (as opposed to the actual). WrongNamespace(Res, Namespace), + /// This has a partial resolution, but is not in the TypeNS and so cannot + /// have associated items or fields. + CannotHaveAssociatedItems(Res, Namespace), /// `String` is the base name of the path (not necessarily the whole link) NotInScope(Cow<'a, str>), /// this is a primitive type without an impls (no associated methods) @@ -90,7 +93,8 @@ impl ResolutionFailure<'a> { | NoPrimitiveImpl(res, _) | NotAnEnum(res) | NotAVariant(res, _) - | WrongNamespace(res, _) => Some(*res), + | WrongNamespace(res, _) + | CannotHaveAssociatedItems(res, _) => Some(*res), NotInScope(_) | NoParentItem | Dummy => None, } } @@ -360,21 +364,39 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { })); } - let (_, ty_res) = cx + let ty_res = cx .enter_resolver(|resolver| { // only types can have associated items resolver.resolve_str_path_error(DUMMY_SP, &path_root, TypeNS, module_id) }) - .map_err(|_| { - ErrorKind::Resolve(ResolutionFailure::NotInScope(path_root.clone().into())) - })?; - if let Res::Err = ty_res { - return if ns == Namespace::ValueNS { - self.variant_field(path_str, current_item, module_id) - } else { - Err(ErrorKind::Resolve(ResolutionFailure::NotInScope(path_root.into()))) - }; - } + .map(|(_, res)| res); + let ty_res = match ty_res { + Err(()) | Ok(Res::Err) => { + return if ns == Namespace::ValueNS { + self.variant_field(path_str, current_item, module_id) + } else { + // See if it only broke because of the namespace. + let kind = cx.enter_resolver(|resolver| { + for &ns in &[MacroNS, ValueNS] { + match resolver + .resolve_str_path_error(DUMMY_SP, &path_root, ns, module_id) + { + Ok((_, Res::Err)) | Err(()) => {} + Ok((_, res)) => { + let res = res.map_id(|_| panic!("unexpected node_id")); + return ResolutionFailure::CannotHaveAssociatedItems( + res, ns, + ); + } + } + } + ResolutionFailure::NotInScope(path_root.into()) + }); + Err(ErrorKind::Resolve(kind)) + }; + } + Ok(res) => res, + }; let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); let res = match ty_res { Res::Def( @@ -1006,14 +1028,12 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { Ok(res) => (res, extra_fragment), Err(mut kind) => { // `macro_resolve` only looks in the macro namespace. Try to give a better error if possible. - //if kind.res().is_none() { for &ns in &[TypeNS, ValueNS] { if let Some(res) = check_full_res(self, ns) { kind = ResolutionFailure::WrongNamespace(res, MacroNS); break; } } - //} resolution_failure( cx, &item, @@ -1456,6 +1476,20 @@ fn resolution_failure( diag.note(¬e); } } + ResolutionFailure::CannotHaveAssociatedItems(res, _) => { + let (item, _) = item(res); + diag.note(&format!("this link partially resolves to {}", item)); + if let Res::Def(kind, def_id) = res { + let name = cx.tcx.item_name(def_id); + let note = format!( + "`{}` is {} {}, not a module or type, and cannot have associated items", + name, + kind.article(), + kind.descr(def_id) + ); + diag.note(¬e); + } + } // TODO: is there ever a case where this happens? ResolutionFailure::NotAnEnum(res) => { let (item, comma) = item(res); diff --git a/src/test/rustdoc-ui/intra-link-errors.rs b/src/test/rustdoc-ui/intra-link-errors.rs index 79ce57c22676f..1a2f24cef2423 100644 --- a/src/test/rustdoc-ui/intra-link-errors.rs +++ b/src/test/rustdoc-ui/intra-link-errors.rs @@ -7,14 +7,14 @@ // FIXME: this could say which path was the first to not be found (in this case, `path`) /// [path::to::nonexistent::module] //~^ ERROR unresolved link -//~| NOTE no item named `path::to::nonexistent` is in scope +//~| NOTE no item named `path::to` is in scope //~| HELP to escape // TODO: why does this say `f` and not `f::A`?? /// [f::A] //~^ ERROR unresolved link -//~| NOTE no item named `f` is in scope -//~| HELP to escape +//~| NOTE this link partially resolves +//~| NOTE `f` is a function, not a module /// [S::A] //~^ ERROR unresolved link diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr index 4044c7fde66f2..0244d2bfde8d9 100644 --- a/src/test/rustdoc-ui/intra-link-errors.stderr +++ b/src/test/rustdoc-ui/intra-link-errors.stderr @@ -9,7 +9,7 @@ note: the lint level is defined here | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ - = note: no item named `path::to::nonexistent` is in scope + = note: no item named `path::to` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: unresolved link to `f::A` @@ -18,8 +18,8 @@ error: unresolved link to `f::A` LL | /// [f::A] | ^^^^ | - = note: no item named `f` is in scope - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + = note: this link partially resolves to the function `f` + = note: `f` is a function, not a module or type, and cannot have associated items error: unresolved link to `S::A` --> $DIR/intra-link-errors.rs:19:6 From 7b8d0befd67ad2472052e3f84cf310b7866b829f Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 21 Aug 2020 12:31:04 -0400 Subject: [PATCH 0123/1052] Remove some TODOs --- src/librustdoc/passes/collect_intra_doc_links.rs | 2 -- src/test/rustdoc-ui/intra-link-errors.rs | 1 - 2 files changed, 3 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index ed411bf2b8dab..0d07f8f0328b4 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -150,7 +150,6 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { let variant_name = // we're not sure this is a variant at all, so use the full string split.next().map(|f| Symbol::intern(f)).ok_or(ErrorKind::Resolve(ResolutionFailure::NotInScope(path_str.into())))?; - // TODO: this looks very wrong, why are we requiring 3 fields? let path = split .next() .map(|f| { @@ -161,7 +160,6 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } f.to_owned() }) - // TODO: is this right? .ok_or(ErrorKind::Resolve(ResolutionFailure::NotInScope( variant_name.to_string().into(), )))?; diff --git a/src/test/rustdoc-ui/intra-link-errors.rs b/src/test/rustdoc-ui/intra-link-errors.rs index 1a2f24cef2423..5bfbdcc495f29 100644 --- a/src/test/rustdoc-ui/intra-link-errors.rs +++ b/src/test/rustdoc-ui/intra-link-errors.rs @@ -10,7 +10,6 @@ //~| NOTE no item named `path::to` is in scope //~| HELP to escape -// TODO: why does this say `f` and not `f::A`?? /// [f::A] //~^ ERROR unresolved link //~| NOTE this link partially resolves From e2d69f2eb115b0b6a433977ae7c5a73c249a4f98 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 21 Aug 2020 13:35:50 -0400 Subject: [PATCH 0124/1052] Make errors more concise and helpful Before: ``` = note: this link partially resolves to the struct `S` = note: no `fmt` in `S` ``` After: ``` = note: the struct `S` has no field or associated item named `fmt` ``` --- .../passes/collect_intra_doc_links.rs | 95 ++++++++++++------- .../rustdoc-ui/assoc-item-not-in-scope.stderr | 4 +- .../rustdoc-ui/intra-doc-alias-ice.stderr | 3 +- src/test/rustdoc-ui/intra-link-errors.rs | 10 +- src/test/rustdoc-ui/intra-link-errors.stderr | 28 +++--- .../rustdoc-ui/intra-links-warning.stderr | 3 +- src/test/rustdoc-ui/lint-group.stderr | 3 +- 7 files changed, 81 insertions(+), 65 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 0d07f8f0328b4..c69850f9d9743 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1406,11 +1406,18 @@ fn resolution_failure( let in_scope = kinds.iter().any(|kind| kind.res().is_some()); let mut reported_not_in_scope = false; let item = |res: Res| { - if let Some(id) = res.opt_def_id() { - (format!("the {} `{}`", res.descr(), cx.tcx.item_name(id).to_string()), ",") - } else { - (format!("{} {}", res.article(), res.descr()), "") - } + format!("the {} `{}`", res.descr(), cx.tcx.item_name(res.def_id()).to_string()) + }; + let assoc_item_not_allowed = |res: Res, diag: &mut DiagnosticBuilder<'_>| { + let def_id = res.def_id(); + let name = cx.tcx.item_name(def_id); + let note = format!( + "`{}` is {} {}, not a module or type, and cannot have associated items", + name, + res.article(), + res.descr() + ); + diag.note(¬e); }; for failure in kinds { match failure { @@ -1425,11 +1432,9 @@ fn resolution_failure( } ResolutionFailure::Dummy => continue, ResolutionFailure::WrongNamespace(res, expected_ns) => { - let (item, comma) = item(res); let note = format!( - "this link resolves to {}{} which is not in the {} namespace", - item, - comma, + "this link resolves to {}, which is not in the {} namespace", + item(res), expected_ns.descr() ); diag.note(¬e); @@ -1450,10 +1455,9 @@ fn resolution_failure( panic!("all intra doc links should have a parent item") } ResolutionFailure::NoPrimitiveImpl(res, _) => { - let (item, comma) = item(res); let note = format!( - "this link partially resolves to {}{} which does not have any associated items", - item, comma, + "this link partially resolves to {}, which does not have any associated items", + item(res), ); diag.note(¬e); } @@ -1465,41 +1469,62 @@ fn resolution_failure( diag.note(¬e); } ResolutionFailure::NoAssocItem(res, assoc_item) => { - let (item, _) = item(res); - diag.note(&format!("this link partially resolves to {}", item)); - // FIXME: when are items neither a primitive nor a Def? - if let Res::Def(_, def_id) = res { - let name = cx.tcx.item_name(def_id); - let note = format!("no `{}` in `{}`", assoc_item, name,); - diag.note(¬e); - } + use DefKind::*; + + let (kind, def_id) = match res { + Res::Def(kind, def_id) => (kind, def_id), + _ => unreachable!( + "primitives are covered above and other `Res` variants aren't possible at module scope" + ), + }; + let name = cx.tcx.item_name(def_id); + let path_description = match kind { + Mod | ForeignMod => "inner item", + Struct => "field or associated item", + Enum | Union => "variant or associated item", + Variant + | Field + | Closure + | Generator + | AssocTy + | AssocConst + | AssocFn + | Fn + | Macro(_) + | Const + | ConstParam + | ExternCrate + | Use + | LifetimeParam + | Ctor(_, _) + | AnonConst => return assoc_item_not_allowed(res, diag), + Trait | TyAlias | ForeignTy | OpaqueTy | TraitAlias | TyParam + | Static => "associated item", + Impl | GlobalAsm => unreachable!("not a path"), + }; + let note = format!( + "the {} `{}` has no {} named `{}`", + res.descr(), + name, + path_description, + assoc_item + ); + diag.note(¬e); } ResolutionFailure::CannotHaveAssociatedItems(res, _) => { - let (item, _) = item(res); - diag.note(&format!("this link partially resolves to {}", item)); - if let Res::Def(kind, def_id) = res { - let name = cx.tcx.item_name(def_id); - let note = format!( - "`{}` is {} {}, not a module or type, and cannot have associated items", - name, - kind.article(), - kind.descr(def_id) - ); - diag.note(¬e); - } + assoc_item_not_allowed(res, diag) } // TODO: is there ever a case where this happens? ResolutionFailure::NotAnEnum(res) => { - let (item, comma) = item(res); let note = - format!("this link resolves to {}{} which is not an enum", item, comma); + format!("this link resolves to {}, which is not an enum", item(res)); diag.note(¬e); diag.note("if this were an enum, it might have a variant which resolved"); } ResolutionFailure::NotAVariant(res, variant) => { let note = format!( "this link partially resolves to {}, but there is no variant named {}", - item(res).0, + item(res), variant ); diag.note(¬e); diff --git a/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr b/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr index 8827c9351a62d..8acfcca2139e3 100644 --- a/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr +++ b/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr @@ -2,14 +2,14 @@ error: unresolved link to `S::fmt` --> $DIR/assoc-item-not-in-scope.rs:4:14 | LL | /// Link to [`S::fmt`] - | ^^^^^^^^ unresolved link + | ^^^^^^^^ | note: the lint level is defined here --> $DIR/assoc-item-not-in-scope.rs:1:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + = note: the struct `S` has no field or associated item named `fmt` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr index 58abe4406a85d..5379a91883753 100644 --- a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr +++ b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr @@ -9,8 +9,7 @@ note: the lint level is defined here | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ - = note: this link partially resolves to the type alias `TypeAlias` - = note: no `hoge` in `TypeAlias` + = note: the type alias `TypeAlias` has no associated item named `hoge` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-link-errors.rs b/src/test/rustdoc-ui/intra-link-errors.rs index 5bfbdcc495f29..ecf2b05e2818b 100644 --- a/src/test/rustdoc-ui/intra-link-errors.rs +++ b/src/test/rustdoc-ui/intra-link-errors.rs @@ -12,23 +12,19 @@ /// [f::A] //~^ ERROR unresolved link -//~| NOTE this link partially resolves //~| NOTE `f` is a function, not a module /// [S::A] //~^ ERROR unresolved link -//~| NOTE this link partially resolves -//~| NOTE no `A` in `S` +//~| NOTE struct `S` has no field or associated item /// [S::fmt] //~^ ERROR unresolved link -//~| NOTE this link partially resolves -//~| NOTE no `fmt` in `S` +//~| NOTE struct `S` has no field or associated item /// [E::D] //~^ ERROR unresolved link -//~| NOTE this link partially resolves -//~| NOTE no `D` in `E` +//~| NOTE enum `E` has no variant or associated item /// [u8::not_found] //~^ ERROR unresolved link diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr index 0244d2bfde8d9..ba091ff854ce6 100644 --- a/src/test/rustdoc-ui/intra-link-errors.stderr +++ b/src/test/rustdoc-ui/intra-link-errors.stderr @@ -13,43 +13,39 @@ LL | #![deny(broken_intra_doc_links)] = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: unresolved link to `f::A` - --> $DIR/intra-link-errors.rs:14:6 + --> $DIR/intra-link-errors.rs:13:6 | LL | /// [f::A] | ^^^^ | - = note: this link partially resolves to the function `f` = note: `f` is a function, not a module or type, and cannot have associated items error: unresolved link to `S::A` - --> $DIR/intra-link-errors.rs:19:6 + --> $DIR/intra-link-errors.rs:17:6 | LL | /// [S::A] | ^^^^ | - = note: this link partially resolves to the struct `S` - = note: no `A` in `S` + = note: the struct `S` has no field or associated item named `A` error: unresolved link to `S::fmt` - --> $DIR/intra-link-errors.rs:24:6 + --> $DIR/intra-link-errors.rs:21:6 | LL | /// [S::fmt] | ^^^^^^ | - = note: this link partially resolves to the struct `S` - = note: no `fmt` in `S` + = note: the struct `S` has no field or associated item named `fmt` error: unresolved link to `E::D` - --> $DIR/intra-link-errors.rs:29:6 + --> $DIR/intra-link-errors.rs:25:6 | LL | /// [E::D] | ^^^^ | - = note: this link partially resolves to the enum `E` - = note: no `D` in `E` + = note: the enum `E` has no variant or associated item named `D` error: unresolved link to `u8::not_found` - --> $DIR/intra-link-errors.rs:34:6 + --> $DIR/intra-link-errors.rs:29:6 | LL | /// [u8::not_found] | ^^^^^^^^^^^^^ @@ -57,7 +53,7 @@ LL | /// [u8::not_found] = note: the builtin type `u8` does not have an associated item named `not_found` error: unresolved link to `S` - --> $DIR/intra-link-errors.rs:38:6 + --> $DIR/intra-link-errors.rs:33:6 | LL | /// [S!] | ^^ help: to link to the struct, use its disambiguator: `struct@S` @@ -65,7 +61,7 @@ LL | /// [S!] = note: this link resolves to the struct `S`, which is not in the macro namespace error: unresolved link to `T::g` - --> $DIR/intra-link-errors.rs:56:6 + --> $DIR/intra-link-errors.rs:51:6 | LL | /// [type@T::g] | ^^^^^^^^^ help: to link to the associated function, use its disambiguator: `T::g()` @@ -73,7 +69,7 @@ LL | /// [type@T::g] = note: this link resolves to the associated function `g`, which is not in the type namespace error: unresolved link to `T::h` - --> $DIR/intra-link-errors.rs:61:6 + --> $DIR/intra-link-errors.rs:56:6 | LL | /// [T::h!] | ^^^^^ @@ -82,7 +78,7 @@ LL | /// [T::h!] = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: unresolved link to `S::h` - --> $DIR/intra-link-errors.rs:48:6 + --> $DIR/intra-link-errors.rs:43:6 | LL | /// [type@S::h] | ^^^^^^^^^ help: to link to the associated function, use its disambiguator: `S::h()` diff --git a/src/test/rustdoc-ui/intra-links-warning.stderr b/src/test/rustdoc-ui/intra-links-warning.stderr index b51c8e89600b0..988a65c7a591c 100644 --- a/src/test/rustdoc-ui/intra-links-warning.stderr +++ b/src/test/rustdoc-ui/intra-links-warning.stderr @@ -5,8 +5,7 @@ LL | //! Test with [Foo::baz], [Bar::foo], ... | ^^^^^^^^ | = note: `#[warn(broken_intra_doc_links)]` on by default - = note: this link partially resolves to the struct `Foo` - = note: no `baz` in `Foo` + = note: the struct `Foo` has no field or associated item named `baz` warning: unresolved link to `Bar::foo` --> $DIR/intra-links-warning.rs:3:35 diff --git a/src/test/rustdoc-ui/lint-group.stderr b/src/test/rustdoc-ui/lint-group.stderr index 04296d2e44a7c..10fcebb27fe0c 100644 --- a/src/test/rustdoc-ui/lint-group.stderr +++ b/src/test/rustdoc-ui/lint-group.stderr @@ -32,7 +32,7 @@ error: unresolved link to `error` --> $DIR/lint-group.rs:9:29 | LL | /// what up, let's make an [error] - | ^^^^^ unresolved link + | ^^^^^ | note: the lint level is defined here --> $DIR/lint-group.rs:7:9 @@ -40,6 +40,7 @@ note: the lint level is defined here LL | #![deny(rustdoc)] | ^^^^^^^ = note: `#[deny(broken_intra_doc_links)]` implied by `#[deny(rustdoc)]` + = note: no item named `error` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: aborting due to 3 previous errors From 19d100278d9609c389780e2692dddaeb45fba301 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 21 Aug 2020 15:00:30 -0400 Subject: [PATCH 0125/1052] Fix failures to resolve primitives Previously, when looking for the associated items for primitives, rustdoc would look for primitives in the current namespace. But all primitives are in the type namespace. To fix this, rustdoc now always looks for primitives in the namespace when considering them as a stepping stone to the associated item. However, fixing that bug caused several duplicate errors because rustdoc now reports the same error in each namespace. To avoid this, rustdoc now ignores all duplicate errors when issuing them. --- .../passes/collect_intra_doc_links.rs | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index c69850f9d9743..9a88c8eb42ad6 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -331,7 +331,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { ErrorKind::Resolve(ResolutionFailure::NotInScope(item_name.to_string().into())) })?; - if let Some((path, prim)) = is_primitive(&path_root, ns) { + if let Some((path, prim)) = is_primitive(&path_root, TypeNS) { let impls = primitive_impl(cx, &path).ok_or_else(|| { ErrorKind::Resolve(ResolutionFailure::NoPrimitiveImpl(prim, path_root.into())) })?; @@ -355,6 +355,12 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { return Ok(link); } } + debug!( + "returning primitive error for {}::{} in {} namespace", + path, + item_name, + ns.descr() + ); return Err(ErrorKind::Resolve(ResolutionFailure::NoPrimitiveAssocItem { res: prim, prim_name: path, @@ -1404,7 +1410,6 @@ fn resolution_failure( &link_range, |diag, sp| { let in_scope = kinds.iter().any(|kind| kind.res().is_some()); - let mut reported_not_in_scope = false; let item = |res: Res| { format!("the {} `{}`", res.descr(), cx.tcx.item_name(res.def_id()).to_string()) }; @@ -1419,14 +1424,19 @@ fn resolution_failure( ); diag.note(¬e); }; + // ignore duplicates + let mut variants_seen = SmallVec::<[_; 3]>::new(); for failure in kinds { + let variant = std::mem::discriminant(&failure); + if variants_seen.contains(&variant) { + continue; + } + variants_seen.push(variant); match failure { - // already handled above ResolutionFailure::NotInScope(base) => { - if in_scope || reported_not_in_scope { + if in_scope { continue; } - reported_not_in_scope = true; diag.note(&format!("no item named `{}` is in scope", base)); diag.help(r#"to escape `[` and `]` characters, add '\' before them like `\[` or `\]`"#); } From ebc8cb470fd137214911fa317ff6b06c6683ad3c Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 21 Aug 2020 15:19:47 -0400 Subject: [PATCH 0126/1052] Turn NoParentItem from a panic into an ICE --- src/librustdoc/passes/collect_intra_doc_links.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 9a88c8eb42ad6..a859d1b2f5f59 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -541,7 +541,6 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }) } else { debug!("attempting to resolve item without parent module: {}", path_str); - // TODO: maybe this should just be an ICE? Err(ErrorKind::Resolve(ResolutionFailure::NoParentItem)) } } @@ -1462,7 +1461,8 @@ fn resolution_failure( } } ResolutionFailure::NoParentItem => { - panic!("all intra doc links should have a parent item") + diag.level = rustc_errors::Level::Bug; + diag.note("all intra doc links should have a parent item"); } ResolutionFailure::NoPrimitiveImpl(res, _) => { let note = format!( @@ -1694,7 +1694,6 @@ fn handle_variant( let parent = if let Some(parent) = cx.tcx.parent(res.def_id()) { parent } else { - // TODO: this should just be an unwrap, there should never be `Variant`s without a parent return Err(ErrorKind::Resolve(ResolutionFailure::NoParentItem)); }; let parent_def = Res::Def(DefKind::Enum, parent); From 6875220e1abea26c67885833c27365854cd7f73c Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 21 Aug 2020 16:12:39 -0400 Subject: [PATCH 0127/1052] Use rustc_resolve's descr() instead of rewriting it --- .../passes/collect_intra_doc_links.rs | 86 ++++++++----------- .../rustdoc-ui/intra-links-anchors.stderr | 6 +- 2 files changed, 38 insertions(+), 54 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index a859d1b2f5f59..1c709cead7017 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -110,12 +110,7 @@ impl ResolutionFailure<'a> { enum AnchorFailure { MultipleAnchors, - Primitive, - Variant, - AssocConstant, - AssocType, - Field, - Method, + RustdocAnchorConflict(Res), } struct LinkCollector<'a, 'tcx> { @@ -288,7 +283,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // Not a trait item; just return what we found. Res::PrimTy(..) => { if extra_fragment.is_some() { - return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive)); + return Err(ErrorKind::AnchorFailure( + AnchorFailure::RustdocAnchorConflict(res), + )); } return Ok((res, Some(path_str.to_owned()))); } @@ -305,7 +302,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } } else if let Some((path, prim)) = is_primitive(path_str, ns) { if extra_fragment.is_some() { - return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive)); + return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict( + prim, + ))); } return Ok((prim, Some(path.to_owned()))); } @@ -444,11 +443,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { ty::AssocKind::Type => "associatedtype", }; Some(if extra_fragment.is_some() { - Err(ErrorKind::AnchorFailure(if kind == ty::AssocKind::Fn { - AnchorFailure::Method - } else { - AnchorFailure::AssocConstant - })) + Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict( + ty_res, + ))) } else { // HACK(jynelson): `clean` expects the type, not the associated item. // but the disambiguator logic expects the associated item. @@ -470,11 +467,17 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }; field.map(|item| { if extra_fragment.is_some() { - Err(ErrorKind::AnchorFailure(if def.is_enum() { - AnchorFailure::Variant - } else { - AnchorFailure::Field - })) + let res = Res::Def( + if def.is_enum() { + DefKind::Variant + } else { + DefKind::Field + }, + item.did, + ); + Err(ErrorKind::AnchorFailure( + AnchorFailure::RustdocAnchorConflict(res), + )) } else { Ok(( ty_res, @@ -518,13 +521,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }; if extra_fragment.is_some() { - Err(ErrorKind::AnchorFailure(if item.kind == ty::AssocKind::Const { - AnchorFailure::AssocConstant - } else if item.kind == ty::AssocKind::Type { - AnchorFailure::AssocType - } else { - AnchorFailure::Method - })) + Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict( + ty_res, + ))) } else { let res = Res::Def(item.kind.as_def_kind(), item.def_id); Ok((res, Some(format!("{}.{}", kind, item_name)))) @@ -889,8 +888,10 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { Some(res.0) } Err(ErrorKind::Resolve(kind)) => kind.full_res(), - // TODO: add `Res` to AnchorFailure - Err(ErrorKind::AnchorFailure(_)) => None, + Err(ErrorKind::AnchorFailure( + AnchorFailure::RustdocAnchorConflict(res), + )) => Some(res), + Err(ErrorKind::AnchorFailure(AnchorFailure::MultipleAnchors)) => None, }; this.kind_side_channel.take().map(|(kind, id)| Res::Def(kind, id)).or(res) }; @@ -1070,7 +1071,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { path_str, &dox, link_range, - AnchorFailure::Primitive, + AnchorFailure::RustdocAnchorConflict(prim), ); continue; } @@ -1555,28 +1556,11 @@ fn anchor_failure( ) { let msg = match failure { AnchorFailure::MultipleAnchors => format!("`{}` contains multiple anchors", path_str), - AnchorFailure::Primitive - | AnchorFailure::Variant - | AnchorFailure::AssocConstant - | AnchorFailure::AssocType - | AnchorFailure::Field - | AnchorFailure::Method => { - let kind = match failure { - AnchorFailure::Primitive => "primitive type", - AnchorFailure::Variant => "enum variant", - AnchorFailure::AssocConstant => "associated constant", - AnchorFailure::AssocType => "associated type", - AnchorFailure::Field => "struct field", - AnchorFailure::Method => "method", - AnchorFailure::MultipleAnchors => unreachable!("should be handled already"), - }; - - format!( - "`{}` contains an anchor, but links to {kind}s are already anchored", - path_str, - kind = kind - ) - } + AnchorFailure::RustdocAnchorConflict(res) => format!( + "`{}` contains an anchor, but links to {kind}s are already anchored", + path_str, + kind = res.descr(), + ), }; report_diagnostic(cx, &msg, item, dox, &link_range, |diag, sp| { @@ -1689,7 +1673,7 @@ fn handle_variant( use rustc_middle::ty::DefIdTree; if extra_fragment.is_some() { - return Err(ErrorKind::AnchorFailure(AnchorFailure::Variant)); + return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res))); } let parent = if let Some(parent) = cx.tcx.parent(res.def_id()) { parent diff --git a/src/test/rustdoc-ui/intra-links-anchors.stderr b/src/test/rustdoc-ui/intra-links-anchors.stderr index e737b84320d94..1825a4ad1fa6b 100644 --- a/src/test/rustdoc-ui/intra-links-anchors.stderr +++ b/src/test/rustdoc-ui/intra-links-anchors.stderr @@ -1,4 +1,4 @@ -error: `Foo::f#hola` contains an anchor, but links to struct fields are already anchored +error: `Foo::f#hola` contains an anchor, but links to fields are already anchored --> $DIR/intra-links-anchors.rs:25:15 | LL | /// Or maybe [Foo::f#hola]. @@ -16,13 +16,13 @@ error: `hello#people#!` contains multiple anchors LL | /// Another anchor error: [hello#people#!]. | ^^^^^^^^^^^^^^ contains invalid anchor -error: `Enum::A#whatever` contains an anchor, but links to enum variants are already anchored +error: `Enum::A#whatever` contains an anchor, but links to variants are already anchored --> $DIR/intra-links-anchors.rs:37:28 | LL | /// Damn enum's variants: [Enum::A#whatever]. | ^^^^^^^^^^^^^^^^ contains invalid anchor -error: `u32#hello` contains an anchor, but links to primitive types are already anchored +error: `u32#hello` contains an anchor, but links to builtin types are already anchored --> $DIR/intra-links-anchors.rs:43:6 | LL | /// [u32#hello] From 418f6089e93d7f784643d55e6782055c9bb479d5 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 21 Aug 2020 16:37:31 -0400 Subject: [PATCH 0128/1052] Give a better error message when linking to a macro with the wrong disambiguator Before: ``` warning: unresolved link to `m` --> m.rs:1:6 | 1 | /// [value@m] | ^^^^^^^ | = note: `#[warn(broken_intra_doc_links)]` on by default = note: no item named `m` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` ``` After: ``` warning: unresolved link to `m` --> m.rs:1:6 | 1 | /// [value@m] | ^^^^^^^ help: to link to the macro, use its disambiguator: `m!` | = note: `#[warn(broken_intra_doc_links)]` on by default = note: this link resolves to the macro `m`, which is not in the value namespace ``` --- .../passes/collect_intra_doc_links.rs | 119 ++++++++++++------ src/test/rustdoc-ui/intra-link-errors.rs | 21 ++++ src/test/rustdoc-ui/intra-link-errors.stderr | 52 ++++++-- 3 files changed, 142 insertions(+), 50 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 1c709cead7017..7bd4b8ca854b5 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -74,8 +74,6 @@ enum ResolutionFailure<'a> { NoAssocItem(Res, Symbol), /// should not ever happen NoParentItem, - /// the root of this path resolved, but it was not an enum. - NotAnEnum(Res), /// this could be an enum variant, but the last path fragment wasn't resolved. /// the `String` is the variant that didn't exist NotAVariant(Res, Symbol), @@ -91,7 +89,6 @@ impl ResolutionFailure<'a> { NoPrimitiveAssocItem { res, .. } | NoAssocItem(res, _) | NoPrimitiveImpl(res, _) - | NotAnEnum(res) | NotAVariant(res, _) | WrongNamespace(res, _) | CannotHaveAssociatedItems(res, _) => Some(*res), @@ -133,6 +130,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { path_str: &'path str, current_item: &Option, module_id: DefId, + extra_fragment: &Option, ) -> Result<(Res, Option), ErrorKind<'path>> { let cx = self.cx; @@ -202,7 +200,28 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { _ => unreachable!(), } } - _ => Err(ErrorKind::Resolve(ResolutionFailure::NotAnEnum(ty_res))), + // `variant_field` looks at 3 different path segments in a row. + // But `NoAssocItem` assumes there are only 2. Check to see if there's + // an intermediate segment that resolves. + _ => { + let intermediate_path = format!("{}::{}", path, variant_name); + // NOTE: we have to be careful here, because we're already in `resolve`. + // We know this doesn't recurse forever because we use a shorter path each time. + // NOTE: this uses `TypeNS` because nothing else has a valid path segment after + let kind = if let Some(intermediate) = self.check_full_res( + TypeNS, + &intermediate_path, + Some(module_id), + current_item, + extra_fragment, + ) { + ResolutionFailure::NoAssocItem(intermediate, variant_field_name) + } else { + // Even with the shorter path, it didn't resolve, so say that. + ResolutionFailure::NoAssocItem(ty_res, variant_name) + }; + Err(ErrorKind::Resolve(kind)) + } } } @@ -376,7 +395,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { let ty_res = match ty_res { Err(()) | Ok(Res::Err) => { return if ns == Namespace::ValueNS { - self.variant_field(path_str, current_item, module_id) + self.variant_field(path_str, current_item, module_id, extra_fragment) } else { // See if it only broke because of the namespace. let kind = cx.enter_resolver(|resolver| { @@ -533,7 +552,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }; res.unwrap_or_else(|| { if ns == Namespace::ValueNS { - self.variant_field(path_str, current_item, module_id) + self.variant_field(path_str, current_item, module_id, extra_fragment) } else { Err(ErrorKind::Resolve(ResolutionFailure::NoAssocItem(ty_res, item_name))) } @@ -543,6 +562,41 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { Err(ErrorKind::Resolve(ResolutionFailure::NoParentItem)) } } + + // used for reporting better errors + fn check_full_res( + &self, + ns: Namespace, + path_str: &str, + base_node: Option, + current_item: &Option, + extra_fragment: &Option, + ) -> Option { + let check_full_res_inner = |this: &Self, result: Result>| { + let res = match result { + Ok(res) => Some(res), + Err(ErrorKind::Resolve(kind)) => kind.full_res(), + Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res))) => { + Some(res) + } + Err(ErrorKind::AnchorFailure(AnchorFailure::MultipleAnchors)) => None, + }; + this.kind_side_channel.take().map(|(kind, id)| Res::Def(kind, id)).or(res) + }; + // cannot be used for macro namespace + let check_full_res = |this: &Self, ns| { + let result = this.resolve(path_str, ns, current_item, base_node, extra_fragment); + check_full_res_inner(this, result.map(|(res, _)| res)) + }; + let check_full_res_macro = |this: &Self| { + let result = this.macro_resolve(path_str, base_node); + check_full_res_inner(this, result.map_err(ErrorKind::Resolve)) + }; + match ns { + Namespace::MacroNS => check_full_res_macro(self), + Namespace::TypeNS | Namespace::ValueNS => check_full_res(self, ns), + } + } } fn resolve_associated_trait_item( @@ -652,7 +706,7 @@ fn traits_implemented_by(cx: &DocContext<'_>, type_: DefId, module: DefId) -> Fx let trait_ref = cx.tcx.impl_trait_ref(impl_).expect("this is not an inherent impl"); // Check if these are the same type. let impl_type = trait_ref.self_ty(); - debug!( + trace!( "comparing type {} with kind {:?} against type {:?}", impl_type, impl_type.kind(), @@ -875,27 +929,6 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } } - // used for reporting better errors - let check_full_res = |this: &mut Self, ns| { - let res = - match this.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment) - { - Ok(res) => { - debug!( - "check_full_res: saw res for {} in {:?} ns: {:?}", - path_str, ns, res.0 - ); - Some(res.0) - } - Err(ErrorKind::Resolve(kind)) => kind.full_res(), - Err(ErrorKind::AnchorFailure( - AnchorFailure::RustdocAnchorConflict(res), - )) => Some(res), - Err(ErrorKind::AnchorFailure(AnchorFailure::MultipleAnchors)) => None, - }; - this.kind_side_channel.take().map(|(kind, id)| Res::Def(kind, id)).or(res) - }; - match disambiguator.map(Disambiguator::ns) { Some(ns @ (ValueNS | TypeNS)) => { match self.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment) @@ -903,12 +936,19 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { Ok(res) => res, Err(ErrorKind::Resolve(mut kind)) => { // We only looked in one namespace. Try to give a better error if possible. - // TODO: handle MacroNS too if kind.full_res().is_none() { let other_ns = if ns == ValueNS { TypeNS } else { ValueNS }; - if let Some(res) = check_full_res(self, other_ns) { - // recall that this stores the _expected_ namespace - kind = ResolutionFailure::WrongNamespace(res, ns); + for &ns in &[other_ns, MacroNS] { + if let Some(res) = self.check_full_res( + ns, + path_str, + base_node, + ¤t_item, + &extra_fragment, + ) { + kind = ResolutionFailure::WrongNamespace(res, ns); + break; + } } } resolution_failure( @@ -1033,7 +1073,13 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { Err(mut kind) => { // `macro_resolve` only looks in the macro namespace. Try to give a better error if possible. for &ns in &[TypeNS, ValueNS] { - if let Some(res) = check_full_res(self, ns) { + if let Some(res) = self.check_full_res( + ns, + path_str, + base_node, + ¤t_item, + &extra_fragment, + ) { kind = ResolutionFailure::WrongNamespace(res, MacroNS); break; } @@ -1525,13 +1571,6 @@ fn resolution_failure( ResolutionFailure::CannotHaveAssociatedItems(res, _) => { assoc_item_not_allowed(res, diag) } - // TODO: is there ever a case where this happens? - ResolutionFailure::NotAnEnum(res) => { - let note = - format!("this link resolves to {}, which is not an enum", item(res)); - diag.note(¬e); - diag.note("if this were an enum, it might have a variant which resolved"); - } ResolutionFailure::NotAVariant(res, variant) => { let note = format!( "this link partially resolves to {}, but there is no variant named {}", diff --git a/src/test/rustdoc-ui/intra-link-errors.rs b/src/test/rustdoc-ui/intra-link-errors.rs index ecf2b05e2818b..33c8d1b3c4965 100644 --- a/src/test/rustdoc-ui/intra-link-errors.rs +++ b/src/test/rustdoc-ui/intra-link-errors.rs @@ -10,6 +10,18 @@ //~| NOTE no item named `path::to` is in scope //~| HELP to escape +/// [std::io::not::here] +//~^ ERROR unresolved link +//~| NOTE the module `io` has no inner item + +/// [std::io::Error::x] +//~^ ERROR unresolved link +//~| NOTE the struct `Error` has no field + +/// [std::io::ErrorKind::x] +//~^ ERROR unresolved link +//~| NOTE the enum `ErrorKind` has no variant + /// [f::A] //~^ ERROR unresolved link //~| NOTE `f` is a function, not a module @@ -60,3 +72,12 @@ impl S { pub trait T { fn g() {} } + +/// [m()] +//~^ ERROR unresolved link +//~| HELP to link to the macro +//~| NOTE not in the value namespace +#[macro_export] +macro_rules! m { + () => {}; +} diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr index ba091ff854ce6..0b9149cd8ea45 100644 --- a/src/test/rustdoc-ui/intra-link-errors.stderr +++ b/src/test/rustdoc-ui/intra-link-errors.stderr @@ -12,16 +12,40 @@ LL | #![deny(broken_intra_doc_links)] = note: no item named `path::to` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -error: unresolved link to `f::A` +error: unresolved link to `std::io::not::here` --> $DIR/intra-link-errors.rs:13:6 | +LL | /// [std::io::not::here] + | ^^^^^^^^^^^^^^^^^^ + | + = note: the module `io` has no inner item named `not` + +error: unresolved link to `std::io::Error::x` + --> $DIR/intra-link-errors.rs:17:6 + | +LL | /// [std::io::Error::x] + | ^^^^^^^^^^^^^^^^^ + | + = note: the struct `Error` has no field or associated item named `x` + +error: unresolved link to `std::io::ErrorKind::x` + --> $DIR/intra-link-errors.rs:21:6 + | +LL | /// [std::io::ErrorKind::x] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: the enum `ErrorKind` has no variant or associated item named `x` + +error: unresolved link to `f::A` + --> $DIR/intra-link-errors.rs:25:6 + | LL | /// [f::A] | ^^^^ | = note: `f` is a function, not a module or type, and cannot have associated items error: unresolved link to `S::A` - --> $DIR/intra-link-errors.rs:17:6 + --> $DIR/intra-link-errors.rs:29:6 | LL | /// [S::A] | ^^^^ @@ -29,7 +53,7 @@ LL | /// [S::A] = note: the struct `S` has no field or associated item named `A` error: unresolved link to `S::fmt` - --> $DIR/intra-link-errors.rs:21:6 + --> $DIR/intra-link-errors.rs:33:6 | LL | /// [S::fmt] | ^^^^^^ @@ -37,7 +61,7 @@ LL | /// [S::fmt] = note: the struct `S` has no field or associated item named `fmt` error: unresolved link to `E::D` - --> $DIR/intra-link-errors.rs:25:6 + --> $DIR/intra-link-errors.rs:37:6 | LL | /// [E::D] | ^^^^ @@ -45,7 +69,7 @@ LL | /// [E::D] = note: the enum `E` has no variant or associated item named `D` error: unresolved link to `u8::not_found` - --> $DIR/intra-link-errors.rs:29:6 + --> $DIR/intra-link-errors.rs:41:6 | LL | /// [u8::not_found] | ^^^^^^^^^^^^^ @@ -53,7 +77,7 @@ LL | /// [u8::not_found] = note: the builtin type `u8` does not have an associated item named `not_found` error: unresolved link to `S` - --> $DIR/intra-link-errors.rs:33:6 + --> $DIR/intra-link-errors.rs:45:6 | LL | /// [S!] | ^^ help: to link to the struct, use its disambiguator: `struct@S` @@ -61,7 +85,7 @@ LL | /// [S!] = note: this link resolves to the struct `S`, which is not in the macro namespace error: unresolved link to `T::g` - --> $DIR/intra-link-errors.rs:51:6 + --> $DIR/intra-link-errors.rs:63:6 | LL | /// [type@T::g] | ^^^^^^^^^ help: to link to the associated function, use its disambiguator: `T::g()` @@ -69,7 +93,7 @@ LL | /// [type@T::g] = note: this link resolves to the associated function `g`, which is not in the type namespace error: unresolved link to `T::h` - --> $DIR/intra-link-errors.rs:56:6 + --> $DIR/intra-link-errors.rs:68:6 | LL | /// [T::h!] | ^^^^^ @@ -78,12 +102,20 @@ LL | /// [T::h!] = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: unresolved link to `S::h` - --> $DIR/intra-link-errors.rs:43:6 + --> $DIR/intra-link-errors.rs:55:6 | LL | /// [type@S::h] | ^^^^^^^^^ help: to link to the associated function, use its disambiguator: `S::h()` | = note: this link resolves to the associated function `h`, which is not in the type namespace -error: aborting due to 10 previous errors +error: unresolved link to `m` + --> $DIR/intra-link-errors.rs:76:6 + | +LL | /// [m()] + | ^^^ help: to link to the macro, use its disambiguator: `m!` + | + = note: this link resolves to the macro `m`, which is not in the value namespace + +error: aborting due to 14 previous errors From 2ca6f11663709bcbc113d3dd223ae51442460e15 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 22 Aug 2020 00:50:26 -0400 Subject: [PATCH 0129/1052] Fix rebase conflicts --- src/librustdoc/passes/collect_intra_doc_links.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 7bd4b8ca854b5..43003c944918e 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -938,9 +938,9 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { // We only looked in one namespace. Try to give a better error if possible. if kind.full_res().is_none() { let other_ns = if ns == ValueNS { TypeNS } else { ValueNS }; - for &ns in &[other_ns, MacroNS] { + for &new_ns in &[other_ns, MacroNS] { if let Some(res) = self.check_full_res( - ns, + new_ns, path_str, base_node, ¤t_item, From bb9d1576044020851ff2f528879a41e1ca0b7b5d Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 25 Aug 2020 17:39:50 -0400 Subject: [PATCH 0130/1052] Address my own review comments - Remove unneeded lifetime parameter - Comment why some code doesn't use `check_full_res` --- src/librustdoc/passes/collect_intra_doc_links.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 43003c944918e..b35ec2e73cb27 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -399,6 +399,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } else { // See if it only broke because of the namespace. let kind = cx.enter_resolver(|resolver| { + // NOTE: this doesn't use `check_full_res` because we explicitly want to ignore `TypeNS` (we already checked it) for &ns in &[MacroNS, ValueNS] { match resolver .resolve_str_path_error(DUMMY_SP, &path_root, ns, module_id) @@ -563,9 +564,15 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } } - // used for reporting better errors + /// Used for reporting better errors. + /// + /// Returns whether the link resolved 'fully' in another namespace. + /// 'fully' here means that all parts of the link resolved, not just some path segments. + /// This returns the `Res` even if it was erroneous for some reason + /// (such as having invalid URL fragments or being in the wrong namespace). fn check_full_res( &self, + // TODO: is this parameter actually needed, since we return results for the wrong namespace? ns: Namespace, path_str: &str, base_node: Option, @@ -1609,10 +1616,10 @@ fn anchor_failure( }); } -fn ambiguity_error<'a>( +fn ambiguity_error( cx: &DocContext<'_>, item: &Item, - path_str: &'a str, + path_str: &str, dox: &str, link_range: Option>, candidates: Vec, From f2826d9e9bcba3c161812fca893f98b3dc010f19 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 25 Aug 2020 18:45:57 -0400 Subject: [PATCH 0131/1052] Show the first path segment which failed to resolve. Before, it would arbitrarily pick the third-to-last if the last three or more did not resolve. --- .../passes/collect_intra_doc_links.rs | 30 +++++++++++++++---- src/test/rustdoc-ui/intra-link-errors.rs | 5 ++-- src/test/rustdoc-ui/intra-link-errors.stderr | 14 +++++---- 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index b35ec2e73cb27..098ac13ffe238 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -156,15 +156,35 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .ok_or(ErrorKind::Resolve(ResolutionFailure::NotInScope( variant_name.to_string().into(), )))?; - let (_, ty_res) = cx + let ty_res = cx .enter_resolver(|resolver| { resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) }) - .map_err(|_| { - ErrorKind::Resolve(ResolutionFailure::NotInScope(path.to_string().into())) - })?; + .map(|(_, res)| res) + .unwrap_or(Res::Err); + // This code only gets hit if three path segments in a row don't get resolved. + // It's a good time to check if _any_ parent of the path gets resolved. + // If so, report it and say the first which failed; if not, say the first path segment didn't resolve. if let Res::Err = ty_res { - return Err(ErrorKind::Resolve(ResolutionFailure::NotInScope(path.to_string().into()))); + let mut current = path.as_str(); + while let Some(parent) = current.rsplitn(2, "::").nth(1) { + current = parent; + if let Some(res) = self.check_full_res( + TypeNS, + ¤t, + Some(module_id), + current_item, + extra_fragment, + ) { + return Err(ErrorKind::Resolve(ResolutionFailure::NoAssocItem( + res, + Symbol::intern(&path), + ))); + } + } + return Err(ErrorKind::Resolve(ResolutionFailure::NotInScope( + current.to_string().into(), + ))); } let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); match ty_res { diff --git a/src/test/rustdoc-ui/intra-link-errors.rs b/src/test/rustdoc-ui/intra-link-errors.rs index 33c8d1b3c4965..d8d4ebeb60bdb 100644 --- a/src/test/rustdoc-ui/intra-link-errors.rs +++ b/src/test/rustdoc-ui/intra-link-errors.rs @@ -4,10 +4,9 @@ // FIXME: this should say that it was skipped (maybe an allowed by default lint?) /// [] -// FIXME: this could say which path was the first to not be found (in this case, `path`) /// [path::to::nonexistent::module] //~^ ERROR unresolved link -//~| NOTE no item named `path::to` is in scope +//~| NOTE no item named `path` is in scope //~| HELP to escape /// [std::io::not::here] @@ -44,7 +43,7 @@ /// [S!] //~^ ERROR unresolved link -//~| HELP to link to the struct, use its disambiguator +//~| HELP to link to the struct, prefix with the item kind //~| NOTE this link resolves to the struct `S` pub fn f() {} #[derive(Debug)] diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr index 0b9149cd8ea45..0275fd692feb4 100644 --- a/src/test/rustdoc-ui/intra-link-errors.stderr +++ b/src/test/rustdoc-ui/intra-link-errors.stderr @@ -9,7 +9,7 @@ note: the lint level is defined here | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ - = note: no item named `path::to` is in scope + = note: no item named `path` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: unresolved link to `std::io::not::here` @@ -80,15 +80,19 @@ error: unresolved link to `S` --> $DIR/intra-link-errors.rs:45:6 | LL | /// [S!] - | ^^ help: to link to the struct, use its disambiguator: `struct@S` + | ^^ | = note: this link resolves to the struct `S`, which is not in the macro namespace +help: to link to the struct, prefix with the item kind + | +LL | /// [struct@S] + | ^^^^^^^^ error: unresolved link to `T::g` --> $DIR/intra-link-errors.rs:63:6 | LL | /// [type@T::g] - | ^^^^^^^^^ help: to link to the associated function, use its disambiguator: `T::g()` + | ^^^^^^^^^ help: to link to the associated function, add parentheses: `T::g()` | = note: this link resolves to the associated function `g`, which is not in the type namespace @@ -105,7 +109,7 @@ error: unresolved link to `S::h` --> $DIR/intra-link-errors.rs:55:6 | LL | /// [type@S::h] - | ^^^^^^^^^ help: to link to the associated function, use its disambiguator: `S::h()` + | ^^^^^^^^^ help: to link to the associated function, add parentheses: `S::h()` | = note: this link resolves to the associated function `h`, which is not in the type namespace @@ -113,7 +117,7 @@ error: unresolved link to `m` --> $DIR/intra-link-errors.rs:76:6 | LL | /// [m()] - | ^^^ help: to link to the macro, use its disambiguator: `m!` + | ^^^ help: to link to the macro, add an exclamation mark: `m!` | = note: this link resolves to the macro `m`, which is not in the value namespace From d67eb1f1487c04cdd2564741828cba0784ed8501 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 28 Aug 2020 00:23:24 -0400 Subject: [PATCH 0132/1052] Don't suggest \[ \] if there's a :: in the path --- .../passes/collect_intra_doc_links.rs | 9 ++++-- src/test/rustdoc-ui/intra-link-errors.rs | 2 -- src/test/rustdoc-ui/intra-link-errors.stderr | 28 +++++++++---------- .../rustdoc-ui/intra-links-warning.stderr | 5 ---- 4 files changed, 20 insertions(+), 24 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 098ac13ffe238..0ae322ee11ae3 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -592,7 +592,6 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { /// (such as having invalid URL fragments or being in the wrong namespace). fn check_full_res( &self, - // TODO: is this parameter actually needed, since we return results for the wrong namespace? ns: Namespace, path_str: &str, base_node: Option, @@ -1511,7 +1510,13 @@ fn resolution_failure( continue; } diag.note(&format!("no item named `{}` is in scope", base)); - diag.help(r#"to escape `[` and `]` characters, add '\' before them like `\[` or `\]`"#); + // If the link has `::` in the path, assume it's meant to be an intra-doc link + if !path_str.contains("::") { + // Otherwise, the `[]` might be unrelated. + // FIXME(https://github.com/raphlinus/pulldown-cmark/issues/373): + // don't show this for autolinks (`<>`), `()` style links, or reference links + diag.help(r#"to escape `[` and `]` characters, add '\' before them like `\[` or `\]`"#); + } } ResolutionFailure::Dummy => continue, ResolutionFailure::WrongNamespace(res, expected_ns) => { diff --git a/src/test/rustdoc-ui/intra-link-errors.rs b/src/test/rustdoc-ui/intra-link-errors.rs index d8d4ebeb60bdb..f66bb8a453305 100644 --- a/src/test/rustdoc-ui/intra-link-errors.rs +++ b/src/test/rustdoc-ui/intra-link-errors.rs @@ -7,7 +7,6 @@ /// [path::to::nonexistent::module] //~^ ERROR unresolved link //~| NOTE no item named `path` is in scope -//~| HELP to escape /// [std::io::not::here] //~^ ERROR unresolved link @@ -67,7 +66,6 @@ impl S { /// [T::h!] //~^ ERROR unresolved link //~| NOTE no item named `T::h` -//~| HELP to escape pub trait T { fn g() {} } diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr index 0275fd692feb4..4dac892b82051 100644 --- a/src/test/rustdoc-ui/intra-link-errors.stderr +++ b/src/test/rustdoc-ui/intra-link-errors.stderr @@ -10,10 +10,9 @@ note: the lint level is defined here LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ = note: no item named `path` is in scope - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: unresolved link to `std::io::not::here` - --> $DIR/intra-link-errors.rs:13:6 + --> $DIR/intra-link-errors.rs:12:6 | LL | /// [std::io::not::here] | ^^^^^^^^^^^^^^^^^^ @@ -21,7 +20,7 @@ LL | /// [std::io::not::here] = note: the module `io` has no inner item named `not` error: unresolved link to `std::io::Error::x` - --> $DIR/intra-link-errors.rs:17:6 + --> $DIR/intra-link-errors.rs:16:6 | LL | /// [std::io::Error::x] | ^^^^^^^^^^^^^^^^^ @@ -29,7 +28,7 @@ LL | /// [std::io::Error::x] = note: the struct `Error` has no field or associated item named `x` error: unresolved link to `std::io::ErrorKind::x` - --> $DIR/intra-link-errors.rs:21:6 + --> $DIR/intra-link-errors.rs:20:6 | LL | /// [std::io::ErrorKind::x] | ^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +36,7 @@ LL | /// [std::io::ErrorKind::x] = note: the enum `ErrorKind` has no variant or associated item named `x` error: unresolved link to `f::A` - --> $DIR/intra-link-errors.rs:25:6 + --> $DIR/intra-link-errors.rs:24:6 | LL | /// [f::A] | ^^^^ @@ -45,7 +44,7 @@ LL | /// [f::A] = note: `f` is a function, not a module or type, and cannot have associated items error: unresolved link to `S::A` - --> $DIR/intra-link-errors.rs:29:6 + --> $DIR/intra-link-errors.rs:28:6 | LL | /// [S::A] | ^^^^ @@ -53,7 +52,7 @@ LL | /// [S::A] = note: the struct `S` has no field or associated item named `A` error: unresolved link to `S::fmt` - --> $DIR/intra-link-errors.rs:33:6 + --> $DIR/intra-link-errors.rs:32:6 | LL | /// [S::fmt] | ^^^^^^ @@ -61,7 +60,7 @@ LL | /// [S::fmt] = note: the struct `S` has no field or associated item named `fmt` error: unresolved link to `E::D` - --> $DIR/intra-link-errors.rs:37:6 + --> $DIR/intra-link-errors.rs:36:6 | LL | /// [E::D] | ^^^^ @@ -69,7 +68,7 @@ LL | /// [E::D] = note: the enum `E` has no variant or associated item named `D` error: unresolved link to `u8::not_found` - --> $DIR/intra-link-errors.rs:41:6 + --> $DIR/intra-link-errors.rs:40:6 | LL | /// [u8::not_found] | ^^^^^^^^^^^^^ @@ -77,7 +76,7 @@ LL | /// [u8::not_found] = note: the builtin type `u8` does not have an associated item named `not_found` error: unresolved link to `S` - --> $DIR/intra-link-errors.rs:45:6 + --> $DIR/intra-link-errors.rs:44:6 | LL | /// [S!] | ^^ @@ -89,7 +88,7 @@ LL | /// [struct@S] | ^^^^^^^^ error: unresolved link to `T::g` - --> $DIR/intra-link-errors.rs:63:6 + --> $DIR/intra-link-errors.rs:62:6 | LL | /// [type@T::g] | ^^^^^^^^^ help: to link to the associated function, add parentheses: `T::g()` @@ -97,16 +96,15 @@ LL | /// [type@T::g] = note: this link resolves to the associated function `g`, which is not in the type namespace error: unresolved link to `T::h` - --> $DIR/intra-link-errors.rs:68:6 + --> $DIR/intra-link-errors.rs:67:6 | LL | /// [T::h!] | ^^^^^ | = note: no item named `T::h` is in scope - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: unresolved link to `S::h` - --> $DIR/intra-link-errors.rs:55:6 + --> $DIR/intra-link-errors.rs:54:6 | LL | /// [type@S::h] | ^^^^^^^^^ help: to link to the associated function, add parentheses: `S::h()` @@ -114,7 +112,7 @@ LL | /// [type@S::h] = note: this link resolves to the associated function `h`, which is not in the type namespace error: unresolved link to `m` - --> $DIR/intra-link-errors.rs:76:6 + --> $DIR/intra-link-errors.rs:74:6 | LL | /// [m()] | ^^^ help: to link to the macro, add an exclamation mark: `m!` diff --git a/src/test/rustdoc-ui/intra-links-warning.stderr b/src/test/rustdoc-ui/intra-links-warning.stderr index 988a65c7a591c..25c6975d3a509 100644 --- a/src/test/rustdoc-ui/intra-links-warning.stderr +++ b/src/test/rustdoc-ui/intra-links-warning.stderr @@ -14,7 +14,6 @@ LL | //! Test with [Foo::baz], [Bar::foo], ... | ^^^^^^^^ | = note: no item named `Bar` is in scope - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `Uniooon::X` --> $DIR/intra-links-warning.rs:6:13 @@ -23,7 +22,6 @@ LL | //! , [Uniooon::X] and [Qux::Z]. | ^^^^^^^^^^ | = note: no item named `Uniooon` is in scope - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `Qux::Z` --> $DIR/intra-links-warning.rs:6:30 @@ -32,7 +30,6 @@ LL | //! , [Uniooon::X] and [Qux::Z]. | ^^^^^^ | = note: no item named `Qux` is in scope - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `Uniooon::X` --> $DIR/intra-links-warning.rs:10:14 @@ -41,7 +38,6 @@ LL | //! , [Uniooon::X] and [Qux::Z]. | ^^^^^^^^^^ | = note: no item named `Uniooon` is in scope - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `Qux::Z` --> $DIR/intra-links-warning.rs:10:31 @@ -50,7 +46,6 @@ LL | //! , [Uniooon::X] and [Qux::Z]. | ^^^^^^ | = note: no item named `Qux` is in scope - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `Qux:Y` --> $DIR/intra-links-warning.rs:14:13 From 8754884b78ee6cff99bd72ebdab39629f6ff88c3 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 5 Sep 2020 20:37:26 +0300 Subject: [PATCH 0133/1052] rustbuild: Do not use `rust-mingw` component when bootstrapping windows-gnu targets --- src/bootstrap/bootstrap.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index c3f1bac177de7..dd9fca4eb620b 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -398,14 +398,6 @@ def support_xz(): with output(self.rustc_stamp()) as rust_stamp: rust_stamp.write(self.date) - # This is required so that we don't mix incompatible MinGW - # libraries/binaries that are included in rust-std with - # the system MinGW ones. - if "pc-windows-gnu" in self.build: - filename = "rust-mingw-{}-{}{}".format( - rustc_channel, self.build, tarball_suffix) - self._download_stage0_helper(filename, "rust-mingw", tarball_suffix) - if self.cargo().startswith(self.bin_root()) and \ (not os.path.exists(self.cargo()) or self.program_out_of_date(self.cargo_stamp())): From ee683ef8532034a4bee01e9aa8fd92dbe38ac6f1 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 28 Aug 2020 00:53:36 -0400 Subject: [PATCH 0134/1052] Say 'prefix with `kind@`' instead of 'prefix with the item kind' This is both more specific and easier to read. --- .../passes/collect_intra_doc_links.rs | 57 +++++++++++++------ src/test/rustdoc-ui/intra-link-errors.rs | 2 +- src/test/rustdoc-ui/intra-link-errors.stderr | 6 +- .../rustdoc-ui/intra-link-prim-conflict.rs | 4 +- .../intra-link-prim-conflict.stderr | 20 ++----- .../rustdoc-ui/intra-links-ambiguity.stderr | 12 ++-- .../intra-links-disambiguator-mismatch.rs | 18 +++--- .../intra-links-disambiguator-mismatch.stderr | 54 +++--------------- 8 files changed, 73 insertions(+), 100 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 0ae322ee11ae3..a19387ad992fa 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1328,21 +1328,16 @@ impl Disambiguator { } } - /// Return (description of the change, suggestion) - fn suggestion_for(self, path_str: &str) -> (&'static str, String) { - const PREFIX: &str = "prefix with the item kind"; - const FUNCTION: &str = "add parentheses"; - const MACRO: &str = "add an exclamation mark"; - + fn suggestion(self) -> Suggestion { let kind = match self { - Disambiguator::Primitive => return (PREFIX, format!("prim@{}", path_str)), + Disambiguator::Primitive => return Suggestion::Prefix("prim"), Disambiguator::Kind(kind) => kind, Disambiguator::Namespace(_) => panic!("display_for cannot be used on namespaces"), }; if kind == DefKind::Macro(MacroKind::Bang) { - return (MACRO, format!("{}!", path_str)); + return Suggestion::Macro; } else if kind == DefKind::Fn || kind == DefKind::AssocFn { - return (FUNCTION, format!("{}()", path_str)); + return Suggestion::Function; } let prefix = match kind { @@ -1367,8 +1362,7 @@ impl Disambiguator { }, }; - // FIXME: if this is an implied shortcut link, it's bad style to suggest `@` - (PREFIX, format!("{}@{}", prefix, path_str)) + Suggestion::Prefix(prefix) } fn ns(self) -> Namespace { @@ -1400,6 +1394,31 @@ impl Disambiguator { } } +enum Suggestion { + Prefix(&'static str), + Function, + Macro, +} + +impl Suggestion { + fn descr(&self) -> Cow<'static, str> { + match self { + Self::Prefix(x) => format!("prefix with `{}@`", x).into(), + Self::Function => "add parentheses".into(), + Self::Macro => "add an exclamation mark".into(), + } + } + + fn as_help(&self, path_str: &str) -> String { + // FIXME: if this is an implied shortcut link, it's bad style to suggest `@` + match self { + Self::Prefix(prefix) => format!("{}@{}", prefix, path_str), + Self::Function => format!("{}()", path_str), + Self::Macro => format!("{}!", path_str), + } + } +} + /// Reports a diagnostic for an intra-doc link. /// /// If no link range is provided, or the source span of the link cannot be determined, the span of @@ -1695,18 +1714,20 @@ fn suggest_disambiguator( sp: Option, link_range: &Option>, ) { - let (action, mut suggestion) = disambiguator.suggestion_for(path_str); - let help = format!("to link to the {}, {}", disambiguator.descr(), action); + let suggestion = disambiguator.suggestion(); + let help = format!("to link to the {}, {}", disambiguator.descr(), suggestion.descr()); if let Some(sp) = sp { let link_range = link_range.as_ref().expect("must have a link range if we have a span"); - if dox.bytes().nth(link_range.start) == Some(b'`') { - suggestion = format!("`{}`", suggestion); - } + let msg = if dox.bytes().nth(link_range.start) == Some(b'`') { + format!("`{}`", suggestion.as_help(path_str)) + } else { + suggestion.as_help(path_str) + }; - diag.span_suggestion(sp, &help, suggestion, Applicability::MaybeIncorrect); + diag.span_suggestion(sp, &help, msg, Applicability::MaybeIncorrect); } else { - diag.help(&format!("{}: {}", help, suggestion)); + diag.help(&format!("{}: {}", help, suggestion.as_help(path_str))); } } diff --git a/src/test/rustdoc-ui/intra-link-errors.rs b/src/test/rustdoc-ui/intra-link-errors.rs index f66bb8a453305..919c46fe1dab2 100644 --- a/src/test/rustdoc-ui/intra-link-errors.rs +++ b/src/test/rustdoc-ui/intra-link-errors.rs @@ -42,7 +42,7 @@ /// [S!] //~^ ERROR unresolved link -//~| HELP to link to the struct, prefix with the item kind +//~| HELP to link to the struct, prefix with `struct@` //~| NOTE this link resolves to the struct `S` pub fn f() {} #[derive(Debug)] diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr index 4dac892b82051..7318193964f8d 100644 --- a/src/test/rustdoc-ui/intra-link-errors.stderr +++ b/src/test/rustdoc-ui/intra-link-errors.stderr @@ -79,13 +79,9 @@ error: unresolved link to `S` --> $DIR/intra-link-errors.rs:44:6 | LL | /// [S!] - | ^^ + | ^^ help: to link to the struct, prefix with `struct@`: `struct@S` | = note: this link resolves to the struct `S`, which is not in the macro namespace -help: to link to the struct, prefix with the item kind - | -LL | /// [struct@S] - | ^^^^^^^^ error: unresolved link to `T::g` --> $DIR/intra-link-errors.rs:62:6 diff --git a/src/test/rustdoc-ui/intra-link-prim-conflict.rs b/src/test/rustdoc-ui/intra-link-prim-conflict.rs index 548d3e2544a00..85738ceae8e61 100644 --- a/src/test/rustdoc-ui/intra-link-prim-conflict.rs +++ b/src/test/rustdoc-ui/intra-link-prim-conflict.rs @@ -18,13 +18,13 @@ /// [struct@char] //~^ ERROR incompatible link -//~| HELP prefix with the item kind +//~| HELP prefix with `mod@` //~| NOTE resolved to a module pub mod char {} pub mod inner { //! [struct@char] //~^ ERROR incompatible link - //~| HELP prefix with the item kind + //~| HELP prefix with `prim@` //~| NOTE resolved to a builtin type } diff --git a/src/test/rustdoc-ui/intra-link-prim-conflict.stderr b/src/test/rustdoc-ui/intra-link-prim-conflict.stderr index 53dccfbf1a2c4..43587a80021af 100644 --- a/src/test/rustdoc-ui/intra-link-prim-conflict.stderr +++ b/src/test/rustdoc-ui/intra-link-prim-conflict.stderr @@ -9,11 +9,11 @@ note: the lint level is defined here | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ -help: to link to the module, prefix with the item kind +help: to link to the module, prefix with `mod@` | LL | /// [mod@char] | ^^^^^^^^ -help: to link to the builtin type, prefix with the item kind +help: to link to the builtin type, prefix with `prim@` | LL | /// [prim@char] | ^^^^^^^^^ @@ -24,11 +24,11 @@ error: `char` is both a module and a builtin type LL | /// [type@char] | ^^^^^^^^^ ambiguous link | -help: to link to the module, prefix with the item kind +help: to link to the module, prefix with `mod@` | LL | /// [mod@char] | ^^^^^^^^ -help: to link to the builtin type, prefix with the item kind +help: to link to the builtin type, prefix with `prim@` | LL | /// [prim@char] | ^^^^^^^^^ @@ -37,25 +37,17 @@ error: incompatible link kind for `char` --> $DIR/intra-link-prim-conflict.rs:19:6 | LL | /// [struct@char] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ help: to link to the module, prefix with `mod@`: `mod@char` | = note: this link resolved to a module, which is not a struct -help: to link to the module, prefix with the item kind - | -LL | /// [mod@char] - | ^^^^^^^^ error: incompatible link kind for `char` --> $DIR/intra-link-prim-conflict.rs:26:10 | LL | //! [struct@char] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ help: to link to the builtin type, prefix with `prim@`: `prim@char` | = note: this link resolved to a builtin type, which is not a struct -help: to link to the builtin type, prefix with the item kind - | -LL | //! [prim@char] - | ^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/rustdoc-ui/intra-links-ambiguity.stderr b/src/test/rustdoc-ui/intra-links-ambiguity.stderr index 7912c046f1c78..17891ca05efa1 100644 --- a/src/test/rustdoc-ui/intra-links-ambiguity.stderr +++ b/src/test/rustdoc-ui/intra-links-ambiguity.stderr @@ -9,7 +9,7 @@ note: the lint level is defined here | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ -help: to link to the struct, prefix with the item kind +help: to link to the struct, prefix with `struct@` | LL | /// [`struct@ambiguous`] is ambiguous. | ^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ error: `ambiguous` is both a struct and a function LL | /// [ambiguous] is ambiguous. | ^^^^^^^^^ ambiguous link | -help: to link to the struct, prefix with the item kind +help: to link to the struct, prefix with `struct@` | LL | /// [struct@ambiguous] is ambiguous. | ^^^^^^^^^^^^^^^^ @@ -39,7 +39,7 @@ error: `multi_conflict` is a struct, a function, and a macro LL | /// [`multi_conflict`] is a three-way conflict. | ^^^^^^^^^^^^^^^^ ambiguous link | -help: to link to the struct, prefix with the item kind +help: to link to the struct, prefix with `struct@` | LL | /// [`struct@multi_conflict`] is a three-way conflict. | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -58,11 +58,11 @@ error: `type_and_value` is both a module and a constant LL | /// Ambiguous [type_and_value]. | ^^^^^^^^^^^^^^ ambiguous link | -help: to link to the module, prefix with the item kind +help: to link to the module, prefix with `mod@` | LL | /// Ambiguous [mod@type_and_value]. | ^^^^^^^^^^^^^^^^^^ -help: to link to the constant, prefix with the item kind +help: to link to the constant, prefix with `const@` | LL | /// Ambiguous [const@type_and_value]. | ^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ error: `foo::bar` is both an enum and a function LL | /// Ambiguous non-implied shortcut link [`foo::bar`]. | ^^^^^^^^^^ ambiguous link | -help: to link to the enum, prefix with the item kind +help: to link to the enum, prefix with `enum@` | LL | /// Ambiguous non-implied shortcut link [`enum@foo::bar`]. | ^^^^^^^^^^^^^^^ diff --git a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs b/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs index 54e507adfe550..b9c8e033b1b21 100644 --- a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs +++ b/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs @@ -14,27 +14,27 @@ trait T {} /// Link to [struct@S] //~^ ERROR incompatible link kind for `S` //~| NOTE this link resolved -//~| HELP prefix with the item kind +//~| HELP prefix with `enum@` /// Link to [mod@S] //~^ ERROR incompatible link kind for `S` //~| NOTE this link resolved -//~| HELP prefix with the item kind +//~| HELP prefix with `enum@` /// Link to [union@S] //~^ ERROR incompatible link kind for `S` //~| NOTE this link resolved -//~| HELP prefix with the item kind +//~| HELP prefix with `enum@` /// Link to [trait@S] //~^ ERROR incompatible link kind for `S` //~| NOTE this link resolved -//~| HELP prefix with the item kind +//~| HELP prefix with `enum@` /// Link to [struct@T] //~^ ERROR incompatible link kind for `T` //~| NOTE this link resolved -//~| HELP prefix with the item kind +//~| HELP prefix with `trait@` /// Link to [derive@m] //~^ ERROR incompatible link kind for `m` @@ -44,22 +44,22 @@ trait T {} /// Link to [const@s] //~^ ERROR incompatible link kind for `s` //~| NOTE this link resolved -//~| HELP prefix with the item kind +//~| HELP prefix with `static@` /// Link to [static@c] //~^ ERROR incompatible link kind for `c` //~| NOTE this link resolved -//~| HELP prefix with the item kind +//~| HELP prefix with `const@` /// Link to [fn@c] //~^ ERROR incompatible link kind for `c` //~| NOTE this link resolved -//~| HELP prefix with the item kind +//~| HELP prefix with `const@` /// Link to [c()] //~^ ERROR incompatible link kind for `c` //~| NOTE this link resolved -//~| HELP prefix with the item kind +//~| HELP prefix with `const@` /// Link to [const@f] //~^ ERROR incompatible link kind for `f` diff --git a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr b/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr index 27b94af0378c2..2e732baf6e01e 100644 --- a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr +++ b/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr @@ -2,7 +2,7 @@ error: incompatible link kind for `S` --> $DIR/intra-links-disambiguator-mismatch.rs:14:14 | LL | /// Link to [struct@S] - | ^^^^^^^^ + | ^^^^^^^^ help: to link to the enum, prefix with `enum@`: `enum@S` | note: the lint level is defined here --> $DIR/intra-links-disambiguator-mismatch.rs:1:9 @@ -10,58 +10,38 @@ note: the lint level is defined here LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ = note: this link resolved to an enum, which is not a struct -help: to link to the enum, prefix with the item kind - | -LL | /// Link to [enum@S] - | ^^^^^^ error: incompatible link kind for `S` --> $DIR/intra-links-disambiguator-mismatch.rs:19:14 | LL | /// Link to [mod@S] - | ^^^^^ + | ^^^^^ help: to link to the enum, prefix with `enum@`: `enum@S` | = note: this link resolved to an enum, which is not a module -help: to link to the enum, prefix with the item kind - | -LL | /// Link to [enum@S] - | ^^^^^^ error: incompatible link kind for `S` --> $DIR/intra-links-disambiguator-mismatch.rs:24:14 | LL | /// Link to [union@S] - | ^^^^^^^ + | ^^^^^^^ help: to link to the enum, prefix with `enum@`: `enum@S` | = note: this link resolved to an enum, which is not a union -help: to link to the enum, prefix with the item kind - | -LL | /// Link to [enum@S] - | ^^^^^^ error: incompatible link kind for `S` --> $DIR/intra-links-disambiguator-mismatch.rs:29:14 | LL | /// Link to [trait@S] - | ^^^^^^^ + | ^^^^^^^ help: to link to the enum, prefix with `enum@`: `enum@S` | = note: this link resolved to an enum, which is not a trait -help: to link to the enum, prefix with the item kind - | -LL | /// Link to [enum@S] - | ^^^^^^ error: incompatible link kind for `T` --> $DIR/intra-links-disambiguator-mismatch.rs:34:14 | LL | /// Link to [struct@T] - | ^^^^^^^^ + | ^^^^^^^^ help: to link to the trait, prefix with `trait@`: `trait@T` | = note: this link resolved to a trait, which is not a struct -help: to link to the trait, prefix with the item kind - | -LL | /// Link to [trait@T] - | ^^^^^^^ error: incompatible link kind for `m` --> $DIR/intra-links-disambiguator-mismatch.rs:39:14 @@ -75,49 +55,33 @@ error: incompatible link kind for `s` --> $DIR/intra-links-disambiguator-mismatch.rs:44:14 | LL | /// Link to [const@s] - | ^^^^^^^ + | ^^^^^^^ help: to link to the static, prefix with `static@`: `static@s` | = note: this link resolved to a static, which is not a constant -help: to link to the static, prefix with the item kind - | -LL | /// Link to [static@s] - | ^^^^^^^^ error: incompatible link kind for `c` --> $DIR/intra-links-disambiguator-mismatch.rs:49:14 | LL | /// Link to [static@c] - | ^^^^^^^^ + | ^^^^^^^^ help: to link to the constant, prefix with `const@`: `const@c` | = note: this link resolved to a constant, which is not a static -help: to link to the constant, prefix with the item kind - | -LL | /// Link to [const@c] - | ^^^^^^^ error: incompatible link kind for `c` --> $DIR/intra-links-disambiguator-mismatch.rs:54:14 | LL | /// Link to [fn@c] - | ^^^^ + | ^^^^ help: to link to the constant, prefix with `const@`: `const@c` | = note: this link resolved to a constant, which is not a function -help: to link to the constant, prefix with the item kind - | -LL | /// Link to [const@c] - | ^^^^^^^ error: incompatible link kind for `c` --> $DIR/intra-links-disambiguator-mismatch.rs:59:14 | LL | /// Link to [c()] - | ^^^ + | ^^^ help: to link to the constant, prefix with `const@`: `const@c` | = note: this link resolved to a constant, which is not a function -help: to link to the constant, prefix with the item kind - | -LL | /// Link to [const@c] - | ^^^^^^^ error: incompatible link kind for `f` --> $DIR/intra-links-disambiguator-mismatch.rs:64:14 From efdc3facdfe931108146587b2f9d22b7dfd217c5 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 28 Aug 2020 01:31:33 -0400 Subject: [PATCH 0135/1052] Give a much better error message when an item has a macro disambiguator Previously, this called `check_full_res` for values and types, but not macros. This would result in not showing when there was a partial resolution for a parent of the item. This now calls `check_full_res`. Additionally, it checks if there was a disambiguator, and if so, says that specific kind wasn't found instead of saying generically 'associated item'. --- .../passes/collect_intra_doc_links.rs | 87 ++++++++++++------- src/test/rustdoc-ui/intra-link-errors.rs | 2 +- src/test/rustdoc-ui/intra-link-errors.stderr | 2 +- 3 files changed, 59 insertions(+), 32 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index a19387ad992fa..df8ecf26a412e 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -262,11 +262,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { false, ) { if let SyntaxExtensionKind::LegacyBang { .. } = ext.kind { - return Ok(res.map_id(|_| panic!("unexpected id"))); + return Some(Ok(res.map_id(|_| panic!("unexpected id")))); } } if let Some(res) = resolver.all_macros().get(&Symbol::intern(path_str)) { - return Ok(res.map_id(|_| panic!("unexpected id"))); + return Some(Ok(res.map_id(|_| panic!("unexpected id")))); } if let Some(module_id) = parent_id { debug!("resolving {} as a macro in the module {:?}", path_str, module_id); @@ -276,14 +276,32 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // don't resolve builtins like `#[derive]` if let Res::Def(..) = res { let res = res.map_id(|_| panic!("unexpected node_id")); - return Ok(res); + return Some(Ok(res)); } } } else { debug!("attempting to resolve item without parent module: {}", path_str); - return Err(ResolutionFailure::NoParentItem); + return Some(Err(ResolutionFailure::NoParentItem)); } - return Err(ResolutionFailure::NotInScope(path_str.into())); + None + }) + // This weird control flow is so we don't borrow the resolver more than once at a time + .unwrap_or_else(|| { + let mut split = path_str.rsplitn(2, "::"); + if let Some((parent, base)) = split.next().and_then(|x| Some((split.next()?, x))) { + if let Some(res) = self.check_full_res(TypeNS, parent, parent_id, &None, &None) { + return Err(if matches!(res, Res::PrimTy(_)) { + ResolutionFailure::NoPrimitiveAssocItem { + res, + prim_name: parent, + assoc_item: Symbol::intern(base), + } + } else { + ResolutionFailure::NoAssocItem(res, Symbol::intern(base)) + }); + } + } + Err(ResolutionFailure::NotInScope(path_str.into())) }) } /// Resolves a string as a path within a particular namespace. Also returns an optional @@ -981,6 +999,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { cx, &item, path_str, + disambiguator, &dox, link_range, smallvec![kind], @@ -1060,6 +1079,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { cx, &item, path_str, + disambiguator, &dox, link_range, candidates.into_iter().filter_map(|res| res.err()).collect(), @@ -1114,6 +1134,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { cx, &item, path_str, + disambiguator, &dox, link_range, smallvec![kind], @@ -1489,6 +1510,7 @@ fn resolution_failure( cx: &DocContext<'_>, item: &Item, path_str: &str, + disambiguator: Option, dox: &str, link_range: Option>, kinds: SmallVec<[ResolutionFailure<'_>; 3]>, @@ -1581,34 +1603,39 @@ fn resolution_failure( let (kind, def_id) = match res { Res::Def(kind, def_id) => (kind, def_id), - _ => unreachable!( - "primitives are covered above and other `Res` variants aren't possible at module scope" + x => unreachable!( + "primitives are covered above and other `Res` variants aren't possible at module scope: {:?}", + x, ), }; let name = cx.tcx.item_name(def_id); - let path_description = match kind { - Mod | ForeignMod => "inner item", - Struct => "field or associated item", - Enum | Union => "variant or associated item", - Variant - | Field - | Closure - | Generator - | AssocTy - | AssocConst - | AssocFn - | Fn - | Macro(_) - | Const - | ConstParam - | ExternCrate - | Use - | LifetimeParam - | Ctor(_, _) - | AnonConst => return assoc_item_not_allowed(res, diag), - Trait | TyAlias | ForeignTy | OpaqueTy | TraitAlias | TyParam - | Static => "associated item", - Impl | GlobalAsm => unreachable!("not a path"), + let path_description = if let Some(disambiguator) = disambiguator { + disambiguator.descr() + } else { + match kind { + Mod | ForeignMod => "inner item", + Struct => "field or associated item", + Enum | Union => "variant or associated item", + Variant + | Field + | Closure + | Generator + | AssocTy + | AssocConst + | AssocFn + | Fn + | Macro(_) + | Const + | ConstParam + | ExternCrate + | Use + | LifetimeParam + | Ctor(_, _) + | AnonConst => return assoc_item_not_allowed(res, diag), + Trait | TyAlias | ForeignTy | OpaqueTy | TraitAlias | TyParam + | Static => "associated item", + Impl | GlobalAsm => unreachable!("not a path"), + } }; let note = format!( "the {} `{}` has no {} named `{}`", diff --git a/src/test/rustdoc-ui/intra-link-errors.rs b/src/test/rustdoc-ui/intra-link-errors.rs index 919c46fe1dab2..ae89f418984d2 100644 --- a/src/test/rustdoc-ui/intra-link-errors.rs +++ b/src/test/rustdoc-ui/intra-link-errors.rs @@ -65,7 +65,7 @@ impl S { /// [T::h!] //~^ ERROR unresolved link -//~| NOTE no item named `T::h` +//~| NOTE `T` has no macro named `h` pub trait T { fn g() {} } diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr index 7318193964f8d..68941d64c7a2c 100644 --- a/src/test/rustdoc-ui/intra-link-errors.stderr +++ b/src/test/rustdoc-ui/intra-link-errors.stderr @@ -97,7 +97,7 @@ error: unresolved link to `T::h` LL | /// [T::h!] | ^^^^^ | - = note: no item named `T::h` is in scope + = note: the trait `T` has no macro named `h` error: unresolved link to `S::h` --> $DIR/intra-link-errors.rs:54:6 From 8318a185f301de617c64376fbd3a2d556296c8bb Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 29 Aug 2020 09:59:57 -0400 Subject: [PATCH 0136/1052] x.py bless --- src/test/rustdoc-ui/intra-link-errors.stderr | 28 ++++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr index 68941d64c7a2c..73e16bef0aa9f 100644 --- a/src/test/rustdoc-ui/intra-link-errors.stderr +++ b/src/test/rustdoc-ui/intra-link-errors.stderr @@ -1,5 +1,5 @@ error: unresolved link to `path::to::nonexistent::module` - --> $DIR/intra-link-errors.rs:8:6 + --> $DIR/intra-link-errors.rs:7:6 | LL | /// [path::to::nonexistent::module] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL | #![deny(broken_intra_doc_links)] = note: no item named `path` is in scope error: unresolved link to `std::io::not::here` - --> $DIR/intra-link-errors.rs:12:6 + --> $DIR/intra-link-errors.rs:11:6 | LL | /// [std::io::not::here] | ^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | /// [std::io::not::here] = note: the module `io` has no inner item named `not` error: unresolved link to `std::io::Error::x` - --> $DIR/intra-link-errors.rs:16:6 + --> $DIR/intra-link-errors.rs:15:6 | LL | /// [std::io::Error::x] | ^^^^^^^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL | /// [std::io::Error::x] = note: the struct `Error` has no field or associated item named `x` error: unresolved link to `std::io::ErrorKind::x` - --> $DIR/intra-link-errors.rs:20:6 + --> $DIR/intra-link-errors.rs:19:6 | LL | /// [std::io::ErrorKind::x] | ^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | /// [std::io::ErrorKind::x] = note: the enum `ErrorKind` has no variant or associated item named `x` error: unresolved link to `f::A` - --> $DIR/intra-link-errors.rs:24:6 + --> $DIR/intra-link-errors.rs:23:6 | LL | /// [f::A] | ^^^^ @@ -44,7 +44,7 @@ LL | /// [f::A] = note: `f` is a function, not a module or type, and cannot have associated items error: unresolved link to `S::A` - --> $DIR/intra-link-errors.rs:28:6 + --> $DIR/intra-link-errors.rs:27:6 | LL | /// [S::A] | ^^^^ @@ -52,7 +52,7 @@ LL | /// [S::A] = note: the struct `S` has no field or associated item named `A` error: unresolved link to `S::fmt` - --> $DIR/intra-link-errors.rs:32:6 + --> $DIR/intra-link-errors.rs:31:6 | LL | /// [S::fmt] | ^^^^^^ @@ -60,7 +60,7 @@ LL | /// [S::fmt] = note: the struct `S` has no field or associated item named `fmt` error: unresolved link to `E::D` - --> $DIR/intra-link-errors.rs:36:6 + --> $DIR/intra-link-errors.rs:35:6 | LL | /// [E::D] | ^^^^ @@ -68,7 +68,7 @@ LL | /// [E::D] = note: the enum `E` has no variant or associated item named `D` error: unresolved link to `u8::not_found` - --> $DIR/intra-link-errors.rs:40:6 + --> $DIR/intra-link-errors.rs:39:6 | LL | /// [u8::not_found] | ^^^^^^^^^^^^^ @@ -76,7 +76,7 @@ LL | /// [u8::not_found] = note: the builtin type `u8` does not have an associated item named `not_found` error: unresolved link to `S` - --> $DIR/intra-link-errors.rs:44:6 + --> $DIR/intra-link-errors.rs:43:6 | LL | /// [S!] | ^^ help: to link to the struct, prefix with `struct@`: `struct@S` @@ -84,7 +84,7 @@ LL | /// [S!] = note: this link resolves to the struct `S`, which is not in the macro namespace error: unresolved link to `T::g` - --> $DIR/intra-link-errors.rs:62:6 + --> $DIR/intra-link-errors.rs:61:6 | LL | /// [type@T::g] | ^^^^^^^^^ help: to link to the associated function, add parentheses: `T::g()` @@ -92,7 +92,7 @@ LL | /// [type@T::g] = note: this link resolves to the associated function `g`, which is not in the type namespace error: unresolved link to `T::h` - --> $DIR/intra-link-errors.rs:67:6 + --> $DIR/intra-link-errors.rs:66:6 | LL | /// [T::h!] | ^^^^^ @@ -100,7 +100,7 @@ LL | /// [T::h!] = note: the trait `T` has no macro named `h` error: unresolved link to `S::h` - --> $DIR/intra-link-errors.rs:54:6 + --> $DIR/intra-link-errors.rs:53:6 | LL | /// [type@S::h] | ^^^^^^^^^ help: to link to the associated function, add parentheses: `S::h()` @@ -108,7 +108,7 @@ LL | /// [type@S::h] = note: this link resolves to the associated function `h`, which is not in the type namespace error: unresolved link to `m` - --> $DIR/intra-link-errors.rs:74:6 + --> $DIR/intra-link-errors.rs:73:6 | LL | /// [m()] | ^^^ help: to link to the macro, add an exclamation mark: `m!` From cd72d9029ff5b2368e5c539f9b326a2eea855127 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 31 Aug 2020 23:28:38 -0400 Subject: [PATCH 0137/1052] Find the first segment that failed to resolve for _any_ namespace Moves this detection into `resolution_failure` to avoid doing unnecessary work and make the control flow a little easier to work with. --- .../passes/collect_intra_doc_links.rs | 109 ++++++++++-------- src/test/rustdoc-ui/intra-link-errors.rs | 8 ++ src/test/rustdoc-ui/intra-link-errors.stderr | 44 ++++--- 3 files changed, 102 insertions(+), 59 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index df8ecf26a412e..d8abf411de7c2 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -60,8 +60,8 @@ enum ResolutionFailure<'a> { /// This has a partial resolution, but is not in the TypeNS and so cannot /// have associated items or fields. CannotHaveAssociatedItems(Res, Namespace), - /// `String` is the base name of the path (not necessarily the whole link) - NotInScope(Cow<'a, str>), + /// `name` is the base name of the path (not necessarily the whole link) + NotInScope { module_id: DefId, name: Cow<'a, str> }, /// this is a primitive type without an impls (no associated methods) /// when will this actually happen? /// the `Res` is the primitive it resolved to @@ -92,7 +92,7 @@ impl ResolutionFailure<'a> { | NotAVariant(res, _) | WrongNamespace(res, _) | CannotHaveAssociatedItems(res, _) => Some(*res), - NotInScope(_) | NoParentItem | Dummy => None, + NotInScope { .. } | NoParentItem | Dummy => None, } } @@ -142,7 +142,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .expect("fold_item should ensure link is non-empty"); let variant_name = // we're not sure this is a variant at all, so use the full string - split.next().map(|f| Symbol::intern(f)).ok_or(ErrorKind::Resolve(ResolutionFailure::NotInScope(path_str.into())))?; + split.next().map(|f| Symbol::intern(f)).ok_or(ErrorKind::Resolve(ResolutionFailure::NotInScope{ + module_id, + name: path_str.into(), + }))?; let path = split .next() .map(|f| { @@ -153,38 +156,21 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } f.to_owned() }) - .ok_or(ErrorKind::Resolve(ResolutionFailure::NotInScope( - variant_name.to_string().into(), - )))?; + .ok_or(ErrorKind::Resolve(ResolutionFailure::NotInScope { + module_id, + name: variant_name.to_string().into(), + }))?; let ty_res = cx .enter_resolver(|resolver| { resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) }) .map(|(_, res)| res) .unwrap_or(Res::Err); - // This code only gets hit if three path segments in a row don't get resolved. - // It's a good time to check if _any_ parent of the path gets resolved. - // If so, report it and say the first which failed; if not, say the first path segment didn't resolve. if let Res::Err = ty_res { - let mut current = path.as_str(); - while let Some(parent) = current.rsplitn(2, "::").nth(1) { - current = parent; - if let Some(res) = self.check_full_res( - TypeNS, - ¤t, - Some(module_id), - current_item, - extra_fragment, - ) { - return Err(ErrorKind::Resolve(ResolutionFailure::NoAssocItem( - res, - Symbol::intern(&path), - ))); - } - } - return Err(ErrorKind::Resolve(ResolutionFailure::NotInScope( - current.to_string().into(), - ))); + return Err(ErrorKind::Resolve(ResolutionFailure::NotInScope { + module_id, + name: path.into(), + })); } let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); match ty_res { @@ -301,7 +287,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }); } } - Err(ResolutionFailure::NotInScope(path_str.into())) + Err(ResolutionFailure::NotInScope { + module_id: parent_id.expect("already saw `Some` when resolving as a macro"), + name: path_str.into(), + }) }) } /// Resolves a string as a path within a particular namespace. Also returns an optional @@ -384,7 +373,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved. .ok_or_else(|| { debug!("found no `::`, assumming {} was correctly not in scope", item_name); - ErrorKind::Resolve(ResolutionFailure::NotInScope(item_name.to_string().into())) + ErrorKind::Resolve(ResolutionFailure::NotInScope { + module_id, + name: item_name.to_string().into(), + }) })?; if let Some((path, prim)) = is_primitive(&path_root, TypeNS) { @@ -451,7 +443,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } } } - ResolutionFailure::NotInScope(path_root.into()) + ResolutionFailure::NotInScope { module_id, name: path_root.into() } }); Err(ErrorKind::Resolve(kind)) }; @@ -996,7 +988,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } } resolution_failure( - cx, + self, &item, path_str, disambiguator, @@ -1076,7 +1068,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { if len == 0 { drop(candidates_iter); resolution_failure( - cx, + self, &item, path_str, disambiguator, @@ -1096,8 +1088,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } else { drop(candidates_iter); if is_derive_trait_collision(&candidates) { - candidates.macro_ns = - Err(ResolutionFailure::NotInScope(path_str.into())); + candidates.macro_ns = Err(ResolutionFailure::Dummy); } // If we're reporting an ambiguity, don't mention the namespaces that failed let candidates = @@ -1131,7 +1122,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } } resolution_failure( - cx, + self, &item, path_str, disambiguator, @@ -1507,7 +1498,7 @@ fn report_diagnostic( } fn resolution_failure( - cx: &DocContext<'_>, + collector: &LinkCollector<'_, '_>, item: &Item, path_str: &str, disambiguator: Option, @@ -1516,7 +1507,7 @@ fn resolution_failure( kinds: SmallVec<[ResolutionFailure<'_>; 3]>, ) { report_diagnostic( - cx, + collector.cx, &format!("unresolved link to `{}`", path_str), item, dox, @@ -1524,11 +1515,15 @@ fn resolution_failure( |diag, sp| { let in_scope = kinds.iter().any(|kind| kind.res().is_some()); let item = |res: Res| { - format!("the {} `{}`", res.descr(), cx.tcx.item_name(res.def_id()).to_string()) + format!( + "the {} `{}`", + res.descr(), + collector.cx.tcx.item_name(res.def_id()).to_string() + ) }; let assoc_item_not_allowed = |res: Res, diag: &mut DiagnosticBuilder<'_>| { let def_id = res.def_id(); - let name = cx.tcx.item_name(def_id); + let name = collector.cx.tcx.item_name(def_id); let note = format!( "`{}` is {} {}, not a module or type, and cannot have associated items", name, @@ -1539,18 +1534,42 @@ fn resolution_failure( }; // ignore duplicates let mut variants_seen = SmallVec::<[_; 3]>::new(); - for failure in kinds { + for mut failure in kinds { + // Check if _any_ parent of the path gets resolved. + // If so, report it and say the first which failed; if not, say the first path segment didn't resolve. + if let ResolutionFailure::NotInScope { module_id, name } = &mut failure { + let mut current = name.as_ref(); + loop { + current = match current.rsplitn(2, "::").nth(1) { + Some(p) => p, + None => { + *name = current.to_owned().into(); + break; + } + }; + if let Some(res) = collector.check_full_res( + TypeNS, + ¤t, + Some(*module_id), + &None, + &None, + ) { + failure = ResolutionFailure::NoAssocItem(res, Symbol::intern(current)); + break; + } + } + } let variant = std::mem::discriminant(&failure); if variants_seen.contains(&variant) { continue; } variants_seen.push(variant); match failure { - ResolutionFailure::NotInScope(base) => { + ResolutionFailure::NotInScope { name, .. } => { if in_scope { continue; } - diag.note(&format!("no item named `{}` is in scope", base)); + diag.note(&format!("no item named `{}` is in scope", name)); // If the link has `::` in the path, assume it's meant to be an intra-doc link if !path_str.contains("::") { // Otherwise, the `[]` might be unrelated. @@ -1608,7 +1627,7 @@ fn resolution_failure( x, ), }; - let name = cx.tcx.item_name(def_id); + let name = collector.cx.tcx.item_name(def_id); let path_description = if let Some(disambiguator) = disambiguator { disambiguator.descr() } else { diff --git a/src/test/rustdoc-ui/intra-link-errors.rs b/src/test/rustdoc-ui/intra-link-errors.rs index ae89f418984d2..477ad6464f887 100644 --- a/src/test/rustdoc-ui/intra-link-errors.rs +++ b/src/test/rustdoc-ui/intra-link-errors.rs @@ -8,6 +8,14 @@ //~^ ERROR unresolved link //~| NOTE no item named `path` is in scope +/// [path::to::nonexistent::macro!] +//~^ ERROR unresolved link +//~| NOTE no item named `path` is in scope + +/// [type@path::to::nonexistent::type] +//~^ ERROR unresolved link +//~| NOTE no item named `path` is in scope + /// [std::io::not::here] //~^ ERROR unresolved link //~| NOTE the module `io` has no inner item diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr index 73e16bef0aa9f..3b1a09f913e9f 100644 --- a/src/test/rustdoc-ui/intra-link-errors.stderr +++ b/src/test/rustdoc-ui/intra-link-errors.stderr @@ -11,16 +11,32 @@ LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ = note: no item named `path` is in scope -error: unresolved link to `std::io::not::here` +error: unresolved link to `path::to::nonexistent::macro` --> $DIR/intra-link-errors.rs:11:6 | +LL | /// [path::to::nonexistent::macro!] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: no item named `path` is in scope + +error: unresolved link to `path::to::nonexistent::type` + --> $DIR/intra-link-errors.rs:15:6 + | +LL | /// [type@path::to::nonexistent::type] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: no item named `path` is in scope + +error: unresolved link to `std::io::not::here` + --> $DIR/intra-link-errors.rs:19:6 + | LL | /// [std::io::not::here] | ^^^^^^^^^^^^^^^^^^ | = note: the module `io` has no inner item named `not` error: unresolved link to `std::io::Error::x` - --> $DIR/intra-link-errors.rs:15:6 + --> $DIR/intra-link-errors.rs:23:6 | LL | /// [std::io::Error::x] | ^^^^^^^^^^^^^^^^^ @@ -28,7 +44,7 @@ LL | /// [std::io::Error::x] = note: the struct `Error` has no field or associated item named `x` error: unresolved link to `std::io::ErrorKind::x` - --> $DIR/intra-link-errors.rs:19:6 + --> $DIR/intra-link-errors.rs:27:6 | LL | /// [std::io::ErrorKind::x] | ^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +52,7 @@ LL | /// [std::io::ErrorKind::x] = note: the enum `ErrorKind` has no variant or associated item named `x` error: unresolved link to `f::A` - --> $DIR/intra-link-errors.rs:23:6 + --> $DIR/intra-link-errors.rs:31:6 | LL | /// [f::A] | ^^^^ @@ -44,7 +60,7 @@ LL | /// [f::A] = note: `f` is a function, not a module or type, and cannot have associated items error: unresolved link to `S::A` - --> $DIR/intra-link-errors.rs:27:6 + --> $DIR/intra-link-errors.rs:35:6 | LL | /// [S::A] | ^^^^ @@ -52,7 +68,7 @@ LL | /// [S::A] = note: the struct `S` has no field or associated item named `A` error: unresolved link to `S::fmt` - --> $DIR/intra-link-errors.rs:31:6 + --> $DIR/intra-link-errors.rs:39:6 | LL | /// [S::fmt] | ^^^^^^ @@ -60,7 +76,7 @@ LL | /// [S::fmt] = note: the struct `S` has no field or associated item named `fmt` error: unresolved link to `E::D` - --> $DIR/intra-link-errors.rs:35:6 + --> $DIR/intra-link-errors.rs:43:6 | LL | /// [E::D] | ^^^^ @@ -68,7 +84,7 @@ LL | /// [E::D] = note: the enum `E` has no variant or associated item named `D` error: unresolved link to `u8::not_found` - --> $DIR/intra-link-errors.rs:39:6 + --> $DIR/intra-link-errors.rs:47:6 | LL | /// [u8::not_found] | ^^^^^^^^^^^^^ @@ -76,7 +92,7 @@ LL | /// [u8::not_found] = note: the builtin type `u8` does not have an associated item named `not_found` error: unresolved link to `S` - --> $DIR/intra-link-errors.rs:43:6 + --> $DIR/intra-link-errors.rs:51:6 | LL | /// [S!] | ^^ help: to link to the struct, prefix with `struct@`: `struct@S` @@ -84,7 +100,7 @@ LL | /// [S!] = note: this link resolves to the struct `S`, which is not in the macro namespace error: unresolved link to `T::g` - --> $DIR/intra-link-errors.rs:61:6 + --> $DIR/intra-link-errors.rs:69:6 | LL | /// [type@T::g] | ^^^^^^^^^ help: to link to the associated function, add parentheses: `T::g()` @@ -92,7 +108,7 @@ LL | /// [type@T::g] = note: this link resolves to the associated function `g`, which is not in the type namespace error: unresolved link to `T::h` - --> $DIR/intra-link-errors.rs:66:6 + --> $DIR/intra-link-errors.rs:74:6 | LL | /// [T::h!] | ^^^^^ @@ -100,7 +116,7 @@ LL | /// [T::h!] = note: the trait `T` has no macro named `h` error: unresolved link to `S::h` - --> $DIR/intra-link-errors.rs:53:6 + --> $DIR/intra-link-errors.rs:61:6 | LL | /// [type@S::h] | ^^^^^^^^^ help: to link to the associated function, add parentheses: `S::h()` @@ -108,12 +124,12 @@ LL | /// [type@S::h] = note: this link resolves to the associated function `h`, which is not in the type namespace error: unresolved link to `m` - --> $DIR/intra-link-errors.rs:73:6 + --> $DIR/intra-link-errors.rs:81:6 | LL | /// [m()] | ^^^ help: to link to the macro, add an exclamation mark: `m!` | = note: this link resolves to the macro `m`, which is not in the value namespace -error: aborting due to 14 previous errors +error: aborting due to 16 previous errors From 2c8a4c8f73e8b36e72b15e7f97ef29ad36c15e17 Mon Sep 17 00:00:00 2001 From: scottmcm Date: Sat, 5 Sep 2020 19:02:21 +0000 Subject: [PATCH 0138/1052] Nightly is currently 1.48 --- library/alloc/src/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index b6d923daaf2ab..4a263829bd421 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -2772,7 +2772,7 @@ impl From<&str> for Vec { } } -#[stable(feature = "array_try_from_vec", since = "1.47.0")] +#[stable(feature = "array_try_from_vec", since = "1.48.0")] impl TryFrom> for [T; N] { type Error = Vec; From 4efe97a3d9a5f2d295bc2fa9bd2bb90edf1986d5 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Sun, 14 Jun 2020 00:47:42 -0400 Subject: [PATCH 0139/1052] Check placement of more attributes --- compiler/rustc_passes/src/check_attr.rs | 111 ++++++- compiler/rustc_typeck/src/collect.rs | 30 +- src/test/ui/check-static-recursion-foreign.rs | 2 +- ...sue-43106-gating-of-builtin-attrs-error.rs | 171 +++++++++++ ...43106-gating-of-builtin-attrs-error.stderr | 274 ++++++++++++++++++ .../issue-43106-gating-of-builtin-attrs.rs | 73 +---- ...issue-43106-gating-of-builtin-attrs.stderr | 264 ++++++++--------- .../issue-43106-gating-of-inline.rs | 31 -- .../issue-43106-gating-of-inline.stderr | 52 ---- src/test/ui/issues/issue-2214.rs | 2 +- src/test/ui/issues/issue-47725.rs | 22 ++ src/test/ui/issues/issue-47725.stderr | 50 ++++ src/test/ui/issues/issue-54044.rs | 7 + src/test/ui/issues/issue-54044.stderr | 18 ++ src/test/ui/macros/issue-68060.rs | 7 +- src/test/ui/macros/issue-68060.stderr | 22 +- .../ui/target-feature/invalid-attribute.rs | 9 +- .../target-feature/invalid-attribute.stderr | 25 +- 18 files changed, 816 insertions(+), 354 deletions(-) create mode 100644 src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.rs create mode 100644 src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.stderr delete mode 100644 src/test/ui/feature-gate/issue-43106-gating-of-inline.rs delete mode 100644 src/test/ui/feature-gate/issue-43106-gating-of-inline.stderr create mode 100644 src/test/ui/issues/issue-47725.rs create mode 100644 src/test/ui/issues/issue-47725.stderr create mode 100644 src/test/ui/issues/issue-54044.rs create mode 100644 src/test/ui/issues/issue-54044.stderr diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 392070839dc2a..037a653e3e019 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -71,6 +71,16 @@ impl CheckAttrVisitor<'tcx> { self.check_track_caller(&attr.span, attrs, span, target) } else if self.tcx.sess.check_name(attr, sym::doc) { self.check_doc_alias(attr, hir_id, target) + } else if self.tcx.sess.check_name(attr, sym::cold) { + self.check_cold(&attr, span, target) + } else if self.tcx.sess.check_name(attr, sym::link_name) { + self.check_link_name(&attr, span, target) + } else if self.tcx.sess.check_name(attr, sym::no_link) { + self.check_no_link(&attr, span, target) + } else if self.tcx.sess.check_name(attr, sym::export_name) { + self.check_export_name(&attr, span, target) + } else if self.tcx.sess.check_name(attr, sym::link_section) { + self.check_link_section(&attr, span, target) } else { true }; @@ -277,6 +287,99 @@ impl CheckAttrVisitor<'tcx> { true } + /// Checks if `#[cold]` is applied to a non-function. Returns `true` if valid. + fn check_cold(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + match target { + Target::Fn | Target::Method(..) | Target::ForeignFn => true, + _ => { + self.tcx + .sess + .struct_span_err(attr.span, "attribute should be applied to a function") + .span_label(*span, "not a function") + .emit(); + false + } + } + } + + /// Checks if `#[link_name]` is applied to an item other than a foreign function or static. Returns `true` if valid. + fn check_link_name(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + if target == Target::ForeignFn || target == Target::ForeignStatic { + true + } else { + let mut err = self.tcx.sess.struct_span_err( + attr.span, + "attribute should be applied to a foreign function or static", + ); + err.span_label(*span, "not a foreign function or static"); + + // See issue #47725 + if target == Target::ForeignMod { + if let Some(value) = attr.value_str() { + err.span_help( + attr.span, + &format!(r#"try `#[link(name = "{}")]` instead"#, value), + ); + } else { + err.span_help(attr.span, r#"try `#[link(name = "...")]` instead"#); + } + } + + err.emit(); + false + } + } + + /// Checks if `#[no_link]` is applied to an `extern crate`. Returns `true` if valid. + fn check_no_link(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + if target == Target::ExternCrate { + true + } else { + self.tcx + .sess + .struct_span_err(attr.span, "attribute should be applied to an `extern crate` item") + .span_label(*span, "not an `extern crate` item") + .emit(); + false + } + } + + /// Checks if `#[export_name]` is applied to a function or static. Returns `true` if valid. + fn check_export_name(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + match target { + Target::Static | Target::Fn | Target::Method(..) => true, + _ => { + self.tcx + .sess + .struct_span_err( + attr.span, + "attribute should be applied to a function or static", + ) + .span_label(*span, "not a function or static") + .emit(); + false + } + } + } + + /// Checks if `#[link_section]` is applied to a function or static. Returns `true` if valid. + fn check_link_section(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + match target { + Target::Static | Target::Fn | Target::Method(..) => true, + _ => { + self.tcx + .sess + .struct_span_err( + attr.span, + "attribute should be applied to a function or static", + ) + .span_label(*span, "not a function or static") + .emit(); + false + } + } + } + /// Checks if the `#[repr]` attributes on `item` are valid. fn check_repr( &self, @@ -421,10 +524,8 @@ impl CheckAttrVisitor<'tcx> { fn check_stmt_attributes(&self, stmt: &hir::Stmt<'_>) { // When checking statements ignore expressions, they will be checked later if let hir::StmtKind::Local(ref l) = stmt.kind { + self.check_attributes(l.hir_id, &l.attrs, &stmt.span, Target::Statement, None); for attr in l.attrs.iter() { - if self.tcx.sess.check_name(attr, sym::inline) { - self.check_inline(l.hir_id, attr, &stmt.span, Target::Statement); - } if self.tcx.sess.check_name(attr, sym::repr) { self.emit_repr_error( attr.span, @@ -442,10 +543,8 @@ impl CheckAttrVisitor<'tcx> { hir::ExprKind::Closure(..) => Target::Closure, _ => Target::Expression, }; + self.check_attributes(expr.hir_id, &expr.attrs, &expr.span, target, None); for attr in expr.attrs.iter() { - if self.tcx.sess.check_name(attr, sym::inline) { - self.check_inline(expr.hir_id, attr, &expr.span, target); - } if self.tcx.sess.check_name(attr, sym::repr) { self.emit_repr_error( attr.span, diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 94555e588bd39..b316f72434973 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2490,10 +2490,17 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { codegen_fn_attrs.export_name = Some(s); } } else if tcx.sess.check_name(attr, sym::target_feature) { - if !tcx.features().target_feature_11 { - check_target_feature_safe_fn(tcx, id, attr.span); - } else if let Some(local_id) = id.as_local() { - if tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal { + if !tcx.is_closure(id) && tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal { + if !tcx.features().target_feature_11 { + let mut err = feature_err( + &tcx.sess.parse_sess, + sym::target_feature_11, + attr.span, + "`#[target_feature(..)]` can only be applied to `unsafe` functions", + ); + err.span_label(tcx.def_span(id), "not an `unsafe` function"); + err.emit(); + } else if let Some(local_id) = id.as_local() { check_target_feature_trait_unsafe(tcx, local_id, attr.span); } } @@ -2750,21 +2757,6 @@ fn check_link_name_xor_ordinal( } } -/// Checks the function annotated with `#[target_feature]` is unsafe, -/// reporting an error if it isn't. -fn check_target_feature_safe_fn(tcx: TyCtxt<'_>, id: DefId, attr_span: Span) { - if tcx.is_closure(id) || tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal { - let mut err = feature_err( - &tcx.sess.parse_sess, - sym::target_feature_11, - attr_span, - "`#[target_feature(..)]` can only be applied to `unsafe` functions", - ); - err.span_label(tcx.def_span(id), "not an `unsafe` function"); - err.emit(); - } -} - /// Checks the function annotated with `#[target_feature]` is not a safe /// trait method implementation, reporting an error if it is. fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span: Span) { diff --git a/src/test/ui/check-static-recursion-foreign.rs b/src/test/ui/check-static-recursion-foreign.rs index 8ca0af8e47a72..536d7933d3e51 100644 --- a/src/test/ui/check-static-recursion-foreign.rs +++ b/src/test/ui/check-static-recursion-foreign.rs @@ -15,7 +15,7 @@ extern crate libc; use libc::c_int; -#[link_name = "check_static_recursion_foreign_helper"] +#[link(name = "check_static_recursion_foreign_helper")] extern "C" { #[allow(dead_code)] static test_static: c_int; diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.rs b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.rs new file mode 100644 index 0000000000000..06cc868994e32 --- /dev/null +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.rs @@ -0,0 +1,171 @@ +// This is testing whether various builtin attributes signals an +// error or warning when put in "weird" places. +// +// (This file sits on its own because it actually signals an error, +// which would mess up the treatment of other cases in +// issue-43106-gating-of-builtin-attrs.rs) + +// ignore-tidy-linelength + +// Crate-level is accepted, though it is almost certainly unused? +#![inline] + +#[inline] +//~^ ERROR attribute should be applied to function or closure +mod inline { + //~^ NOTE not a function or closure + + mod inner { #![inline] } + //~^ ERROR attribute should be applied to function or closure + //~| NOTE not a function or closure + + #[inline = "2100"] fn f() { } + //~^ ERROR attribute must be of the form + //~| WARN this was previously accepted + //~| NOTE #[deny(ill_formed_attribute_input)]` on by default + //~| NOTE for more information, see issue #57571 + + #[inline] struct S; + //~^ ERROR attribute should be applied to function or closure + //~| NOTE not a function or closure + + #[inline] type T = S; + //~^ ERROR attribute should be applied to function or closure + //~| NOTE not a function or closure + + #[inline] impl S { } + //~^ ERROR attribute should be applied to function or closure + //~| NOTE not a function or closure +} + +#[no_link] +//~^ ERROR attribute should be applied to an `extern crate` item +mod no_link { + //~^ NOTE not an `extern crate` item + + mod inner { #![no_link] } + //~^ ERROR attribute should be applied to an `extern crate` item + //~| NOTE not an `extern crate` item + + #[no_link] fn f() { } + //~^ ERROR attribute should be applied to an `extern crate` item + //~| NOTE not an `extern crate` item + + #[no_link] struct S; + //~^ ERROR attribute should be applied to an `extern crate` item + //~| NOTE not an `extern crate` item + + #[no_link]type T = S; + //~^ ERROR attribute should be applied to an `extern crate` item + //~| NOTE not an `extern crate` item + + #[no_link] impl S { } + //~^ ERROR attribute should be applied to an `extern crate` item + //~| NOTE not an `extern crate` item +} + +#[cold] +//~^ ERROR attribute should be applied to a function +mod cold { + //~^ NOTE not a function + + mod inner { #![cold] } + //~^ ERROR attribute should be applied to a function + //~| NOTE not a function + + #[cold] fn f() { } + + #[cold] struct S; + //~^ ERROR attribute should be applied to a function + //~| NOTE not a function + + #[cold] type T = S; + //~^ ERROR attribute should be applied to a function + //~| NOTE not a function + + #[cold] impl S { } + //~^ ERROR attribute should be applied to a function + //~| NOTE not a function +} + +#[export_name = "2200"] +//~^ ERROR attribute should be applied to a function or static +mod export_name { + //~^ NOTE not a function or static + + mod inner { #![export_name="2200"] } + //~^ ERROR attribute should be applied to a function or static + //~| NOTE not a function or static + + #[export_name = "2200"] fn f() { } + + #[export_name = "2200"] struct S; + //~^ ERROR attribute should be applied to a function or static + //~| NOTE not a function or static + + #[export_name = "2200"] type T = S; + //~^ ERROR attribute should be applied to a function or static + //~| NOTE not a function or static + + #[export_name = "2200"] impl S { } + //~^ ERROR attribute should be applied to a function or static + //~| NOTE not a function or static +} + +#[link_name = "1900"] +//~^ ERROR attribute should be applied to a foreign function or static +mod link_name { + //~^ NOTE not a foreign function or static + + #[link_name = "1900"] + //~^ ERROR attribute should be applied to a foreign function or static + //~| HELP try `#[link(name = "1900")]` instead + extern { } + //~^ NOTE not a foreign function or static + + mod inner { #![link_name="1900"] } + //~^ ERROR attribute should be applied to a foreign function or static + //~| NOTE not a foreign function or static + + #[link_name = "1900"] fn f() { } + //~^ ERROR attribute should be applied to a foreign function or static + //~| NOTE not a foreign function or static + + #[link_name = "1900"] struct S; + //~^ ERROR attribute should be applied to a foreign function or static + //~| NOTE not a foreign function or static + + #[link_name = "1900"] type T = S; + //~^ ERROR attribute should be applied to a foreign function or static + //~| NOTE not a foreign function or static + + #[link_name = "1900"] impl S { } + //~^ ERROR attribute should be applied to a foreign function or static + //~| NOTE not a foreign function or static +} + +#[link_section = "1800"] +//~^ ERROR attribute should be applied to a function or static +mod link_section { + //~^ NOTE not a function or static + + mod inner { #![link_section="1800"] } + //~^ ERROR attribute should be applied to a function or static + //~| NOTE not a function or static + + #[link_section = "1800"] fn f() { } + + #[link_section = "1800"] struct S; + //~^ ERROR attribute should be applied to a function or static + //~| NOTE not a function or static + + #[link_section = "1800"] type T = S; + //~^ ERROR attribute should be applied to a function or static + //~| NOTE not a function or static + + #[link_section = "1800"] impl S { } + //~^ ERROR attribute should be applied to a function or static + //~| NOTE not a function or static +} + +fn main() {} diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.stderr new file mode 100644 index 0000000000000..7b18774b6e558 --- /dev/null +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.stderr @@ -0,0 +1,274 @@ +error: attribute must be of the form `#[inline]` or `#[inline(always|never)]` + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:22:5 + | +LL | #[inline = "2100"] fn f() { } + | ^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(ill_formed_attribute_input)]` 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 #57571 + +error[E0518]: attribute should be applied to function or closure + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:13:1 + | +LL | #[inline] + | ^^^^^^^^^ +LL | +LL | / mod inline { +LL | | +LL | | +LL | | mod inner { #![inline] } +... | +LL | | +LL | | } + | |_- not a function or closure + +error: attribute should be applied to an `extern crate` item + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:41:1 + | +LL | #[no_link] + | ^^^^^^^^^^ +LL | +LL | / mod no_link { +LL | | +LL | | +LL | | mod inner { #![no_link] } +... | +LL | | +LL | | } + | |_- not an `extern crate` item + +error: attribute should be applied to a function + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:67:1 + | +LL | #[cold] + | ^^^^^^^ +LL | +LL | / mod cold { +LL | | +LL | | +LL | | mod inner { #![cold] } +... | +LL | | +LL | | } + | |_- not a function + +error: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:91:1 + | +LL | #[export_name = "2200"] + | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | / mod export_name { +LL | | +LL | | +LL | | mod inner { #![export_name="2200"] } +... | +LL | | +LL | | } + | |_- not a function or static + +error: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:115:1 + | +LL | #[link_name = "1900"] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | / mod link_name { +LL | | +LL | | +LL | | #[link_name = "1900"] +... | +LL | | +LL | | } + | |_- not a foreign function or static + +error: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:147:1 + | +LL | #[link_section = "1800"] + | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | / mod link_section { +LL | | +LL | | +LL | | mod inner { #![link_section="1800"] } +... | +LL | | +LL | | } + | |_- not a function or static + +error[E0518]: attribute should be applied to function or closure + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:18:17 + | +LL | mod inner { #![inline] } + | ------------^^^^^^^^^^-- not a function or closure + +error[E0518]: attribute should be applied to function or closure + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:28:5 + | +LL | #[inline] struct S; + | ^^^^^^^^^ --------- not a function or closure + +error[E0518]: attribute should be applied to function or closure + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:32:5 + | +LL | #[inline] type T = S; + | ^^^^^^^^^ ----------- not a function or closure + +error[E0518]: attribute should be applied to function or closure + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:36:5 + | +LL | #[inline] impl S { } + | ^^^^^^^^^ ---------- not a function or closure + +error: attribute should be applied to an `extern crate` item + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:46:17 + | +LL | mod inner { #![no_link] } + | ------------^^^^^^^^^^^-- not an `extern crate` item + +error: attribute should be applied to an `extern crate` item + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:50:5 + | +LL | #[no_link] fn f() { } + | ^^^^^^^^^^ ---------- not an `extern crate` item + +error: attribute should be applied to an `extern crate` item + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:54:5 + | +LL | #[no_link] struct S; + | ^^^^^^^^^^ --------- not an `extern crate` item + +error: attribute should be applied to an `extern crate` item + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:58:5 + | +LL | #[no_link]type T = S; + | ^^^^^^^^^^----------- not an `extern crate` item + +error: attribute should be applied to an `extern crate` item + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:62:5 + | +LL | #[no_link] impl S { } + | ^^^^^^^^^^ ---------- not an `extern crate` item + +error: attribute should be applied to a function + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:72:17 + | +LL | mod inner { #![cold] } + | ------------^^^^^^^^-- not a function + +error: attribute should be applied to a function + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:78:5 + | +LL | #[cold] struct S; + | ^^^^^^^ --------- not a function + +error: attribute should be applied to a function + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:82:5 + | +LL | #[cold] type T = S; + | ^^^^^^^ ----------- not a function + +error: attribute should be applied to a function + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:86:5 + | +LL | #[cold] impl S { } + | ^^^^^^^ ---------- not a function + +error: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:96:17 + | +LL | mod inner { #![export_name="2200"] } + | ------------^^^^^^^^^^^^^^^^^^^^^^-- not a function or static + +error: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:102:5 + | +LL | #[export_name = "2200"] struct S; + | ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a function or static + +error: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:106:5 + | +LL | #[export_name = "2200"] type T = S; + | ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a function or static + +error: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:110:5 + | +LL | #[export_name = "2200"] impl S { } + | ^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a function or static + +error: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:120:5 + | +LL | #[link_name = "1900"] + | ^^^^^^^^^^^^^^^^^^^^^ +... +LL | extern { } + | ---------- not a foreign function or static + | +help: try `#[link(name = "1900")]` instead + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:120:5 + | +LL | #[link_name = "1900"] + | ^^^^^^^^^^^^^^^^^^^^^ + +error: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:126:17 + | +LL | mod inner { #![link_name="1900"] } + | ------------^^^^^^^^^^^^^^^^^^^^-- not a foreign function or static + +error: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:130:5 + | +LL | #[link_name = "1900"] fn f() { } + | ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static + +error: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:134:5 + | +LL | #[link_name = "1900"] struct S; + | ^^^^^^^^^^^^^^^^^^^^^ --------- not a foreign function or static + +error: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:138:5 + | +LL | #[link_name = "1900"] type T = S; + | ^^^^^^^^^^^^^^^^^^^^^ ----------- not a foreign function or static + +error: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:142:5 + | +LL | #[link_name = "1900"] impl S { } + | ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static + +error: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:152:17 + | +LL | mod inner { #![link_section="1800"] } + | ------------^^^^^^^^^^^^^^^^^^^^^^^-- not a function or static + +error: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:158:5 + | +LL | #[link_section = "1800"] struct S; + | ^^^^^^^^^^^^^^^^^^^^^^^^ --------- not a function or static + +error: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:162:5 + | +LL | #[link_section = "1800"] type T = S; + | ^^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a function or static + +error: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:166:5 + | +LL | #[link_section = "1800"] impl S { } + | ^^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a function or static + +error: aborting due to 34 previous errors + +For more information about this error, try `rustc --explain E0518`. diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs index f702b10ccd126..aea1ce6f5aeae 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs @@ -72,7 +72,7 @@ #![doc = "2400"] #![cold] #![export_name = "2200"] -// see issue-43106-gating-of-inline.rs +// see issue-43106-gating-of-builtin-attrs-error.rs #![link()] #![link_name = "1900"] #![link_section = "1800"] @@ -367,25 +367,6 @@ mod no_mangle { #[no_mangle] impl S { } } -#[no_link] -//~^ WARN unused attribute -mod no_link { - mod inner { #![no_link] } - //~^ WARN unused attribute - - #[no_link] fn f() { } - //~^ WARN unused attribute - - #[no_link] struct S; - //~^ WARN unused attribute - - #[no_link]type T = S; - //~^ WARN unused attribute - - #[no_link] impl S { } - //~^ WARN unused attribute -} - #[should_panic] //~^ WARN unused attribute mod should_panic { @@ -524,32 +505,6 @@ mod doc { #[doc = "2400"] impl S { } } -#[cold] -mod cold { - mod inner { #![cold] } - - #[cold] fn f() { } - - #[cold] struct S; - - #[cold] type T = S; - - #[cold] impl S { } -} - -#[export_name = "2200"] -mod export_name { - mod inner { #![export_name="2200"] } - - #[export_name = "2200"] fn f() { } - - #[export_name = "2200"] struct S; - - #[export_name = "2200"] type T = S; - - #[export_name = "2200"] impl S { } -} - // Note that this is a `check-pass` test, so it // will never invoke the linker. These are here nonetheless to point // out that we allow them at non-crate-level (though I do not know @@ -568,32 +523,6 @@ mod link { #[link()] impl S { } } -#[link_name = "1900"] -mod link_name { - mod inner { #![link_name="1900"] } - - #[link_name = "1900"] fn f() { } - - #[link_name = "1900"] struct S; - - #[link_name = "1900"] type T = S; - - #[link_name = "1900"] impl S { } -} - -#[link_section = "1800"] -mod link_section { - mod inner { #![link_section="1800"] } - - #[link_section = "1800"] fn f() { } - - #[link_section = "1800"] struct S; - - #[link_section = "1800"] type T = S; - - #[link_section = "1800"] impl S { } -} - struct StructForDeprecated; #[deprecated] diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr index 02bed6723bf72..ebb81275df139 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr @@ -173,13 +173,13 @@ LL | #[deny(x5100)] impl S { } | ^^^^^ warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:466:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:447:1 | LL | #[macro_escape] | ^^^^^^^^^^^^^^^ warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:469:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:450:17 | LL | mod inner { #![macro_escape] } | ^^^^^^^^^^^^^^^^ @@ -463,707 +463,671 @@ LL | #[automatically_derived] warning: unused attribute --> $DIR/issue-43106-gating-of-builtin-attrs.rs:373:17 | -LL | mod inner { #![no_link] } - | ^^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:376:5 - | -LL | #[no_link] fn f() { } - | ^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:379:5 - | -LL | #[no_link] struct S; - | ^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:382:5 - | -LL | #[no_link]type T = S; - | ^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:385:5 - | -LL | #[no_link] impl S { } - | ^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:370:1 - | -LL | #[no_link] - | ^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:392:17 - | LL | mod inner { #![should_panic] } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:395:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:376:5 | LL | #[should_panic] fn f() { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:398:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:379:5 | LL | #[should_panic] struct S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:401:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:382:5 | LL | #[should_panic] type T = S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:404:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:385:5 | LL | #[should_panic] impl S { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:389:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:370:1 | LL | #[should_panic] | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:411:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:392:17 | LL | mod inner { #![ignore] } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:414:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:395:5 | LL | #[ignore] fn f() { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:417:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:398:5 | LL | #[ignore] struct S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:420:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:401:5 | LL | #[ignore] type T = S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:423:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:404:5 | LL | #[ignore] impl S { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:408:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:389:1 | LL | #[ignore] | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:430:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:411:17 | LL | mod inner { #![no_implicit_prelude] } | ^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:433:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:414:5 | LL | #[no_implicit_prelude] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:436:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:417:5 | LL | #[no_implicit_prelude] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:439:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:420:5 | LL | #[no_implicit_prelude] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:442:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:423:5 | LL | #[no_implicit_prelude] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:427:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:408:1 | LL | #[no_implicit_prelude] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:449:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:430:17 | LL | mod inner { #![reexport_test_harness_main="2900"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:452:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:433:5 | LL | #[reexport_test_harness_main = "2900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:455:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:436:5 | LL | #[reexport_test_harness_main = "2900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:458:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:439:5 | LL | #[reexport_test_harness_main = "2900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:461:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:442:5 | LL | #[reexport_test_harness_main = "2900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:446:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:427:1 | LL | #[reexport_test_harness_main = "2900"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:472:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:453:5 | LL | #[macro_escape] fn f() { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:475:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:456:5 | LL | #[macro_escape] struct S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:478:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:459:5 | LL | #[macro_escape] type T = S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:481:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:462:5 | LL | #[macro_escape] impl S { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:489:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:470:17 | LL | mod inner { #![no_std] } | ^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:489:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:470:17 | LL | mod inner { #![no_std] } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:493:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:474:5 | LL | #[no_std] fn f() { } | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:493:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:474:5 | LL | #[no_std] fn f() { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:497:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:478:5 | LL | #[no_std] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:497:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:478:5 | LL | #[no_std] struct S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:501:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:482:5 | LL | #[no_std] type T = S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:501:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:482:5 | LL | #[no_std] type T = S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:505:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:486:5 | LL | #[no_std] impl S { } | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:505:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:486:5 | LL | #[no_std] impl S { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:485:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:466:1 | LL | #[no_std] | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:485:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:466:1 | LL | #[no_std] | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:644:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:573:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:644:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:573:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:648:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:577:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:648:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:577:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:652:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:581:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:652:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:581:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:656:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:585:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:656:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:585:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:660:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:589:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:660:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:589:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:640:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:569:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:640:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:569:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:669:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:598:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:669:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:598:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:673:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:602:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:673:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:602:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:677:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:606:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:677:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:606:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:681:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:610:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:681:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:610:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:614:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:614:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:665:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:594:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:665:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:594:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:694:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:623:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:694:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:623:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:698:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:627:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:698:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:627:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:702:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:631:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:702:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:631:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:635:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:635:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:639:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:639:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:690:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:619:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:690:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:619:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:649:17 | LL | mod inner { #![no_main] } | ^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:649:17 | LL | mod inner { #![no_main] } | ^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:653:5 | LL | #[no_main] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:653:5 | LL | #[no_main] fn f() { } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:657:5 | LL | #[no_main] struct S; | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:657:5 | LL | #[no_main] struct S; | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:732:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:661:5 | LL | #[no_main] type T = S; | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:732:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:661:5 | LL | #[no_main] type T = S; | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:736:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:665:5 | LL | #[no_main] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:736:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:665:5 | LL | #[no_main] impl S { } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:645:1 | LL | #[no_main] | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:645:1 | LL | #[no_main] | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:687:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:687:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:691:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:691:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:766:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:695:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:766:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:695:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:699:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:699:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:774:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:703:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:774:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:703:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:754:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:683:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:754:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:683:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:783:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:783:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:787:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:787:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:791:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:791:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:795:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:795:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:799:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:799:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:779:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:779:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1234,5 +1198,5 @@ warning: unused attribute LL | #![proc_macro_derive()] | ^^^^^^^^^^^^^^^^^^^^^^^ -warning: 203 warnings emitted +warning: 197 warnings emitted diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-inline.rs b/src/test/ui/feature-gate/issue-43106-gating-of-inline.rs deleted file mode 100644 index 80c602eb00afb..0000000000000 --- a/src/test/ui/feature-gate/issue-43106-gating-of-inline.rs +++ /dev/null @@ -1,31 +0,0 @@ -// This is testing whether `#[inline]` signals an error or warning -// when put in "weird" places. -// -// (This file sits on its own because it actually signals an error, -// which would mess up the treatment of other cases in -// issue-43106-gating-of-builtin-attrs.rs) - -// Crate-level is accepted, though it is almost certainly unused? -#![inline] - -#[inline] -//~^ ERROR attribute should be applied to function or closure -mod inline { - mod inner { #![inline] } - //~^ ERROR attribute should be applied to function or closure - - #[inline = "2100"] fn f() { } - //~^ ERROR attribute must be of the form - //~| WARN this was previously accepted - - #[inline] struct S; - //~^ ERROR attribute should be applied to function or closure - - #[inline] type T = S; - //~^ ERROR attribute should be applied to function or closure - - #[inline] impl S { } - //~^ ERROR attribute should be applied to function or closure -} - -fn main() {} diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-inline.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-inline.stderr deleted file mode 100644 index 0987937192fe2..0000000000000 --- a/src/test/ui/feature-gate/issue-43106-gating-of-inline.stderr +++ /dev/null @@ -1,52 +0,0 @@ -error: attribute must be of the form `#[inline]` or `#[inline(always|never)]` - --> $DIR/issue-43106-gating-of-inline.rs:17:5 - | -LL | #[inline = "2100"] fn f() { } - | ^^^^^^^^^^^^^^^^^^ - | - = note: `#[deny(ill_formed_attribute_input)]` 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 #57571 - -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-inline.rs:11:1 - | -LL | #[inline] - | ^^^^^^^^^ -LL | -LL | / mod inline { -LL | | mod inner { #![inline] } -LL | | -LL | | -... | -LL | | -LL | | } - | |_- not a function or closure - -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-inline.rs:14:17 - | -LL | mod inner { #![inline] } - | ------------^^^^^^^^^^-- not a function or closure - -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-inline.rs:21:5 - | -LL | #[inline] struct S; - | ^^^^^^^^^ --------- not a function or closure - -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-inline.rs:24:5 - | -LL | #[inline] type T = S; - | ^^^^^^^^^ ----------- not a function or closure - -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-inline.rs:27:5 - | -LL | #[inline] impl S { } - | ^^^^^^^^^ ---------- not a function or closure - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0518`. diff --git a/src/test/ui/issues/issue-2214.rs b/src/test/ui/issues/issue-2214.rs index c4c56cd109d67..e04eff7cc4d89 100644 --- a/src/test/ui/issues/issue-2214.rs +++ b/src/test/ui/issues/issue-2214.rs @@ -23,7 +23,7 @@ fn lgamma(n: c_double, value: &mut isize) -> c_double { mod m { use libc::{c_double, c_int}; - #[link_name = "m"] + #[link(name = "m")] extern { #[cfg(any(all(unix, not(target_os = "vxworks")), target_os = "cloudabi"))] #[link_name="lgamma_r"] diff --git a/src/test/ui/issues/issue-47725.rs b/src/test/ui/issues/issue-47725.rs new file mode 100644 index 0000000000000..50f50ed153229 --- /dev/null +++ b/src/test/ui/issues/issue-47725.rs @@ -0,0 +1,22 @@ +#[link_name = "foo"] //~ ERROR attribute should be applied to a foreign function or static +struct Foo; //~ NOTE not a foreign function or static + +#[link_name = "foobar"] +//~^ ERROR attribute should be applied to a foreign function or static +//~| HELP try `#[link(name = "foobar")]` instead +extern "C" { + fn foo() -> u32; +} +//~^^^ NOTE not a foreign function or static + +#[link_name] +//~^ ERROR malformed `link_name` attribute input +//~| HELP must be of the form +//~| ERROR attribute should be applied to a foreign function or static +//~| HELP try `#[link(name = "...")]` instead +extern "C" { + fn bar() -> u32; +} +//~^^^ NOTE not a foreign function or static + +fn main() {} diff --git a/src/test/ui/issues/issue-47725.stderr b/src/test/ui/issues/issue-47725.stderr new file mode 100644 index 0000000000000..8623317c7a0d4 --- /dev/null +++ b/src/test/ui/issues/issue-47725.stderr @@ -0,0 +1,50 @@ +error: malformed `link_name` attribute input + --> $DIR/issue-47725.rs:12:1 + | +LL | #[link_name] + | ^^^^^^^^^^^^ help: must be of the form: `#[link_name = "name"]` + +error: attribute should be applied to a foreign function or static + --> $DIR/issue-47725.rs:1:1 + | +LL | #[link_name = "foo"] + | ^^^^^^^^^^^^^^^^^^^^ +LL | struct Foo; + | ----------- not a foreign function or static + +error: attribute should be applied to a foreign function or static + --> $DIR/issue-47725.rs:4:1 + | +LL | #[link_name = "foobar"] + | ^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | / extern "C" { +LL | | fn foo() -> u32; +LL | | } + | |_- not a foreign function or static + | +help: try `#[link(name = "foobar")]` instead + --> $DIR/issue-47725.rs:4:1 + | +LL | #[link_name = "foobar"] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: attribute should be applied to a foreign function or static + --> $DIR/issue-47725.rs:12:1 + | +LL | #[link_name] + | ^^^^^^^^^^^^ +... +LL | / extern "C" { +LL | | fn bar() -> u32; +LL | | } + | |_- not a foreign function or static + | +help: try `#[link(name = "...")]` instead + --> $DIR/issue-47725.rs:12:1 + | +LL | #[link_name] + | ^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/issues/issue-54044.rs b/src/test/ui/issues/issue-54044.rs new file mode 100644 index 0000000000000..eb0cf27ffbb70 --- /dev/null +++ b/src/test/ui/issues/issue-54044.rs @@ -0,0 +1,7 @@ +#[cold] //~ ERROR attribute should be applied to a function +struct Foo; //~ NOTE not a function + +fn main() { + #[cold] //~ ERROR attribute should be applied to a function + 5; //~ NOTE not a function +} diff --git a/src/test/ui/issues/issue-54044.stderr b/src/test/ui/issues/issue-54044.stderr new file mode 100644 index 0000000000000..2561629260710 --- /dev/null +++ b/src/test/ui/issues/issue-54044.stderr @@ -0,0 +1,18 @@ +error: attribute should be applied to a function + --> $DIR/issue-54044.rs:1:1 + | +LL | #[cold] + | ^^^^^^^ +LL | struct Foo; + | ----------- not a function + +error: attribute should be applied to a function + --> $DIR/issue-54044.rs:5:5 + | +LL | #[cold] + | ^^^^^^^ +LL | 5; + | - not a function + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/macros/issue-68060.rs b/src/test/ui/macros/issue-68060.rs index 8772e98b6e9bb..1feddc4ebd89f 100644 --- a/src/test/ui/macros/issue-68060.rs +++ b/src/test/ui/macros/issue-68060.rs @@ -2,10 +2,11 @@ fn main() { (0..) .map( #[target_feature(enable = "")] - //~^ ERROR: the feature named `` is not valid for this target - //~| ERROR: `#[target_feature(..)]` can only be applied to `unsafe` functions + //~^ ERROR: attribute should be applied to a function + //~| ERROR: the feature named `` is not valid for this target #[track_caller] - //~^ ERROR: `#[track_caller]` requires Rust ABI + //~^ ERROR: attribute should be applied to function [E0739] + //~| ERROR: `#[track_caller]` requires Rust ABI [E0737] |_| (), ) .next(); diff --git a/src/test/ui/macros/issue-68060.stderr b/src/test/ui/macros/issue-68060.stderr index b9b2f946c5967..5def8780fbf02 100644 --- a/src/test/ui/macros/issue-68060.stderr +++ b/src/test/ui/macros/issue-68060.stderr @@ -1,14 +1,20 @@ -error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions +error: attribute should be applied to a function --> $DIR/issue-68060.rs:4:13 | LL | #[target_feature(enable = "")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | |_| (), - | ------ not an `unsafe` function + | ------ not a function + +error[E0739]: attribute should be applied to function + --> $DIR/issue-68060.rs:7:13 | - = note: see issue #69098 for more information - = help: add `#![feature(target_feature_11)]` to the crate attributes to enable +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ +... +LL | |_| (), + | ------ not a function error: the feature named `` is not valid for this target --> $DIR/issue-68060.rs:4:30 @@ -17,12 +23,12 @@ LL | #[target_feature(enable = "")] | ^^^^^^^^^^^ `` is not valid for this target error[E0737]: `#[track_caller]` requires Rust ABI - --> $DIR/issue-68060.rs:7:13 + --> $DIR/issue-68060.rs:8:13 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0658, E0737. -For more information about an error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0737, E0739. +For more information about an error, try `rustc --explain E0737`. diff --git a/src/test/ui/target-feature/invalid-attribute.rs b/src/test/ui/target-feature/invalid-attribute.rs index 98afded6712d7..3c2e34bb8c3e1 100644 --- a/src/test/ui/target-feature/invalid-attribute.rs +++ b/src/test/ui/target-feature/invalid-attribute.rs @@ -79,13 +79,16 @@ impl Quux for Foo { } fn main() { + #[target_feature(enable = "sse2")] + //~^ ERROR attribute should be applied to a function unsafe { foo(); bar(); } + //~^^^^ NOTE not a function + #[target_feature(enable = "sse2")] - //~^ ERROR `#[target_feature(..)]` can only be applied to `unsafe` functions - //~| NOTE see issue #69098 + //~^ ERROR attribute should be applied to a function || {}; - //~^ NOTE not an `unsafe` function + //~^ NOTE not a function } diff --git a/src/test/ui/target-feature/invalid-attribute.stderr b/src/test/ui/target-feature/invalid-attribute.stderr index 3d629afb9a610..c06538c5b8fe7 100644 --- a/src/test/ui/target-feature/invalid-attribute.stderr +++ b/src/test/ui/target-feature/invalid-attribute.stderr @@ -94,17 +94,26 @@ error: cannot use `#[inline(always)]` with `#[target_feature]` LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ -error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions - --> $DIR/invalid-attribute.rs:86:5 +error: attribute should be applied to a function + --> $DIR/invalid-attribute.rs:82:5 + | +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | / unsafe { +LL | | foo(); +LL | | bar(); +LL | | } + | |_____- not a function + +error: attribute should be applied to a function + --> $DIR/invalid-attribute.rs:90:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... +LL | LL | || {}; - | ----- not an `unsafe` function - | - = note: see issue #69098 for more information - = help: add `#![feature(target_feature_11)]` to the crate attributes to enable + | ----- not a function error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions --> $DIR/invalid-attribute.rs:74:5 @@ -118,6 +127,6 @@ LL | fn foo() {} = note: see issue #69098 for more information = help: add `#![feature(target_feature_11)]` to the crate attributes to enable -error: aborting due to 14 previous errors +error: aborting due to 15 previous errors For more information about this error, try `rustc --explain E0658`. From f745b34960b2146dbaa7337856e7c5461cca29d5 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Sat, 11 Jul 2020 10:29:35 -0400 Subject: [PATCH 0140/1052] Emit warnings for misplaced attributes used by some crates --- compiler/rustc_passes/src/check_attr.rs | 153 +++-- ...sue-43106-gating-of-builtin-attrs-error.rs | 80 --- ...43106-gating-of-builtin-attrs-error.stderr | 150 +---- .../issue-43106-gating-of-builtin-attrs.rs | 124 +++- ...issue-43106-gating-of-builtin-attrs.stderr | 580 +++++++++++------- src/test/ui/issues/issue-47725.rs | 13 +- src/test/ui/issues/issue-47725.stderr | 30 +- src/test/ui/issues/issue-54044.rs | 11 +- src/test/ui/issues/issue-54044.stderr | 15 +- src/test/ui/macros/issue-68060.rs | 3 + src/test/ui/macros/issue-68060.stderr | 2 +- .../ui/target-feature/invalid-attribute.rs | 10 +- .../target-feature/invalid-attribute.stderr | 50 +- 13 files changed, 691 insertions(+), 530 deletions(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 037a653e3e019..fdb1f24de263d 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -66,22 +66,24 @@ impl CheckAttrVisitor<'tcx> { } else if self.tcx.sess.check_name(attr, sym::marker) { self.check_marker(attr, span, target) } else if self.tcx.sess.check_name(attr, sym::target_feature) { - self.check_target_feature(attr, span, target) + self.check_target_feature(hir_id, attr, span, target) } else if self.tcx.sess.check_name(attr, sym::track_caller) { self.check_track_caller(&attr.span, attrs, span, target) } else if self.tcx.sess.check_name(attr, sym::doc) { self.check_doc_alias(attr, hir_id, target) - } else if self.tcx.sess.check_name(attr, sym::cold) { - self.check_cold(&attr, span, target) - } else if self.tcx.sess.check_name(attr, sym::link_name) { - self.check_link_name(&attr, span, target) } else if self.tcx.sess.check_name(attr, sym::no_link) { self.check_no_link(&attr, span, target) } else if self.tcx.sess.check_name(attr, sym::export_name) { self.check_export_name(&attr, span, target) - } else if self.tcx.sess.check_name(attr, sym::link_section) { - self.check_link_section(&attr, span, target) } else { + // lint-only checks + if self.tcx.sess.check_name(attr, sym::cold) { + self.check_cold(hir_id, attr, span, target); + } else if self.tcx.sess.check_name(attr, sym::link_name) { + self.check_link_name(hir_id, attr, span, target); + } else if self.tcx.sess.check_name(attr, sym::link_section) { + self.check_link_section(hir_id, attr, span, target); + } true }; } @@ -212,10 +214,31 @@ impl CheckAttrVisitor<'tcx> { } /// Checks if the `#[target_feature]` attribute on `item` is valid. Returns `true` if valid. - fn check_target_feature(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + fn check_target_feature( + &self, + hir_id: HirId, + attr: &Attribute, + span: &Span, + target: Target, + ) -> bool { match target { Target::Fn | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true, + // FIXME: #[target_feature] was previously erroneously allowed on statements and some + // crates used this, so only emit a warning. + Target::Statement => { + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build("attribute should be applied to a function") + .warn( + "this was previously accepted by the compiler but is \ + being phased out; it will become a hard error in \ + a future release!", + ) + .span_label(*span, "not a function") + .emit(); + }); + true + } _ => { self.tcx .sess @@ -288,45 +311,58 @@ impl CheckAttrVisitor<'tcx> { } /// Checks if `#[cold]` is applied to a non-function. Returns `true` if valid. - fn check_cold(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) { match target { - Target::Fn | Target::Method(..) | Target::ForeignFn => true, + Target::Fn | Target::Method(..) | Target::ForeignFn => {} _ => { - self.tcx - .sess - .struct_span_err(attr.span, "attribute should be applied to a function") - .span_label(*span, "not a function") - .emit(); - false + // FIXME: #[cold] was previously allowed on non-functions and some crates used + // this, so only emit a warning. + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build("attribute should be applied to a function") + .warn( + "this was previously accepted by the compiler but is \ + being phased out; it will become a hard error in \ + a future release!", + ) + .span_label(*span, "not a function") + .emit(); + }); } } } - /// Checks if `#[link_name]` is applied to an item other than a foreign function or static. Returns `true` if valid. - fn check_link_name(&self, attr: &Attribute, span: &Span, target: Target) -> bool { - if target == Target::ForeignFn || target == Target::ForeignStatic { - true - } else { - let mut err = self.tcx.sess.struct_span_err( - attr.span, - "attribute should be applied to a foreign function or static", - ); - err.span_label(*span, "not a foreign function or static"); - - // See issue #47725 - if target == Target::ForeignMod { - if let Some(value) = attr.value_str() { - err.span_help( - attr.span, - &format!(r#"try `#[link(name = "{}")]` instead"#, value), + /// Checks if `#[link_name]` is applied to an item other than a foreign function or static. + fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) { + match target { + Target::ForeignFn | Target::ForeignStatic => {} + _ => { + // FIXME: #[cold] was previously allowed on non-functions/statics and some crates + // used this, so only emit a warning. + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + let mut diag = + lint.build("attribute should be applied to a foreign function or static"); + diag.warn( + "this was previously accepted by the compiler but is \ + being phased out; it will become a hard error in \ + a future release!", ); - } else { - err.span_help(attr.span, r#"try `#[link(name = "...")]` instead"#); - } - } - err.emit(); - false + // See issue #47725 + if let Target::ForeignMod = target { + if let Some(value) = attr.value_str() { + diag.span_help( + attr.span, + &format!(r#"try `#[link(name = "{}")]` instead"#, value), + ); + } else { + diag.span_help(attr.span, r#"try `#[link(name = "...")]` instead"#); + } + } + + diag.span_label(*span, "not a foreign function or static"); + diag.emit(); + }); + } } } @@ -362,20 +398,23 @@ impl CheckAttrVisitor<'tcx> { } } - /// Checks if `#[link_section]` is applied to a function or static. Returns `true` if valid. - fn check_link_section(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + /// Checks if `#[link_section]` is applied to a function or static. + fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) { match target { - Target::Static | Target::Fn | Target::Method(..) => true, + Target::Static | Target::Fn | Target::Method(..) => {} _ => { - self.tcx - .sess - .struct_span_err( - attr.span, - "attribute should be applied to a function or static", - ) - .span_label(*span, "not a function or static") - .emit(); - false + // FIXME: #[link_section] was previously allowed on non-functions/statics and some + // crates used this, so only emit a warning. + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build("attribute should be applied to a function or static") + .warn( + "this was previously accepted by the compiler but is \ + being phased out; it will become a hard error in \ + a future release!", + ) + .span_label(*span, "not a function or static") + .emit(); + }); } } } @@ -424,7 +463,11 @@ impl CheckAttrVisitor<'tcx> { } sym::simd => { is_simd = true; - if target != Target::Struct { ("a", "struct") } else { continue } + if target != Target::Struct { + ("a", "struct") + } else { + continue; + } } sym::transparent => { is_transparent = true; @@ -461,7 +504,11 @@ impl CheckAttrVisitor<'tcx> { | sym::isize | sym::usize => { int_reprs += 1; - if target != Target::Enum { ("an", "enum") } else { continue } + if target != Target::Enum { + ("an", "enum") + } else { + continue; + } } _ => continue, }; diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.rs b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.rs index 06cc868994e32..3ac8ba5232de7 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.rs +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.rs @@ -64,30 +64,6 @@ mod no_link { //~| NOTE not an `extern crate` item } -#[cold] -//~^ ERROR attribute should be applied to a function -mod cold { - //~^ NOTE not a function - - mod inner { #![cold] } - //~^ ERROR attribute should be applied to a function - //~| NOTE not a function - - #[cold] fn f() { } - - #[cold] struct S; - //~^ ERROR attribute should be applied to a function - //~| NOTE not a function - - #[cold] type T = S; - //~^ ERROR attribute should be applied to a function - //~| NOTE not a function - - #[cold] impl S { } - //~^ ERROR attribute should be applied to a function - //~| NOTE not a function -} - #[export_name = "2200"] //~^ ERROR attribute should be applied to a function or static mod export_name { @@ -112,60 +88,4 @@ mod export_name { //~| NOTE not a function or static } -#[link_name = "1900"] -//~^ ERROR attribute should be applied to a foreign function or static -mod link_name { - //~^ NOTE not a foreign function or static - - #[link_name = "1900"] - //~^ ERROR attribute should be applied to a foreign function or static - //~| HELP try `#[link(name = "1900")]` instead - extern { } - //~^ NOTE not a foreign function or static - - mod inner { #![link_name="1900"] } - //~^ ERROR attribute should be applied to a foreign function or static - //~| NOTE not a foreign function or static - - #[link_name = "1900"] fn f() { } - //~^ ERROR attribute should be applied to a foreign function or static - //~| NOTE not a foreign function or static - - #[link_name = "1900"] struct S; - //~^ ERROR attribute should be applied to a foreign function or static - //~| NOTE not a foreign function or static - - #[link_name = "1900"] type T = S; - //~^ ERROR attribute should be applied to a foreign function or static - //~| NOTE not a foreign function or static - - #[link_name = "1900"] impl S { } - //~^ ERROR attribute should be applied to a foreign function or static - //~| NOTE not a foreign function or static -} - -#[link_section = "1800"] -//~^ ERROR attribute should be applied to a function or static -mod link_section { - //~^ NOTE not a function or static - - mod inner { #![link_section="1800"] } - //~^ ERROR attribute should be applied to a function or static - //~| NOTE not a function or static - - #[link_section = "1800"] fn f() { } - - #[link_section = "1800"] struct S; - //~^ ERROR attribute should be applied to a function or static - //~| NOTE not a function or static - - #[link_section = "1800"] type T = S; - //~^ ERROR attribute should be applied to a function or static - //~| NOTE not a function or static - - #[link_section = "1800"] impl S { } - //~^ ERROR attribute should be applied to a function or static - //~| NOTE not a function or static -} - fn main() {} diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.stderr index 7b18774b6e558..c9255d2be129b 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.stderr @@ -38,23 +38,8 @@ LL | | LL | | } | |_- not an `extern crate` item -error: attribute should be applied to a function - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:67:1 - | -LL | #[cold] - | ^^^^^^^ -LL | -LL | / mod cold { -LL | | -LL | | -LL | | mod inner { #![cold] } -... | -LL | | -LL | | } - | |_- not a function - error: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:91:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:67:1 | LL | #[export_name = "2200"] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -68,36 +53,6 @@ LL | | LL | | } | |_- not a function or static -error: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:115:1 - | -LL | #[link_name = "1900"] - | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | / mod link_name { -LL | | -LL | | -LL | | #[link_name = "1900"] -... | -LL | | -LL | | } - | |_- not a foreign function or static - -error: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:147:1 - | -LL | #[link_section = "1800"] - | ^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | / mod link_section { -LL | | -LL | | -LL | | mod inner { #![link_section="1800"] } -... | -LL | | -LL | | } - | |_- not a function or static - error[E0518]: attribute should be applied to function or closure --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:18:17 | @@ -152,123 +107,30 @@ error: attribute should be applied to an `extern crate` item LL | #[no_link] impl S { } | ^^^^^^^^^^ ---------- not an `extern crate` item -error: attribute should be applied to a function - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:72:17 - | -LL | mod inner { #![cold] } - | ------------^^^^^^^^-- not a function - -error: attribute should be applied to a function - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:78:5 - | -LL | #[cold] struct S; - | ^^^^^^^ --------- not a function - -error: attribute should be applied to a function - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:82:5 - | -LL | #[cold] type T = S; - | ^^^^^^^ ----------- not a function - -error: attribute should be applied to a function - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:86:5 - | -LL | #[cold] impl S { } - | ^^^^^^^ ---------- not a function - error: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:96:17 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:72:17 | LL | mod inner { #![export_name="2200"] } | ------------^^^^^^^^^^^^^^^^^^^^^^-- not a function or static error: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:102:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:78:5 | LL | #[export_name = "2200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a function or static error: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:106:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:82:5 | LL | #[export_name = "2200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a function or static error: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:110:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:86:5 | LL | #[export_name = "2200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a function or static -error: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:120:5 - | -LL | #[link_name = "1900"] - | ^^^^^^^^^^^^^^^^^^^^^ -... -LL | extern { } - | ---------- not a foreign function or static - | -help: try `#[link(name = "1900")]` instead - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:120:5 - | -LL | #[link_name = "1900"] - | ^^^^^^^^^^^^^^^^^^^^^ - -error: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:126:17 - | -LL | mod inner { #![link_name="1900"] } - | ------------^^^^^^^^^^^^^^^^^^^^-- not a foreign function or static - -error: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:130:5 - | -LL | #[link_name = "1900"] fn f() { } - | ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static - -error: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:134:5 - | -LL | #[link_name = "1900"] struct S; - | ^^^^^^^^^^^^^^^^^^^^^ --------- not a foreign function or static - -error: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:138:5 - | -LL | #[link_name = "1900"] type T = S; - | ^^^^^^^^^^^^^^^^^^^^^ ----------- not a foreign function or static - -error: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:142:5 - | -LL | #[link_name = "1900"] impl S { } - | ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static - -error: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:152:17 - | -LL | mod inner { #![link_section="1800"] } - | ------------^^^^^^^^^^^^^^^^^^^^^^^-- not a function or static - -error: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:158:5 - | -LL | #[link_section = "1800"] struct S; - | ^^^^^^^^^^^^^^^^^^^^^^^^ --------- not a function or static - -error: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:162:5 - | -LL | #[link_section = "1800"] type T = S; - | ^^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a function or static - -error: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:166:5 - | -LL | #[link_section = "1800"] impl S { } - | ^^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a function or static - -error: aborting due to 34 previous errors +error: aborting due to 17 previous errors For more information about this error, try `rustc --explain E0518`. diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs index aea1ce6f5aeae..d6a3ffd566f75 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs @@ -31,14 +31,19 @@ // occurrences in the source text. // check-pass +// ignore-tidy-linelength #![feature(test, plugin_registrar)] #![warn(unused_attributes, unknown_lints)] +//~^ NOTE the lint level is defined here +//~| NOTE the lint level is defined here // Exception, a gated and deprecated attribute. -#![plugin_registrar] //~ WARN unused attribute +#![plugin_registrar] +//~^ WARN unused attribute //~| WARN use of deprecated attribute +//~| HELP may be removed in a future compiler version // UNGATED WHITE-LISTED BUILT-IN ATTRIBUTES @@ -88,12 +93,18 @@ #![crate_name = "0900"] #![crate_type = "bin"] // cannot pass "0800" here -#![crate_id = "10"] //~ WARN use of deprecated attribute +#![crate_id = "10"] +//~^ WARN use of deprecated attribute +//~| HELP remove this attribute // FIXME(#44232) we should warn that this isn't used. -#![feature(rust1)] //~ WARN no longer requires an attribute to enable +#![feature(rust1)] +//~^ WARN no longer requires an attribute to enable +//~| NOTE `#[warn(stable_features)]` on by default -#![no_start] //~ WARN use of deprecated attribute +#![no_start] +//~^ WARN use of deprecated attribute +//~| HELP remove this attribute // (cannot easily gating state of crate-level #[no_main]; but non crate-level is below at "0400") #![no_builtins] @@ -217,24 +228,30 @@ mod macro_export { #[plugin_registrar] //~^ WARN unused attribute //~| WARN use of deprecated attribute +//~| HELP may be removed in a future compiler version mod plugin_registrar { mod inner { #![plugin_registrar] } //~^ WARN unused attribute //~| WARN use of deprecated attribute + //~| HELP may be removed in a future compiler version + //~| NOTE `#[warn(deprecated)]` on by default // for `fn f()` case, see gated-plugin_registrar.rs #[plugin_registrar] struct S; //~^ WARN unused attribute //~| WARN use of deprecated attribute + //~| HELP may be removed in a future compiler version #[plugin_registrar] type T = S; //~^ WARN unused attribute //~| WARN use of deprecated attribute + //~| HELP may be removed in a future compiler version #[plugin_registrar] impl S { } //~^ WARN unused attribute //~| WARN use of deprecated attribute + //~| HELP may be removed in a future compiler version } #[main] @@ -449,6 +466,7 @@ mod reexport_test_harness_main { mod macro_escape { mod inner { #![macro_escape] } //~^ WARN `#[macro_escape]` is a deprecated synonym for `#[macro_use]` + //~| HELP try an outer attribute: `#[macro_use]` #[macro_escape] fn f() { } //~^ WARN unused attribute @@ -505,6 +523,104 @@ mod doc { #[doc = "2400"] impl S { } } +#[cold] +//~^ WARN attribute should be applied to a function +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +mod cold { + //~^ NOTE not a function + + mod inner { #![cold] } + //~^ WARN attribute should be applied to a function + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function + + #[cold] fn f() { } + + #[cold] struct S; + //~^ WARN attribute should be applied to a function + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function + + #[cold] type T = S; + //~^ WARN attribute should be applied to a function + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function + + #[cold] impl S { } + //~^ WARN attribute should be applied to a function + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function +} + +#[link_name = "1900"] +//~^ WARN attribute should be applied to a foreign function or static [unused_attributes] +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +mod link_name { + //~^ NOTE not a foreign function or static + + #[link_name = "1900"] + //~^ WARN attribute should be applied to a foreign function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| HELP try `#[link(name = "1900")]` instead + extern { } + //~^ NOTE not a foreign function or static + + mod inner { #![link_name="1900"] } + //~^ WARN attribute should be applied to a foreign function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a foreign function or static + + #[link_name = "1900"] fn f() { } + //~^ WARN attribute should be applied to a foreign function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a foreign function or static + + #[link_name = "1900"] struct S; + //~^ WARN attribute should be applied to a foreign function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a foreign function or static + + #[link_name = "1900"] type T = S; + //~^ WARN attribute should be applied to a foreign function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a foreign function or static + + #[link_name = "1900"] impl S { } + //~^ WARN attribute should be applied to a foreign function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a foreign function or static +} + +#[link_section = "1800"] +//~^ WARN attribute should be applied to a function or static [unused_attributes] +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +mod link_section { + //~^ NOTE not a function or static + + mod inner { #![link_section="1800"] } + //~^ WARN attribute should be applied to a function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function or static + + #[link_section = "1800"] fn f() { } + + #[link_section = "1800"] struct S; + //~^ WARN attribute should be applied to a function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function or static + + #[link_section = "1800"] type T = S; + //~^ WARN attribute should be applied to a function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function or static + + #[link_section = "1800"] impl S { } + //~^ WARN attribute should be applied to a function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function or static +} + + // Note that this is a `check-pass` test, so it // will never invoke the linker. These are here nonetheless to point // out that we allow them at non-crate-level (though I do not know diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr index ebb81275df139..05a9c0e975fa0 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr @@ -1,185 +1,185 @@ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:45:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:50:9 | LL | #![warn(x5400)] | ^^^^^ | note: the lint level is defined here - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:36:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:37:28 | LL | #![warn(unused_attributes, unknown_lints)] | ^^^^^^^^^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:46:10 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:51:10 | LL | #![allow(x5300)] | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:47:11 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:52:11 | LL | #![forbid(x5200)] | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:48:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:9 | LL | #![deny(x5100)] | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:105:8 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:116:8 | LL | #[warn(x5400)] | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:108:25 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:119:25 | LL | mod inner { #![warn(x5400)] } | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:111:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:122:12 | LL | #[warn(x5400)] fn f() { } | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:114:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:125:12 | LL | #[warn(x5400)] struct S; | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:117:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:128:12 | LL | #[warn(x5400)] type T = S; | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:120:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:131:12 | LL | #[warn(x5400)] impl S { } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:124:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:135:9 | LL | #[allow(x5300)] | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:127:26 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:138:26 | LL | mod inner { #![allow(x5300)] } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:130:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:141:13 | LL | #[allow(x5300)] fn f() { } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:133:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:144:13 | LL | #[allow(x5300)] struct S; | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:136:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:147:13 | LL | #[allow(x5300)] type T = S; | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:139:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:150:13 | LL | #[allow(x5300)] impl S { } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:143:10 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:154:10 | LL | #[forbid(x5200)] | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:146:27 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:157:27 | LL | mod inner { #![forbid(x5200)] } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:149:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:160:14 | LL | #[forbid(x5200)] fn f() { } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:152:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:163:14 | LL | #[forbid(x5200)] struct S; | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:155:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:166:14 | LL | #[forbid(x5200)] type T = S; | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:158:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:169:14 | LL | #[forbid(x5200)] impl S { } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:162:8 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:173:8 | LL | #[deny(x5100)] | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:165:25 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:176:25 | LL | mod inner { #![deny(x5100)] } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:168:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:179:12 | LL | #[deny(x5100)] fn f() { } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:171:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:182:12 | LL | #[deny(x5100)] struct S; | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:174:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:185:12 | LL | #[deny(x5100)] type T = S; | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:177:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:188:12 | LL | #[deny(x5100)] impl S { } | ^^^^^ warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:447:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:464:1 | LL | #[macro_escape] | ^^^^^^^^^^^^^^^ warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:450:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:467:17 | LL | mod inner { #![macro_escape] } | ^^^^^^^^^^^^^^^^ @@ -187,7 +187,7 @@ LL | mod inner { #![macro_escape] } = help: try an outer attribute: `#[macro_use]` warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:221:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:233:17 | LL | mod inner { #![plugin_registrar] } | ^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version @@ -195,49 +195,225 @@ LL | mod inner { #![plugin_registrar] } = note: `#[warn(deprecated)]` on by default warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:227:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:241:5 | LL | #[plugin_registrar] struct S; | ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:231:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:246:5 | LL | #[plugin_registrar] type T = S; | ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:235:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:251:5 | LL | #[plugin_registrar] impl S { } | ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:217:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:228:1 | LL | #[plugin_registrar] | ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:40:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:43:1 | LL | #![plugin_registrar] | ^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version warning: use of deprecated attribute `crate_id`: no longer used. - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:91:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:96:1 | LL | #![crate_id = "10"] | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute warning: use of deprecated attribute `no_start`: no longer used. - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:96:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:105:1 | LL | #![no_start] | ^^^^^^^^^^^^ help: remove this attribute +warning: attribute should be applied to a function + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:526:1 + | +LL | #[cold] + | ^^^^^^^ +... +LL | / mod cold { +LL | | +LL | | +LL | | mod inner { #![cold] } +... | +LL | | +LL | | } + | |_- not a function + | +note: the lint level is defined here + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:37:9 + | +LL | #![warn(unused_attributes, unknown_lints)] + | ^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:555:1 + | +LL | #[link_name = "1900"] + | ^^^^^^^^^^^^^^^^^^^^^ +... +LL | / mod link_name { +LL | | +LL | | +LL | | #[link_name = "1900"] +... | +LL | | +LL | | } + | |_- not a foreign function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:594:1 + | +LL | #[link_section = "1800"] + | ^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | / mod link_section { +LL | | +LL | | +LL | | mod inner { #![link_section="1800"] } +... | +LL | | +LL | | } + | |_- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:532:17 + | +LL | mod inner { #![cold] } + | ------------^^^^^^^^-- not a function + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:539:5 + | +LL | #[cold] struct S; + | ^^^^^^^ --------- not a function + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:544:5 + | +LL | #[cold] type T = S; + | ^^^^^^^ ----------- not a function + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:549:5 + | +LL | #[cold] impl S { } + | ^^^^^^^ ---------- not a function + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:561:5 + | +LL | #[link_name = "1900"] + | ^^^^^^^^^^^^^^^^^^^^^ +... +LL | extern { } + | ---------- not a foreign function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +help: try `#[link(name = "1900")]` instead + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:561:5 + | +LL | #[link_name = "1900"] + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:568:17 + | +LL | mod inner { #![link_name="1900"] } + | ------------^^^^^^^^^^^^^^^^^^^^-- not a foreign function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:573:5 + | +LL | #[link_name = "1900"] fn f() { } + | ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:578:5 + | +LL | #[link_name = "1900"] struct S; + | ^^^^^^^^^^^^^^^^^^^^^ --------- not a foreign function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:583:5 + | +LL | #[link_name = "1900"] type T = S; + | ^^^^^^^^^^^^^^^^^^^^^ ----------- not a foreign function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:588:5 + | +LL | #[link_name = "1900"] impl S { } + | ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:600:17 + | +LL | mod inner { #![link_section="1800"] } + | ------------^^^^^^^^^^^^^^^^^^^^^^^-- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:607:5 + | +LL | #[link_section = "1800"] struct S; + | ^^^^^^^^^^^^^^^^^^^^^^^^ --------- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:612:5 + | +LL | #[link_section = "1800"] type T = S; + | ^^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:617:5 + | +LL | #[link_section = "1800"] impl S { } + | ^^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + warning: the feature `rust1` has been stable since 1.0.0 and no longer requires an attribute to enable - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:94:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:101:12 | LL | #![feature(rust1)] | ^^^^^ @@ -245,958 +421,952 @@ LL | #![feature(rust1)] = note: `#[warn(stable_features)]` on by default warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:185:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:196:5 | LL | #[macro_use] fn f() { } | ^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:36:9 - | -LL | #![warn(unused_attributes, unknown_lints)] - | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:188:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:199:5 | LL | #[macro_use] struct S; | ^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:191:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:202:5 | LL | #[macro_use] type T = S; | ^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:194:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:205:5 | LL | #[macro_use] impl S { } | ^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:201:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:212:17 | LL | mod inner { #![macro_export] } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:204:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:215:5 | LL | #[macro_export] fn f() { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:207:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:218:5 | LL | #[macro_export] struct S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:210:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:221:5 | LL | #[macro_export] type T = S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:213:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:224:5 | LL | #[macro_export] impl S { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:198:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:209:1 | LL | #[macro_export] | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:221:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:233:17 | LL | mod inner { #![plugin_registrar] } | ^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:227:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:241:5 | LL | #[plugin_registrar] struct S; | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:231:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:246:5 | LL | #[plugin_registrar] type T = S; | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:235:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:251:5 | LL | #[plugin_registrar] impl S { } | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:217:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:228:1 | LL | #[plugin_registrar] | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:243:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:260:17 | LL | mod inner { #![main] } | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:248:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:265:5 | LL | #[main] struct S; | ^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:251:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:268:5 | LL | #[main] type T = S; | ^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:254:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:271:5 | LL | #[main] impl S { } | ^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:240:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:257:1 | LL | #[main] | ^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:261:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:278:17 | LL | mod inner { #![start] } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:266:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:283:5 | LL | #[start] struct S; | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:269:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:286:5 | LL | #[start] type T = S; | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:272:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:289:5 | LL | #[start] impl S { } | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:258:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:275:1 | LL | #[start] | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:325:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:342:5 | LL | #[path = "3800"] fn f() { } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:328:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:345:5 | LL | #[path = "3800"] struct S; | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:331:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:348:5 | LL | #[path = "3800"] type T = S; | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:334:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:351:5 | LL | #[path = "3800"] impl S { } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:341:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:358:17 | LL | mod inner { #![automatically_derived] } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:344:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:361:5 | LL | #[automatically_derived] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:347:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:364:5 | LL | #[automatically_derived] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:350:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:367:5 | LL | #[automatically_derived] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:353:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:370:5 | LL | #[automatically_derived] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:338:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:355:1 | LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:373:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:390:17 | LL | mod inner { #![should_panic] } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:376:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:393:5 | LL | #[should_panic] fn f() { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:379:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:396:5 | LL | #[should_panic] struct S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:382:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:399:5 | LL | #[should_panic] type T = S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:385:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:402:5 | LL | #[should_panic] impl S { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:370:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:387:1 | LL | #[should_panic] | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:392:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:409:17 | LL | mod inner { #![ignore] } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:395:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:412:5 | LL | #[ignore] fn f() { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:398:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:415:5 | LL | #[ignore] struct S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:401:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:418:5 | LL | #[ignore] type T = S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:404:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:421:5 | LL | #[ignore] impl S { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:389:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:406:1 | LL | #[ignore] | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:411:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:428:17 | LL | mod inner { #![no_implicit_prelude] } | ^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:414:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:431:5 | LL | #[no_implicit_prelude] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:417:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:434:5 | LL | #[no_implicit_prelude] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:420:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:437:5 | LL | #[no_implicit_prelude] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:423:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:440:5 | LL | #[no_implicit_prelude] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:408:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:425:1 | LL | #[no_implicit_prelude] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:430:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:447:17 | LL | mod inner { #![reexport_test_harness_main="2900"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:433:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:450:5 | LL | #[reexport_test_harness_main = "2900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:436:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:453:5 | LL | #[reexport_test_harness_main = "2900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:439:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:456:5 | LL | #[reexport_test_harness_main = "2900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:442:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:459:5 | LL | #[reexport_test_harness_main = "2900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:427:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:444:1 | LL | #[reexport_test_harness_main = "2900"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:453:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:471:5 | LL | #[macro_escape] fn f() { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:456:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:474:5 | LL | #[macro_escape] struct S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:459:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:477:5 | LL | #[macro_escape] type T = S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:462:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:480:5 | LL | #[macro_escape] impl S { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:470:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:488:17 | LL | mod inner { #![no_std] } | ^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:470:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:488:17 | LL | mod inner { #![no_std] } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:474:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:492:5 | LL | #[no_std] fn f() { } | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:474:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:492:5 | LL | #[no_std] fn f() { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:478:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:496:5 | LL | #[no_std] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:478:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:496:5 | LL | #[no_std] struct S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:482:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:500:5 | LL | #[no_std] type T = S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:482:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:500:5 | LL | #[no_std] type T = S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:486:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:504:5 | LL | #[no_std] impl S { } | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:486:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:504:5 | LL | #[no_std] impl S { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:466:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:484:1 | LL | #[no_std] | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:466:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:484:1 | LL | #[no_std] | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:573:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:689:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:573:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:689:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:577:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:693:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:577:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:693:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:581:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:697:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:581:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:697:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:585:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:585:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:589:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:705:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:589:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:705:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:569:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:569:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:598:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:714:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:598:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:714:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:602:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:602:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:606:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:722:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:606:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:722:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:610:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:610:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:614:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:730:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:614:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:730:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:594:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:594:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:623:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:739:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:623:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:739:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:627:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:743:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:627:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:743:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:631:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:747:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:631:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:747:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:635:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:751:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:635:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:751:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:639:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:755:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:639:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:755:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:619:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:735:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:619:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:735:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:649:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:765:17 | LL | mod inner { #![no_main] } | ^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:649:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:765:17 | LL | mod inner { #![no_main] } | ^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:653:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:769:5 | LL | #[no_main] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:653:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:769:5 | LL | #[no_main] fn f() { } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:657:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:773:5 | LL | #[no_main] struct S; | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:657:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:773:5 | LL | #[no_main] struct S; | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:661:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:777:5 | LL | #[no_main] type T = S; | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:661:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:777:5 | LL | #[no_main] type T = S; | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:665:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:781:5 | LL | #[no_main] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:665:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:781:5 | LL | #[no_main] impl S { } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:645:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:761:1 | LL | #[no_main] | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:645:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:761:1 | LL | #[no_main] | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:687:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:803:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:687:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:803:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:691:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:807:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:691:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:807:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:695:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:811:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:695:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:811:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:699:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:815:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:699:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:815:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:703:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:819:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:703:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:819:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:683:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:799:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:683:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:799:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:828:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:828:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:832:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:832:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:836:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:836:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:840:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:840:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:844:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:844:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:824:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:824:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:40:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:43:1 | LL | #![plugin_registrar] | ^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:50:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:55:1 | LL | #![macro_export] | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:58:1 | LL | #![main] | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:54:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:59:1 | LL | #![start] | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:57:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1 | LL | #![repr()] | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:59:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:64:1 | LL | #![path = "3800"] | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:60:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:65:1 | LL | #![automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:67:1 | LL | #![no_link] | ^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:64:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:69:1 | LL | #![should_panic] | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:65:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:70:1 | LL | #![ignore] | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:71:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:76:1 | LL | #![proc_macro_derive()] | ^^^^^^^^^^^^^^^^^^^^^^^ -warning: 197 warnings emitted +warning: 214 warnings emitted diff --git a/src/test/ui/issues/issue-47725.rs b/src/test/ui/issues/issue-47725.rs index 50f50ed153229..21108da500614 100644 --- a/src/test/ui/issues/issue-47725.rs +++ b/src/test/ui/issues/issue-47725.rs @@ -1,8 +1,14 @@ -#[link_name = "foo"] //~ ERROR attribute should be applied to a foreign function or static +// ignore-tidy-linelength +#![warn(unused_attributes)] //~ NOTE lint level is defined here + +#[link_name = "foo"] +//~^ WARN attribute should be applied to a foreign function or static [unused_attributes] +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! struct Foo; //~ NOTE not a foreign function or static #[link_name = "foobar"] -//~^ ERROR attribute should be applied to a foreign function or static +//~^ WARN attribute should be applied to a foreign function or static [unused_attributes] +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! //~| HELP try `#[link(name = "foobar")]` instead extern "C" { fn foo() -> u32; @@ -12,7 +18,8 @@ extern "C" { #[link_name] //~^ ERROR malformed `link_name` attribute input //~| HELP must be of the form -//~| ERROR attribute should be applied to a foreign function or static +//~| WARN attribute should be applied to a foreign function or static [unused_attributes] +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! //~| HELP try `#[link(name = "...")]` instead extern "C" { fn bar() -> u32; diff --git a/src/test/ui/issues/issue-47725.stderr b/src/test/ui/issues/issue-47725.stderr index 8623317c7a0d4..b1e8d3292eb93 100644 --- a/src/test/ui/issues/issue-47725.stderr +++ b/src/test/ui/issues/issue-47725.stderr @@ -1,19 +1,27 @@ error: malformed `link_name` attribute input - --> $DIR/issue-47725.rs:12:1 + --> $DIR/issue-47725.rs:18:1 | LL | #[link_name] | ^^^^^^^^^^^^ help: must be of the form: `#[link_name = "name"]` -error: attribute should be applied to a foreign function or static - --> $DIR/issue-47725.rs:1:1 +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-47725.rs:4:1 | LL | #[link_name = "foo"] | ^^^^^^^^^^^^^^^^^^^^ +... LL | struct Foo; | ----------- not a foreign function or static + | +note: the lint level is defined here + --> $DIR/issue-47725.rs:2:9 + | +LL | #![warn(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -error: attribute should be applied to a foreign function or static - --> $DIR/issue-47725.rs:4:1 +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-47725.rs:9:1 | LL | #[link_name = "foobar"] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,14 +31,15 @@ LL | | fn foo() -> u32; LL | | } | |_- not a foreign function or static | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! help: try `#[link(name = "foobar")]` instead - --> $DIR/issue-47725.rs:4:1 + --> $DIR/issue-47725.rs:9:1 | LL | #[link_name = "foobar"] | ^^^^^^^^^^^^^^^^^^^^^^^ -error: attribute should be applied to a foreign function or static - --> $DIR/issue-47725.rs:12:1 +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-47725.rs:18:1 | LL | #[link_name] | ^^^^^^^^^^^^ @@ -40,11 +49,12 @@ LL | | fn bar() -> u32; LL | | } | |_- not a foreign function or static | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! help: try `#[link(name = "...")]` instead - --> $DIR/issue-47725.rs:12:1 + --> $DIR/issue-47725.rs:18:1 | LL | #[link_name] | ^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to previous error; 3 warnings emitted diff --git a/src/test/ui/issues/issue-54044.rs b/src/test/ui/issues/issue-54044.rs index eb0cf27ffbb70..3f0b8bc5e384e 100644 --- a/src/test/ui/issues/issue-54044.rs +++ b/src/test/ui/issues/issue-54044.rs @@ -1,7 +1,14 @@ -#[cold] //~ ERROR attribute should be applied to a function +// ignore-tidy-linelength +#![deny(unused_attributes)] //~ NOTE lint level is defined here + +#[cold] +//~^ ERROR attribute should be applied to a function +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! struct Foo; //~ NOTE not a function fn main() { - #[cold] //~ ERROR attribute should be applied to a function + #[cold] + //~^ ERROR attribute should be applied to a function + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! 5; //~ NOTE not a function } diff --git a/src/test/ui/issues/issue-54044.stderr b/src/test/ui/issues/issue-54044.stderr index 2561629260710..a13e84bbee1a6 100644 --- a/src/test/ui/issues/issue-54044.stderr +++ b/src/test/ui/issues/issue-54044.stderr @@ -1,18 +1,29 @@ error: attribute should be applied to a function - --> $DIR/issue-54044.rs:1:1 + --> $DIR/issue-54044.rs:4:1 | LL | #[cold] | ^^^^^^^ +... LL | struct Foo; | ----------- not a function + | +note: the lint level is defined here + --> $DIR/issue-54044.rs:2:9 + | +LL | #![deny(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: attribute should be applied to a function - --> $DIR/issue-54044.rs:5:5 + --> $DIR/issue-54044.rs:10:5 | LL | #[cold] | ^^^^^^^ +... LL | 5; | - not a function + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: aborting due to 2 previous errors diff --git a/src/test/ui/macros/issue-68060.rs b/src/test/ui/macros/issue-68060.rs index 1feddc4ebd89f..78c695d002578 100644 --- a/src/test/ui/macros/issue-68060.rs +++ b/src/test/ui/macros/issue-68060.rs @@ -4,10 +4,13 @@ fn main() { #[target_feature(enable = "")] //~^ ERROR: attribute should be applied to a function //~| ERROR: the feature named `` is not valid for this target + //~| NOTE: `` is not valid for this target #[track_caller] //~^ ERROR: attribute should be applied to function [E0739] //~| ERROR: `#[track_caller]` requires Rust ABI [E0737] |_| (), + //~^ NOTE: not a function + //~| NOTE: not a function ) .next(); } diff --git a/src/test/ui/macros/issue-68060.stderr b/src/test/ui/macros/issue-68060.stderr index 5def8780fbf02..fa236939a40d7 100644 --- a/src/test/ui/macros/issue-68060.stderr +++ b/src/test/ui/macros/issue-68060.stderr @@ -8,7 +8,7 @@ LL | |_| (), | ------ not a function error[E0739]: attribute should be applied to function - --> $DIR/issue-68060.rs:7:13 + --> $DIR/issue-68060.rs:8:13 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ diff --git a/src/test/ui/target-feature/invalid-attribute.rs b/src/test/ui/target-feature/invalid-attribute.rs index 3c2e34bb8c3e1..5ea7821554300 100644 --- a/src/test/ui/target-feature/invalid-attribute.rs +++ b/src/test/ui/target-feature/invalid-attribute.rs @@ -13,6 +13,7 @@ // ignore-sparc64 #![feature(target_feature)] +#![warn(unused_attributes)] #[target_feature = "+sse2"] //~^ ERROR malformed `target_feature` attribute @@ -48,17 +49,20 @@ struct Foo; #[target_feature(enable = "sse2")] //~^ ERROR attribute should be applied to a function -enum Bar { } +enum Bar {} //~^ NOTE not a function #[target_feature(enable = "sse2")] //~^ ERROR attribute should be applied to a function -union Qux { f1: u16, f2: u16 } +union Qux { //~^ NOTE not a function + f1: u16, + f2: u16, +} #[target_feature(enable = "sse2")] //~^ ERROR attribute should be applied to a function -trait Baz { } +trait Baz {} //~^ NOTE not a function #[inline(always)] diff --git a/src/test/ui/target-feature/invalid-attribute.stderr b/src/test/ui/target-feature/invalid-attribute.stderr index c06538c5b8fe7..8c8e24ccc55cc 100644 --- a/src/test/ui/target-feature/invalid-attribute.stderr +++ b/src/test/ui/target-feature/invalid-attribute.stderr @@ -1,29 +1,29 @@ error: malformed `target_feature` attribute input - --> $DIR/invalid-attribute.rs:17:1 + --> $DIR/invalid-attribute.rs:18:1 | LL | #[target_feature = "+sse2"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[target_feature(enable = "name")]` error: the feature named `foo` is not valid for this target - --> $DIR/invalid-attribute.rs:19:18 + --> $DIR/invalid-attribute.rs:20:18 | LL | #[target_feature(enable = "foo")] | ^^^^^^^^^^^^^^ `foo` is not valid for this target error: malformed `target_feature` attribute input - --> $DIR/invalid-attribute.rs:22:18 + --> $DIR/invalid-attribute.rs:23:18 | LL | #[target_feature(bar)] | ^^^ help: must be of the form: `enable = ".."` error: malformed `target_feature` attribute input - --> $DIR/invalid-attribute.rs:24:18 + --> $DIR/invalid-attribute.rs:25:18 | LL | #[target_feature(disable = "baz")] | ^^^^^^^^^^^^^^^ help: must be of the form: `enable = ".."` error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions - --> $DIR/invalid-attribute.rs:28:1 + --> $DIR/invalid-attribute.rs:29:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | fn bar() {} = help: add `#![feature(target_feature_11)]` to the crate attributes to enable error: attribute should be applied to a function - --> $DIR/invalid-attribute.rs:34:1 + --> $DIR/invalid-attribute.rs:35:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | mod another {} | -------------- not a function error: attribute should be applied to a function - --> $DIR/invalid-attribute.rs:39:1 + --> $DIR/invalid-attribute.rs:40:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -53,7 +53,7 @@ LL | const FOO: usize = 7; | --------------------- not a function error: attribute should be applied to a function - --> $DIR/invalid-attribute.rs:44:1 + --> $DIR/invalid-attribute.rs:45:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -62,40 +62,44 @@ LL | struct Foo; | ----------- not a function error: attribute should be applied to a function - --> $DIR/invalid-attribute.rs:49:1 + --> $DIR/invalid-attribute.rs:50:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | -LL | enum Bar { } - | ------------ not a function +LL | enum Bar {} + | ----------- not a function error: attribute should be applied to a function - --> $DIR/invalid-attribute.rs:54:1 + --> $DIR/invalid-attribute.rs:55:1 | -LL | #[target_feature(enable = "sse2")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | -LL | union Qux { f1: u16, f2: u16 } - | ------------------------------ not a function +LL | / union Qux { +LL | | +LL | | f1: u16, +LL | | f2: u16, +LL | | } + | |_- not a function error: attribute should be applied to a function - --> $DIR/invalid-attribute.rs:59:1 + --> $DIR/invalid-attribute.rs:63:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | -LL | trait Baz { } - | ------------- not a function +LL | trait Baz {} + | ------------ not a function error: cannot use `#[inline(always)]` with `#[target_feature]` - --> $DIR/invalid-attribute.rs:64:1 + --> $DIR/invalid-attribute.rs:68:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ error: attribute should be applied to a function - --> $DIR/invalid-attribute.rs:82:5 + --> $DIR/invalid-attribute.rs:86:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -107,7 +111,7 @@ LL | | } | |_____- not a function error: attribute should be applied to a function - --> $DIR/invalid-attribute.rs:90:5 + --> $DIR/invalid-attribute.rs:94:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -116,7 +120,7 @@ LL | || {}; | ----- not a function error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions - --> $DIR/invalid-attribute.rs:74:5 + --> $DIR/invalid-attribute.rs:78:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 0c62ef08bd1a1860c4d6d1c22489d287a9359129 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Wed, 12 Aug 2020 12:43:14 -0400 Subject: [PATCH 0141/1052] Allow #[cold], #[track_caller] on closures. Fix whitespace in error messages. --- compiler/rustc_passes/src/check_attr.rs | 26 ++++++++++++------------- src/test/ui/macros/issue-68060.rs | 4 +--- src/test/ui/macros/issue-68060.stderr | 14 ++----------- 3 files changed, 16 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index fdb1f24de263d..5fb59012fb719 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -121,12 +121,12 @@ impl CheckAttrVisitor<'tcx> { lint.build("`#[inline]` is ignored on constants") .warn( "this was previously accepted by the compiler but is \ - being phased out; it will become a hard error in \ - a future release!", + being phased out; it will become a hard error in \ + a future release!", ) .note( "see issue #65833 \ - for more information", + for more information", ) .emit(); }); @@ -165,7 +165,7 @@ impl CheckAttrVisitor<'tcx> { .emit(); false } - Target::Fn | Target::Method(..) | Target::ForeignFn => true, + Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => true, _ => { struct_span_err!( self.tcx.sess, @@ -231,8 +231,8 @@ impl CheckAttrVisitor<'tcx> { lint.build("attribute should be applied to a function") .warn( "this was previously accepted by the compiler but is \ - being phased out; it will become a hard error in \ - a future release!", + being phased out; it will become a hard error in \ + a future release!", ) .span_label(*span, "not a function") .emit(); @@ -313,7 +313,7 @@ impl CheckAttrVisitor<'tcx> { /// Checks if `#[cold]` is applied to a non-function. Returns `true` if valid. fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) { match target { - Target::Fn | Target::Method(..) | Target::ForeignFn => {} + Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => {} _ => { // FIXME: #[cold] was previously allowed on non-functions and some crates used // this, so only emit a warning. @@ -321,8 +321,8 @@ impl CheckAttrVisitor<'tcx> { lint.build("attribute should be applied to a function") .warn( "this was previously accepted by the compiler but is \ - being phased out; it will become a hard error in \ - a future release!", + being phased out; it will become a hard error in \ + a future release!", ) .span_label(*span, "not a function") .emit(); @@ -343,8 +343,8 @@ impl CheckAttrVisitor<'tcx> { lint.build("attribute should be applied to a foreign function or static"); diag.warn( "this was previously accepted by the compiler but is \ - being phased out; it will become a hard error in \ - a future release!", + being phased out; it will become a hard error in \ + a future release!", ); // See issue #47725 @@ -409,8 +409,8 @@ impl CheckAttrVisitor<'tcx> { lint.build("attribute should be applied to a function or static") .warn( "this was previously accepted by the compiler but is \ - being phased out; it will become a hard error in \ - a future release!", + being phased out; it will become a hard error in \ + a future release!", ) .span_label(*span, "not a function or static") .emit(); diff --git a/src/test/ui/macros/issue-68060.rs b/src/test/ui/macros/issue-68060.rs index 78c695d002578..f82eb338f4c68 100644 --- a/src/test/ui/macros/issue-68060.rs +++ b/src/test/ui/macros/issue-68060.rs @@ -6,11 +6,9 @@ fn main() { //~| ERROR: the feature named `` is not valid for this target //~| NOTE: `` is not valid for this target #[track_caller] - //~^ ERROR: attribute should be applied to function [E0739] - //~| ERROR: `#[track_caller]` requires Rust ABI [E0737] + //~^ ERROR: `#[track_caller]` requires Rust ABI [E0737] |_| (), //~^ NOTE: not a function - //~| NOTE: not a function ) .next(); } diff --git a/src/test/ui/macros/issue-68060.stderr b/src/test/ui/macros/issue-68060.stderr index fa236939a40d7..a01c3827bb5a5 100644 --- a/src/test/ui/macros/issue-68060.stderr +++ b/src/test/ui/macros/issue-68060.stderr @@ -7,15 +7,6 @@ LL | #[target_feature(enable = "")] LL | |_| (), | ------ not a function -error[E0739]: attribute should be applied to function - --> $DIR/issue-68060.rs:8:13 - | -LL | #[track_caller] - | ^^^^^^^^^^^^^^^ -... -LL | |_| (), - | ------ not a function - error: the feature named `` is not valid for this target --> $DIR/issue-68060.rs:4:30 | @@ -28,7 +19,6 @@ error[E0737]: `#[track_caller]` requires Rust ABI LL | #[track_caller] | ^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0737, E0739. -For more information about an error, try `rustc --explain E0737`. +For more information about this error, try `rustc --explain E0737`. From acd68b503d033e0fc94fb5e68cb06ce369b6bd63 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Sat, 5 Sep 2020 21:29:54 -0400 Subject: [PATCH 0142/1052] Fix broken test on musl --- src/test/ui/check-static-recursion-foreign.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/test/ui/check-static-recursion-foreign.rs b/src/test/ui/check-static-recursion-foreign.rs index 536d7933d3e51..3072deb6c5a3d 100644 --- a/src/test/ui/check-static-recursion-foreign.rs +++ b/src/test/ui/check-static-recursion-foreign.rs @@ -1,6 +1,5 @@ // run-pass -#![allow(dead_code)] // Static recursion check shouldn't fail when given a foreign item (#18279) // aux-build:check_static_recursion_foreign_helper.rs @@ -15,12 +14,10 @@ extern crate libc; use libc::c_int; -#[link(name = "check_static_recursion_foreign_helper")] extern "C" { - #[allow(dead_code)] static test_static: c_int; } -static B: &'static c_int = unsafe { &test_static }; +pub static B: &'static c_int = unsafe { &test_static }; pub fn main() {} From 8f69266f799c2fc33a871c41f72a1d79eef4126e Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Sat, 5 Sep 2020 22:12:24 -0400 Subject: [PATCH 0143/1052] Emit warnings on misplaced #[no_mangle] --- compiler/rustc_passes/src/check_attr.rs | 23 ++ .../issue-43106-gating-of-builtin-attrs.rs | 15 + ...issue-43106-gating-of-builtin-attrs.stderr | 325 ++++++++++-------- 3 files changed, 225 insertions(+), 138 deletions(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 5fb59012fb719..efe947daa2866 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -83,6 +83,8 @@ impl CheckAttrVisitor<'tcx> { self.check_link_name(hir_id, attr, span, target); } else if self.tcx.sess.check_name(attr, sym::link_section) { self.check_link_section(hir_id, attr, span, target); + } else if self.tcx.sess.check_name(attr, sym::no_mangle) { + self.check_no_mangle(hir_id, attr, span, target); } true }; @@ -419,6 +421,27 @@ impl CheckAttrVisitor<'tcx> { } } + /// Checks if `#[no_mangle]` is applied to a function or static. + fn check_no_mangle(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) { + match target { + Target::Static | Target::Fn | Target::Method(..) => {} + _ => { + // FIXME: #[no_mangle] was previously allowed on non-functions/statics and some + // crates used this, so only emit a warning. + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build("attribute should be applied to a function or static") + .warn( + "this was previously accepted by the compiler but is \ + being phased out; it will become a hard error in \ + a future release!", + ) + .span_label(*span, "not a function or static") + .emit(); + }); + } + } + } + /// Checks if the `#[repr]` attributes on `item` are valid. fn check_repr( &self, diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs index d6a3ffd566f75..f94434f459df9 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs @@ -372,16 +372,31 @@ mod automatically_derived { } #[no_mangle] +//~^ WARN attribute should be applied to a function or static [unused_attributes] +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! mod no_mangle { + //~^ NOTE not a function or static mod inner { #![no_mangle] } + //~^ WARN attribute should be applied to a function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function or static #[no_mangle] fn f() { } #[no_mangle] struct S; + //~^ WARN attribute should be applied to a function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function or static #[no_mangle] type T = S; + //~^ WARN attribute should be applied to a function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function or static #[no_mangle] impl S { } + //~^ WARN attribute should be applied to a function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function or static } #[should_panic] diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr index 05a9c0e975fa0..461c1bd610794 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr @@ -173,13 +173,13 @@ LL | #[deny(x5100)] impl S { } | ^^^^^ warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:464:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:479:1 | LL | #[macro_escape] | ^^^^^^^^^^^^^^^ warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:467:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:482:17 | LL | mod inner { #![macro_escape] } | ^^^^^^^^^^^^^^^^ @@ -236,8 +236,30 @@ warning: use of deprecated attribute `no_start`: no longer used. LL | #![no_start] | ^^^^^^^^^^^^ help: remove this attribute +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:374:1 + | +LL | #[no_mangle] + | ^^^^^^^^^^^^ +... +LL | / mod no_mangle { +LL | | +LL | | mod inner { #![no_mangle] } +LL | | +... | +LL | | +LL | | } + | |_- not a function or static + | +note: the lint level is defined here + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:37:9 + | +LL | #![warn(unused_attributes, unknown_lints)] + | ^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + warning: attribute should be applied to a function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:526:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:541:1 | LL | #[cold] | ^^^^^^^ @@ -251,15 +273,10 @@ LL | | LL | | } | |_- not a function | -note: the lint level is defined here - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:37:9 - | -LL | #![warn(unused_attributes, unknown_lints)] - | ^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:555:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:570:1 | LL | #[link_name = "1900"] | ^^^^^^^^^^^^^^^^^^^^^ @@ -276,7 +293,7 @@ LL | | } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:594:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:609:1 | LL | #[link_section = "1800"] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -292,8 +309,40 @@ LL | | } | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:379:17 + | +LL | mod inner { #![no_mangle] } + | ------------^^^^^^^^^^^^^-- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:386:5 + | +LL | #[no_mangle] struct S; + | ^^^^^^^^^^^^ --------- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:391:5 + | +LL | #[no_mangle] type T = S; + | ^^^^^^^^^^^^ ----------- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:396:5 + | +LL | #[no_mangle] impl S { } + | ^^^^^^^^^^^^ ---------- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + warning: attribute should be applied to a function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:532:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:547:17 | LL | mod inner { #![cold] } | ------------^^^^^^^^-- not a function @@ -301,7 +350,7 @@ LL | mod inner { #![cold] } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:539:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:554:5 | LL | #[cold] struct S; | ^^^^^^^ --------- not a function @@ -309,7 +358,7 @@ LL | #[cold] struct S; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:544:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:559:5 | LL | #[cold] type T = S; | ^^^^^^^ ----------- not a function @@ -317,7 +366,7 @@ LL | #[cold] type T = S; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:549:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:564:5 | LL | #[cold] impl S { } | ^^^^^^^ ---------- not a function @@ -325,7 +374,7 @@ LL | #[cold] impl S { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:561:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:576:5 | LL | #[link_name = "1900"] | ^^^^^^^^^^^^^^^^^^^^^ @@ -335,13 +384,13 @@ LL | extern { } | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! help: try `#[link(name = "1900")]` instead - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:561:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:576:5 | LL | #[link_name = "1900"] | ^^^^^^^^^^^^^^^^^^^^^ warning: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:568:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:583:17 | LL | mod inner { #![link_name="1900"] } | ------------^^^^^^^^^^^^^^^^^^^^-- not a foreign function or static @@ -349,7 +398,7 @@ LL | mod inner { #![link_name="1900"] } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:573:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:588:5 | LL | #[link_name = "1900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static @@ -357,7 +406,7 @@ LL | #[link_name = "1900"] fn f() { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:578:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:593:5 | LL | #[link_name = "1900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^ --------- not a foreign function or static @@ -365,7 +414,7 @@ LL | #[link_name = "1900"] struct S; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:583:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:598:5 | LL | #[link_name = "1900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^ ----------- not a foreign function or static @@ -373,7 +422,7 @@ LL | #[link_name = "1900"] type T = S; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:588:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:603:5 | LL | #[link_name = "1900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static @@ -381,7 +430,7 @@ LL | #[link_name = "1900"] impl S { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:600:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:615:17 | LL | mod inner { #![link_section="1800"] } | ------------^^^^^^^^^^^^^^^^^^^^^^^-- not a function or static @@ -389,7 +438,7 @@ LL | mod inner { #![link_section="1800"] } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:607:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:622:5 | LL | #[link_section = "1800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^ --------- not a function or static @@ -397,7 +446,7 @@ LL | #[link_section = "1800"] struct S; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:612:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:627:5 | LL | #[link_section = "1800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a function or static @@ -405,7 +454,7 @@ LL | #[link_section = "1800"] type T = S; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:617:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:632:5 | LL | #[link_section = "1800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a function or static @@ -631,673 +680,673 @@ LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:390:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:405:17 | LL | mod inner { #![should_panic] } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:393:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:408:5 | LL | #[should_panic] fn f() { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:396:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:411:5 | LL | #[should_panic] struct S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:399:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:414:5 | LL | #[should_panic] type T = S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:402:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:417:5 | LL | #[should_panic] impl S { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:387:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:402:1 | LL | #[should_panic] | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:409:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:424:17 | LL | mod inner { #![ignore] } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:412:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:427:5 | LL | #[ignore] fn f() { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:415:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:430:5 | LL | #[ignore] struct S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:418:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:433:5 | LL | #[ignore] type T = S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:421:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:436:5 | LL | #[ignore] impl S { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:406:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:421:1 | LL | #[ignore] | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:428:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:443:17 | LL | mod inner { #![no_implicit_prelude] } | ^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:431:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:446:5 | LL | #[no_implicit_prelude] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:434:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:449:5 | LL | #[no_implicit_prelude] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:437:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:452:5 | LL | #[no_implicit_prelude] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:440:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:455:5 | LL | #[no_implicit_prelude] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:425:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:440:1 | LL | #[no_implicit_prelude] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:447:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:462:17 | LL | mod inner { #![reexport_test_harness_main="2900"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:450:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:465:5 | LL | #[reexport_test_harness_main = "2900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:453:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:468:5 | LL | #[reexport_test_harness_main = "2900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:456:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:471:5 | LL | #[reexport_test_harness_main = "2900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:459:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:474:5 | LL | #[reexport_test_harness_main = "2900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:444:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:459:1 | LL | #[reexport_test_harness_main = "2900"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:471:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:486:5 | LL | #[macro_escape] fn f() { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:474:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:489:5 | LL | #[macro_escape] struct S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:477:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:492:5 | LL | #[macro_escape] type T = S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:480:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:495:5 | LL | #[macro_escape] impl S { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:488:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:503:17 | LL | mod inner { #![no_std] } | ^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:488:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:503:17 | LL | mod inner { #![no_std] } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:492:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:507:5 | LL | #[no_std] fn f() { } | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:492:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:507:5 | LL | #[no_std] fn f() { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:496:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:511:5 | LL | #[no_std] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:496:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:511:5 | LL | #[no_std] struct S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:500:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:515:5 | LL | #[no_std] type T = S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:500:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:515:5 | LL | #[no_std] type T = S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:504:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:519:5 | LL | #[no_std] impl S { } | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:504:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:519:5 | LL | #[no_std] impl S { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:484:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:499:1 | LL | #[no_std] | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:484:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:499:1 | LL | #[no_std] | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:689:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:689:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:693:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:693:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:697:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:697:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:705:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:705:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:714:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:714:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:733:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:733:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:722:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:722:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:741:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:741:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:730:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:745:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:730:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:745:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:739:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:754:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:739:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:754:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:743:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:743:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:747:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:747:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:751:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:766:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:751:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:766:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:755:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:755:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:735:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:735:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:765:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:780:17 | LL | mod inner { #![no_main] } | ^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:765:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:780:17 | LL | mod inner { #![no_main] } | ^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:769:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:784:5 | LL | #[no_main] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:769:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:784:5 | LL | #[no_main] fn f() { } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:773:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:788:5 | LL | #[no_main] struct S; | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:773:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:788:5 | LL | #[no_main] struct S; | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:777:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:792:5 | LL | #[no_main] type T = S; | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:777:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:792:5 | LL | #[no_main] type T = S; | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:781:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:796:5 | LL | #[no_main] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:781:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:796:5 | LL | #[no_main] impl S { } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:761:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:776:1 | LL | #[no_main] | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:761:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:776:1 | LL | #[no_main] | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:803:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:818:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:803:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:818:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:807:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:822:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:807:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:822:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:811:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:826:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:811:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:826:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:815:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:830:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:815:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:830:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:819:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:834:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:819:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:834:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:799:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:814:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:799:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:814:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:828:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:843:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:828:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:843:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:832:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:847:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:832:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:847:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:836:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:851:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:836:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:851:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:840:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:855:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:840:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:855:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:844:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:859:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:844:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:859:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:824:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:839:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:824:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:839:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1368,5 +1417,5 @@ warning: unused attribute LL | #![proc_macro_derive()] | ^^^^^^^^^^^^^^^^^^^^^^^ -warning: 214 warnings emitted +warning: 219 warnings emitted From 685f04220ee584f00f60e5ff9d7aca16351c5399 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Sun, 6 Sep 2020 12:00:22 +0800 Subject: [PATCH 0144/1052] Clean up vec benches bench_in_place style --- library/alloc/benches/vec.rs | 43 ++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/library/alloc/benches/vec.rs b/library/alloc/benches/vec.rs index 5ba3e0e00572c..6703a99b15155 100644 --- a/library/alloc/benches/vec.rs +++ b/library/alloc/benches/vec.rs @@ -457,9 +457,7 @@ fn bench_clone_from_10_1000_0100(b: &mut Bencher) { } macro_rules! bench_in_place { - ( - $($fname:ident, $type:ty , $count:expr, $init: expr);* - ) => { + ($($fname:ident, $type:ty, $count:expr, $init:expr);*) => { $( #[bench] fn $fname(b: &mut Bencher) { @@ -467,7 +465,8 @@ macro_rules! bench_in_place { let src: Vec<$type> = black_box(vec![$init; $count]); let mut sink = src.into_iter() .enumerate() - .map(|(idx, e)| { (idx as $type) ^ e }).collect::>(); + .map(|(idx, e)| idx as $type ^ e) + .collect::>(); black_box(sink.as_mut_ptr()) }); } @@ -476,24 +475,24 @@ macro_rules! bench_in_place { } bench_in_place![ - bench_in_place_xxu8_i0_0010, u8, 10, 0; - bench_in_place_xxu8_i0_0100, u8, 100, 0; - bench_in_place_xxu8_i0_1000, u8, 1000, 0; - bench_in_place_xxu8_i1_0010, u8, 10, 1; - bench_in_place_xxu8_i1_0100, u8, 100, 1; - bench_in_place_xxu8_i1_1000, u8, 1000, 1; - bench_in_place_xu32_i0_0010, u32, 10, 0; - bench_in_place_xu32_i0_0100, u32, 100, 0; - bench_in_place_xu32_i0_1000, u32, 1000, 0; - bench_in_place_xu32_i1_0010, u32, 10, 1; - bench_in_place_xu32_i1_0100, u32, 100, 1; - bench_in_place_xu32_i1_1000, u32, 1000, 1; - bench_in_place_u128_i0_0010, u128, 10, 0; - bench_in_place_u128_i0_0100, u128, 100, 0; - bench_in_place_u128_i0_1000, u128, 1000, 0; - bench_in_place_u128_i1_0010, u128, 10, 1; - bench_in_place_u128_i1_0100, u128, 100, 1; - bench_in_place_u128_i1_1000, u128, 1000, 1 + bench_in_place_xxu8_0010_i0, u8, 10, 0; + bench_in_place_xxu8_0100_i0, u8, 100, 0; + bench_in_place_xxu8_1000_i0, u8, 1000, 0; + bench_in_place_xxu8_0010_i1, u8, 10, 1; + bench_in_place_xxu8_0100_i1, u8, 100, 1; + bench_in_place_xxu8_1000_i1, u8, 1000, 1; + bench_in_place_xu32_0010_i0, u32, 10, 0; + bench_in_place_xu32_0100_i0, u32, 100, 0; + bench_in_place_xu32_1000_i0, u32, 1000, 0; + bench_in_place_xu32_0010_i1, u32, 10, 1; + bench_in_place_xu32_0100_i1, u32, 100, 1; + bench_in_place_xu32_1000_i1, u32, 1000, 1; + bench_in_place_u128_0010_i0, u128, 10, 0; + bench_in_place_u128_0100_i0, u128, 100, 0; + bench_in_place_u128_1000_i0, u128, 1000, 0; + bench_in_place_u128_0010_i1, u128, 10, 1; + bench_in_place_u128_0100_i1, u128, 100, 1; + bench_in_place_u128_1000_i1, u128, 1000, 1 ]; #[bench] From 78097d96828c16a259fa9b5c2430e8d9ff1820b3 Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Sun, 6 Sep 2020 19:24:37 +0200 Subject: [PATCH 0145/1052] initial attempt to add aarch64-unknown-linux-musl to dist-linux-arm --- .../host-x86_64/dist-arm-linux/Dockerfile | 13 +++++++++++-- .../dist-arm-linux/arm-linux-gnueabi.config | 17 ++--------------- src/tools/build-manifest/src/main.rs | 1 + 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile index ba93f6ad82403..88b13eab2d08c 100644 --- a/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile @@ -6,6 +6,14 @@ RUN sh /scripts/cross-apt-packages.sh COPY scripts/crosstool-ng-1.24.sh /scripts/ RUN sh /scripts/crosstool-ng-1.24.sh +WORKDIR /build + +COPY scripts/musl-toolchain.sh /build/ +# We need to mitigate rust-lang/rust#34978 when compiling musl itself as well +RUN CFLAGS="-Wa,--compress-debug-sections=none -Wl,--compress-debug-sections=none" \ + CXXFLAGS="-Wa,--compress-debug-sections=none -Wl,--compress-debug-sections=none" \ + bash musl-toolchain.sh aarch64 && rm -rf build + COPY scripts/rustbuild-setup.sh /scripts/ RUN sh /scripts/rustbuild-setup.sh USER rustbuild @@ -25,7 +33,8 @@ ENV CC_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-gcc \ AR_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-ar \ CXX_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-g++ -ENV HOSTS=arm-unknown-linux-gnueabi +ENV HOSTS=arm-unknown-linux-gnueabi,aarch64-unknown-linux-musl -ENV RUST_CONFIGURE_ARGS --enable-full-tools --disable-docs +ENV RUST_CONFIGURE_ARGS --enable-full-tools --disable-docs --musl-root-aarch64=/usr/local/aarch64-linux-musl \ + --set target.aarch64-unknown-linux-musl.crt-static=false ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/host-x86_64/dist-arm-linux/arm-linux-gnueabi.config b/src/ci/docker/host-x86_64/dist-arm-linux/arm-linux-gnueabi.config index 1dcdbd1a9008b..66709a4004caf 100644 --- a/src/ci/docker/host-x86_64/dist-arm-linux/arm-linux-gnueabi.config +++ b/src/ci/docker/host-x86_64/dist-arm-linux/arm-linux-gnueabi.config @@ -14,6 +14,7 @@ CT_CONFIGURE_has_autoconf_2_65_or_newer=y CT_CONFIGURE_has_autoreconf_2_65_or_newer=y CT_CONFIGURE_has_automake_1_15_or_newer=y CT_CONFIGURE_has_gnu_m4_1_4_12_or_newer=y +CT_CONFIGURE_has_python_3_4_or_newer=y CT_CONFIGURE_has_bison_2_7_or_newer=y CT_CONFIGURE_has_python=y CT_CONFIGURE_has_git=y @@ -132,12 +133,6 @@ CT_ARCH_ARM=y # CT_ARCH_XTENSA is not set CT_ARCH="arm" CT_ARCH_CHOICE_KSYM="ARM" -# CT_ARCH_ALPHA_EV4 is not set -# CT_ARCH_ALPHA_EV45 is not set -# CT_ARCH_ALPHA_EV5 is not set -# CT_ARCH_ALPHA_EV56 is not set -# CT_ARCH_ALPHA_EV6 is not set -# CT_ARCH_ALPHA_EV67 is not set CT_ARCH_CPU="" CT_ARCH_TUNE="" CT_ARCH_ARM_SHOW=y @@ -371,8 +366,6 @@ CT_ALL_BINUTILS_CHOICES="BINUTILS" # C-library # CT_LIBC_GLIBC=y -# CT_LIBC_NEWLIB is not set -# CT_LIBC_NONE is not set # CT_LIBC_UCLIBC is not set CT_LIBC="glibc" CT_LIBC_CHOICE_KSYM="GLIBC" @@ -389,6 +382,7 @@ CT_GLIBC_USE="GLIBC" CT_GLIBC_PKG_NAME="glibc" CT_GLIBC_SRC_RELEASE=y CT_GLIBC_PATCH_ORDER="global" +# CT_GLIBC_V_2_29 is not set # CT_GLIBC_V_2_28 is not set # CT_GLIBC_V_2_27 is not set # CT_GLIBC_V_2_26 is not set @@ -407,7 +401,6 @@ CT_GLIBC_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz" CT_GLIBC_SIGNATURE_FORMAT="packed/.sig" CT_GLIBC_2_29_or_older=y CT_GLIBC_older_than_2_29=y -CT_GLIBC_REQUIRE_older_than_2_29=y CT_GLIBC_2_27_or_older=y CT_GLIBC_older_than_2_27=y CT_GLIBC_2_26_or_older=y @@ -447,12 +440,6 @@ CT_GLIBC_FORCE_UNWIND=y CT_GLIBC_KERNEL_VERSION_AS_HEADERS=y # CT_GLIBC_KERNEL_VERSION_CHOSEN is not set CT_GLIBC_MIN_KERNEL="3.2.101" -# CT_GLIBC_SSP_DEFAULT is not set -# CT_GLIBC_SSP_NO is not set -# CT_GLIBC_SSP_YES is not set -# CT_GLIBC_SSP_ALL is not set -# CT_GLIBC_SSP_STRONG is not set -# CT_NEWLIB_USE_REDHAT is not set CT_ALL_LIBC_CHOICES="AVR_LIBC BIONIC GLIBC MINGW_W64 MOXIEBOX MUSL NEWLIB NONE UCLIBC" CT_LIBC_SUPPORT_THREADS_ANY=y CT_LIBC_SUPPORT_THREADS_NATIVE=y diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 58022484fa6cc..ff9ee67763ba5 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -16,6 +16,7 @@ use std::process::{Command, Stdio}; static HOSTS: &[&str] = &[ "aarch64-unknown-linux-gnu", + "aarch64-unknown-linux-musl", "arm-unknown-linux-gnueabi", "arm-unknown-linux-gnueabihf", "armv7-unknown-linux-gnueabihf", From 77d11c3ce2976adaee83cf5b9f60449467557868 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 4 Sep 2020 20:54:07 +0300 Subject: [PATCH 0146/1052] rustbuild: Build tests with LLD if `use-lld = true` was passed --- src/bootstrap/builder.rs | 6 +++--- src/bootstrap/lib.rs | 11 ++++------- src/bootstrap/test.rs | 5 ++--- src/test/run-make-fulldeps/tools.mk | 4 ++-- 4 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 4708b207156c9..33b03d57dd43c 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -755,7 +755,7 @@ impl<'a> Builder<'a> { cmd.env_remove("MAKEFLAGS"); cmd.env_remove("MFLAGS"); - if let Some(linker) = self.linker(compiler.host, true) { + if let Some(linker) = self.linker(compiler.host) { cmd.env("RUSTC_TARGET_LINKER", linker); } cmd @@ -1041,11 +1041,11 @@ impl<'a> Builder<'a> { } } - if let Some(host_linker) = self.linker(compiler.host, true) { + if let Some(host_linker) = self.linker(compiler.host) { cargo.env("RUSTC_HOST_LINKER", host_linker); } - if let Some(target_linker) = self.linker(target, true) { + if let Some(target_linker) = self.linker(target) { let target = crate::envify(&target.triple); cargo.env(&format!("CARGO_TARGET_{}_LINKER", target), target_linker); } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 1b655f55fb071..642f1ea9c0095 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -850,7 +850,7 @@ impl Build { } /// Returns the path to the linker for the given target if it needs to be overridden. - fn linker(&self, target: TargetSelection, can_use_lld: bool) -> Option<&Path> { + fn linker(&self, target: TargetSelection) -> Option<&Path> { if let Some(linker) = self.config.target_config.get(&target).and_then(|c| c.linker.as_ref()) { Some(linker) @@ -863,12 +863,9 @@ impl Build { && !target.contains("msvc") { Some(self.cc(target)) - } else if target.contains("msvc") - && can_use_lld - && self.config.use_lld - && self.build == target - { - // Currently we support using LLD directly via `rust.use_lld` option only with MSVC + } else if target.contains("msvc") && self.config.use_lld && self.build == target { + // `rust.use_lld` means using LLD directly only for MSVC, for other targets it only + // adds `-fuse-ld=lld` to already selected linker. Some(&self.initial_lld) } else { None diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index a7c9b99f45f3d..f7eb2aecc0dc8 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -600,7 +600,7 @@ impl Step for RustdocTheme { .env("CFG_RELEASE_CHANNEL", &builder.config.channel) .env("RUSTDOC_REAL", builder.rustdoc(self.compiler)) .env("RUSTC_BOOTSTRAP", "1"); - if let Some(linker) = builder.linker(self.compiler.host, true) { + if let Some(linker) = builder.linker(self.compiler.host) { cmd.env("RUSTC_TARGET_LINKER", linker); } try_run(builder, &mut cmd); @@ -1061,8 +1061,7 @@ impl Step for Compiletest { flags.push("-Zunstable-options".to_string()); flags.push(builder.config.cmd.rustc_args().join(" ")); - // Don't use LLD here since we want to test that rustc finds and uses a linker by itself. - if let Some(linker) = builder.linker(target, false) { + if let Some(linker) = builder.linker(target) { cmd.arg("--linker").arg(linker); } diff --git a/src/test/run-make-fulldeps/tools.mk b/src/test/run-make-fulldeps/tools.mk index f9b6d34229593..634c9ece3f5c8 100644 --- a/src/test/run-make-fulldeps/tools.mk +++ b/src/test/run-make-fulldeps/tools.mk @@ -11,8 +11,8 @@ BARE_RUSTDOC := $(HOST_RPATH_ENV) '$(RUSTDOC)' RUSTC := $(BARE_RUSTC) --out-dir $(TMPDIR) -L $(TMPDIR) $(RUSTFLAGS) RUSTDOC := $(BARE_RUSTDOC) -L $(TARGET_RPATH_DIR) ifdef RUSTC_LINKER -RUSTC := $(RUSTC) -Clinker=$(RUSTC_LINKER) -RUSTDOC := $(RUSTDOC) -Clinker=$(RUSTC_LINKER) +RUSTC := $(RUSTC) -Clinker='$(RUSTC_LINKER)' +RUSTDOC := $(RUSTDOC) -Clinker='$(RUSTC_LINKER)' endif #CC := $(CC) -L $(TMPDIR) HTMLDOCCK := '$(PYTHON)' '$(S)/src/etc/htmldocck.py' From 8e6b563b934c0f5b57b38c57efdd005ed100d64c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 6 Sep 2020 20:44:50 +0300 Subject: [PATCH 0147/1052] rustbuild: Build tests with LLD if `use-lld = true` was passed (non-msvc) --- src/bootstrap/test.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index f7eb2aecc0dc8..f56c994523c13 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1067,10 +1067,16 @@ impl Step for Compiletest { let mut hostflags = flags.clone(); hostflags.push(format!("-Lnative={}", builder.test_helpers_out(compiler.host).display())); + if builder.config.use_lld && !compiler.host.triple.contains("msvc") { + hostflags.push("-Clink-args=-fuse-ld=lld".to_string()); + } cmd.arg("--host-rustcflags").arg(hostflags.join(" ")); let mut targetflags = flags; targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display())); + if builder.config.use_lld && !target.contains("msvc") { + targetflags.push("-Clink-args=-fuse-ld=lld".to_string()); + } cmd.arg("--target-rustcflags").arg(targetflags.join(" ")); cmd.arg("--docck-python").arg(builder.python()); From 5118a51b4d49a139ea21d280001105948de298f7 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 6 Sep 2020 22:07:14 +0300 Subject: [PATCH 0148/1052] rustbuild: Propagate LLD to more places when `use-lld` is enabled --- src/bootstrap/bin/rustc.rs | 3 +++ src/bootstrap/bin/rustdoc.rs | 5 ++++- src/bootstrap/builder.rs | 8 +++++++- src/bootstrap/test.rs | 5 ++++- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 4dd71ebade1a4..3694bdbf67054 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -112,6 +112,9 @@ fn main() { if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") { cmd.arg(format!("-Clinker={}", host_linker)); } + if env::var_os("RUSTC_HOST_FUSE_LD_LLD").is_some() { + cmd.arg("-Clink-args=-fuse-ld=lld"); + } if let Ok(s) = env::var("RUSTC_HOST_CRT_STATIC") { if s == "true" { diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index ab846adf9423b..cb58eb89ad870 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -42,11 +42,14 @@ fn main() { if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() { cmd.arg("-Z").arg("force-unstable-if-unmarked"); } - if let Some(linker) = env::var_os("RUSTC_TARGET_LINKER") { + if let Some(linker) = env::var_os("RUSTDOC_LINKER") { let mut arg = OsString::from("-Clinker="); arg.push(&linker); cmd.arg(arg); } + if env::var_os("RUSTDOC_FUSE_LD_LLD").is_some() { + cmd.arg("-Clink-args=-fuse-ld=lld"); + } // Needed to be able to run all rustdoc tests. if let Some(ref x) = env::var_os("RUSTDOC_RESOURCE_SUFFIX") { diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 33b03d57dd43c..ca2e159d2d948 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -756,7 +756,10 @@ impl<'a> Builder<'a> { cmd.env_remove("MFLAGS"); if let Some(linker) = self.linker(compiler.host) { - cmd.env("RUSTC_TARGET_LINKER", linker); + cmd.env("RUSTDOC_LINKER", linker); + } + if self.config.use_lld && !compiler.host.contains("msvc") { + cmd.env("RUSTDOC_FUSE_LD_LLD", "1"); } cmd } @@ -1044,6 +1047,9 @@ impl<'a> Builder<'a> { if let Some(host_linker) = self.linker(compiler.host) { cargo.env("RUSTC_HOST_LINKER", host_linker); } + if self.config.use_lld && !compiler.host.contains("msvc") { + cargo.env("RUSTC_HOST_FUSE_LD_LLD", "1"); + } if let Some(target_linker) = self.linker(target) { let target = crate::envify(&target.triple); diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index f56c994523c13..98a219e39792d 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -601,7 +601,10 @@ impl Step for RustdocTheme { .env("RUSTDOC_REAL", builder.rustdoc(self.compiler)) .env("RUSTC_BOOTSTRAP", "1"); if let Some(linker) = builder.linker(self.compiler.host) { - cmd.env("RUSTC_TARGET_LINKER", linker); + cmd.env("RUSTDOC_LINKER", linker); + } + if builder.config.use_lld && !self.compiler.host.contains("msvc") { + cmd.env("RUSTDOC_FUSE_LD_LLD", "1"); } try_run(builder, &mut cmd); } From b27fca71d46b2da88611bb5cc8cfb6e90c0a4af0 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 7 Sep 2020 00:39:58 +0300 Subject: [PATCH 0149/1052] rustbuild: Deduplicate LLD checks slightly --- src/bootstrap/builder.rs | 7 +++---- src/bootstrap/lib.rs | 10 +++++++--- src/bootstrap/test.rs | 6 +++--- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index ca2e159d2d948..c7fc360c23312 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -758,7 +758,7 @@ impl<'a> Builder<'a> { if let Some(linker) = self.linker(compiler.host) { cmd.env("RUSTDOC_LINKER", linker); } - if self.config.use_lld && !compiler.host.contains("msvc") { + if self.is_fuse_ld_lld(compiler.host) { cmd.env("RUSTDOC_FUSE_LD_LLD", "1"); } cmd @@ -1047,7 +1047,7 @@ impl<'a> Builder<'a> { if let Some(host_linker) = self.linker(compiler.host) { cargo.env("RUSTC_HOST_LINKER", host_linker); } - if self.config.use_lld && !compiler.host.contains("msvc") { + if self.is_fuse_ld_lld(compiler.host) { cargo.env("RUSTC_HOST_FUSE_LD_LLD", "1"); } @@ -1055,8 +1055,7 @@ impl<'a> Builder<'a> { let target = crate::envify(&target.triple); cargo.env(&format!("CARGO_TARGET_{}_LINKER", target), target_linker); } - - if self.config.use_lld && !target.contains("msvc") { + if self.is_fuse_ld_lld(target) { rustflags.arg("-Clink-args=-fuse-ld=lld"); } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 642f1ea9c0095..8d60284cd4ff0 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -863,15 +863,19 @@ impl Build { && !target.contains("msvc") { Some(self.cc(target)) - } else if target.contains("msvc") && self.config.use_lld && self.build == target { - // `rust.use_lld` means using LLD directly only for MSVC, for other targets it only - // adds `-fuse-ld=lld` to already selected linker. + } else if self.config.use_lld && !self.is_fuse_ld_lld(target) && self.build == target { Some(&self.initial_lld) } else { None } } + // LLD is used through `-fuse-ld=lld` rather than directly. + // Only MSVC targets use LLD directly at the moment. + fn is_fuse_ld_lld(&self, target: TargetSelection) -> bool { + self.config.use_lld && !target.contains("msvc") + } + /// Returns if this target should statically link the C runtime, if specified fn crt_static(&self, target: TargetSelection) -> Option { if target.contains("pc-windows-msvc") { diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 98a219e39792d..732028fb6ed47 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -603,7 +603,7 @@ impl Step for RustdocTheme { if let Some(linker) = builder.linker(self.compiler.host) { cmd.env("RUSTDOC_LINKER", linker); } - if builder.config.use_lld && !self.compiler.host.contains("msvc") { + if builder.is_fuse_ld_lld(self.compiler.host) { cmd.env("RUSTDOC_FUSE_LD_LLD", "1"); } try_run(builder, &mut cmd); @@ -1070,14 +1070,14 @@ impl Step for Compiletest { let mut hostflags = flags.clone(); hostflags.push(format!("-Lnative={}", builder.test_helpers_out(compiler.host).display())); - if builder.config.use_lld && !compiler.host.triple.contains("msvc") { + if builder.is_fuse_ld_lld(compiler.host) { hostflags.push("-Clink-args=-fuse-ld=lld".to_string()); } cmd.arg("--host-rustcflags").arg(hostflags.join(" ")); let mut targetflags = flags; targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display())); - if builder.config.use_lld && !target.contains("msvc") { + if builder.is_fuse_ld_lld(target) { targetflags.push("-Clink-args=-fuse-ld=lld".to_string()); } cmd.arg("--target-rustcflags").arg(targetflags.join(" ")); From 9fa9208bd5c3725f98dd88f761956c01ce5fd527 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Fri, 4 Sep 2020 11:56:54 +0200 Subject: [PATCH 0150/1052] Restrict unnecessary_sort_by to non-ref copy types --- clippy_lints/src/unnecessary_sort_by.rs | 13 ++++++-- tests/ui/unnecessary_sort_by.fixed | 42 ++++++++++++++++++++++--- tests/ui/unnecessary_sort_by.rs | 42 ++++++++++++++++++++++--- 3 files changed, 87 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/unnecessary_sort_by.rs b/clippy_lints/src/unnecessary_sort_by.rs index 8b00d29acb52c..9b6a9075a2954 100644 --- a/clippy_lints/src/unnecessary_sort_by.rs +++ b/clippy_lints/src/unnecessary_sort_by.rs @@ -1,5 +1,4 @@ use crate::utils; -use crate::utils::paths; use crate::utils::sugg::Sugg; use if_chain::if_chain; use rustc_errors::Applicability; @@ -171,12 +170,22 @@ fn mirrored_exprs( } fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { + // NOTE: Vectors of references are not supported. In order to avoid hitting https://github.com/rust-lang/rust/issues/34162, + // (different unnamed lifetimes for closure arg and return type) we need to make sure the suggested + // closure parameter is not a reference in case we suggest `Reverse`. Trying to destructure more + // than one level of references would add some extra complexity as we would have to compensate + // in the closure body. + if_chain! { if let ExprKind::MethodCall(name_ident, _, args, _) = &expr.kind; if let name = name_ident.ident.name.to_ident_string(); if name == "sort_by" || name == "sort_unstable_by"; if let [vec, Expr { kind: ExprKind::Closure(_, _, closure_body_id, _, _), .. }] = args; - if utils::match_type(cx, &cx.typeck_results().expr_ty(vec), &paths::VEC); + let vec_ty = cx.typeck_results().expr_ty(vec); + if utils::is_type_diagnostic_item(cx, vec_ty, sym!(vec_type)); + let ty = vec_ty.walk().nth(1).unwrap().expect_ty(); // T in Vec + if !matches!(&ty.kind(), ty::Ref(..)); + if utils::is_copy(cx, ty); if let closure_body = cx.tcx.hir().body(*closure_body_id); if let &[ Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..}, diff --git a/tests/ui/unnecessary_sort_by.fixed b/tests/ui/unnecessary_sort_by.fixed index 31c2ba0f9c589..ad0d0387db03c 100644 --- a/tests/ui/unnecessary_sort_by.fixed +++ b/tests/ui/unnecessary_sort_by.fixed @@ -25,17 +25,25 @@ fn unnecessary_sort_by() { vec.sort_by(|_, b| b.cmp(&5)); vec.sort_by(|_, b| b.cmp(c)); vec.sort_unstable_by(|a, _| a.cmp(c)); + + // Ignore vectors of references + let mut vec: Vec<&&&isize> = vec![&&&3, &&&6, &&&1, &&&2, &&&5]; + vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs())); + vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs())); + vec.sort_by(|a, b| b.cmp(a)); + vec.sort_unstable_by(|a, b| b.cmp(a)); } -// Should not be linted to avoid hitting https://github.com/rust-lang/rust/issues/34162 +// Do not suggest returning a reference to the closure parameter of `Vec::sort_by_key` mod issue_5754 { - struct Test(String); + #[derive(Clone, Copy)] + struct Test(usize); #[derive(PartialOrd, Ord, PartialEq, Eq)] - struct Wrapper<'a>(&'a str); + struct Wrapper<'a>(&'a usize); impl Test { - fn name(&self) -> &str { + fn name(&self) -> &usize { &self.0 } @@ -60,7 +68,33 @@ mod issue_5754 { } } +// `Vec::sort_by_key` closure parameter is `F: FnMut(&T) -> K` +// The suggestion is destructuring T and we know T is not a reference, so test that non-Copy T are +// not linted. +mod issue_6001 { + struct Test(String); + + impl Test { + // Return an owned type so that we don't hit the fix for 5754 + fn name(&self) -> String { + self.0.clone() + } + } + + pub fn test() { + let mut args: Vec = vec![]; + + // Forward + args.sort_by(|a, b| a.name().cmp(&b.name())); + args.sort_unstable_by(|a, b| a.name().cmp(&b.name())); + // Reverse + args.sort_by(|a, b| b.name().cmp(&a.name())); + args.sort_unstable_by(|a, b| b.name().cmp(&a.name())); + } +} + fn main() { unnecessary_sort_by(); issue_5754::test(); + issue_6001::test(); } diff --git a/tests/ui/unnecessary_sort_by.rs b/tests/ui/unnecessary_sort_by.rs index a3c8ae468ede7..9746f6e6849dd 100644 --- a/tests/ui/unnecessary_sort_by.rs +++ b/tests/ui/unnecessary_sort_by.rs @@ -25,17 +25,25 @@ fn unnecessary_sort_by() { vec.sort_by(|_, b| b.cmp(&5)); vec.sort_by(|_, b| b.cmp(c)); vec.sort_unstable_by(|a, _| a.cmp(c)); + + // Ignore vectors of references + let mut vec: Vec<&&&isize> = vec![&&&3, &&&6, &&&1, &&&2, &&&5]; + vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs())); + vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs())); + vec.sort_by(|a, b| b.cmp(a)); + vec.sort_unstable_by(|a, b| b.cmp(a)); } -// Should not be linted to avoid hitting https://github.com/rust-lang/rust/issues/34162 +// Do not suggest returning a reference to the closure parameter of `Vec::sort_by_key` mod issue_5754 { - struct Test(String); + #[derive(Clone, Copy)] + struct Test(usize); #[derive(PartialOrd, Ord, PartialEq, Eq)] - struct Wrapper<'a>(&'a str); + struct Wrapper<'a>(&'a usize); impl Test { - fn name(&self) -> &str { + fn name(&self) -> &usize { &self.0 } @@ -60,7 +68,33 @@ mod issue_5754 { } } +// `Vec::sort_by_key` closure parameter is `F: FnMut(&T) -> K` +// The suggestion is destructuring T and we know T is not a reference, so test that non-Copy T are +// not linted. +mod issue_6001 { + struct Test(String); + + impl Test { + // Return an owned type so that we don't hit the fix for 5754 + fn name(&self) -> String { + self.0.clone() + } + } + + pub fn test() { + let mut args: Vec = vec![]; + + // Forward + args.sort_by(|a, b| a.name().cmp(&b.name())); + args.sort_unstable_by(|a, b| a.name().cmp(&b.name())); + // Reverse + args.sort_by(|a, b| b.name().cmp(&a.name())); + args.sort_unstable_by(|a, b| b.name().cmp(&a.name())); + } +} + fn main() { unnecessary_sort_by(); issue_5754::test(); + issue_6001::test(); } From 9046a9343bbf298cf835a6b4189827fffae38eb3 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Thu, 3 Sep 2020 20:31:18 -0700 Subject: [PATCH 0151/1052] Improved the MIR spanview output * Adds missing "tail" spans (spans that continue beyond the end of overlapping spans) * Adds a caret to highlight empty spans associated with MIR elements that have a position, but otherwise would not be visible. * Adds visual pointing brackets at the beginning and end of each span --- .../src/transform/instrument_coverage.rs | 2 +- compiler/rustc_mir/src/util/spanview.rs | 379 +++++++++++---- .../spanview_block.main.mir_map.0.html | 6 +- .../spanview_statement.main.mir_map.0.html | 8 +- .../spanview_terminator.main.mir_map.0.html | 6 +- ...lse.main.-------.InstrumentCoverage.0.html | 449 +++++++++++++----- ...lse.main.-------.InstrumentCoverage.0.html | 449 +++++++++++++----- 7 files changed, 980 insertions(+), 319 deletions(-) diff --git a/compiler/rustc_mir/src/transform/instrument_coverage.rs b/compiler/rustc_mir/src/transform/instrument_coverage.rs index d3a2bd241230e..8f43df8a6cbd1 100644 --- a/compiler/rustc_mir/src/transform/instrument_coverage.rs +++ b/compiler/rustc_mir/src/transform/instrument_coverage.rs @@ -309,7 +309,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { for coverage_region in coverage_regions { span_viewables.push(SpanViewable { span: coverage_region.span, - title: format!("{}", coverage_region.blocks[0].index()), + id: format!("{}", coverage_region.blocks[0].index()), tooltip: self.make_tooltip_text(coverage_region), }); } diff --git a/compiler/rustc_mir/src/util/spanview.rs b/compiler/rustc_mir/src/util/spanview.rs index b2f2b5fc1e6f4..fe33fffe0ead1 100644 --- a/compiler/rustc_mir/src/util/spanview.rs +++ b/compiler/rustc_mir/src/util/spanview.rs @@ -3,13 +3,16 @@ use rustc_middle::hir; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; use rustc_session::config::MirSpanview; -use rustc_span::{BytePos, Pos, Span}; +use rustc_span::{BytePos, Pos, Span, SyntaxContext}; +use std::cmp; use std::io::{self, Write}; -use std::iter::Peekable; pub const TOOLTIP_INDENT: &str = " "; +const CARET: char = '\u{2038}'; // Unicode `CARET` +const ANNOTATION_LEFT_BRACKET: char = '\u{298a}'; // Unicode `Z NOTATION RIGHT BINDING BRACKET +const ANNOTATION_RIGHT_BRACKET: char = '\u{2989}'; // Unicode `Z NOTATION LEFT BINDING BRACKET` const NEW_LINE_SPAN: &str = "\n"; const HEADER: &str = r#" @@ -80,7 +83,7 @@ const FOOTER: &str = r#" /// Metadata to highlight the span of a MIR BasicBlock, Statement, or Terminator. pub struct SpanViewable { pub span: Span, - pub title: String, + pub id: String, pub tooltip: String, } @@ -139,16 +142,22 @@ where W: Write, { let fn_span = fn_span(tcx, def_id); - writeln!(w, "{}", HEADER)?; - let mut next_pos = fn_span.lo(); + let mut from_pos = fn_span.lo(); let end_pos = fn_span.hi(); let source_map = tcx.sess.source_map(); - let start = source_map.lookup_char_pos(next_pos); + let start = source_map.lookup_char_pos(from_pos); + let indent_to_initial_start_col = " ".repeat(start.col.to_usize()); + debug!( + "fn_span source is:\n{}{}", + indent_to_initial_start_col, + source_map.span_to_snippet(fn_span).expect("function should have printable source") + ); + writeln!(w, "{}", HEADER)?; write!( w, r#"
{}"#, start.line - 1, - " ".repeat(start.col.to_usize()) + indent_to_initial_start_col, )?; span_viewables.sort_unstable_by(|a, b| { let a = a.span; @@ -163,14 +172,43 @@ where } .unwrap() }); - let mut ordered_span_viewables = span_viewables.iter().peekable(); + let mut ordered_viewables = &span_viewables[..]; + const LOWEST_VIEWABLE_LAYER: usize = 1; let mut alt = false; - while ordered_span_viewables.peek().is_some() { - next_pos = write_span_viewables(tcx, next_pos, &mut ordered_span_viewables, false, 1, w)?; - alt = !alt; + while ordered_viewables.len() > 0 { + debug!( + "calling write_next_viewable with from_pos={}, end_pos={}, and viewables len={}", + from_pos.to_usize(), + end_pos.to_usize(), + ordered_viewables.len() + ); + let (next_from_pos, next_ordered_viewables) = write_next_viewable_with_overlaps( + tcx, + from_pos, + end_pos, + ordered_viewables, + alt, + LOWEST_VIEWABLE_LAYER, + w, + )?; + debug!( + "DONE calling write_next_viewable, with new from_pos={}, \ + and remaining viewables len={}", + next_from_pos.to_usize(), + next_ordered_viewables.len() + ); + assert!( + from_pos != next_from_pos || ordered_viewables.len() != next_ordered_viewables.len(), + "write_next_viewable_with_overlaps() must make a state change" + ); + from_pos = next_from_pos; + if next_ordered_viewables.len() != ordered_viewables.len() { + ordered_viewables = next_ordered_viewables; + alt = !alt; + } } - if next_pos < end_pos { - write_coverage_gap(tcx, next_pos, end_pos, w)?; + if from_pos < end_pos { + write_coverage_gap(tcx, from_pos, end_pos, w)?; } write!(w, r#"
"#)?; writeln!(w, "{}", FOOTER)?; @@ -233,9 +271,9 @@ fn statement_span_viewable<'tcx>( if !body_span.contains(span) { return None; } - let title = format!("bb{}[{}]", bb.index(), i); - let tooltip = tooltip(tcx, &title, span, vec![statement.clone()], &None); - Some(SpanViewable { span, title, tooltip }) + let id = format!("{}[{}]", bb.index(), i); + let tooltip = tooltip(tcx, &id, span, vec![statement.clone()], &None); + Some(SpanViewable { span, id, tooltip }) } fn terminator_span_viewable<'tcx>( @@ -249,9 +287,9 @@ fn terminator_span_viewable<'tcx>( if !body_span.contains(span) { return None; } - let title = format!("bb{}`{}`", bb.index(), terminator_kind_name(term)); - let tooltip = tooltip(tcx, &title, span, vec![], &data.terminator); - Some(SpanViewable { span, title, tooltip }) + let id = format!("{}:{}", bb.index(), terminator_kind_name(term)); + let tooltip = tooltip(tcx, &id, span, vec![], &data.terminator); + Some(SpanViewable { span, id, tooltip }) } fn block_span_viewable<'tcx>( @@ -264,16 +302,16 @@ fn block_span_viewable<'tcx>( if !body_span.contains(span) { return None; } - let title = format!("bb{}", bb.index()); - let tooltip = tooltip(tcx, &title, span, data.statements.clone(), &data.terminator); - Some(SpanViewable { span, title, tooltip }) + let id = format!("{}", bb.index()); + let tooltip = tooltip(tcx, &id, span, data.statements.clone(), &data.terminator); + Some(SpanViewable { span, id, tooltip }) } fn compute_block_span<'tcx>(data: &BasicBlockData<'tcx>, body_span: Span) -> Span { let mut span = data.terminator().source_info.span; for statement_span in data.statements.iter().map(|statement| statement.source_info.span) { - // Only combine Spans from the function's body_span. - if body_span.contains(statement_span) { + // Only combine Spans from the root context, and within the function's body_span. + if statement_span.ctxt() == SyntaxContext::root() && body_span.contains(statement_span) { span = span.to(statement_span); } } @@ -286,100 +324,217 @@ fn compute_block_span<'tcx>(data: &BasicBlockData<'tcx>, body_span: Span) -> Spa /// The `layer` is incremented for each overlap, and the `alt` bool alternates between true /// and false, for each adjacent non-overlapping span. Source code between the spans (code /// that is not in any coverage region) has neutral styling. -fn write_span_viewables<'tcx, 'b, W>( +fn write_next_viewable_with_overlaps<'tcx, 'b, W>( tcx: TyCtxt<'tcx>, - next_pos: BytePos, - ordered_span_viewables: &mut Peekable>, + mut from_pos: BytePos, + mut to_pos: BytePos, + ordered_viewables: &'b [SpanViewable], alt: bool, layer: usize, w: &mut W, -) -> io::Result +) -> io::Result<(BytePos, &'b [SpanViewable])> where W: Write, { - let span_viewable = - ordered_span_viewables.next().expect("ordered_span_viewables should have some"); - if next_pos < span_viewable.span.lo() { - write_coverage_gap(tcx, next_pos, span_viewable.span.lo(), w)?; + let debug_indent = " ".repeat(layer); + let (viewable, mut remaining_viewables) = + ordered_viewables.split_first().expect("ordered_viewables should have some"); + + if from_pos < viewable.span.lo() { + debug!( + "{}advance from_pos to next SpanViewable (from from_pos={} to viewable.span.lo()={} \ + of {:?}), with to_pos={}", + debug_indent, + from_pos.to_usize(), + viewable.span.lo().to_usize(), + viewable.span, + to_pos.to_usize() + ); + let hi = cmp::min(viewable.span.lo(), to_pos); + write_coverage_gap(tcx, from_pos, hi, w)?; + from_pos = hi; + if from_pos < viewable.span.lo() { + debug!( + "{}EARLY RETURN: stopped before getting to next SpanViewable, at {}", + debug_indent, + from_pos.to_usize() + ); + return Ok((from_pos, ordered_viewables)); + } } - let mut remaining_span = span_viewable.span; + + if from_pos < viewable.span.hi() { + // Set to_pos to the end of this `viewable` to ensure the recursive calls stop writing + // with room to print the tail. + to_pos = cmp::min(viewable.span.hi(), to_pos); + debug!( + "{}update to_pos (if not closer) to viewable.span.hi()={}; to_pos is now {}", + debug_indent, + viewable.span.hi().to_usize(), + to_pos.to_usize() + ); + } + let mut subalt = false; - loop { - let next_span_viewable = match ordered_span_viewables.peek() { - None => break, - Some(span_viewable) => *span_viewable, + while remaining_viewables.len() > 0 && remaining_viewables[0].span.overlaps(viewable.span) { + let overlapping_viewable = &remaining_viewables[0]; + debug!("{}overlapping_viewable.span={:?}", debug_indent, overlapping_viewable.span); + + let span = + trim_span(viewable.span, from_pos, cmp::min(overlapping_viewable.span.lo(), to_pos)); + let mut some_html_snippet = if from_pos <= viewable.span.hi() || viewable.span.is_empty() { + // `viewable` is not yet fully rendered, so start writing the span, up to either the + // `to_pos` or the next `overlapping_viewable`, whichever comes first. + debug!( + "{}make html_snippet (may not write it if early exit) for partial span {:?} \ + of viewable.span {:?}", + debug_indent, span, viewable.span + ); + from_pos = span.hi(); + make_html_snippet(tcx, span, Some(&viewable)) + } else { + None }; - if !next_span_viewable.span.overlaps(remaining_span) { - break; + + // Defer writing the HTML snippet (until after early return checks) ONLY for empty spans. + // An empty Span with Some(html_snippet) is probably a tail marker. If there is an early + // exit, there should be another opportunity to write the tail marker. + if !span.is_empty() { + if let Some(ref html_snippet) = some_html_snippet { + debug!( + "{}write html_snippet for that partial span of viewable.span {:?}", + debug_indent, viewable.span + ); + write_span(html_snippet, &viewable.tooltip, alt, layer, w)?; + } + some_html_snippet = None; } - write_span( - tcx, - remaining_span.until(next_span_viewable.span), - Some(span_viewable), - alt, - layer, - w, - )?; - let next_pos = write_span_viewables( + + if from_pos < overlapping_viewable.span.lo() { + debug!( + "{}EARLY RETURN: from_pos={} has not yet reached the \ + overlapping_viewable.span {:?}", + debug_indent, + from_pos.to_usize(), + overlapping_viewable.span + ); + // must have reached `to_pos` before reaching the start of the + // `overlapping_viewable.span` + return Ok((from_pos, ordered_viewables)); + } + + if from_pos == to_pos + && !(from_pos == overlapping_viewable.span.lo() && overlapping_viewable.span.is_empty()) + { + debug!( + "{}EARLY RETURN: from_pos=to_pos={} and overlapping_viewable.span {:?} is not \ + empty, or not from_pos", + debug_indent, + to_pos.to_usize(), + overlapping_viewable.span + ); + // `to_pos` must have occurred before the overlapping viewable. Return + // `ordered_viewables` so we can continue rendering the `viewable`, from after the + // `to_pos`. + return Ok((from_pos, ordered_viewables)); + } + + if let Some(ref html_snippet) = some_html_snippet { + debug!( + "{}write html_snippet for that partial span of viewable.span {:?}", + debug_indent, viewable.span + ); + write_span(html_snippet, &viewable.tooltip, alt, layer, w)?; + } + + debug!( + "{}recursively calling write_next_viewable with from_pos={}, to_pos={}, \ + and viewables len={}", + debug_indent, + from_pos.to_usize(), + to_pos.to_usize(), + remaining_viewables.len() + ); + // Write the overlaps (and the overlaps' overlaps, if any) up to `to_pos`. + let (next_from_pos, next_remaining_viewables) = write_next_viewable_with_overlaps( tcx, - next_span_viewable.span.lo(), - ordered_span_viewables, + from_pos, + to_pos, + &remaining_viewables, subalt, layer + 1, w, )?; - subalt = !subalt; - if next_pos < remaining_span.hi() { - remaining_span = remaining_span.with_lo(next_pos); - } else { - return Ok(next_pos); + debug!( + "{}DONE recursively calling write_next_viewable, with new from_pos={}, and remaining \ + viewables len={}", + debug_indent, + next_from_pos.to_usize(), + next_remaining_viewables.len() + ); + assert!( + from_pos != next_from_pos + || remaining_viewables.len() != next_remaining_viewables.len(), + "write_next_viewable_with_overlaps() must make a state change" + ); + from_pos = next_from_pos; + if next_remaining_viewables.len() != remaining_viewables.len() { + remaining_viewables = next_remaining_viewables; + subalt = !subalt; + } + } + if from_pos <= viewable.span.hi() { + let span = trim_span(viewable.span, from_pos, to_pos); + debug!( + "{}After overlaps, writing (end span?) {:?} of viewable.span {:?}", + debug_indent, span, viewable.span + ); + if let Some(ref html_snippet) = make_html_snippet(tcx, span, Some(&viewable)) { + from_pos = span.hi(); + write_span(html_snippet, &viewable.tooltip, alt, layer, w)?; } } - write_span(tcx, remaining_span, Some(span_viewable), alt, layer, w) + debug!("{}RETURN: No more overlap", debug_indent); + Ok(( + from_pos, + if from_pos < viewable.span.hi() { ordered_viewables } else { remaining_viewables }, + )) } +#[inline(always)] fn write_coverage_gap<'tcx, W>( tcx: TyCtxt<'tcx>, lo: BytePos, hi: BytePos, w: &mut W, -) -> io::Result +) -> io::Result<()> where W: Write, { - write_span(tcx, Span::with_root_ctxt(lo, hi), None, false, 0, w) + let span = Span::with_root_ctxt(lo, hi); + if let Some(ref html_snippet) = make_html_snippet(tcx, span, None) { + write_span(html_snippet, "", false, 0, w) + } else { + Ok(()) + } } -fn write_span<'tcx, W>( - tcx: TyCtxt<'tcx>, - span: Span, - span_viewable: Option<&SpanViewable>, +fn write_span( + html_snippet: &str, + tooltip: &str, alt: bool, layer: usize, w: &mut W, -) -> io::Result +) -> io::Result<()> where W: Write, { - let source_map = tcx.sess.source_map(); - let snippet = source_map - .span_to_snippet(span) - .unwrap_or_else(|err| bug!("span_to_snippet error for span {:?}: {:?}", span, err)); - let labeled_snippet = if let Some(SpanViewable { title, .. }) = span_viewable { - if span.is_empty() { - format!(r#"@{}"#, title) - } else { - format!(r#"@{}: {}"#, title, escape_html(&snippet)) - } - } else { - snippet - }; - let maybe_alt = if layer > 0 { + let maybe_alt_class = if layer > 0 { if alt { " odd" } else { " even" } } else { "" }; - let maybe_tooltip = if let Some(SpanViewable { tooltip, .. }) = span_viewable { + let maybe_title_attr = if !tooltip.is_empty() { format!(" title=\"{}\"", escape_attr(tooltip)) } else { "".to_owned() @@ -387,32 +542,73 @@ where if layer == 1 { write!(w, "")?; } - for (i, line) in labeled_snippet.lines().enumerate() { + for (i, line) in html_snippet.lines().enumerate() { if i > 0 { write!(w, "{}", NEW_LINE_SPAN)?; } write!( w, r#"{}"#, - maybe_alt, layer, maybe_tooltip, line + maybe_alt_class, layer, maybe_title_attr, line )?; } + // Check for and translate trailing newlines, because `str::lines()` ignores them + if html_snippet.ends_with('\n') { + write!(w, "{}", NEW_LINE_SPAN)?; + } if layer == 1 { write!(w, "")?; } - Ok(span.hi()) + Ok(()) +} + +fn make_html_snippet<'tcx>( + tcx: TyCtxt<'tcx>, + span: Span, + some_viewable: Option<&SpanViewable>, +) -> Option { + let source_map = tcx.sess.source_map(); + let snippet = source_map + .span_to_snippet(span) + .unwrap_or_else(|err| bug!("span_to_snippet error for span {:?}: {:?}", span, err)); + let html_snippet = if let Some(viewable) = some_viewable { + let is_head = span.lo() == viewable.span.lo(); + let is_tail = span.hi() == viewable.span.hi(); + let mut labeled_snippet = if is_head { + format!(r#"{}{}"#, viewable.id, ANNOTATION_LEFT_BRACKET) + } else { + "".to_owned() + }; + if span.is_empty() { + if is_head && is_tail { + labeled_snippet.push(CARET); + } + } else { + labeled_snippet.push_str(&escape_html(&snippet)); + }; + if is_tail { + labeled_snippet.push_str(&format!( + r#"{}{}"#, + ANNOTATION_RIGHT_BRACKET, viewable.id + )); + } + labeled_snippet + } else { + escape_html(&snippet) + }; + if html_snippet.is_empty() { None } else { Some(html_snippet) } } fn tooltip<'tcx>( tcx: TyCtxt<'tcx>, - title: &str, + spanview_id: &str, span: Span, statements: Vec>, terminator: &Option>, ) -> String { let source_map = tcx.sess.source_map(); let mut text = Vec::new(); - text.push(format!("{}: {}:", title, &source_map.span_to_string(span))); + text.push(format!("{}: {}:", spanview_id, &source_map.span_to_string(span))); for statement in statements { let source_range = source_range_no_file(tcx, &statement.source_info.span); text.push(format!( @@ -436,10 +632,25 @@ fn tooltip<'tcx>( text.join("") } +fn trim_span(span: Span, from_pos: BytePos, to_pos: BytePos) -> Span { + trim_span_hi(trim_span_lo(span, from_pos), to_pos) +} + +fn trim_span_lo(span: Span, from_pos: BytePos) -> Span { + if from_pos <= span.lo() { span } else { span.with_lo(cmp::min(span.hi(), from_pos)) } +} + +fn trim_span_hi(span: Span, to_pos: BytePos) -> Span { + if to_pos >= span.hi() { span } else { span.with_hi(cmp::max(span.lo(), to_pos)) } +} + fn fn_span<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Span { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.as_local().expect("expected DefId is local")); - tcx.hir().span(hir_id) + let fn_decl_span = tcx.hir().span(hir_id); + let body_span = hir_body(tcx, def_id).value.span; + debug_assert_eq!(fn_decl_span.ctxt(), body_span.ctxt()); + fn_decl_span.to(body_span) } fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx rustc_hir::Body<'tcx> { diff --git a/src/test/mir-opt/spanview_block.main.mir_map.0.html b/src/test/mir-opt/spanview_block.main.mir_map.0.html index 7c1b7bc3b84b0..8f6b1307971b6 100644 --- a/src/test/mir-opt/spanview_block.main.mir_map.0.html +++ b/src/test/mir-opt/spanview_block.main.mir_map.0.html @@ -59,9 +59,9 @@ -
fn main() fn main() @bb0: {}@bb2
+ 5:13-5:13: Goto: goto -> bb2">0⦊{}⦉0
2⦊⦉2
diff --git a/src/test/mir-opt/spanview_statement.main.mir_map.0.html b/src/test/mir-opt/spanview_statement.main.mir_map.0.html index f8662a3277a05..072d22473a991 100644 --- a/src/test/mir-opt/spanview_statement.main.mir_map.0.html +++ b/src/test/mir-opt/spanview_statement.main.mir_map.0.html @@ -59,9 +59,9 @@ -
fn main() @bb0[0]: {}@bb0`Goto`@bb2`Return`
+
fn main() 0[0]⦊{}⦉0[0]0:Goto⦊⦉0:Goto2:Return⦊⦉2:Return
diff --git a/src/test/mir-opt/spanview_terminator.main.mir_map.0.html b/src/test/mir-opt/spanview_terminator.main.mir_map.0.html index d0a11a8d2629d..e023f0f8aeac9 100644 --- a/src/test/mir-opt/spanview_terminator.main.mir_map.0.html +++ b/src/test/mir-opt/spanview_terminator.main.mir_map.0.html @@ -59,8 +59,8 @@ -
fn main() {}@bb0`Goto`@bb2`Return`
+
fn main() {}0:Goto⦊⦉0:Goto2:Return⦊⦉2:Return
diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html index faa5d65e7e787..1ea9aba488e77 100644 --- a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html @@ -62,12 +62,12 @@
fn main() { let mut countdown = 0; @22⦊@44⦊@3: if 3⦊if @0: true0⦊true⦉0@3: { + 5:5-7:6: Goto: goto -> bb5"> { countdown = 10; } + 5:5-7:6: Goto: goto -> bb5"> }⦉3⦉4⦉2 - @6 6⦊@99⦊@25: if 25⦊if @5: countdown > 75⦊countdown > 7⦉5@25: { + 9:5-18:6: Goto: goto -> bb28"> { @8: countdown -= 48⦊countdown -= 4⦉8@25: ; + 9:5-18:6: Goto: goto -> bb28">; } else @10: if 10⦊if @7: countdown > 2@10: { + 11:12-18:6: SwitchInt: switchInt(_8) -> [false: bb11, otherwise: bb10]">7⦊countdown > 2⦉7 { @2222⦊@23@21: if 23⦊21⦊if @1414⦊@1515⦊@1616⦊@1313⦊@2020⦊@1212⦊@1818⦊@1919⦊@17: countdown < 1 || countdown > 517⦊countdown < 1 || countdown > 5⦉17⦉19⦉18@12: || countdown != 9@21: { + 12:12-12:42: SwitchInt: switchInt(move _13) -> [false: bb19, otherwise: bb17]"> || countdown != 9⦉12⦉20⦉13⦉16⦉15⦉14 { countdown = 0; @24: } + 15:9-15:23: Assert: assert(!move (_19.1: bool), "attempt to compute `{} - {}` which would overflow", _1, const 5_i32) -> [success: bb25, unwind: bb1]">24⦊}⦉22⦉23⦉21⦉21 countdown -= 5@10: ; + 15:9-15:23: Assert: assert(!move (_19.1: bool), "attempt to compute `{} - {}` which would overflow", _1, const 5_i32) -> [success: bb25, unwind: bb1]"> countdown -= 5⦉24; } else { @2727⦊@11: return; + 17:9-17:15: Goto: goto -> bb27">11⦊return; } }⦉11⦉6⦉9⦉25⦉25⦉25⦉10⦉10⦉10⦉11@27: + 17:9-17:15: Goto: goto -> bb26"> @@ -230,11 +294,11 @@ 51:1-51:2: StorageDead: StorageDead(_1) 17:9-17:15: Goto: goto -> bb26"> @3030⦊@31@29: if 31⦊29⦊if @28: true@29: { + 21:5-23:6: SwitchInt: switchInt(_23) -> [false: bb30, otherwise: bb29]">28⦊true⦉28 { countdown = 10; } }⦉29⦉31⦉30@27: + 17:9-17:15: Goto: goto -> bb26"> @3333⦊@5252⦊@36: if 36⦊if @32: countdown > 732⦊countdown > 7⦉32@36: { + 25:5-34:6: Goto: goto -> bb53"> { @35: countdown -= 435⦊countdown -= 4⦉35@36: ; + 25:5-34:6: Goto: goto -> bb53">; } else @37: if 37⦊if @34: countdown > 2@37: { + 27:12-34:6: SwitchInt: switchInt(_28) -> [false: bb38, otherwise: bb37]">34⦊countdown > 2⦉34 { @4848⦊@5050⦊@49: if 49⦊if @3939⦊@4747⦊@4040⦊@4343⦊@4242⦊@4141⦊@4646⦊@4545⦊@44: countdown < 1 || countdown > 544⦊countdown < 1 || countdown > 5⦉44⦉45⦉46@41: || countdown != 9 || countdown != 9⦉41⦉42⦉43⦉40⦉47⦉39@49: { + 28:9-30:10: Goto: goto -> bb51"> { countdown = 0; @@ -358,13 +459,25 @@ 30:9-30:10: StorageDead: StorageDead(_31) 30:9-30:10: StorageDead: StorageDead(_30) 31:9-31:23: Assign: _39 = CheckedSub(_21, const 5_i32) - 31:9-31:23: Assert: assert(!move (_39.1: bool), "attempt to compute `{} - {}` which would overflow", _21, const 5_i32) -> [success: bb52, unwind: bb1]">@51: } + 31:9-31:23: Assert: assert(!move (_39.1: bool), "attempt to compute `{} - {}` which would overflow", _21, const 5_i32) -> [success: bb52, unwind: bb1]">51⦊}⦉48⦉50⦉49⦉49 countdown -= 5@37: ; + 31:9-31:23: Assert: assert(!move (_39.1: bool), "attempt to compute `{} - {}` which would overflow", _21, const 5_i32) -> [success: bb52, unwind: bb1]"> countdown -= 5⦉51; } else { @38: return; + 33:9-33:15: Goto: goto -> bb27">38⦊return; } + 33:9-33:15: Goto: goto -> bb27"> }⦉33⦉52⦉36⦉36⦉36⦉37⦉37⦉37 @56@5456⦊54⦊@55: if 55⦊if @53: true53⦊true⦉53@55: { + 37:5-39:6: Goto: goto -> bb57"> { countdown = 10; } }⦉55⦉54⦉56@38: + 33:9-33:15: Goto: goto -> bb27"> @61@5861⦊58⦊@77: if 77⦊if @57: countdown > 757⦊countdown > 7⦉57@77: { + 41:5-50:6: Goto: goto -> bb78"> { @60: countdown -= 460⦊countdown -= 4⦉60@77: ; + 41:5-50:6: Goto: goto -> bb78">; } else @62: if 62⦊if @59: countdown > 2@62: { + 43:12-50:6: SwitchInt: switchInt(_47) -> [false: bb63, otherwise: bb62]">59⦊countdown > 2⦉59 { @7575⦊@74@73: if 74⦊73⦊if @6767⦊@6868⦊@6565⦊@7272⦊@6464⦊@6666⦊@6969⦊@7171⦊@70: countdown < 1 || countdown > 570⦊countdown < 1 || countdown > 5⦉70⦉71⦉69@66: || countdown != 9@73: { + 44:12-44:60: Goto: goto -> bb68"> || countdown != 9⦉66⦉64⦉72⦉65⦉68⦉67 { countdown = 0; @76: } + 47:9-47:23: Assert: assert(!move (_58.1: bool), "attempt to compute `{} - {}` which would overflow", _41, const 5_i32) -> [success: bb77, unwind: bb1]">76⦊}⦉75⦉74⦉73⦉73 countdown -= 5@62: ; + 47:9-47:23: Assert: assert(!move (_58.1: bool), "attempt to compute `{} - {}` which would overflow", _41, const 5_i32) -> [success: bb77, unwind: bb1]"> countdown -= 5⦉76; } else { @63: return; + 49:9-49:15: Goto: goto -> bb26">63⦊return; } }⦉61⦉58⦉77⦉77⦉77⦉62⦉62⦉62 +@78: }@26
+ 51:2-51:2: Goto: goto -> bb26">78⦊}⦉78
⦉63⦉38⦉2726⦊⦉26
diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html index faa5d65e7e787..1ea9aba488e77 100644 --- a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html @@ -62,12 +62,12 @@
fn main() { let mut countdown = 0; @22⦊@44⦊@3: if 3⦊if @0: true0⦊true⦉0@3: { + 5:5-7:6: Goto: goto -> bb5"> { countdown = 10; } + 5:5-7:6: Goto: goto -> bb5"> }⦉3⦉4⦉2 - @6 6⦊@99⦊@25: if 25⦊if @5: countdown > 75⦊countdown > 7⦉5@25: { + 9:5-18:6: Goto: goto -> bb28"> { @8: countdown -= 48⦊countdown -= 4⦉8@25: ; + 9:5-18:6: Goto: goto -> bb28">; } else @10: if 10⦊if @7: countdown > 2@10: { + 11:12-18:6: SwitchInt: switchInt(_8) -> [false: bb11, otherwise: bb10]">7⦊countdown > 2⦉7 { @2222⦊@23@21: if 23⦊21⦊if @1414⦊@1515⦊@1616⦊@1313⦊@2020⦊@1212⦊@1818⦊@1919⦊@17: countdown < 1 || countdown > 517⦊countdown < 1 || countdown > 5⦉17⦉19⦉18@12: || countdown != 9@21: { + 12:12-12:42: SwitchInt: switchInt(move _13) -> [false: bb19, otherwise: bb17]"> || countdown != 9⦉12⦉20⦉13⦉16⦉15⦉14 { countdown = 0; @24: } + 15:9-15:23: Assert: assert(!move (_19.1: bool), "attempt to compute `{} - {}` which would overflow", _1, const 5_i32) -> [success: bb25, unwind: bb1]">24⦊}⦉22⦉23⦉21⦉21 countdown -= 5@10: ; + 15:9-15:23: Assert: assert(!move (_19.1: bool), "attempt to compute `{} - {}` which would overflow", _1, const 5_i32) -> [success: bb25, unwind: bb1]"> countdown -= 5⦉24; } else { @2727⦊@11: return; + 17:9-17:15: Goto: goto -> bb27">11⦊return; } }⦉11⦉6⦉9⦉25⦉25⦉25⦉10⦉10⦉10⦉11@27: + 17:9-17:15: Goto: goto -> bb26"> @@ -230,11 +294,11 @@ 51:1-51:2: StorageDead: StorageDead(_1) 17:9-17:15: Goto: goto -> bb26"> @3030⦊@31@29: if 31⦊29⦊if @28: true@29: { + 21:5-23:6: SwitchInt: switchInt(_23) -> [false: bb30, otherwise: bb29]">28⦊true⦉28 { countdown = 10; } }⦉29⦉31⦉30@27: + 17:9-17:15: Goto: goto -> bb26"> @3333⦊@5252⦊@36: if 36⦊if @32: countdown > 732⦊countdown > 7⦉32@36: { + 25:5-34:6: Goto: goto -> bb53"> { @35: countdown -= 435⦊countdown -= 4⦉35@36: ; + 25:5-34:6: Goto: goto -> bb53">; } else @37: if 37⦊if @34: countdown > 2@37: { + 27:12-34:6: SwitchInt: switchInt(_28) -> [false: bb38, otherwise: bb37]">34⦊countdown > 2⦉34 { @4848⦊@5050⦊@49: if 49⦊if @3939⦊@4747⦊@4040⦊@4343⦊@4242⦊@4141⦊@4646⦊@4545⦊@44: countdown < 1 || countdown > 544⦊countdown < 1 || countdown > 5⦉44⦉45⦉46@41: || countdown != 9 || countdown != 9⦉41⦉42⦉43⦉40⦉47⦉39@49: { + 28:9-30:10: Goto: goto -> bb51"> { countdown = 0; @@ -358,13 +459,25 @@ 30:9-30:10: StorageDead: StorageDead(_31) 30:9-30:10: StorageDead: StorageDead(_30) 31:9-31:23: Assign: _39 = CheckedSub(_21, const 5_i32) - 31:9-31:23: Assert: assert(!move (_39.1: bool), "attempt to compute `{} - {}` which would overflow", _21, const 5_i32) -> [success: bb52, unwind: bb1]">@51: } + 31:9-31:23: Assert: assert(!move (_39.1: bool), "attempt to compute `{} - {}` which would overflow", _21, const 5_i32) -> [success: bb52, unwind: bb1]">51⦊}⦉48⦉50⦉49⦉49 countdown -= 5@37: ; + 31:9-31:23: Assert: assert(!move (_39.1: bool), "attempt to compute `{} - {}` which would overflow", _21, const 5_i32) -> [success: bb52, unwind: bb1]"> countdown -= 5⦉51; } else { @38: return; + 33:9-33:15: Goto: goto -> bb27">38⦊return; } + 33:9-33:15: Goto: goto -> bb27"> }⦉33⦉52⦉36⦉36⦉36⦉37⦉37⦉37 @56@5456⦊54⦊@55: if 55⦊if @53: true53⦊true⦉53@55: { + 37:5-39:6: Goto: goto -> bb57"> { countdown = 10; } }⦉55⦉54⦉56@38: + 33:9-33:15: Goto: goto -> bb27"> @61@5861⦊58⦊@77: if 77⦊if @57: countdown > 757⦊countdown > 7⦉57@77: { + 41:5-50:6: Goto: goto -> bb78"> { @60: countdown -= 460⦊countdown -= 4⦉60@77: ; + 41:5-50:6: Goto: goto -> bb78">; } else @62: if 62⦊if @59: countdown > 2@62: { + 43:12-50:6: SwitchInt: switchInt(_47) -> [false: bb63, otherwise: bb62]">59⦊countdown > 2⦉59 { @7575⦊@74@73: if 74⦊73⦊if @6767⦊@6868⦊@6565⦊@7272⦊@6464⦊@6666⦊@6969⦊@7171⦊@70: countdown < 1 || countdown > 570⦊countdown < 1 || countdown > 5⦉70⦉71⦉69@66: || countdown != 9@73: { + 44:12-44:60: Goto: goto -> bb68"> || countdown != 9⦉66⦉64⦉72⦉65⦉68⦉67 { countdown = 0; @76: } + 47:9-47:23: Assert: assert(!move (_58.1: bool), "attempt to compute `{} - {}` which would overflow", _41, const 5_i32) -> [success: bb77, unwind: bb1]">76⦊}⦉75⦉74⦉73⦉73 countdown -= 5@62: ; + 47:9-47:23: Assert: assert(!move (_58.1: bool), "attempt to compute `{} - {}` which would overflow", _41, const 5_i32) -> [success: bb77, unwind: bb1]"> countdown -= 5⦉76; } else { @63: return; + 49:9-49:15: Goto: goto -> bb26">63⦊return; } }⦉61⦉58⦉77⦉77⦉77⦉62⦉62⦉62 +@78: }@26
+ 51:2-51:2: Goto: goto -> bb26">78⦊}⦉78
⦉63⦉38⦉2726⦊⦉26
From 3d89ee9586354e736cfe4a472d8aaa507d10f77c Mon Sep 17 00:00:00 2001 From: scottmcm Date: Mon, 7 Sep 2020 02:30:42 +0000 Subject: [PATCH 0152/1052] Typo fix Thanks, Amanieu Co-authored-by: Amanieu d'Antras --- library/alloc/src/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 4a263829bd421..ccba23f684877 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -2813,7 +2813,7 @@ impl TryFrom> for [T; N] { // SAFETY: `.set_len(0)` is always sound. unsafe { vec.set_len(0) }; - // SAFETY: A `Vec`'s pointer is always aligned property, and + // SAFETY: A `Vec`'s pointer is always aligned properly, and // the alignment the array needs is the same as the items. // We checked earlier that we have sufficient items. // The items will not double-drop as the `set_len` From 3740b0064d20646e9aa484bac14076563cbf1032 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Mon, 7 Sep 2020 15:10:31 +0800 Subject: [PATCH 0153/1052] Add align to rustc-attrs unstable book --- src/doc/unstable-book/src/language-features/rustc-attrs.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/unstable-book/src/language-features/rustc-attrs.md b/src/doc/unstable-book/src/language-features/rustc-attrs.md index 2967200faf80d..a67e364ba3fc3 100644 --- a/src/doc/unstable-book/src/language-features/rustc-attrs.md +++ b/src/doc/unstable-book/src/language-features/rustc-attrs.md @@ -13,8 +13,8 @@ The `rustc_attrs` feature allows debugging rustc type layouts by using with `cargo check`) as an alternative to `rustc -Z print-type-sizes` that is way more verbose. -Options provided by `#[rustc_layout(...)]` are `debug`, `size`, `abi`. -Note that it only work best with sized type without generics. +Options provided by `#[rustc_layout(...)]` are `debug`, `size`, `align`, +`abi`. Note that it only work best with sized type without generics. ## Examples From caeb5544ecd9dba4d67b68b8c1b32d8132c6d5f2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Sep 2020 11:31:37 +0200 Subject: [PATCH 0154/1052] do not inline black_box when building for Miri --- library/core/src/hint.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index d40a380286762..a7b8c2f373a9e 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -108,7 +108,8 @@ pub fn spin_loop() { /// Note however, that `black_box` is only (and can only be) provided on a "best-effort" basis. The /// extent to which it can block optimisations may vary depending upon the platform and code-gen /// backend used. Programs cannot rely on `black_box` for *correctness* in any way. -#[inline] +#[cfg_attr(not(miri), inline)] +#[cfg_attr(miri, inline(never))] #[unstable(feature = "test", issue = "50297")] #[allow(unreachable_code)] // this makes #[cfg] a bit easier below. pub fn black_box(dummy: T) -> T { From 4b5cd544d1268df8f95424a7dc77ce6c852bac56 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Sep 2020 11:37:35 +0200 Subject: [PATCH 0155/1052] use black_box instead of local optimziation barriers in const tests where possible --- .../ui/consts/cast-discriminant-zst-enum.rs | 14 ++++++-------- src/test/ui/consts/const_discriminant.rs | 17 ++++++----------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/src/test/ui/consts/cast-discriminant-zst-enum.rs b/src/test/ui/consts/cast-discriminant-zst-enum.rs index a77258120111e..743043609ec32 100644 --- a/src/test/ui/consts/cast-discriminant-zst-enum.rs +++ b/src/test/ui/consts/cast-discriminant-zst-enum.rs @@ -1,5 +1,6 @@ // run-pass // Test a ZST enum whose dicriminant is ~0i128. This caused an ICE when casting to a i32. +use std::hint::black_box; #[derive(Copy, Clone)] enum Nums { @@ -12,9 +13,6 @@ const NEG_ONE_I32: i32 = Nums::NegOne as i32; const NEG_ONE_I64: i64 = Nums::NegOne as i64; const NEG_ONE_I128: i128 = Nums::NegOne as i128; -#[inline(never)] -fn identity(t: T) -> T { t } - fn test_as_arg(n: Nums) { assert_eq!(-1i8, n as i8); assert_eq!(-1i16, n as i16); @@ -31,11 +29,11 @@ fn main() { assert_eq!(-1i64, kind as i64); assert_eq!(-1i128, kind as i128); - assert_eq!(-1i8, identity(kind) as i8); - assert_eq!(-1i16, identity(kind) as i16); - assert_eq!(-1i32, identity(kind) as i32); - assert_eq!(-1i64, identity(kind) as i64); - assert_eq!(-1i128, identity(kind) as i128); + assert_eq!(-1i8, black_box(kind) as i8); + assert_eq!(-1i16, black_box(kind) as i16); + assert_eq!(-1i32, black_box(kind) as i32); + assert_eq!(-1i64, black_box(kind) as i64); + assert_eq!(-1i128, black_box(kind) as i128); test_as_arg(Nums::NegOne); diff --git a/src/test/ui/consts/const_discriminant.rs b/src/test/ui/consts/const_discriminant.rs index 1ad5134e71c52..24fb760f5a3f7 100644 --- a/src/test/ui/consts/const_discriminant.rs +++ b/src/test/ui/consts/const_discriminant.rs @@ -1,14 +1,9 @@ // run-pass -#![feature(const_discriminant)] +#![feature(const_discriminant, test)] #![allow(dead_code)] use std::mem::{discriminant, Discriminant}; - -// `discriminant(const_expr)` may get const-propagated. -// As we want to check that const-eval is equal to ordinary exection, -// we wrap `const_expr` with a function which is not const to prevent this. -#[inline(never)] -fn identity(x: T) -> T { x } +use std::hint::black_box; enum Test { A(u8), @@ -31,10 +26,10 @@ const TEST_V: Discriminant = discriminant(&SingleVariant::V); fn main() { assert_eq!(TEST_A, TEST_A_OTHER); - assert_eq!(TEST_A, discriminant(identity(&Test::A(17)))); - assert_eq!(TEST_B, discriminant(identity(&Test::B))); + assert_eq!(TEST_A, discriminant(black_box(&Test::A(17)))); + assert_eq!(TEST_B, discriminant(black_box(&Test::B))); assert_ne!(TEST_A, TEST_B); - assert_ne!(TEST_B, discriminant(identity(&Test::C { a: 42, b: 7 }))); + assert_ne!(TEST_B, discriminant(black_box(&Test::C { a: 42, b: 7 }))); - assert_eq!(TEST_V, discriminant(identity(&SingleVariant::V))); + assert_eq!(TEST_V, discriminant(black_box(&SingleVariant::V))); } From 47668edb64ed1f8676cfcb4c9ccb6fe018f660c5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Sep 2020 13:04:41 +0200 Subject: [PATCH 0156/1052] Separate feature flags Co-authored-by: Ivan Tham --- src/test/ui/consts/const_discriminant.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/ui/consts/const_discriminant.rs b/src/test/ui/consts/const_discriminant.rs index 24fb760f5a3f7..d016d236dbf81 100644 --- a/src/test/ui/consts/const_discriminant.rs +++ b/src/test/ui/consts/const_discriminant.rs @@ -1,5 +1,6 @@ // run-pass -#![feature(const_discriminant, test)] +#![feature(const_discriminant)] +#![feature(test)] #![allow(dead_code)] use std::mem::{discriminant, Discriminant}; From 284b16913aa6fccdf7b14edc3bb2693aadd39919 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Sep 2020 13:05:59 +0200 Subject: [PATCH 0157/1052] add missing feature flag --- src/test/ui/consts/cast-discriminant-zst-enum.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/ui/consts/cast-discriminant-zst-enum.rs b/src/test/ui/consts/cast-discriminant-zst-enum.rs index 743043609ec32..9c02d232e134b 100644 --- a/src/test/ui/consts/cast-discriminant-zst-enum.rs +++ b/src/test/ui/consts/cast-discriminant-zst-enum.rs @@ -1,5 +1,6 @@ // run-pass // Test a ZST enum whose dicriminant is ~0i128. This caused an ICE when casting to a i32. +#![feature(test)] use std::hint::black_box; #[derive(Copy, Clone)] From 44726ba57cbb4aff6d349f301e5e174c7ef6ae02 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 7 Sep 2020 07:58:48 -0400 Subject: [PATCH 0158/1052] Note that parallel-compiler = true causes tests to fail --- config.toml.example | 1 + 1 file changed, 1 insertion(+) diff --git a/config.toml.example b/config.toml.example index 9abb8add785a9..93541bbb60ca2 100644 --- a/config.toml.example +++ b/config.toml.example @@ -371,6 +371,7 @@ #incremental = false # Build a multi-threaded rustc +# FIXME(#75760): Some UI tests fail when this option is enabled. #parallel-compiler = false # The default linker that will be hard-coded into the generated compiler for From f422ef141a1185f721093205fabc6f5a57e3dcc0 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 10 Aug 2020 07:16:30 -0400 Subject: [PATCH 0159/1052] Add CONST_ITEM_MUTATION lint Fixes #74053 Fixes #55721 This PR adds a new lint `CONST_ITEM_MUTATION`. Given an item `const FOO: SomeType = ..`, this lint fires on: * Attempting to write directly to a field (`FOO.field = some_val`) or array entry (`FOO.array_field[0] = val`) * Taking a mutable reference to the `const` item (`&mut FOO`), including through an autoderef `FOO.some_mut_self_method()` The lint message explains that since each use of a constant creates a new temporary, the original `const` item will not be modified. --- compiler/rustc_middle/src/mir/mod.rs | 2 + .../src/borrow_check/diagnostics/mod.rs | 97 ++++++--------- .../transform/check_const_item_mutation.rs | 114 ++++++++++++++++++ compiler/rustc_mir/src/transform/mod.rs | 2 + compiler/rustc_mir/src/util/find_self_call.rs | 35 ++++++ compiler/rustc_mir/src/util/mod.rs | 2 + .../src/build/expr/as_constant.rs | 2 +- .../rustc_mir_build/src/build/expr/as_temp.rs | 3 + compiler/rustc_mir_build/src/thir/cx/expr.rs | 15 ++- compiler/rustc_mir_build/src/thir/mod.rs | 4 + compiler/rustc_session/src/lint/builtin.rs | 7 ++ src/test/ui/error-codes/E0017.rs | 2 + src/test/ui/error-codes/E0017.stderr | 41 ++++++- src/test/ui/error-codes/E0388.rs | 2 + src/test/ui/error-codes/E0388.stderr | 39 +++++- src/test/ui/lint/lint-const-item-mutation.rs | 21 ++++ .../ui/lint/lint-const-item-mutation.stderr | 89 ++++++++++++++ 17 files changed, 406 insertions(+), 71 deletions(-) create mode 100644 compiler/rustc_mir/src/transform/check_const_item_mutation.rs create mode 100644 compiler/rustc_mir/src/util/find_self_call.rs create mode 100644 src/test/ui/lint/lint-const-item-mutation.rs create mode 100644 src/test/ui/lint/lint-const-item-mutation.stderr diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 1181ba6bbf946..d6d76595f3b9b 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -899,6 +899,8 @@ pub enum LocalInfo<'tcx> { User(ClearCrossCrate>), /// A temporary created that references the static with the given `DefId`. StaticRef { def_id: DefId, is_thread_local: bool }, + /// A temporary created that references the const with the given `DefId` + ConstRef { def_id: DefId }, } impl<'tcx> LocalDecl<'tcx> { diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs index 88ff0271228e0..f51bf7730ea09 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs @@ -804,68 +804,51 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("move_spans: target_temp = {:?}", target_temp); if let Some(Terminator { - kind: TerminatorKind::Call { func, args, fn_span, from_hir_call, .. }, - .. + kind: TerminatorKind::Call { fn_span, from_hir_call, .. }, .. }) = &self.body[location.block].terminator { - let mut method_did = None; - if let Operand::Constant(box Constant { literal: ty::Const { ty, .. }, .. }) = func { - if let ty::FnDef(def_id, _) = *ty.kind() { - debug!("move_spans: fn = {:?}", def_id); - if let Some(ty::AssocItem { fn_has_self_parameter, .. }) = - self.infcx.tcx.opt_associated_item(def_id) - { - if *fn_has_self_parameter { - method_did = Some(def_id); - } - } - } - } + let method_did = if let Some(method_did) = + crate::util::find_self_call(self.infcx.tcx, &self.body, target_temp, location.block) + { + method_did + } else { + return normal_ret; + }; let tcx = self.infcx.tcx; - let method_did = if let Some(did) = method_did { did } else { return normal_ret }; - - if let [Operand::Move(self_place), ..] = **args { - if self_place.as_local() == Some(target_temp) { - let parent = tcx.parent(method_did); - let is_fn_once = parent == tcx.lang_items().fn_once_trait(); - let is_operator = !from_hir_call - && parent.map_or(false, |p| { - tcx.lang_items().group(LangItemGroup::Op).contains(&p) - }); - let fn_call_span = *fn_span; - - let self_arg = tcx.fn_arg_names(method_did)[0]; - - let kind = if is_fn_once { - FnSelfUseKind::FnOnceCall - } else if is_operator { - FnSelfUseKind::Operator { self_arg } - } else { - debug!( - "move_spans: method_did={:?}, fn_call_span={:?}", - method_did, fn_call_span - ); - let implicit_into_iter = matches!( - fn_call_span.desugaring_kind(), - Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter)) - ); - FnSelfUseKind::Normal { self_arg, implicit_into_iter } - }; - return FnSelfUse { - var_span: stmt.source_info.span, - fn_call_span, - fn_span: self - .infcx - .tcx - .sess - .source_map() - .guess_head_span(self.infcx.tcx.def_span(method_did)), - kind, - }; - } - } + let parent = tcx.parent(method_did); + let is_fn_once = parent == tcx.lang_items().fn_once_trait(); + let is_operator = !from_hir_call + && parent.map_or(false, |p| tcx.lang_items().group(LangItemGroup::Op).contains(&p)); + let fn_call_span = *fn_span; + + let self_arg = tcx.fn_arg_names(method_did)[0]; + + let kind = if is_fn_once { + FnSelfUseKind::FnOnceCall + } else if is_operator { + FnSelfUseKind::Operator { self_arg } + } else { + debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span); + let implicit_into_iter = matches!( + fn_call_span.desugaring_kind(), + Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter)) + ); + FnSelfUseKind::Normal { self_arg, implicit_into_iter } + }; + + return FnSelfUse { + var_span: stmt.source_info.span, + fn_call_span, + fn_span: self + .infcx + .tcx + .sess + .source_map() + .guess_head_span(self.infcx.tcx.def_span(method_did)), + kind, + }; } normal_ret } diff --git a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs new file mode 100644 index 0000000000000..589268e39bda9 --- /dev/null +++ b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs @@ -0,0 +1,114 @@ +use rustc_errors::DiagnosticBuilder; +use rustc_middle::lint::LintDiagnosticBuilder; +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; +use rustc_session::lint::builtin::CONST_ITEM_MUTATION; +use rustc_span::def_id::DefId; + +use crate::transform::{MirPass, MirSource}; + +pub struct CheckConstItemMutation; + +impl<'tcx> MirPass<'tcx> for CheckConstItemMutation { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { + let mut checker = ConstMutationChecker { body, tcx, target_local: None }; + checker.visit_body(&body); + } +} + +struct ConstMutationChecker<'a, 'tcx> { + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, + target_local: Option, +} + +impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> { + fn is_const_item(&self, local: Local) -> Option { + if let Some(box LocalInfo::ConstRef { def_id }) = self.body.local_decls[local].local_info { + Some(def_id) + } else { + None + } + } + fn lint_const_item_usage( + &self, + const_item: DefId, + location: Location, + decorate: impl for<'b> FnOnce(LintDiagnosticBuilder<'b>) -> DiagnosticBuilder<'b>, + ) { + let source_info = self.body.source_info(location); + let lint_root = self.body.source_scopes[source_info.scope] + .local_data + .as_ref() + .assert_crate_local() + .lint_root; + + self.tcx.struct_span_lint_hir(CONST_ITEM_MUTATION, lint_root, source_info.span, |lint| { + decorate(lint) + .span_note(self.tcx.def_span(const_item), "`const` item defined here") + .emit() + }); + } +} + +impl<'a, 'tcx> Visitor<'tcx> for ConstMutationChecker<'a, 'tcx> { + fn visit_statement(&mut self, stmt: &Statement<'tcx>, loc: Location) { + if let StatementKind::Assign(box (lhs, _)) = &stmt.kind { + // Check for assignment to fields of a constant + // Assigning directly to a constant (e.g. `FOO = true;`) is a hard error, + // so emitting a lint would be redundant. + if !lhs.projection.is_empty() { + if let Some(def_id) = self.is_const_item(lhs.local) { + self.lint_const_item_usage(def_id, loc, |lint| { + let mut lint = lint.build("attempting to modify a `const` item"); + lint.note("each usage of a `const` item creates a new temporary - the original `const` item will not be modified"); + lint + }) + } + } + // We are looking for MIR of the form: + // + // ``` + // _1 = const FOO; + // _2 = &mut _1; + // method_call(_2, ..) + // ``` + // + // Record our current LHS, so that we can detect this + // pattern in `visit_rvalue` + self.target_local = lhs.as_local(); + } + self.super_statement(stmt, loc); + self.target_local = None; + } + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, loc: Location) { + if let Rvalue::Ref(_, BorrowKind::Mut { .. }, place) = rvalue { + let local = place.local; + if let Some(def_id) = self.is_const_item(local) { + // If this Rvalue is being used as the right-hand side of a + // `StatementKind::Assign`, see if it ends up getting used as + // the `self` parameter of a method call (as the terminator of our current + // BasicBlock). If so, we emit a more specific lint. + let method_did = self.target_local.and_then(|target_local| { + crate::util::find_self_call(self.tcx, &self.body, target_local, loc.block) + }); + let lint_loc = + if method_did.is_some() { self.body.terminator_loc(loc.block) } else { loc }; + self.lint_const_item_usage(def_id, lint_loc, |lint| { + let mut lint = lint.build("taking a mutable reference to a `const` item"); + lint + .note("each usage of a `const` item creates a new temporary") + .note("the mutable reference will refer to this temporary, not the original `const` item"); + + if let Some(method_did) = method_did { + lint.span_note(self.tcx.def_span(method_did), "mutable reference created due to call to this method"); + } + + lint + }); + } + } + self.super_rvalue(rvalue, loc); + } +} diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index c3a34756122a1..98f93ae6da0fe 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -16,6 +16,7 @@ use std::borrow::Cow; pub mod add_call_guards; pub mod add_moves_for_packed_drops; pub mod add_retag; +pub mod check_const_item_mutation; pub mod check_consts; pub mod check_packed_ref; pub mod check_unsafety; @@ -307,6 +308,7 @@ fn mir_const<'tcx>( &[&[ // MIR-level lints. &check_packed_ref::CheckPackedRef, + &check_const_item_mutation::CheckConstItemMutation, // What we need to do constant evaluation. &simplify::SimplifyCfg::new("initial"), &rustc_peek::SanityCheck, diff --git a/compiler/rustc_mir/src/util/find_self_call.rs b/compiler/rustc_mir/src/util/find_self_call.rs new file mode 100644 index 0000000000000..049b5f01214cf --- /dev/null +++ b/compiler/rustc_mir/src/util/find_self_call.rs @@ -0,0 +1,35 @@ +use rustc_middle::mir::*; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::def_id::DefId; + +/// Checks if the specified `local` is used as the `self` prameter of a method call +/// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is +/// returned. +pub fn find_self_call( + tcx: TyCtxt<'_>, + body: &Body<'_>, + local: Local, + block: BasicBlock, +) -> Option { + debug!("find_self_call(local={:?}): terminator={:?}", local, &body[block].terminator); + if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) = + &body[block].terminator + { + debug!("find_self_call: func={:?}", func); + if let Operand::Constant(box Constant { literal: ty::Const { ty, .. }, .. }) = func { + if let ty::FnDef(def_id, _) = *ty.kind() { + if let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) = + tcx.opt_associated_item(def_id) + { + debug!("find_self_call: args={:?}", args); + if let [Operand::Move(self_place) | Operand::Copy(self_place), ..] = **args { + if self_place.as_local() == Some(local) { + return Some(def_id); + } + } + } + } + } + } + None +} diff --git a/compiler/rustc_mir/src/util/mod.rs b/compiler/rustc_mir/src/util/mod.rs index ed0fafb1aac16..699f3bcf0146f 100644 --- a/compiler/rustc_mir/src/util/mod.rs +++ b/compiler/rustc_mir/src/util/mod.rs @@ -7,12 +7,14 @@ pub mod storage; mod alignment; pub mod collect_writes; +mod find_self_call; mod graphviz; pub(crate) mod pretty; pub(crate) mod spanview; pub use self::aggregate::expand_aggregate; pub use self::alignment::is_disaligned; +pub use self::find_self_call::find_self_call; pub use self::graphviz::write_node_label as write_graphviz_node_label; pub use self::graphviz::{graphviz_safe_def_name, write_mir_graphviz}; pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty, PassWhere}; diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 982aefcf6045c..244a70f83b03e 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -21,7 +21,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let Expr { ty, temp_lifetime: _, span, kind } = expr; match kind { ExprKind::Scope { region_scope: _, lint_level: _, value } => this.as_constant(value), - ExprKind::Literal { literal, user_ty } => { + ExprKind::Literal { literal, user_ty, const_id: _ } => { let user_ty = user_ty.map(|user_ty| { this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { span, diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs index a9cc0cc2f2475..9984b527ffdb4 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -76,6 +76,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { local_decl.local_info = Some(box LocalInfo::StaticRef { def_id, is_thread_local: true }); } + ExprKind::Literal { const_id: Some(def_id), .. } => { + local_decl.local_info = Some(box LocalInfo::ConstRef { def_id }); + } _ => {} } this.local_decls.push(local_decl) diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index e9e49d054b88d..70c7abc265492 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -247,6 +247,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( hir::ExprKind::Lit(ref lit) => ExprKind::Literal { literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, false), user_ty: None, + const_id: None, }, hir::ExprKind::Binary(op, ref lhs, ref rhs) => { @@ -306,6 +307,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( ExprKind::Literal { literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true), user_ty: None, + const_id: None, } } else { ExprKind::Unary { op: UnOp::Neg, arg: arg.to_ref() } @@ -447,6 +449,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( kind: ExprKind::Literal { literal: ty::Const::zero_sized(cx.tcx, ty), user_ty, + const_id: None, }, } .to_ref(), @@ -473,6 +476,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( kind: ExprKind::Literal { literal: ty::Const::zero_sized(cx.tcx, ty), user_ty: None, + const_id: None, }, } .to_ref(), @@ -585,7 +589,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( temp_lifetime, ty: var_ty, span: expr.span, - kind: ExprKind::Literal { literal, user_ty: None }, + kind: ExprKind::Literal { literal, user_ty: None, const_id: None }, } .to_ref() }; @@ -714,7 +718,11 @@ fn method_callee<'a, 'tcx>( temp_lifetime, ty, span, - kind: ExprKind::Literal { literal: ty::Const::zero_sized(cx.tcx(), ty), user_ty }, + kind: ExprKind::Literal { + literal: ty::Const::zero_sized(cx.tcx(), ty), + user_ty, + const_id: None, + }, } } @@ -777,6 +785,7 @@ fn convert_path_expr<'a, 'tcx>( ExprKind::Literal { literal: ty::Const::zero_sized(cx.tcx, cx.typeck_results().node_type(expr.hir_id)), user_ty, + const_id: None, } } @@ -794,6 +803,7 @@ fn convert_path_expr<'a, 'tcx>( .tcx .mk_const(ty::Const { val, ty: cx.typeck_results().node_type(expr.hir_id) }), user_ty: None, + const_id: Some(def_id), } } @@ -810,6 +820,7 @@ fn convert_path_expr<'a, 'tcx>( ty: cx.typeck_results().node_type(expr.hir_id), }), user_ty, + const_id: Some(def_id), } } diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs index 2837bfa040ff7..4d57fd5c64f8d 100644 --- a/compiler/rustc_mir_build/src/thir/mod.rs +++ b/compiler/rustc_mir_build/src/thir/mod.rs @@ -273,6 +273,10 @@ crate enum ExprKind<'tcx> { Literal { literal: &'tcx Const<'tcx>, user_ty: Option>>, + /// The `DefId` of the `const` item this literal + /// was produced from, if this is not a user-written + /// literal value. + const_id: Option, }, /// A literal containing the address of a `static`. /// diff --git a/compiler/rustc_session/src/lint/builtin.rs b/compiler/rustc_session/src/lint/builtin.rs index 2db4d2a7f51d9..74b68bfe2a5c3 100644 --- a/compiler/rustc_session/src/lint/builtin.rs +++ b/compiler/rustc_session/src/lint/builtin.rs @@ -232,6 +232,12 @@ declare_lint! { "detects unaligned references to fields of packed structs", } +declare_lint! { + pub CONST_ITEM_MUTATION, + Warn, + "detects attempts to mutate a `const` item", +} + declare_lint! { pub SAFE_PACKED_BORROWS, Warn, @@ -572,6 +578,7 @@ declare_lint_pass! { CONST_ERR, RENAMED_AND_REMOVED_LINTS, UNALIGNED_REFERENCES, + CONST_ITEM_MUTATION, SAFE_PACKED_BORROWS, PATTERNS_IN_FNS_WITHOUT_BODY, LATE_BOUND_LIFETIME_ARGUMENTS, diff --git a/src/test/ui/error-codes/E0017.rs b/src/test/ui/error-codes/E0017.rs index 818dec1207b96..54d3cc54a84d9 100644 --- a/src/test/ui/error-codes/E0017.rs +++ b/src/test/ui/error-codes/E0017.rs @@ -3,9 +3,11 @@ const C: i32 = 2; static mut M: i32 = 3; const CR: &'static mut i32 = &mut C; //~ ERROR E0764 + //~| WARN taking a mutable static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0764 //~| ERROR E0019 //~| ERROR cannot borrow static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0764 + //~| WARN taking a mutable static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR E0764 fn main() {} diff --git a/src/test/ui/error-codes/E0017.stderr b/src/test/ui/error-codes/E0017.stderr index c1d96de1dca7c..40ef6bd97b3b0 100644 --- a/src/test/ui/error-codes/E0017.stderr +++ b/src/test/ui/error-codes/E0017.stderr @@ -1,3 +1,18 @@ +warning: taking a mutable reference to a `const` item + --> $DIR/E0017.rs:5:30 + | +LL | const CR: &'static mut i32 = &mut C; + | ^^^^^^ + | + = note: `#[warn(const_item_mutation)]` on by default + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: `const` item defined here + --> $DIR/E0017.rs:2:1 + | +LL | const C: i32 = 2; + | ^^^^^^^^^^^^^^^^^ + error[E0764]: mutable references are not allowed in constants --> $DIR/E0017.rs:5:30 | @@ -5,7 +20,7 @@ LL | const CR: &'static mut i32 = &mut C; | ^^^^^^ `&mut` is only allowed in `const fn` error[E0019]: static contains unimplemented expression type - --> $DIR/E0017.rs:6:39 + --> $DIR/E0017.rs:7:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ @@ -13,30 +28,44 @@ LL | static STATIC_REF: &'static mut i32 = &mut X; = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0764]: mutable references are not allowed in statics - --> $DIR/E0017.rs:6:39 + --> $DIR/E0017.rs:7:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ `&mut` is only allowed in `const fn` error[E0596]: cannot borrow immutable static item `X` as mutable - --> $DIR/E0017.rs:6:39 + --> $DIR/E0017.rs:7:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ cannot borrow as mutable +warning: taking a mutable reference to a `const` item + --> $DIR/E0017.rs:10:38 + | +LL | static CONST_REF: &'static mut i32 = &mut C; + | ^^^^^^ + | + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: `const` item defined here + --> $DIR/E0017.rs:2:1 + | +LL | const C: i32 = 2; + | ^^^^^^^^^^^^^^^^^ + error[E0764]: mutable references are not allowed in statics - --> $DIR/E0017.rs:9:38 + --> $DIR/E0017.rs:10:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ `&mut` is only allowed in `const fn` error[E0764]: mutable references are not allowed in statics - --> $DIR/E0017.rs:10:52 + --> $DIR/E0017.rs:12:52 | LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; | ^^^^^^ `&mut` is only allowed in `const fn` -error: aborting due to 6 previous errors +error: aborting due to 6 previous errors; 2 warnings emitted Some errors have detailed explanations: E0019, E0596, E0764. For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/error-codes/E0388.rs b/src/test/ui/error-codes/E0388.rs index 13131017c2e07..8ad586bb30f1e 100644 --- a/src/test/ui/error-codes/E0388.rs +++ b/src/test/ui/error-codes/E0388.rs @@ -2,9 +2,11 @@ static X: i32 = 1; const C: i32 = 2; const CR: &'static mut i32 = &mut C; //~ ERROR E0764 + //~| WARN taking a mutable static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0019 //~| ERROR cannot borrow //~| ERROR E0764 static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0764 + //~| WARN taking a mutable fn main() {} diff --git a/src/test/ui/error-codes/E0388.stderr b/src/test/ui/error-codes/E0388.stderr index f09100bac43ce..39bc717ceec3e 100644 --- a/src/test/ui/error-codes/E0388.stderr +++ b/src/test/ui/error-codes/E0388.stderr @@ -1,3 +1,18 @@ +warning: taking a mutable reference to a `const` item + --> $DIR/E0388.rs:4:30 + | +LL | const CR: &'static mut i32 = &mut C; + | ^^^^^^ + | + = note: `#[warn(const_item_mutation)]` on by default + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: `const` item defined here + --> $DIR/E0388.rs:2:1 + | +LL | const C: i32 = 2; + | ^^^^^^^^^^^^^^^^^ + error[E0764]: mutable references are not allowed in constants --> $DIR/E0388.rs:4:30 | @@ -5,7 +20,7 @@ LL | const CR: &'static mut i32 = &mut C; | ^^^^^^ `&mut` is only allowed in `const fn` error[E0019]: static contains unimplemented expression type - --> $DIR/E0388.rs:5:39 + --> $DIR/E0388.rs:6:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ @@ -13,24 +28,38 @@ LL | static STATIC_REF: &'static mut i32 = &mut X; = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0764]: mutable references are not allowed in statics - --> $DIR/E0388.rs:5:39 + --> $DIR/E0388.rs:6:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ `&mut` is only allowed in `const fn` error[E0596]: cannot borrow immutable static item `X` as mutable - --> $DIR/E0388.rs:5:39 + --> $DIR/E0388.rs:6:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ cannot borrow as mutable +warning: taking a mutable reference to a `const` item + --> $DIR/E0388.rs:9:38 + | +LL | static CONST_REF: &'static mut i32 = &mut C; + | ^^^^^^ + | + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: `const` item defined here + --> $DIR/E0388.rs:2:1 + | +LL | const C: i32 = 2; + | ^^^^^^^^^^^^^^^^^ + error[E0764]: mutable references are not allowed in statics - --> $DIR/E0388.rs:8:38 + --> $DIR/E0388.rs:9:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ `&mut` is only allowed in `const fn` -error: aborting due to 5 previous errors +error: aborting due to 5 previous errors; 2 warnings emitted Some errors have detailed explanations: E0019, E0596, E0764. For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/lint/lint-const-item-mutation.rs b/src/test/ui/lint/lint-const-item-mutation.rs new file mode 100644 index 0000000000000..92d29a7dae475 --- /dev/null +++ b/src/test/ui/lint/lint-const-item-mutation.rs @@ -0,0 +1,21 @@ +// check-pass + +struct MyStruct { + field: bool, + inner_array: [char; 1], +} +impl MyStruct { + fn use_mut(&mut self) {} +} + +const ARRAY: [u8; 1] = [25]; +const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'] }; + +fn main() { + ARRAY[0] = 5; //~ WARN attempting to modify + MY_STRUCT.field = false; //~ WARN attempting to modify + MY_STRUCT.inner_array[0] = 'b'; //~ WARN attempting to modify + MY_STRUCT.use_mut(); //~ WARN taking + &mut MY_STRUCT; //~ WARN taking + (&mut MY_STRUCT).use_mut(); //~ WARN taking +} diff --git a/src/test/ui/lint/lint-const-item-mutation.stderr b/src/test/ui/lint/lint-const-item-mutation.stderr new file mode 100644 index 0000000000000..2d8f2c49744ba --- /dev/null +++ b/src/test/ui/lint/lint-const-item-mutation.stderr @@ -0,0 +1,89 @@ +warning: attempting to modify a `const` item + --> $DIR/lint-const-item-mutation.rs:15:5 + | +LL | ARRAY[0] = 5; + | ^^^^^^^^^^^^ + | + = note: `#[warn(const_item_mutation)]` on by default + = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:11:1 + | +LL | const ARRAY: [u8; 1] = [25]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: attempting to modify a `const` item + --> $DIR/lint-const-item-mutation.rs:16:5 + | +LL | MY_STRUCT.field = false; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:12:1 + | +LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'] }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: attempting to modify a `const` item + --> $DIR/lint-const-item-mutation.rs:17:5 + | +LL | MY_STRUCT.inner_array[0] = 'b'; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:12:1 + | +LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'] }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: taking a mutable reference to a `const` item + --> $DIR/lint-const-item-mutation.rs:18:5 + | +LL | MY_STRUCT.use_mut(); + | ^^^^^^^^^^^^^^^^^^^ + | + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: mutable reference created due to call to this method + --> $DIR/lint-const-item-mutation.rs:8:5 + | +LL | fn use_mut(&mut self) {} + | ^^^^^^^^^^^^^^^^^^^^^ +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:12:1 + | +LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'] }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: taking a mutable reference to a `const` item + --> $DIR/lint-const-item-mutation.rs:19:5 + | +LL | &mut MY_STRUCT; + | ^^^^^^^^^^^^^^ + | + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:12:1 + | +LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'] }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: taking a mutable reference to a `const` item + --> $DIR/lint-const-item-mutation.rs:20:5 + | +LL | (&mut MY_STRUCT).use_mut(); + | ^^^^^^^^^^^^^^^^ + | + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:12:1 + | +LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'] }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 6 warnings emitted + From 3d30ef7818b9ed562f2c48f3d6d15d90253ae732 Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Mon, 7 Sep 2020 22:17:31 +0900 Subject: [PATCH 0160/1052] Restrict `same_item_push` to suppress false positives It emits a lint when the pushed item is a literal, a constant and an immutable binding that are initialized with those. --- clippy_lints/src/loops.rs | 83 ++++++++++++++++++++++++++-------- tests/ui/same_item_push.rs | 13 ++++++ tests/ui/same_item_push.stderr | 34 ++++++++------ 3 files changed, 97 insertions(+), 33 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index f13e369907b2d..f417e3a0caf95 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1153,27 +1153,70 @@ fn detect_same_item_push<'tcx>( let vec_str = snippet_with_macro_callsite(cx, vec.span, ""); let item_str = snippet_with_macro_callsite(cx, pushed_item.span, ""); if let ExprKind::Path(ref qpath) = pushed_item.kind { - if_chain! { - if let Res::Local(hir_id) = qpath_res(cx, qpath, pushed_item.hir_id); - let node = cx.tcx.hir().get(hir_id); - if let Node::Binding(pat) = node; - if let PatKind::Binding(bind_ann, ..) = pat.kind; - if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable); - then { - span_lint_and_help( - cx, - SAME_ITEM_PUSH, - vec.span, - "it looks like the same item is being pushed into this Vec", - None, - &format!( - "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", - item_str, vec_str, item_str - ), - ) - } + match qpath_res(cx, qpath, pushed_item.hir_id) { + // immutable bindings that are initialized with literal or constant + Res::Local(hir_id) => { + if_chain! { + let node = cx.tcx.hir().get(hir_id); + if let Node::Binding(pat) = node; + if let PatKind::Binding(bind_ann, ..) = pat.kind; + if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable); + let parent_node = cx.tcx.hir().get_parent_node(hir_id); + if let Some(Node::Local(parent_let_expr)) = cx.tcx.hir().find(parent_node); + if let rustc_hir::Local { init: Some(init), .. } = parent_let_expr; + then { + match init.kind { + // immutable bindings that are initialized with literal + ExprKind::Lit(..) => { + span_lint_and_help( + cx, + SAME_ITEM_PUSH, + vec.span, + "it looks like the same item is being pushed into this Vec", + None, + &format!( + "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", + item_str, vec_str, item_str + ), + ) + }, + // immutable bindings that are initialized with constant + ExprKind::Path(ref path) => { + if let Res::Def(DefKind::Const, ..) = qpath_res(cx, path, init.hir_id) { + span_lint_and_help( + cx, + SAME_ITEM_PUSH, + vec.span, + "it looks like the same item is being pushed into this Vec", + None, + &format!( + "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", + item_str, vec_str, item_str + ), + ) + } + } + _ => {}, + } + } + } + }, + // constant + Res::Def(DefKind::Const, ..) => span_lint_and_help( + cx, + SAME_ITEM_PUSH, + vec.span, + "it looks like the same item is being pushed into this Vec", + None, + &format!( + "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", + item_str, vec_str, item_str + ), + ), + _ => {}, } - } else if mutated_variables(pushed_item, cx).map_or(false, |mutvars| mutvars.is_empty()) { + } else if let ExprKind::Lit(..) = pushed_item.kind { + // literal span_lint_and_help( cx, SAME_ITEM_PUSH, diff --git a/tests/ui/same_item_push.rs b/tests/ui/same_item_push.rs index 0928820892b13..bd4792c4a76be 100644 --- a/tests/ui/same_item_push.rs +++ b/tests/ui/same_item_push.rs @@ -1,5 +1,7 @@ #![warn(clippy::same_item_push)] +const VALUE: u8 = 7; + fn mutate_increment(x: &mut u8) -> u8 { *x += 1; *x @@ -111,4 +113,15 @@ fn main() { for _ in 0..10 { vec15.push(Box::new(S {})); } + + let mut vec16 = Vec::new(); + for _ in 0..20 { + vec16.push(VALUE); + } + + let mut vec17 = Vec::new(); + let item = VALUE; + for _ in 0..20 { + vec17.push(item); + } } diff --git a/tests/ui/same_item_push.stderr b/tests/ui/same_item_push.stderr index ddc5d48cd4135..4896479791af4 100644 --- a/tests/ui/same_item_push.stderr +++ b/tests/ui/same_item_push.stderr @@ -1,22 +1,14 @@ error: it looks like the same item is being pushed into this Vec - --> $DIR/same_item_push.rs:16:9 - | -LL | spaces.push(vec![b' ']); - | ^^^^^^ - | - = note: `-D clippy::same-item-push` implied by `-D warnings` - = help: try using vec![vec![b' '];SIZE] or spaces.resize(NEW_SIZE, vec![b' ']) - -error: it looks like the same item is being pushed into this Vec - --> $DIR/same_item_push.rs:22:9 + --> $DIR/same_item_push.rs:24:9 | LL | vec2.push(item); | ^^^^ | + = note: `-D clippy::same-item-push` implied by `-D warnings` = help: try using vec![item;SIZE] or vec2.resize(NEW_SIZE, item) error: it looks like the same item is being pushed into this Vec - --> $DIR/same_item_push.rs:28:9 + --> $DIR/same_item_push.rs:30:9 | LL | vec3.push(item); | ^^^^ @@ -24,12 +16,28 @@ LL | vec3.push(item); = help: try using vec![item;SIZE] or vec3.resize(NEW_SIZE, item) error: it looks like the same item is being pushed into this Vec - --> $DIR/same_item_push.rs:33:9 + --> $DIR/same_item_push.rs:35:9 | LL | vec4.push(13); | ^^^^ | = help: try using vec![13;SIZE] or vec4.resize(NEW_SIZE, 13) -error: aborting due to 4 previous errors +error: it looks like the same item is being pushed into this Vec + --> $DIR/same_item_push.rs:119:9 + | +LL | vec16.push(VALUE); + | ^^^^^ + | + = help: try using vec![VALUE;SIZE] or vec16.resize(NEW_SIZE, VALUE) + +error: it looks like the same item is being pushed into this Vec + --> $DIR/same_item_push.rs:125:9 + | +LL | vec17.push(item); + | ^^^^^ + | + = help: try using vec![item;SIZE] or vec17.resize(NEW_SIZE, item) + +error: aborting due to 5 previous errors From 619ca76731e7209288fd3ebf1ae243c050486c12 Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Tue, 8 Sep 2020 08:25:31 +0900 Subject: [PATCH 0161/1052] Refactoring: use inner function --- clippy_lints/src/loops.rs | 69 ++++++++++++--------------------------- 1 file changed, 21 insertions(+), 48 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index f417e3a0caf95..c27acdd22365d 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1150,8 +1150,6 @@ fn detect_same_item_push<'tcx>( { // Make sure that the push does not involve possibly mutating values if let PatKind::Wild = pat.kind { - let vec_str = snippet_with_macro_callsite(cx, vec.span, ""); - let item_str = snippet_with_macro_callsite(cx, pushed_item.span, ""); if let ExprKind::Path(ref qpath) = pushed_item.kind { match qpath_res(cx, qpath, pushed_item.hir_id) { // immutable bindings that are initialized with literal or constant @@ -1167,33 +1165,11 @@ fn detect_same_item_push<'tcx>( then { match init.kind { // immutable bindings that are initialized with literal - ExprKind::Lit(..) => { - span_lint_and_help( - cx, - SAME_ITEM_PUSH, - vec.span, - "it looks like the same item is being pushed into this Vec", - None, - &format!( - "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", - item_str, vec_str, item_str - ), - ) - }, + ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item), // immutable bindings that are initialized with constant ExprKind::Path(ref path) => { if let Res::Def(DefKind::Const, ..) = qpath_res(cx, path, init.hir_id) { - span_lint_and_help( - cx, - SAME_ITEM_PUSH, - vec.span, - "it looks like the same item is being pushed into this Vec", - None, - &format!( - "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", - item_str, vec_str, item_str - ), - ) + emit_lint(cx, vec, pushed_item); } } _ => {}, @@ -1202,37 +1178,34 @@ fn detect_same_item_push<'tcx>( } }, // constant - Res::Def(DefKind::Const, ..) => span_lint_and_help( - cx, - SAME_ITEM_PUSH, - vec.span, - "it looks like the same item is being pushed into this Vec", - None, - &format!( - "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", - item_str, vec_str, item_str - ), - ), + Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item), _ => {}, } } else if let ExprKind::Lit(..) = pushed_item.kind { // literal - span_lint_and_help( - cx, - SAME_ITEM_PUSH, - vec.span, - "it looks like the same item is being pushed into this Vec", - None, - &format!( - "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", - item_str, vec_str, item_str - ), - ) + emit_lint(cx, vec, pushed_item); } } } } } + + fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>) { + let vec_str = snippet_with_macro_callsite(cx, vec.span, ""); + let item_str = snippet_with_macro_callsite(cx, pushed_item.span, ""); + + span_lint_and_help( + cx, + SAME_ITEM_PUSH, + vec.span, + "it looks like the same item is being pushed into this Vec", + None, + &format!( + "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", + item_str, vec_str, item_str + ), + ) + } } /// Checks for looping over a range and then indexing a sequence with it. From 5d085ad011a602e004e7d33fa0b9074c7dab36fc Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Tue, 8 Sep 2020 08:34:51 +0900 Subject: [PATCH 0162/1052] Some refactoring --- clippy_lints/src/loops.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index c27acdd22365d..c59185bd7bd15 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1131,6 +1131,10 @@ fn detect_same_item_push<'tcx>( body: &'tcx Expr<'_>, _: &'tcx Expr<'_>, ) { + if !matches!(pat.kind, PatKind::Wild) { + return; + } + // Determine whether it is safe to lint the body let mut same_item_push_visitor = SameItemPushVisitor { should_lint: true, @@ -1149,8 +1153,8 @@ fn detect_same_item_push<'tcx>( .map_or(false, |id| implements_trait(cx, ty, id, &[])) { // Make sure that the push does not involve possibly mutating values - if let PatKind::Wild = pat.kind { - if let ExprKind::Path(ref qpath) = pushed_item.kind { + match pushed_item.kind { + ExprKind::Path(ref qpath) => { match qpath_res(cx, qpath, pushed_item.hir_id) { // immutable bindings that are initialized with literal or constant Res::Local(hir_id) => { @@ -1161,7 +1165,7 @@ fn detect_same_item_push<'tcx>( if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable); let parent_node = cx.tcx.hir().get_parent_node(hir_id); if let Some(Node::Local(parent_let_expr)) = cx.tcx.hir().find(parent_node); - if let rustc_hir::Local { init: Some(init), .. } = parent_let_expr; + if let Some(init) = parent_let_expr.init; then { match init.kind { // immutable bindings that are initialized with literal @@ -1181,10 +1185,9 @@ fn detect_same_item_push<'tcx>( Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item), _ => {}, } - } else if let ExprKind::Lit(..) = pushed_item.kind { - // literal - emit_lint(cx, vec, pushed_item); - } + }, + ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item), + _ => {}, } } } From b869aa5f316ae065ce2215e69811e3216c6250cb Mon Sep 17 00:00:00 2001 From: marmeladema Date: Sun, 30 Aug 2020 18:31:34 +0100 Subject: [PATCH 0163/1052] Add saturating methods for `Duration` --- library/core/src/lib.rs | 1 + library/core/src/time.rs | 97 +++++++++++++++++++++++++ library/core/tests/lib.rs | 2 + library/core/tests/time.rs | 30 ++++++++ src/test/ui/consts/duration-consts-2.rs | 42 +++++++---- 5 files changed, 156 insertions(+), 16 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 29bbf062f22e4..c3cadcbb01e31 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -100,6 +100,7 @@ #![feature(doc_cfg)] #![feature(doc_spotlight)] #![feature(duration_consts_2)] +#![feature(duration_saturating_ops)] #![feature(extern_types)] #![feature(fundamental)] #![feature(intrinsics)] diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 5741f8a53b522..f39781788d7c0 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -108,6 +108,34 @@ impl Duration { #[unstable(feature = "duration_constants", issue = "57391")] pub const NANOSECOND: Duration = Duration::from_nanos(1); + /// The minimum duration. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_constants)] + /// use std::time::Duration; + /// + /// assert_eq!(Duration::MIN, Duration::new(0, 0)); + /// ``` + #[unstable(feature = "duration_constants", issue = "57391")] + pub const MIN: Duration = Duration::from_nanos(0); + + /// The maximum duration. + /// + /// It is roughly equal to a duration of 584,942,417,355 years. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_constants)] + /// use std::time::Duration; + /// + /// assert_eq!(Duration::MAX, Duration::new(u64::MAX, 1_000_000_000 - 1)); + /// ``` + #[unstable(feature = "duration_constants", issue = "57391")] + pub const MAX: Duration = Duration::new(u64::MAX, NANOS_PER_SEC - 1); + /// Creates a new `Duration` from the specified number of whole seconds and /// additional nanoseconds. /// @@ -450,6 +478,29 @@ impl Duration { } } + /// Saturating `Duration` addition. Computes `self + other`, returning [`Duration::MAX`] + /// if overflow occurred. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_saturating_ops)] + /// #![feature(duration_constants)] + /// use std::time::Duration; + /// + /// assert_eq!(Duration::new(0, 0).saturating_add(Duration::new(0, 1)), Duration::new(0, 1)); + /// assert_eq!(Duration::new(1, 0).saturating_add(Duration::new(u64::MAX, 0)), Duration::MAX); + /// ``` + #[unstable(feature = "duration_saturating_ops", issue = "76416")] + #[inline] + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn saturating_add(self, rhs: Duration) -> Duration { + match self.checked_add(rhs) { + Some(res) => res, + None => Duration::MAX, + } + } + /// Checked `Duration` subtraction. Computes `self - other`, returning [`None`] /// if the result would be negative or if overflow occurred. /// @@ -485,6 +536,29 @@ impl Duration { } } + /// Saturating `Duration` subtraction. Computes `self - other`, returning [`Duration::MIN`] + /// if the result would be negative or if overflow occurred. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_saturating_ops)] + /// #![feature(duration_constants)] + /// use std::time::Duration; + /// + /// assert_eq!(Duration::new(0, 1).saturating_sub(Duration::new(0, 0)), Duration::new(0, 1)); + /// assert_eq!(Duration::new(0, 0).saturating_sub(Duration::new(0, 1)), Duration::MIN); + /// ``` + #[unstable(feature = "duration_saturating_ops", issue = "76416")] + #[inline] + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn saturating_sub(self, rhs: Duration) -> Duration { + match self.checked_sub(rhs) { + Some(res) => res, + None => Duration::MIN, + } + } + /// Checked `Duration` multiplication. Computes `self * other`, returning /// [`None`] if overflow occurred. /// @@ -515,6 +589,29 @@ impl Duration { None } + /// Saturating `Duration` multiplication. Computes `self * other`, returning + /// [`Duration::MAX`] if overflow occurred. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_saturating_ops)] + /// #![feature(duration_constants)] + /// use std::time::Duration; + /// + /// assert_eq!(Duration::new(0, 500_000_001).saturating_mul(2), Duration::new(1, 2)); + /// assert_eq!(Duration::new(u64::MAX - 1, 0).saturating_mul(2), Duration::MAX); + /// ``` + #[unstable(feature = "duration_saturating_ops", issue = "76416")] + #[inline] + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn saturating_mul(self, rhs: u32) -> Duration { + match self.checked_mul(rhs) { + Some(res) => res, + None => Duration::MAX, + } + } + /// Checked `Duration` division. Computes `self / other`, returning [`None`] /// if `other == 0`. /// diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 4a651e5aa0ee3..a2e294ace1860 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -10,6 +10,8 @@ #![feature(core_private_diy_float)] #![feature(debug_non_exhaustive)] #![feature(dec2flt)] +#![feature(duration_constants)] +#![feature(duration_saturating_ops)] #![feature(exact_size_is_empty)] #![feature(fixed_size_array)] #![feature(flt2dec)] diff --git a/library/core/tests/time.rs b/library/core/tests/time.rs index 7a6675dc82fa6..4f90eb63b0472 100644 --- a/library/core/tests/time.rs +++ b/library/core/tests/time.rs @@ -89,6 +89,16 @@ fn checked_add() { assert_eq!(Duration::new(1, 0).checked_add(Duration::new(u64::MAX, 0)), None); } +#[test] +fn saturating_add() { + assert_eq!(Duration::new(0, 0).saturating_add(Duration::new(0, 1)), Duration::new(0, 1)); + assert_eq!( + Duration::new(0, 500_000_000).saturating_add(Duration::new(0, 500_000_001)), + Duration::new(1, 1) + ); + assert_eq!(Duration::new(1, 0).saturating_add(Duration::new(u64::MAX, 0)), Duration::MAX); +} + #[test] fn sub() { assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), Duration::new(0, 1)); @@ -107,6 +117,17 @@ fn checked_sub() { assert_eq!(zero.checked_sub(one_sec), None); } +#[test] +fn saturating_sub() { + let zero = Duration::new(0, 0); + let one_nano = Duration::new(0, 1); + let one_sec = Duration::new(1, 0); + assert_eq!(one_nano.saturating_sub(zero), Duration::new(0, 1)); + assert_eq!(one_sec.saturating_sub(one_nano), Duration::new(0, 999_999_999)); + assert_eq!(zero.saturating_sub(one_nano), Duration::MIN); + assert_eq!(zero.saturating_sub(one_sec), Duration::MIN); +} + #[test] #[should_panic] fn sub_bad1() { @@ -136,6 +157,15 @@ fn checked_mul() { assert_eq!(Duration::new(u64::MAX - 1, 0).checked_mul(2), None); } +#[test] +fn saturating_mul() { + assert_eq!(Duration::new(0, 1).saturating_mul(2), Duration::new(0, 2)); + assert_eq!(Duration::new(1, 1).saturating_mul(3), Duration::new(3, 3)); + assert_eq!(Duration::new(0, 500_000_001).saturating_mul(4), Duration::new(2, 4)); + assert_eq!(Duration::new(0, 500_000_001).saturating_mul(4000), Duration::new(2000, 4000)); + assert_eq!(Duration::new(u64::MAX - 1, 0).saturating_mul(2), Duration::MAX); +} + #[test] fn div() { assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0)); diff --git a/src/test/ui/consts/duration-consts-2.rs b/src/test/ui/consts/duration-consts-2.rs index c8b3939933126..bc0969e4f1fba 100644 --- a/src/test/ui/consts/duration-consts-2.rs +++ b/src/test/ui/consts/duration-consts-2.rs @@ -3,6 +3,7 @@ #![feature(const_panic)] #![feature(duration_consts_2)] #![feature(div_duration)] +#![feature(duration_saturating_ops)] use std::time::Duration; @@ -15,29 +16,29 @@ fn duration() { const MAX : Duration = Duration::new(u64::MAX, 1_000_000_000 - 1); - const MAX_ADD_ZERO : Option = MAX.checked_add(ZERO); - assert_eq!(MAX_ADD_ZERO, Some(MAX)); + const MAX_CHECKED_ADD_ZERO : Option = MAX.checked_add(ZERO); + assert_eq!(MAX_CHECKED_ADD_ZERO, Some(MAX)); - const MAX_ADD_ONE : Option = MAX.checked_add(ONE); - assert_eq!(MAX_ADD_ONE, None); + const MAX_CHECKED_ADD_ONE : Option = MAX.checked_add(ONE); + assert_eq!(MAX_CHECKED_ADD_ONE, None); - const ONE_SUB_ONE : Option = ONE.checked_sub(ONE); - assert_eq!(ONE_SUB_ONE, Some(ZERO)); + const ONE_CHECKED_SUB_ONE : Option = ONE.checked_sub(ONE); + assert_eq!(ONE_CHECKED_SUB_ONE, Some(ZERO)); - const ZERO_SUB_ONE : Option = ZERO.checked_sub(ONE); - assert_eq!(ZERO_SUB_ONE, None); + const ZERO_CHECKED_SUB_ONE : Option = ZERO.checked_sub(ONE); + assert_eq!(ZERO_CHECKED_SUB_ONE, None); - const ONE_MUL_ONE : Option = ONE.checked_mul(1); - assert_eq!(ONE_MUL_ONE, Some(ONE)); + const ONE_CHECKED_MUL_ONE : Option = ONE.checked_mul(1); + assert_eq!(ONE_CHECKED_MUL_ONE, Some(ONE)); - const MAX_MUL_TWO : Option = MAX.checked_mul(2); - assert_eq!(MAX_MUL_TWO, None); + const MAX_CHECKED_MUL_TWO : Option = MAX.checked_mul(2); + assert_eq!(MAX_CHECKED_MUL_TWO, None); - const ONE_DIV_ONE : Option = ONE.checked_div(1); - assert_eq!(ONE_DIV_ONE, Some(ONE)); + const ONE_CHECKED_DIV_ONE : Option = ONE.checked_div(1); + assert_eq!(ONE_CHECKED_DIV_ONE, Some(ONE)); - const ONE_DIV_ZERO : Option = ONE.checked_div(0); - assert_eq!(ONE_DIV_ZERO, None); + const ONE_CHECKED_DIV_ZERO : Option = ONE.checked_div(0); + assert_eq!(ONE_CHECKED_DIV_ZERO, None); const MAX_AS_F32 : f32 = MAX.as_secs_f32(); assert_eq!(MAX_AS_F32, 18446744000000000000.0_f32); @@ -50,6 +51,15 @@ fn duration() { const ONE_AS_F64 : f64 = ONE.div_duration_f64(ONE); assert_eq!(ONE_AS_F64, 1.0_f64); + + const MAX_SATURATING_ADD_ONE : Duration = MAX.saturating_add(ONE); + assert_eq!(MAX_SATURATING_ADD_ONE, MAX); + + const ZERO_SATURATING_SUB_ONE : Duration = ZERO.saturating_sub(ONE); + assert_eq!(ZERO_SATURATING_SUB_ONE, ZERO); + + const MAX_SATURATING_MUL_TWO : Duration = MAX.saturating_mul(2); + assert_eq!(MAX_SATURATING_MUL_TWO, MAX); } fn main() { From ed4dcc04d8957e35da8256f6ffdd1ac574af4a76 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 7 Sep 2020 20:32:09 -0400 Subject: [PATCH 0164/1052] Make rustdoc output deterministic for UI tests --- src/test/rustdoc-ui/failed-doctest-output.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/rustdoc-ui/failed-doctest-output.rs b/src/test/rustdoc-ui/failed-doctest-output.rs index fcbd7cabc6900..90cdb5127bea2 100644 --- a/src/test/rustdoc-ui/failed-doctest-output.rs +++ b/src/test/rustdoc-ui/failed-doctest-output.rs @@ -2,7 +2,7 @@ // FIXME: if/when the output of the test harness can be tested on its own, this test should be // adapted to use that, and that normalize line can go away -// compile-flags:--test +// compile-flags:--test --test-args --test-threads=1 // rustc-env:RUST_BACKTRACE=0 // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" // failure-status: 101 From 3a3a08585f0a0240c7b73efd5c77e78d2af38755 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Tue, 8 Sep 2020 09:08:25 +0800 Subject: [PATCH 0165/1052] Unstable book rust-attrs does not work on generics Co-authored-by: Peter Todd --- src/doc/unstable-book/src/language-features/rustc-attrs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/unstable-book/src/language-features/rustc-attrs.md b/src/doc/unstable-book/src/language-features/rustc-attrs.md index a67e364ba3fc3..1d9409ee9e438 100644 --- a/src/doc/unstable-book/src/language-features/rustc-attrs.md +++ b/src/doc/unstable-book/src/language-features/rustc-attrs.md @@ -14,7 +14,7 @@ with `cargo check`) as an alternative to `rustc -Z print-type-sizes` that is way more verbose. Options provided by `#[rustc_layout(...)]` are `debug`, `size`, `align`, -`abi`. Note that it only work best with sized type without generics. +`abi`. Note that it only works on sized types without generics. ## Examples From 0c9bf13f5f11047bb03313624f0430d93d4e840d Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 7 Sep 2020 22:06:23 -0400 Subject: [PATCH 0166/1052] Add a script to automatically update Rust/Clang versions --- src/doc/rustc/src/linker-plugin-lto.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/doc/rustc/src/linker-plugin-lto.md b/src/doc/rustc/src/linker-plugin-lto.md index c0b14352b7d1a..7ddd5ae52752e 100644 --- a/src/doc/rustc/src/linker-plugin-lto.md +++ b/src/doc/rustc/src/linker-plugin-lto.md @@ -89,6 +89,28 @@ rustc -Clinker-plugin-lto="/path/to/LLVMgold.so" -L. -Copt-level=2 ./main.rs ## Toolchain Compatibility + + In order for this kind of LTO to work, the LLVM linker plugin must be able to handle the LLVM bitcode produced by both `rustc` and `clang`. From f64ddc60a504a7dfee41fec477dd678d54d19b22 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Tue, 8 Sep 2020 10:43:52 +0200 Subject: [PATCH 0167/1052] triagebot: enable github releases synchronization --- triagebot.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 707e381b06e47..bcdc40017b526 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -99,3 +99,9 @@ message_on_add = """\ - Needs `I-nominated`? """ message_on_remove = "Issue #{number}'s prioritization request has been removed." + +[github-releases] +format = "rustc" +project-name = "Rust" +changelog-path = "RELEASES.md" +changelog-branch = "master" From c8262fd87b91e6a699483d8d66ef1be3ced00a71 Mon Sep 17 00:00:00 2001 From: ortem Date: Tue, 8 Sep 2020 12:20:49 +0300 Subject: [PATCH 0168/1052] Add missed spaces to GCC-WARNING.txt --- src/bootstrap/dist.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index c1022099a0230..b3ab498e73fc0 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -323,8 +323,8 @@ fn make_win_dist( // Warn windows-gnu users that the bundled GCC cannot compile C files builder.create( &target_bin_dir.join("GCC-WARNING.txt"), - "gcc.exe contained in this folder cannot be used for compiling C files - it is only\ - used as a linker. In order to be able to compile projects containing C code use\ + "gcc.exe contained in this folder cannot be used for compiling C files - it is only \ + used as a linker. In order to be able to compile projects containing C code use \ the GCC provided by MinGW or Cygwin.", ); From 0065e33c24213c538ffd76b0cc771e4668819969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Tue, 8 Sep 2020 11:32:25 +0200 Subject: [PATCH 0169/1052] rustbuild: don't set PYTHON_EXECUTABLE and WITH_POLLY cmake vars since they are no longer supported by llvm CMake Warning: Manually-specified variables were not used by the project: PYTHON_EXECUTABLE WITH_POLLY --- src/bootstrap/native.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index a0c79e38f9d8c..6cd850bc0bfaa 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -169,7 +169,6 @@ impl Step for Llvm { .define("LLVM_INCLUDE_TESTS", "OFF") .define("LLVM_INCLUDE_DOCS", "OFF") .define("LLVM_INCLUDE_BENCHMARKS", "OFF") - .define("WITH_POLLY", "OFF") .define("LLVM_ENABLE_TERMINFO", "OFF") .define("LLVM_ENABLE_LIBEDIT", "OFF") .define("LLVM_ENABLE_BINDINGS", "OFF") @@ -305,10 +304,6 @@ impl Step for Llvm { cfg.define("LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN", "YES"); } - if let Some(ref python) = builder.config.python { - cfg.define("PYTHON_EXECUTABLE", python); - } - configure_cmake(builder, target, &mut cfg, true); // FIXME: we don't actually need to build all LLVM tools and all LLVM From 2c9f82e7d22a5cd3f704ed0b932a17fa53f1145b Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Tue, 8 Sep 2020 22:45:27 +0900 Subject: [PATCH 0170/1052] Add some tests to `same_item_push` Add tests in which the variable is initialized with a match expression and function call --- tests/ui/same_item_push.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/ui/same_item_push.rs b/tests/ui/same_item_push.rs index bd4792c4a76be..7ca829854db18 100644 --- a/tests/ui/same_item_push.rs +++ b/tests/ui/same_item_push.rs @@ -11,6 +11,10 @@ fn increment(x: u8) -> u8 { x + 1 } +fn fun() -> usize { + 42 +} + fn main() { // Test for basic case let mut spaces = Vec::with_capacity(10); @@ -124,4 +128,21 @@ fn main() { for _ in 0..20 { vec17.push(item); } + + let mut vec18 = Vec::new(); + let item = 42; + let item = fun(); + for _ in 0..20 { + vec18.push(item); + } + + let mut vec19 = Vec::new(); + let key = 1; + for _ in 0..20 { + let item = match key { + 1 => 10, + _ => 0, + }; + vec19.push(item); + } } From 952c04674e4225d231f0ba78dff32abf7c06cb8b Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Tue, 8 Sep 2020 23:03:15 +0900 Subject: [PATCH 0171/1052] Refactoring: tests in `same_item_push` --- tests/ui/same_item_push.rs | 99 +++++++++++++++++----------------- tests/ui/same_item_push.stderr | 40 +++++++------- 2 files changed, 71 insertions(+), 68 deletions(-) diff --git a/tests/ui/same_item_push.rs b/tests/ui/same_item_push.rs index 7ca829854db18..a37c8782ec330 100644 --- a/tests/ui/same_item_push.rs +++ b/tests/ui/same_item_push.rs @@ -16,64 +16,76 @@ fn fun() -> usize { } fn main() { - // Test for basic case - let mut spaces = Vec::with_capacity(10); - for _ in 0..10 { - spaces.push(vec![b' ']); - } - - let mut vec2: Vec = Vec::new(); + // ** linted cases ** + let mut vec: Vec = Vec::new(); let item = 2; for _ in 5..=20 { - vec2.push(item); + vec.push(item); } - let mut vec3: Vec = Vec::new(); + let mut vec: Vec = Vec::new(); for _ in 0..15 { let item = 2; - vec3.push(item); + vec.push(item); } - let mut vec4: Vec = Vec::new(); + let mut vec: Vec = Vec::new(); for _ in 0..15 { - vec4.push(13); + vec.push(13); + } + + let mut vec = Vec::new(); + for _ in 0..20 { + vec.push(VALUE); + } + + let mut vec = Vec::new(); + let item = VALUE; + for _ in 0..20 { + vec.push(item); + } + + // ** non-linted cases ** + let mut spaces = Vec::with_capacity(10); + for _ in 0..10 { + spaces.push(vec![b' ']); } // Suggestion should not be given as pushed variable can mutate - let mut vec5: Vec = Vec::new(); + let mut vec: Vec = Vec::new(); let mut item: u8 = 2; for _ in 0..30 { - vec5.push(mutate_increment(&mut item)); + vec.push(mutate_increment(&mut item)); } - let mut vec6: Vec = Vec::new(); + let mut vec: Vec = Vec::new(); let mut item: u8 = 2; let mut item2 = &mut mutate_increment(&mut item); for _ in 0..30 { - vec6.push(mutate_increment(item2)); + vec.push(mutate_increment(item2)); } - let mut vec7: Vec = Vec::new(); + let mut vec: Vec = Vec::new(); for (a, b) in [0, 1, 4, 9, 16].iter().enumerate() { - vec7.push(a); + vec.push(a); } - let mut vec8: Vec = Vec::new(); + let mut vec: Vec = Vec::new(); for i in 0..30 { - vec8.push(increment(i)); + vec.push(increment(i)); } - let mut vec9: Vec = Vec::new(); + let mut vec: Vec = Vec::new(); for i in 0..30 { - vec9.push(i + i * i); + vec.push(i + i * i); } // Suggestion should not be given as there are multiple pushes that are not the same - let mut vec10: Vec = Vec::new(); + let mut vec: Vec = Vec::new(); let item: u8 = 2; for _ in 0..30 { - vec10.push(item); - vec10.push(item * 2); + vec.push(item); + vec.push(item * 2); } // Suggestion should not be given as Vec is not involved @@ -88,23 +100,23 @@ fn main() { for i in 0..30 { vec_a.push(A { kind: i }); } - let mut vec12: Vec = Vec::new(); + let mut vec: Vec = Vec::new(); for a in vec_a { - vec12.push(2u8.pow(a.kind)); + vec.push(2u8.pow(a.kind)); } // Fix #5902 - let mut vec13: Vec = Vec::new(); + let mut vec: Vec = Vec::new(); let mut item = 0; for _ in 0..10 { - vec13.push(item); + vec.push(item); item += 10; } // Fix #5979 - let mut vec14: Vec = Vec::new(); + let mut vec: Vec = Vec::new(); for _ in 0..10 { - vec14.push(std::fs::File::open("foobar").unwrap()); + vec.push(std::fs::File::open("foobar").unwrap()); } // Fix #5979 #[derive(Clone)] @@ -113,36 +125,27 @@ fn main() { trait T {} impl T for S {} - let mut vec15: Vec> = Vec::new(); + let mut vec: Vec> = Vec::new(); for _ in 0..10 { - vec15.push(Box::new(S {})); - } - - let mut vec16 = Vec::new(); - for _ in 0..20 { - vec16.push(VALUE); - } - - let mut vec17 = Vec::new(); - let item = VALUE; - for _ in 0..20 { - vec17.push(item); + vec.push(Box::new(S {})); } - let mut vec18 = Vec::new(); + // Fix #5985 + let mut vec = Vec::new(); let item = 42; let item = fun(); for _ in 0..20 { - vec18.push(item); + vec.push(item); } - let mut vec19 = Vec::new(); + // Fix #5985 + let mut vec = Vec::new(); let key = 1; for _ in 0..20 { let item = match key { 1 => 10, _ => 0, }; - vec19.push(item); + vec.push(item); } } diff --git a/tests/ui/same_item_push.stderr b/tests/ui/same_item_push.stderr index 4896479791af4..d9ffa15780ad0 100644 --- a/tests/ui/same_item_push.stderr +++ b/tests/ui/same_item_push.stderr @@ -1,43 +1,43 @@ error: it looks like the same item is being pushed into this Vec - --> $DIR/same_item_push.rs:24:9 + --> $DIR/same_item_push.rs:23:9 | -LL | vec2.push(item); - | ^^^^ +LL | vec.push(item); + | ^^^ | = note: `-D clippy::same-item-push` implied by `-D warnings` - = help: try using vec![item;SIZE] or vec2.resize(NEW_SIZE, item) + = help: try using vec![item;SIZE] or vec.resize(NEW_SIZE, item) error: it looks like the same item is being pushed into this Vec - --> $DIR/same_item_push.rs:30:9 + --> $DIR/same_item_push.rs:29:9 | -LL | vec3.push(item); - | ^^^^ +LL | vec.push(item); + | ^^^ | - = help: try using vec![item;SIZE] or vec3.resize(NEW_SIZE, item) + = help: try using vec![item;SIZE] or vec.resize(NEW_SIZE, item) error: it looks like the same item is being pushed into this Vec - --> $DIR/same_item_push.rs:35:9 + --> $DIR/same_item_push.rs:34:9 | -LL | vec4.push(13); - | ^^^^ +LL | vec.push(13); + | ^^^ | - = help: try using vec![13;SIZE] or vec4.resize(NEW_SIZE, 13) + = help: try using vec![13;SIZE] or vec.resize(NEW_SIZE, 13) error: it looks like the same item is being pushed into this Vec - --> $DIR/same_item_push.rs:119:9 + --> $DIR/same_item_push.rs:39:9 | -LL | vec16.push(VALUE); - | ^^^^^ +LL | vec.push(VALUE); + | ^^^ | - = help: try using vec![VALUE;SIZE] or vec16.resize(NEW_SIZE, VALUE) + = help: try using vec![VALUE;SIZE] or vec.resize(NEW_SIZE, VALUE) error: it looks like the same item is being pushed into this Vec - --> $DIR/same_item_push.rs:125:9 + --> $DIR/same_item_push.rs:45:9 | -LL | vec17.push(item); - | ^^^^^ +LL | vec.push(item); + | ^^^ | - = help: try using vec![item;SIZE] or vec17.resize(NEW_SIZE, item) + = help: try using vec![item;SIZE] or vec.resize(NEW_SIZE, item) error: aborting due to 5 previous errors From 1d8ae3aa12567b8461436ac10ba9fc4da55adb29 Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Tue, 8 Sep 2020 23:12:04 +0900 Subject: [PATCH 0172/1052] Address `items_after_statement` --- clippy_lints/src/loops.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index c59185bd7bd15..6c54c07869ad1 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1131,6 +1131,23 @@ fn detect_same_item_push<'tcx>( body: &'tcx Expr<'_>, _: &'tcx Expr<'_>, ) { + fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>) { + let vec_str = snippet_with_macro_callsite(cx, vec.span, ""); + let item_str = snippet_with_macro_callsite(cx, pushed_item.span, ""); + + span_lint_and_help( + cx, + SAME_ITEM_PUSH, + vec.span, + "it looks like the same item is being pushed into this Vec", + None, + &format!( + "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", + item_str, vec_str, item_str + ), + ) + } + if !matches!(pat.kind, PatKind::Wild) { return; } @@ -1192,23 +1209,6 @@ fn detect_same_item_push<'tcx>( } } } - - fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>) { - let vec_str = snippet_with_macro_callsite(cx, vec.span, ""); - let item_str = snippet_with_macro_callsite(cx, pushed_item.span, ""); - - span_lint_and_help( - cx, - SAME_ITEM_PUSH, - vec.span, - "it looks like the same item is being pushed into this Vec", - None, - &format!( - "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", - item_str, vec_str, item_str - ), - ) - } } /// Checks for looping over a range and then indexing a sequence with it. From a899ad2e125e8dd3a0a339df1f8457ef8cab3cc7 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Tue, 8 Sep 2020 23:35:19 +0900 Subject: [PATCH 0173/1052] Change suggestion to `create_dir_all({})` from `std::fs::create_dir_all({})` --- clippy_lints/src/create_dir.rs | 2 +- tests/ui/create_dir.fixed | 6 ++++-- tests/ui/create_dir.rs | 2 ++ tests/ui/create_dir.stderr | 8 ++++---- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs index f80a0efa7a554..4002fb655a5eb 100644 --- a/clippy_lints/src/create_dir.rs +++ b/clippy_lints/src/create_dir.rs @@ -42,7 +42,7 @@ impl LateLintPass<'_> for CreateDir { expr.span, "calling `std::fs::create_dir` where there may be a better way", "consider calling `std::fs::create_dir_all` instead", - format!("std::fs::create_dir_all({})", snippet(cx, args[0].span, "..")), + format!("create_dir_all({})", snippet(cx, args[0].span, "..")), Applicability::MaybeIncorrect, ) } diff --git a/tests/ui/create_dir.fixed b/tests/ui/create_dir.fixed index 0e28f87e33d4f..8ed53a56ac043 100644 --- a/tests/ui/create_dir.fixed +++ b/tests/ui/create_dir.fixed @@ -2,12 +2,14 @@ #![allow(unused_must_use)] #![warn(clippy::create_dir)] +use std::fs::create_dir_all; + fn create_dir() {} fn main() { // Should be warned - std::fs::create_dir_all("foo"); - std::fs::create_dir_all("bar").unwrap(); + create_dir_all("foo"); + create_dir_all("bar").unwrap(); // Shouldn't be warned create_dir(); diff --git a/tests/ui/create_dir.rs b/tests/ui/create_dir.rs index 1f226298c0d0d..19c8fc24ba23f 100644 --- a/tests/ui/create_dir.rs +++ b/tests/ui/create_dir.rs @@ -2,6 +2,8 @@ #![allow(unused_must_use)] #![warn(clippy::create_dir)] +use std::fs::create_dir_all; + fn create_dir() {} fn main() { diff --git a/tests/ui/create_dir.stderr b/tests/ui/create_dir.stderr index 0c97bdd0f7aba..67298fc47095c 100644 --- a/tests/ui/create_dir.stderr +++ b/tests/ui/create_dir.stderr @@ -1,16 +1,16 @@ error: calling `std::fs::create_dir` where there may be a better way - --> $DIR/create_dir.rs:9:5 + --> $DIR/create_dir.rs:11:5 | LL | std::fs::create_dir("foo"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `std::fs::create_dir_all` instead: `std::fs::create_dir_all("foo")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `std::fs::create_dir_all` instead: `create_dir_all("foo")` | = note: `-D clippy::create-dir` implied by `-D warnings` error: calling `std::fs::create_dir` where there may be a better way - --> $DIR/create_dir.rs:10:5 + --> $DIR/create_dir.rs:12:5 | LL | std::fs::create_dir("bar").unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `std::fs::create_dir_all` instead: `std::fs::create_dir_all("bar")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `std::fs::create_dir_all` instead: `create_dir_all("bar")` error: aborting due to 2 previous errors From c81935e6dfd3877db266f0a01d9323f203f92eda Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 6 Aug 2020 10:00:08 +0200 Subject: [PATCH 0174/1052] make `ConstEvaluatable` more strict --- compiler/rustc_middle/src/mir/mod.rs | 27 ++++++++-- .../src/traits/fulfill.rs | 18 ++++--- .../rustc_trait_selection/src/traits/mod.rs | 1 + .../src/traits/select/mod.rs | 20 +++---- .../traits/const_evaluatable.rs | 54 +++++++++++++++++++ .../ui/const_evaluatable/associated_const.rs | 11 ++++ .../issue-70453-polymorphic-ctfe.rs | 3 +- .../issue-70453-polymorphic-ctfe.stderr | 10 ++++ src/test/ui/impl-trait/issue-56445.rs | 3 +- .../lazy_normalization_consts/issue-73980.rs | 2 +- .../issue-73980.stderr | 10 ++++ 11 files changed, 133 insertions(+), 26 deletions(-) create mode 100644 src/librustc_trait_selection/traits/const_evaluatable.rs create mode 100644 src/test/ui/const_evaluatable/associated_const.rs create mode 100644 src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr create mode 100644 src/test/ui/lazy_normalization_consts/issue-73980.stderr diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 96e2a0ba618a3..197e8dd534112 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -186,6 +186,19 @@ pub struct Body<'tcx> { /// FIXME(oli-obk): rewrite the promoted during promotion to eliminate the cell components. pub ignore_interior_mut_in_const_validation: bool, + /// Does this body use generic parameters. This is used for the `ConstEvaluatable` check. + /// + /// Note that this does not actually mean that this body is not computable right now. + /// The repeat count in the following example is polymorphic, but can still be evaluated + /// without knowing anything about the type parameter `T`. + /// + /// ```rust + /// fn test() { + /// let _ = [0; std::mem::size_of::<*mut T>()]; + /// } + /// ``` + pub is_polymorphic: bool, + predecessor_cache: PredecessorCache, } @@ -208,7 +221,7 @@ impl<'tcx> Body<'tcx> { local_decls.len() ); - Body { + let mut body = Body { phase: MirPhase::Build, basic_blocks, source_scopes, @@ -224,8 +237,11 @@ impl<'tcx> Body<'tcx> { span, required_consts: Vec::new(), ignore_interior_mut_in_const_validation: false, + is_polymorphic: false, predecessor_cache: PredecessorCache::new(), - } + }; + body.is_polymorphic = body.has_param_types_or_consts(); + body } /// Returns a partially initialized MIR body containing only a list of basic blocks. @@ -234,7 +250,7 @@ impl<'tcx> Body<'tcx> { /// is only useful for testing but cannot be `#[cfg(test)]` because it is used in a different /// crate. pub fn new_cfg_only(basic_blocks: IndexVec>) -> Self { - Body { + let mut body = Body { phase: MirPhase::Build, basic_blocks, source_scopes: IndexVec::new(), @@ -250,8 +266,11 @@ impl<'tcx> Body<'tcx> { generator_kind: None, var_debug_info: Vec::new(), ignore_interior_mut_in_const_validation: false, + is_polymorphic: false, predecessor_cache: PredecessorCache::new(), - } + }; + body.is_polymorphic = body.has_param_types_or_consts(); + body } #[inline] diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index a5c6dc042abc3..989c6e6dbc215 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -10,6 +10,7 @@ use rustc_middle::ty::ToPredicate; use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable}; use std::marker::PhantomData; +use super::const_evaluatable; use super::project; use super::select::SelectionContext; use super::wf; @@ -458,16 +459,17 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } ty::PredicateAtom::ConstEvaluatable(def_id, substs) => { - match self.selcx.infcx().const_eval_resolve( - obligation.param_env, + const_evaluatable::is_const_evaluatable( + self.selcx.infcx(), def_id, substs, - None, - Some(obligation.cause.span), - ) { - Ok(_) => ProcessResult::Changed(vec![]), - Err(err) => ProcessResult::Error(CodeSelectionError(ConstEvalFailure(err))), - } + obligation.param_env, + obligation.cause.span, + ) + .map_or_else( + |e| ProcessResult::Error(CodeSelectionError(ConstEvalFailure(e))), + |()| ProcessResult::Changed(vec![]), + ) } ty::PredicateAtom::ConstEquate(c1, c2) => { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index fe406e88c5260..49dac873cde2d 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -7,6 +7,7 @@ pub mod auto_trait; mod chalk_fulfill; pub mod codegen; mod coherence; +mod const_evaluatable; mod engine; pub mod error_reporting; mod fulfill; diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 4258d8e3010a4..5a1e1eb89a60c 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -6,6 +6,7 @@ use self::EvaluationResult::*; use self::SelectionCandidate::*; use super::coherence::{self, Conflict}; +use super::const_evaluatable; use super::project; use super::project::normalize_with_depth_to; use super::util; @@ -542,17 +543,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::PredicateAtom::ConstEvaluatable(def_id, substs) => { - match self.tcx().const_eval_resolve( - obligation.param_env, + const_evaluatable::is_const_evaluatable( + self.infcx, def_id, substs, - None, - None, - ) { - Ok(_) => Ok(EvaluatedToOk), - Err(ErrorHandled::TooGeneric) => Ok(EvaluatedToAmbig), - Err(_) => Ok(EvaluatedToErr), - } + obligation.param_env, + obligation.cause.span, + ) + .map(|()| EvaluatedToOk) + .or_else(|e| match e { + ErrorHandled::TooGeneric => Ok(EvaluatedToAmbig), + _ => Ok(EvaluatedToErr), + }) } ty::PredicateAtom::ConstEquate(c1, c2) => { diff --git a/src/librustc_trait_selection/traits/const_evaluatable.rs b/src/librustc_trait_selection/traits/const_evaluatable.rs new file mode 100644 index 0000000000000..eb0e7f16fa37a --- /dev/null +++ b/src/librustc_trait_selection/traits/const_evaluatable.rs @@ -0,0 +1,54 @@ +use rustc_middle::ty::{self, TypeFoldable}; +use rustc_infer::infer::InferCtxt; +use rustc_middle::ty::subst::SubstsRef; +use rustc_span::Span; +use rustc_span::def_id::DefId; +use rustc_middle::mir::interpret::ErrorHandled; +use rustc_hir::def::DefKind; + +pub fn is_const_evaluatable<'cx, 'tcx>( + infcx: &InferCtxt<'cx, 'tcx>, + def: ty::WithOptConstParam, + substs: SubstsRef<'tcx>, + param_env: ty::ParamEnv<'tcx>, + span: Span, +) -> Result<(), ErrorHandled> +{ + let def_kind = infcx.tcx.def_kind(def.did); + match def_kind { + DefKind::AnonConst => { + let mir_body = if let Some(def) = def.as_const_arg() { + infcx.tcx.optimized_mir_of_const_arg(def) + } else { + infcx.tcx.optimized_mir(def.did) + }; + if mir_body.is_polymorphic { + return Err(ErrorHandled::TooGeneric); + } + } + _ => { + if substs.has_param_types_or_consts() { + return Err(ErrorHandled::TooGeneric); + } + } + } + + match infcx.const_eval_resolve( + param_env, + def, + substs, + None, + Some(span), + ) { + Ok(_) => Ok(()), + Err(err) => { + if matches!(err, ErrorHandled::TooGeneric) { + infcx.tcx.sess.delay_span_bug( + span, + &format!("ConstEvaluatable too generic: {:?}, {:?}, {:?}", def, substs, param_env), + ); + } + Err(err) + } + } +} \ No newline at end of file diff --git a/src/test/ui/const_evaluatable/associated_const.rs b/src/test/ui/const_evaluatable/associated_const.rs new file mode 100644 index 0000000000000..a6777632254b7 --- /dev/null +++ b/src/test/ui/const_evaluatable/associated_const.rs @@ -0,0 +1,11 @@ +// check-pass +struct Foo(T); +impl Foo { + const VALUE: usize = std::mem::size_of::(); +} + +fn test() { + let _ = [0; Foo::::VALUE]; +} + +fn main() {} diff --git a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs index 5a528379b0414..5fe526df5a741 100644 --- a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs +++ b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs @@ -1,5 +1,3 @@ -// run-pass - #![feature(arbitrary_enum_discriminant, core_intrinsics)] extern crate core; @@ -9,6 +7,7 @@ use core::intrinsics::discriminant_value; enum MyWeirdOption { None = 0, Some(T) = core::mem::size_of::<*mut T>(), + //~^ ERROR constant expression depends on a generic parameter } fn main() { diff --git a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr new file mode 100644 index 0000000000000..9aba2ea543f4c --- /dev/null +++ b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-70453-polymorphic-ctfe.rs:9:15 + | +LL | Some(T) = core::mem::size_of::<*mut T>(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/impl-trait/issue-56445.rs b/src/test/ui/impl-trait/issue-56445.rs index a34d7bae3a6ca..6dd1648c9b84c 100644 --- a/src/test/ui/impl-trait/issue-56445.rs +++ b/src/test/ui/impl-trait/issue-56445.rs @@ -5,8 +5,7 @@ use std::marker::PhantomData; -pub struct S<'a> -{ +pub struct S<'a> { pub m1: PhantomData<&'a u8>, pub m2: [u8; S::size()], } diff --git a/src/test/ui/lazy_normalization_consts/issue-73980.rs b/src/test/ui/lazy_normalization_consts/issue-73980.rs index 339b22c0b423d..2e4cb9ff7a825 100644 --- a/src/test/ui/lazy_normalization_consts/issue-73980.rs +++ b/src/test/ui/lazy_normalization_consts/issue-73980.rs @@ -1,4 +1,3 @@ -// check-pass #![feature(lazy_normalization_consts)] #![allow(incomplete_features)] @@ -10,5 +9,6 @@ impl L { } impl X::S]> {} +//~^ ERROR constant expression depends on a generic parameter fn main() {} diff --git a/src/test/ui/lazy_normalization_consts/issue-73980.stderr b/src/test/ui/lazy_normalization_consts/issue-73980.stderr new file mode 100644 index 0000000000000..5ca11bf55fc58 --- /dev/null +++ b/src/test/ui/lazy_normalization_consts/issue-73980.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-73980.rs:11:9 + | +LL | impl X::S]> {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + From ef6100e846f215b92f0d3b951557ed2528000f61 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 6 Aug 2020 10:48:36 +0200 Subject: [PATCH 0175/1052] convert to future compat lint --- compiler/rustc_session/src/lint/builtin.rs | 11 ++++ .../traits/const_evaluatable.rs | 65 ++++++++++--------- .../issue-70453-polymorphic-ctfe.rs | 4 +- .../issue-70453-polymorphic-ctfe.stderr | 10 +-- .../lazy_normalization_consts/issue-73980.rs | 4 +- .../issue-73980.stderr | 10 +-- 6 files changed, 65 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_session/src/lint/builtin.rs b/compiler/rustc_session/src/lint/builtin.rs index 2db4d2a7f51d9..66497df66cad5 100644 --- a/compiler/rustc_session/src/lint/builtin.rs +++ b/compiler/rustc_session/src/lint/builtin.rs @@ -539,6 +539,16 @@ declare_lint! { }; } +declare_lint! { + pub CONST_EVALUATABLE_UNCHECKED, + Warn, + "detects a generic constant is used in a type without a emitting a warning", + @future_incompatible = FutureIncompatibleInfo { + reference: "TODO", + edition: None, + }; +} + declare_lint_pass! { /// Does nothing as a lint pass, but registers some `Lint`s /// that are used by other parts of the compiler. @@ -612,6 +622,7 @@ declare_lint_pass! { UNSAFE_OP_IN_UNSAFE_FN, INCOMPLETE_INCLUDE, CENUM_IMPL_DROP_CAST, + CONST_EVALUATABLE_UNCHECKED, ] } diff --git a/src/librustc_trait_selection/traits/const_evaluatable.rs b/src/librustc_trait_selection/traits/const_evaluatable.rs index eb0e7f16fa37a..87762cc43a199 100644 --- a/src/librustc_trait_selection/traits/const_evaluatable.rs +++ b/src/librustc_trait_selection/traits/const_evaluatable.rs @@ -1,10 +1,11 @@ -use rustc_middle::ty::{self, TypeFoldable}; +use rustc_hir::def::DefKind; use rustc_infer::infer::InferCtxt; +use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::subst::SubstsRef; -use rustc_span::Span; +use rustc_middle::ty::{self, TypeFoldable}; +use rustc_session::lint; use rustc_span::def_id::DefId; -use rustc_middle::mir::interpret::ErrorHandled; -use rustc_hir::def::DefKind; +use rustc_span::Span; pub fn is_const_evaluatable<'cx, 'tcx>( infcx: &InferCtxt<'cx, 'tcx>, @@ -12,8 +13,31 @@ pub fn is_const_evaluatable<'cx, 'tcx>( substs: SubstsRef<'tcx>, param_env: ty::ParamEnv<'tcx>, span: Span, -) -> Result<(), ErrorHandled> -{ +) -> Result<(), ErrorHandled> { + let future_compat_lint = || { + if let Some(local_def_id) = def.did.as_local() { + infcx.tcx.struct_span_lint_hir( + lint::builtin::CONST_EVALUATABLE_UNCHECKED, + infcx.tcx.hir().as_local_hir_id(local_def_id), + span, + |err| { + err.build("cannot use constants which depend on generic parameters in types") + .emit(); + }, + ); + } + }; + + // FIXME: We should only try to evaluate a given constant here if it is fully concrete + // as we don't want to allow things like `[u8; std::mem::size_of::<*mut T>()]`. + // + // We previously did not check this, so we only emit a future compat warning if + // const evaluation succeeds and the given constant is still polymorphic for now + // and hopefully soon change this to an error. + // + // See #74595 for more details about this. + let concrete = infcx.const_eval_resolve(param_env, def, substs, None, Some(span)); + let def_kind = infcx.tcx.def_kind(def.did); match def_kind { DefKind::AnonConst => { @@ -22,33 +46,16 @@ pub fn is_const_evaluatable<'cx, 'tcx>( } else { infcx.tcx.optimized_mir(def.did) }; - if mir_body.is_polymorphic { - return Err(ErrorHandled::TooGeneric); + if mir_body.is_polymorphic && concrete.is_ok() { + future_compat_lint(); } } _ => { - if substs.has_param_types_or_consts() { - return Err(ErrorHandled::TooGeneric); + if substs.has_param_types_or_consts() && concrete.is_ok() { + future_compat_lint(); } } } - match infcx.const_eval_resolve( - param_env, - def, - substs, - None, - Some(span), - ) { - Ok(_) => Ok(()), - Err(err) => { - if matches!(err, ErrorHandled::TooGeneric) { - infcx.tcx.sess.delay_span_bug( - span, - &format!("ConstEvaluatable too generic: {:?}, {:?}, {:?}", def, substs, param_env), - ); - } - Err(err) - } - } -} \ No newline at end of file + concrete.map(drop) +} diff --git a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs index 5fe526df5a741..cdc1db4c0b482 100644 --- a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs +++ b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs @@ -1,3 +1,4 @@ +// run-pass #![feature(arbitrary_enum_discriminant, core_intrinsics)] extern crate core; @@ -7,7 +8,8 @@ use core::intrinsics::discriminant_value; enum MyWeirdOption { None = 0, Some(T) = core::mem::size_of::<*mut T>(), - //~^ ERROR constant expression depends on a generic parameter + //~^ WARN cannot use constants which depend on generic parameters in types + //~| WARN this was previously accepted by the compiler but is being phased out } fn main() { diff --git a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr index 9aba2ea543f4c..2aeb1b32bcb0a 100644 --- a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr +++ b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr @@ -1,10 +1,12 @@ -error: constant expression depends on a generic parameter - --> $DIR/issue-70453-polymorphic-ctfe.rs:9:15 +warning: cannot use constants which depend on generic parameters in types + --> $DIR/issue-70453-polymorphic-ctfe.rs:10:15 | LL | Some(T) = core::mem::size_of::<*mut T>(), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: this may fail depending on what value the parameter takes + = note: `#[warn(const_evaluatable_unchecked)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see TODO -error: aborting due to previous error +warning: 1 warning emitted diff --git a/src/test/ui/lazy_normalization_consts/issue-73980.rs b/src/test/ui/lazy_normalization_consts/issue-73980.rs index 2e4cb9ff7a825..e10040652c78d 100644 --- a/src/test/ui/lazy_normalization_consts/issue-73980.rs +++ b/src/test/ui/lazy_normalization_consts/issue-73980.rs @@ -1,3 +1,4 @@ +// check-pass #![feature(lazy_normalization_consts)] #![allow(incomplete_features)] @@ -9,6 +10,7 @@ impl L { } impl X::S]> {} -//~^ ERROR constant expression depends on a generic parameter +//~^ WARN cannot use constants which depend on generic parameters +//~| WARN this was previously accepted by the compiler but is being phased out fn main() {} diff --git a/src/test/ui/lazy_normalization_consts/issue-73980.stderr b/src/test/ui/lazy_normalization_consts/issue-73980.stderr index 5ca11bf55fc58..8636407a3a102 100644 --- a/src/test/ui/lazy_normalization_consts/issue-73980.stderr +++ b/src/test/ui/lazy_normalization_consts/issue-73980.stderr @@ -1,10 +1,12 @@ -error: constant expression depends on a generic parameter - --> $DIR/issue-73980.rs:11:9 +warning: cannot use constants which depend on generic parameters in types + --> $DIR/issue-73980.rs:12:9 | LL | impl X::S]> {} | ^^^^^^^^^^^^^^^^^^^^^ | - = note: this may fail depending on what value the parameter takes + = note: `#[warn(const_evaluatable_unchecked)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see TODO -error: aborting due to previous error +warning: 1 warning emitted From c10ad0d888df19e7185e15f811fdb011278f3c20 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 6 Aug 2020 22:12:21 +0200 Subject: [PATCH 0176/1052] review --- compiler/rustc_middle/src/mir/mod.rs | 4 ++++ .../rustc_trait_selection/src/traits/fulfill.rs | 11 +++++------ .../rustc_trait_selection/src/traits/select/mod.rs | 13 ++++++------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 197e8dd534112..3c041bbc0aedd 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -197,6 +197,10 @@ pub struct Body<'tcx> { /// let _ = [0; std::mem::size_of::<*mut T>()]; /// } /// ``` + /// + /// **WARNING**: Do not change this flags after the MIR was originally created, even if an optimization + /// removed the last mention of all generic params. We do not want to rely on optimizations and + /// potentially allow things like `[u8; std::mem::size_of::() * 0]` due to this. pub is_polymorphic: bool, predecessor_cache: PredecessorCache, diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 989c6e6dbc215..4818022bf6202 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -459,17 +459,16 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } ty::PredicateAtom::ConstEvaluatable(def_id, substs) => { - const_evaluatable::is_const_evaluatable( + match const_evaluatable::is_const_evaluatable( self.selcx.infcx(), def_id, substs, obligation.param_env, obligation.cause.span, - ) - .map_or_else( - |e| ProcessResult::Error(CodeSelectionError(ConstEvalFailure(e))), - |()| ProcessResult::Changed(vec![]), - ) + ) { + Ok(()) => ProcessResult::Changed(vec![]), + Err(e) => ProcessResult::Error(CodeSelectionError(ConstEvalFailure(e))), + } } ty::PredicateAtom::ConstEquate(c1, c2) => { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 5a1e1eb89a60c..7e8e2baa8a13d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -543,18 +543,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::PredicateAtom::ConstEvaluatable(def_id, substs) => { - const_evaluatable::is_const_evaluatable( + match const_evaluatable::is_const_evaluatable( self.infcx, def_id, substs, obligation.param_env, obligation.cause.span, - ) - .map(|()| EvaluatedToOk) - .or_else(|e| match e { - ErrorHandled::TooGeneric => Ok(EvaluatedToAmbig), - _ => Ok(EvaluatedToErr), - }) + ) { + Ok(()) => Ok(EvaluatedToOk), + Err(ErrorHandled::TooGeneric) => Ok(EvaluatedToAmbig), + Err(_) => Ok(EvaluatedToErr), + } } ty::PredicateAtom::ConstEquate(c1, c2) => { From 78046448638c8db12db51b8f7bbbe29860d79c4e Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 6 Aug 2020 22:32:12 +0200 Subject: [PATCH 0177/1052] add tests --- ...{associated_const.rs => associated-const.rs} | 0 src/test/ui/const_evaluatable/function-call.rs | 17 +++++++++++++++++ .../ui/const_evaluatable/function-call.stderr | 12 ++++++++++++ 3 files changed, 29 insertions(+) rename src/test/ui/const_evaluatable/{associated_const.rs => associated-const.rs} (100%) create mode 100644 src/test/ui/const_evaluatable/function-call.rs create mode 100644 src/test/ui/const_evaluatable/function-call.stderr diff --git a/src/test/ui/const_evaluatable/associated_const.rs b/src/test/ui/const_evaluatable/associated-const.rs similarity index 100% rename from src/test/ui/const_evaluatable/associated_const.rs rename to src/test/ui/const_evaluatable/associated-const.rs diff --git a/src/test/ui/const_evaluatable/function-call.rs b/src/test/ui/const_evaluatable/function-call.rs new file mode 100644 index 0000000000000..b13a0369a00eb --- /dev/null +++ b/src/test/ui/const_evaluatable/function-call.rs @@ -0,0 +1,17 @@ +// check-pass + +const fn foo() -> usize { + if std::mem::size_of::<*mut T>() < 8 { // size of *mut T does not depend on T + std::mem::size_of::() + } else { + 8 + } +} + +fn test() { + let _ = [0; foo::()]; + //~^ WARN cannot use constants which depend on generic parameters in types + //~| WARN this was previously accepted by the compiler but is being phased out +} + +fn main() {} diff --git a/src/test/ui/const_evaluatable/function-call.stderr b/src/test/ui/const_evaluatable/function-call.stderr new file mode 100644 index 0000000000000..5240015c37a34 --- /dev/null +++ b/src/test/ui/const_evaluatable/function-call.stderr @@ -0,0 +1,12 @@ +warning: cannot use constants which depend on generic parameters in types + --> $DIR/function-call.rs:12:17 + | +LL | let _ = [0; foo::()]; + | ^^^^^^^^^^ + | + = note: `#[warn(const_evaluatable_unchecked)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see TODO + +warning: 1 warning emitted + From 1dd00e60b92cba4a84da0946ef63346e12ebd3d2 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 1 Sep 2020 16:17:41 +0200 Subject: [PATCH 0178/1052] add tracking issue, fix rebase --- compiler/rustc_session/src/lint/builtin.rs | 2 +- .../rustc_trait_selection/src}/traits/const_evaluatable.rs | 2 +- src/test/ui/const_evaluatable/function-call.stderr | 2 +- .../ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr | 2 +- src/test/ui/lazy_normalization_consts/issue-73980.stderr | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename {src/librustc_trait_selection => compiler/rustc_trait_selection/src}/traits/const_evaluatable.rs (96%) diff --git a/compiler/rustc_session/src/lint/builtin.rs b/compiler/rustc_session/src/lint/builtin.rs index 66497df66cad5..2bcf10b8b3878 100644 --- a/compiler/rustc_session/src/lint/builtin.rs +++ b/compiler/rustc_session/src/lint/builtin.rs @@ -544,7 +544,7 @@ declare_lint! { Warn, "detects a generic constant is used in a type without a emitting a warning", @future_incompatible = FutureIncompatibleInfo { - reference: "TODO", + reference: "issue #76200 ", edition: None, }; } diff --git a/src/librustc_trait_selection/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs similarity index 96% rename from src/librustc_trait_selection/traits/const_evaluatable.rs rename to compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 87762cc43a199..013cd71ea305d 100644 --- a/src/librustc_trait_selection/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -18,7 +18,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( if let Some(local_def_id) = def.did.as_local() { infcx.tcx.struct_span_lint_hir( lint::builtin::CONST_EVALUATABLE_UNCHECKED, - infcx.tcx.hir().as_local_hir_id(local_def_id), + infcx.tcx.hir().local_def_id_to_hir_id(local_def_id), span, |err| { err.build("cannot use constants which depend on generic parameters in types") diff --git a/src/test/ui/const_evaluatable/function-call.stderr b/src/test/ui/const_evaluatable/function-call.stderr index 5240015c37a34..a15637196062f 100644 --- a/src/test/ui/const_evaluatable/function-call.stderr +++ b/src/test/ui/const_evaluatable/function-call.stderr @@ -6,7 +6,7 @@ LL | let _ = [0; foo::()]; | = note: `#[warn(const_evaluatable_unchecked)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see TODO + = note: for more information, see issue #76200 warning: 1 warning emitted diff --git a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr index 2aeb1b32bcb0a..906927e705ee8 100644 --- a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr +++ b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr @@ -6,7 +6,7 @@ LL | Some(T) = core::mem::size_of::<*mut T>(), | = note: `#[warn(const_evaluatable_unchecked)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see TODO + = note: for more information, see issue #76200 warning: 1 warning emitted diff --git a/src/test/ui/lazy_normalization_consts/issue-73980.stderr b/src/test/ui/lazy_normalization_consts/issue-73980.stderr index 8636407a3a102..5ed1ca362f411 100644 --- a/src/test/ui/lazy_normalization_consts/issue-73980.stderr +++ b/src/test/ui/lazy_normalization_consts/issue-73980.stderr @@ -6,7 +6,7 @@ LL | impl X::S]> {} | = note: `#[warn(const_evaluatable_unchecked)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see TODO + = note: for more information, see issue #76200 warning: 1 warning emitted From 4226a17845333e3c0495bd85e5836c24b2a70b97 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 8 Sep 2020 16:47:19 +0200 Subject: [PATCH 0179/1052] fix test --- src/test/ui/const_evaluatable/function-call.rs | 1 + src/test/ui/const_evaluatable/function-call.stderr | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/test/ui/const_evaluatable/function-call.rs b/src/test/ui/const_evaluatable/function-call.rs index b13a0369a00eb..9b54a541e6906 100644 --- a/src/test/ui/const_evaluatable/function-call.rs +++ b/src/test/ui/const_evaluatable/function-call.rs @@ -1,4 +1,5 @@ // check-pass +#![warn(const_evaluatable_unchecked)] const fn foo() -> usize { if std::mem::size_of::<*mut T>() < 8 { // size of *mut T does not depend on T diff --git a/src/test/ui/const_evaluatable/function-call.stderr b/src/test/ui/const_evaluatable/function-call.stderr index a15637196062f..a63a2643ad2c2 100644 --- a/src/test/ui/const_evaluatable/function-call.stderr +++ b/src/test/ui/const_evaluatable/function-call.stderr @@ -1,10 +1,14 @@ warning: cannot use constants which depend on generic parameters in types - --> $DIR/function-call.rs:12:17 + --> $DIR/function-call.rs:13:17 | LL | let _ = [0; foo::()]; | ^^^^^^^^^^ | - = note: `#[warn(const_evaluatable_unchecked)]` on by default +note: the lint level is defined here + --> $DIR/function-call.rs:2:9 + | +LL | #![warn(const_evaluatable_unchecked)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #76200 From c3c84ad027941b3011138d38d7797b202812fbb2 Mon Sep 17 00:00:00 2001 From: moonheart08 Date: Tue, 8 Sep 2020 10:35:35 -0500 Subject: [PATCH 0180/1052] Convert MAXIMUM_ZST_CAPACITY to be calculated in a const instead of multiple target_pointer_width checks. --- library/alloc/src/collections/vec_deque.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/library/alloc/src/collections/vec_deque.rs b/library/alloc/src/collections/vec_deque.rs index cc2ef25a5a7d1..664ba48fcf565 100644 --- a/library/alloc/src/collections/vec_deque.rs +++ b/library/alloc/src/collections/vec_deque.rs @@ -32,12 +32,8 @@ mod tests; const INITIAL_CAPACITY: usize = 7; // 2^3 - 1 const MINIMUM_CAPACITY: usize = 1; // 2 - 1 -#[cfg(target_pointer_width = "16")] -const MAXIMUM_ZST_CAPACITY: usize = 1 << (16 - 1); // Largest possible power of two -#[cfg(target_pointer_width = "32")] -const MAXIMUM_ZST_CAPACITY: usize = 1 << (32 - 1); // Largest possible power of two -#[cfg(target_pointer_width = "64")] -const MAXIMUM_ZST_CAPACITY: usize = 1 << (64 - 1); // Largest possible power of two + +const MAXIMUM_ZST_CAPACITY: usize = 1 << ((core::mem::size_of::() << 3) - 1); // Largest possible power of two /// A double-ended queue implemented with a growable ring buffer. /// From 4f1c4a99d4d98f1acea3c9c7cc55355aa46119aa Mon Sep 17 00:00:00 2001 From: Ricky Date: Tue, 8 Sep 2020 12:05:18 -0400 Subject: [PATCH 0181/1052] Fixed typo in lint and test --- clippy_lints/src/map_err_ignore.rs | 4 ++-- tests/ui/map_err.stderr | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/map_err_ignore.rs b/clippy_lints/src/map_err_ignore.rs index 649de4133e067..fa59b6ec37061 100644 --- a/clippy_lints/src/map_err_ignore.rs +++ b/clippy_lints/src/map_err_ignore.rs @@ -7,7 +7,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { /// **What it does:** Checks for instances of `map_err(|_| Some::Enum)` /// - /// **Why is this bad?** This map_err throws away the original error rather than allowing the enum to bubble the original error + /// **Why is this bad?** This map_err throws away the original error rather than allowing the enum to contain and report the cause of the error /// /// **Known problems:** None. /// @@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for MapErrIgnore { cx, MAP_ERR_IGNORE, body_span, - "`map_else(|_|...` ignores the original error", + "`map_err(|_|...` ignores the original error", None, "Consider wrapping the error in an enum variant", ); diff --git a/tests/ui/map_err.stderr b/tests/ui/map_err.stderr index 7a269ab95ab27..e4e6a289ba030 100644 --- a/tests/ui/map_err.stderr +++ b/tests/ui/map_err.stderr @@ -1,4 +1,4 @@ -error: `map_else(|_|...` ignores the original error +error: `map_err(|_|...` ignores the original error --> $DIR/map_err.rs:21:32 | LL | println!("{:?}", x.map_err(|_| Errors::Ignored)); From 75e471ade9ea6095eef6cd4ef35cfc0b8bfc9410 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 8 Sep 2020 19:01:05 +0200 Subject: [PATCH 0182/1052] Add MaybeUninit::drop. ManuallyDrop's documentation tells the user to use MaybeUninit instead when handling uninitialized data. However, the main functionality of ManuallyDrop (drop) was not available directly on MaybeUninit. Adding it makes it easier to switch from one to the other. --- library/core/src/mem/maybe_uninit.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index b64abf68c5e4a..e826ec0a5e3ee 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -2,6 +2,7 @@ use crate::any::type_name; use crate::fmt; use crate::intrinsics; use crate::mem::ManuallyDrop; +use crate::ptr; /// A wrapper type to construct uninitialized instances of `T`. /// @@ -573,6 +574,28 @@ impl MaybeUninit { } } + /// Drops the contained value in place. + /// + /// If you have ownership of the `MaybeUninit`, it is preferable to use + /// [`assume_init`] instead, which prevents duplicating the content. + /// + /// # Safety + /// + /// Calling this when the content is not yet fully initialized causes undefined + /// behavior: it is up to the caller to guarantee that the `MaybeUninit` really + /// is in an initialized state. + /// + /// This function runs the destructor of the contained value in place. + /// Afterwards, the memory is considered uninitialized again, but remains unmodified. + /// + /// [`assume_init`]: MaybeUninit::assume_init + #[unstable(feature = "maybe_uninit_extra", issue = "63567")] + pub unsafe fn drop(&mut self) { + // SAFETY: the caller must guarantee that `self` is initialized. + // Dropping the value in place is safe if that is the case. + unsafe { ptr::drop_in_place(self.as_mut_ptr()) } + } + /// Gets a shared reference to the contained value. /// /// This can be useful when we want to access a `MaybeUninit` that has been From 2ac89ff994c9ddcc49eed2b06ff5327bc09f4118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 7 Sep 2020 18:42:29 -0700 Subject: [PATCH 0183/1052] Point at named argument not found when using `format_args_capture` instead of whole format string --- compiler/rustc_builtin_macros/src/format.rs | 9 ++++-- .../format-args-capture-missing-variables.rs | 6 ++-- ...rmat-args-capture-missing-variables.stderr | 31 ++++++++----------- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 5d6f791f13719..550524e652af7 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -543,9 +543,12 @@ impl<'a, 'b> Context<'a, 'b> { let idx = self.args.len(); self.arg_types.push(Vec::new()); self.arg_unique_types.push(Vec::new()); - self.args.push( - self.ecx.expr_ident(self.fmtsp, Ident::new(name, self.fmtsp)), - ); + let span = if self.is_literal { + *self.arg_spans.get(self.curpiece).unwrap_or(&self.fmtsp) + } else { + self.fmtsp + }; + self.args.push(self.ecx.expr_ident(span, Ident::new(name, span))); self.names.insert(name, idx); self.verify_arg_type(Exact(idx), ty) } else { diff --git a/src/test/ui/fmt/format-args-capture-missing-variables.rs b/src/test/ui/fmt/format-args-capture-missing-variables.rs index 3c596ae3bb899..3a4b6144b04db 100644 --- a/src/test/ui/fmt/format-args-capture-missing-variables.rs +++ b/src/test/ui/fmt/format-args-capture-missing-variables.rs @@ -5,7 +5,7 @@ fn main() { //~^ ERROR: cannot find value `foo` in this scope //~^^ ERROR: cannot find value `bar` in this scope - format!("{foo}"); //~ ERROR: cannot find value `foo` in this scope + format!("{foo}"); //~ ERROR: cannot find value `foo` in this scope format!("{valuea} {valueb}", valuea=5, valuec=7); //~^ ERROR cannot find value `valueb` in this scope @@ -16,7 +16,7 @@ fn main() { {foo} "##); - //~^^^^^ ERROR: cannot find value `foo` in this scope + //~^^^ ERROR: cannot find value `foo` in this scope - panic!("{foo} {bar}", bar=1); //~ ERROR: cannot find value `foo` in this scope + panic!("{foo} {bar}", bar=1); //~ ERROR: cannot find value `foo` in this scope } diff --git a/src/test/ui/fmt/format-args-capture-missing-variables.stderr b/src/test/ui/fmt/format-args-capture-missing-variables.stderr index c3d740eef9d3c..ec2faa4185b3e 100644 --- a/src/test/ui/fmt/format-args-capture-missing-variables.stderr +++ b/src/test/ui/fmt/format-args-capture-missing-variables.stderr @@ -7,45 +7,40 @@ LL | format!("{valuea} {valueb}", valuea=5, valuec=7); | formatting specifier missing error[E0425]: cannot find value `foo` in this scope - --> $DIR/format-args-capture-missing-variables.rs:4:13 + --> $DIR/format-args-capture-missing-variables.rs:4:17 | LL | format!("{} {foo} {} {bar} {}", 1, 2, 3); - | ^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + | ^^^^^ not found in this scope error[E0425]: cannot find value `bar` in this scope - --> $DIR/format-args-capture-missing-variables.rs:4:13 + --> $DIR/format-args-capture-missing-variables.rs:4:26 | LL | format!("{} {foo} {} {bar} {}", 1, 2, 3); - | ^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + | ^^^^^ not found in this scope error[E0425]: cannot find value `foo` in this scope - --> $DIR/format-args-capture-missing-variables.rs:8:13 + --> $DIR/format-args-capture-missing-variables.rs:8:14 | LL | format!("{foo}"); - | ^^^^^^^ not found in this scope + | ^^^^^ not found in this scope error[E0425]: cannot find value `valueb` in this scope - --> $DIR/format-args-capture-missing-variables.rs:10:13 + --> $DIR/format-args-capture-missing-variables.rs:10:23 | LL | format!("{valuea} {valueb}", valuea=5, valuec=7); - | ^^^^^^^^^^^^^^^^^^^ not found in this scope + | ^^^^^^^^ not found in this scope error[E0425]: cannot find value `foo` in this scope - --> $DIR/format-args-capture-missing-variables.rs:14:13 + --> $DIR/format-args-capture-missing-variables.rs:16:9 | -LL | format!(r##" - | _____________^ -LL | | -LL | | {foo} -LL | | -LL | | "##); - | |_______^ not found in this scope +LL | {foo} + | ^^^^^ not found in this scope error[E0425]: cannot find value `foo` in this scope - --> $DIR/format-args-capture-missing-variables.rs:21:12 + --> $DIR/format-args-capture-missing-variables.rs:21:13 | LL | panic!("{foo} {bar}", bar=1); - | ^^^^^^^^^^^^^ not found in this scope + | ^^^^^ not found in this scope error: aborting due to 7 previous errors From caef83282bfede657faf38d43967f577841b3be4 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 8 Sep 2020 19:34:23 +0200 Subject: [PATCH 0184/1052] Fix doc comment on MaybeUninit::drop. --- library/core/src/mem/maybe_uninit.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index e826ec0a5e3ee..001ee0898d45e 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -576,8 +576,7 @@ impl MaybeUninit { /// Drops the contained value in place. /// - /// If you have ownership of the `MaybeUninit`, it is preferable to use - /// [`assume_init`] instead, which prevents duplicating the content. + /// If you have ownership of the `MaybeUninit`, you can use [`assume_init`] instead. /// /// # Safety /// From e02952c0cc6b360ac914f97da1dfcc46fd82f92c Mon Sep 17 00:00:00 2001 From: Braden Nelson Date: Tue, 8 Sep 2020 13:11:08 -0500 Subject: [PATCH 0185/1052] Update library/alloc/src/collections/vec_deque.rs Replace lshift with multiply Co-authored-by: Mara Bos --- library/alloc/src/collections/vec_deque.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/collections/vec_deque.rs b/library/alloc/src/collections/vec_deque.rs index 664ba48fcf565..f7f488f2f0716 100644 --- a/library/alloc/src/collections/vec_deque.rs +++ b/library/alloc/src/collections/vec_deque.rs @@ -33,7 +33,7 @@ mod tests; const INITIAL_CAPACITY: usize = 7; // 2^3 - 1 const MINIMUM_CAPACITY: usize = 1; // 2 - 1 -const MAXIMUM_ZST_CAPACITY: usize = 1 << ((core::mem::size_of::() << 3) - 1); // Largest possible power of two +const MAXIMUM_ZST_CAPACITY: usize = 1 << (core::mem::size_of::() * 8 - 1); // Largest possible power of two /// A double-ended queue implemented with a growable ring buffer. /// From 69ffed763d1540c387db3b578848184026da0484 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 7 Sep 2020 13:40:23 +0200 Subject: [PATCH 0186/1052] Add error explanation for E0755 --- compiler/rustc_error_codes/src/error_codes.rs | 2 +- .../src/error_codes/E0755.md | 28 +++++++++++++++++++ src/test/ui/ffi_pure.stderr | 1 + 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0755.md diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 789a1fc35a64f..af9ca7e10fcf4 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -440,6 +440,7 @@ E0751: include_str!("./error_codes/E0751.md"), E0752: include_str!("./error_codes/E0752.md"), E0753: include_str!("./error_codes/E0753.md"), E0754: include_str!("./error_codes/E0754.md"), +E0755: include_str!("./error_codes/E0755.md"), E0758: include_str!("./error_codes/E0758.md"), E0759: include_str!("./error_codes/E0759.md"), E0760: include_str!("./error_codes/E0760.md"), @@ -631,7 +632,6 @@ E0773: include_str!("./error_codes/E0773.md"), E0722, // Malformed `#[optimize]` attribute E0726, // non-explicit (not `'_`) elided lifetime in unsupported position // E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. - E0755, // `#[ffi_pure]` is only allowed on foreign functions E0756, // `#[ffi_const]` is only allowed on foreign functions E0757, // `#[ffi_const]` functions cannot be `#[ffi_pure]` E0772, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`. diff --git a/compiler/rustc_error_codes/src/error_codes/E0755.md b/compiler/rustc_error_codes/src/error_codes/E0755.md new file mode 100644 index 0000000000000..88b7f48496906 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0755.md @@ -0,0 +1,28 @@ +The `ffi_pure` attribute was used on a non-foreign function. + +Erroneous code example: + +```compile_fail,E0755 +#![feature(ffi_pure)] + +#[ffi_pure] // error! +pub fn foo() {} +# fn main() {} +``` + +The `ffi_pure` attribute can only be used on foreign functions which do not have +side effects or infinite loops: + +``` +#![feature(ffi_pure)] + +extern "C" { + #[ffi_pure] // ok! + pub fn strlen(s: *const i8) -> isize; +} +# fn main() {} +``` + +You can find more information about it in the [unstable Rust Book]. + +[unstable Rust Book]: https://doc.rust-lang.org/unstable-book/language-features/ffi-pure.html diff --git a/src/test/ui/ffi_pure.stderr b/src/test/ui/ffi_pure.stderr index 3a849c0bca79c..bc911c85ddb29 100644 --- a/src/test/ui/ffi_pure.stderr +++ b/src/test/ui/ffi_pure.stderr @@ -6,3 +6,4 @@ LL | #[ffi_pure] error: aborting due to previous error +For more information about this error, try `rustc --explain E0755`. From 75a2c68fb66fb9aac2805e298d20578019a0c129 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 8 Sep 2020 22:08:25 +0300 Subject: [PATCH 0187/1052] Update comment in config.toml.example --- config.toml.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.toml.example b/config.toml.example index 9abb8add785a9..d2f94bc9ef321 100644 --- a/config.toml.example +++ b/config.toml.example @@ -429,7 +429,7 @@ # supported platforms. The LLD from the bootstrap distribution will be used # and not the LLD compiled during the bootstrap. # -# LLD will not be used if we're cross linking or running tests. +# LLD will not be used if we're cross linking. # # Explicitly setting the linker for a target will override this option when targeting MSVC. #use-lld = false From 0aaf56f5fc0f2d64f3202021d0b8d735007d7bcf Mon Sep 17 00:00:00 2001 From: moonheart08 Date: Tue, 8 Sep 2020 15:00:47 -0500 Subject: [PATCH 0188/1052] Remove a stray ignore-tidy-undocumented-unsafe There were no undocumented unsafe blocks in the file. --- library/core/src/ptr/unique.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs index 78647eee3389a..cd6afdccc29d7 100644 --- a/library/core/src/ptr/unique.rs +++ b/library/core/src/ptr/unique.rs @@ -4,8 +4,6 @@ use crate::marker::{PhantomData, Unsize}; use crate::mem; use crate::ops::{CoerceUnsized, DispatchFromDyn}; -// ignore-tidy-undocumented-unsafe - /// A wrapper around a raw non-null `*mut T` that indicates that the possessor /// of this wrapper owns the referent. Useful for building abstractions like /// `Box`, `Vec`, `String`, and `HashMap`. From 325acefee485d93c29da6e5641e823dd1d7de059 Mon Sep 17 00:00:00 2001 From: Camelid Date: Tue, 8 Sep 2020 14:36:36 -0700 Subject: [PATCH 0189/1052] Use intra-doc links in `core::ptr` The only link that I did not change is a link to a function on the `pointer` primitive because intra-doc links for the `pointer` primitive don't work yet (see #63351). --- library/core/src/ptr/mod.rs | 77 ++++++++++--------------------------- 1 file changed, 21 insertions(+), 56 deletions(-) diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 68b5d1df71cb2..219835bfae0f9 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -54,16 +54,9 @@ //! [aliasing]: ../../nomicon/aliasing.html //! [book]: ../../book/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer //! [ub]: ../../reference/behavior-considered-undefined.html -//! [null]: ./fn.null.html //! [zst]: ../../nomicon/exotic-sizes.html#zero-sized-types-zsts -//! [atomic operations]: ../../std/sync/atomic/index.html -//! [`copy`]: ../../std/ptr/fn.copy.html +//! [atomic operations]: crate::sync::atomic //! [`offset`]: ../../std/primitive.pointer.html#method.offset -//! [`read_unaligned`]: ./fn.read_unaligned.html -//! [`write_unaligned`]: ./fn.write_unaligned.html -//! [`read_volatile`]: ./fn.read_volatile.html -//! [`write_volatile`]: ./fn.write_volatile.html -//! [`NonNull::dangling`]: ./struct.NonNull.html#method.dangling #![stable(feature = "rust1", since = "1.0.0")] @@ -118,9 +111,9 @@ mod mut_ptr; /// done automatically by the compiler. This means the fields of packed structs /// are not dropped in-place. /// -/// [`ptr::read`]: ../ptr/fn.read.html -/// [`ptr::read_unaligned`]: ../ptr/fn.read_unaligned.html -/// [pinned]: ../pin/index.html +/// [`ptr::read`]: self::read +/// [`ptr::read_unaligned`]: self::read_unaligned +/// [pinned]: crate::pin /// /// # Safety /// @@ -141,9 +134,7 @@ mod mut_ptr; /// /// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// -/// [valid]: ../ptr/index.html#safety -/// [`Copy`]: ../marker/trait.Copy.html -/// [`write`]: ../ptr/fn.write.html +/// [valid]: #safety /// /// # Examples /// @@ -243,9 +234,9 @@ pub(crate) struct FatPtr { /// The `len` argument is the number of **elements**, not the number of bytes. /// /// This function is safe, but actually using the return value is unsafe. -/// See the documentation of [`from_raw_parts`] for slice safety requirements. +/// See the documentation of [`slice::from_raw_parts`] for slice safety requirements. /// -/// [`from_raw_parts`]: ../../std/slice/fn.from_raw_parts.html +/// [`slice::from_raw_parts`]: crate::slice::from_raw_parts /// /// # Examples /// @@ -274,10 +265,9 @@ pub const fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { /// See the documentation of [`slice_from_raw_parts`] for more details. /// /// This function is safe, but actually using the return value is unsafe. -/// See the documentation of [`from_raw_parts_mut`] for slice safety requirements. +/// See the documentation of [`slice::from_raw_parts_mut`] for slice safety requirements. /// -/// [`slice_from_raw_parts`]: fn.slice_from_raw_parts.html -/// [`from_raw_parts_mut`]: ../../std/slice/fn.from_raw_parts_mut.html +/// [`slice::from_raw_parts_mut`]: crate::slice::from_raw_parts_mut /// /// # Examples /// @@ -316,8 +306,6 @@ pub const fn slice_from_raw_parts_mut(data: *mut T, len: usize) -> *mut [T] { /// overlapping region of memory from `x` will be used. This is demonstrated /// in the second example below. /// -/// [`mem::swap`]: ../mem/fn.swap.html -/// /// # Safety /// /// Behavior is undefined if any of the following conditions are violated: @@ -328,7 +316,7 @@ pub const fn slice_from_raw_parts_mut(data: *mut T, len: usize) -> *mut [T] { /// /// Note that even if `T` has size `0`, the pointers must be non-NULL and properly aligned. /// -/// [valid]: ../ptr/index.html#safety +/// [valid]: #safety /// /// # Examples /// @@ -406,7 +394,7 @@ pub unsafe fn swap(x: *mut T, y: *mut T) { /// Note that even if the effectively copied size (`count * size_of::()`) is `0`, /// the pointers must be non-NULL and properly aligned. /// -/// [valid]: ../ptr/index.html#safety +/// [valid]: #safety /// /// # Examples /// @@ -533,8 +521,6 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// operates on raw pointers instead of references. When references are /// available, [`mem::replace`] should be preferred. /// -/// [`mem::replace`]: ../mem/fn.replace.html -/// /// # Safety /// /// Behavior is undefined if any of the following conditions are violated: @@ -547,7 +533,7 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// /// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// -/// [valid]: ../ptr/index.html#safety +/// [valid]: #safety /// /// # Examples /// @@ -682,11 +668,7 @@ pub unsafe fn replace(dst: *mut T, mut src: T) -> T { /// assert_eq!(s, "bar"); /// ``` /// -/// [`mem::swap`]: ../mem/fn.swap.html -/// [valid]: ../ptr/index.html#safety -/// [`Copy`]: ../marker/trait.Copy.html -/// [`read_unaligned`]: ./fn.read_unaligned.html -/// [`write`]: ./fn.write.html +/// [valid]: #safety #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn read(src: *const T) -> T { @@ -723,11 +705,8 @@ pub unsafe fn read(src: *const T) -> T { /// /// Note that even if `T` has size `0`, the pointer must be non-NULL. /// -/// [`Copy`]: ../marker/trait.Copy.html -/// [`read`]: ./fn.read.html -/// [`write_unaligned`]: ./fn.write_unaligned.html -/// [read-ownership]: ./fn.read.html#ownership-of-the-returned-value -/// [valid]: ../ptr/index.html#safety +/// [read-ownership]: read#ownership-of-the-returned-value +/// [valid]: #safety /// /// ## On `packed` structs /// @@ -819,8 +798,6 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// This is appropriate for initializing uninitialized memory, or overwriting /// memory that has previously been [`read`] from. /// -/// [`read`]: ./fn.read.html -/// /// # Safety /// /// Behavior is undefined if any of the following conditions are violated: @@ -832,8 +809,7 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// /// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// -/// [valid]: ../ptr/index.html#safety -/// [`write_unaligned`]: ./fn.write_unaligned.html +/// [valid]: #safety /// /// # Examples /// @@ -888,8 +864,6 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// assert_eq!(foo, "bar"); /// assert_eq!(bar, "foo"); /// ``` -/// -/// [`mem::swap`]: ../mem/fn.swap.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn write(dst: *mut T, src: T) { @@ -916,9 +890,6 @@ pub unsafe fn write(dst: *mut T, src: T) { /// This is appropriate for initializing uninitialized memory, or overwriting /// memory that has previously been read with [`read_unaligned`]. /// -/// [`write`]: ./fn.write.html -/// [`read_unaligned`]: ./fn.read_unaligned.html -/// /// # Safety /// /// Behavior is undefined if any of the following conditions are violated: @@ -927,7 +898,7 @@ pub unsafe fn write(dst: *mut T, src: T) { /// /// Note that even if `T` has size `0`, the pointer must be non-NULL. /// -/// [valid]: ../ptr/index.html#safety +/// [valid]: #safety /// /// ## On `packed` structs /// @@ -1007,8 +978,6 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// to not be elided or reordered by the compiler across other volatile /// operations. /// -/// [`write_volatile`]: ./fn.write_volatile.html -/// /// # Notes /// /// Rust does not currently have a rigorously and formally defined memory model, @@ -1041,10 +1010,8 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// /// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// -/// [valid]: ../ptr/index.html#safety -/// [`Copy`]: ../marker/trait.Copy.html -/// [`read`]: ./fn.read.html -/// [read-ownership]: ./fn.read.html#ownership-of-the-returned-value +/// [valid]: #safety +/// [read-ownership]: read#ownership-of-the-returned-value /// /// Just like in C, whether an operation is volatile has no bearing whatsoever /// on questions involving concurrent access from multiple threads. Volatile @@ -1089,8 +1056,6 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// Additionally, it does not drop `src`. Semantically, `src` is moved into the /// location pointed to by `dst`. /// -/// [`read_volatile`]: ./fn.read_volatile.html -/// /// # Notes /// /// Rust does not currently have a rigorously and formally defined memory model, @@ -1115,12 +1080,12 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// -/// [valid]: ../ptr/index.html#safety +/// [valid]: #safety /// /// Just like in C, whether an operation is volatile has no bearing whatsoever /// on questions involving concurrent access from multiple threads. Volatile /// accesses behave exactly like non-atomic accesses in that regard. In particular, -/// a race between a `write_volatile` and any other operation (reading or writing) +/// a race between a [`write_volatile`] and any other operation (reading or writing) /// on the same location is undefined behavior. /// /// # Examples From f23670ed68c4871a3048bf24f7ad2aa426555b6e Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 8 Sep 2020 17:59:43 -0400 Subject: [PATCH 0190/1052] Adjust Clippy for CONST_ITEM_MUTATION lint We no longer lint assignments to const item fields in the `temporary_assignment` lint, since this is now covered by the `CONST_ITEM_MUTATION` lint. Additionally, we `#![allow(const_item_mutation)]` in the `borrow_interior_mutable_const.rs` test. Clippy UI tests are run with `-D warnings`, which seems to cause builtin lints to prevent Clippy lints from running. --- clippy_lints/src/temporary_assignment.rs | 4 +-- tests/ui/borrow_interior_mutable_const.rs | 1 + tests/ui/borrow_interior_mutable_const.stderr | 32 ++++++++--------- tests/ui/temporary_assignment.rs | 1 + tests/ui/temporary_assignment.stderr | 34 +++---------------- 5 files changed, 24 insertions(+), 48 deletions(-) diff --git a/clippy_lints/src/temporary_assignment.rs b/clippy_lints/src/temporary_assignment.rs index 1aeff1baa362e..2b6ddadd4c112 100644 --- a/clippy_lints/src/temporary_assignment.rs +++ b/clippy_lints/src/temporary_assignment.rs @@ -1,5 +1,4 @@ use crate::utils::{is_adjusted, span_lint}; -use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -22,10 +21,9 @@ declare_clippy_lint! { "assignments to temporaries" } -fn is_temporary(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { +fn is_temporary(_cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { match &expr.kind { ExprKind::Struct(..) | ExprKind::Tup(..) => true, - ExprKind::Path(qpath) => matches!(cx.qpath_res(qpath, expr.hir_id), Res::Def(DefKind::Const, ..)), _ => false, } } diff --git a/tests/ui/borrow_interior_mutable_const.rs b/tests/ui/borrow_interior_mutable_const.rs index a414832bcd362..39f8751054850 100644 --- a/tests/ui/borrow_interior_mutable_const.rs +++ b/tests/ui/borrow_interior_mutable_const.rs @@ -1,5 +1,6 @@ #![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}; diff --git a/tests/ui/borrow_interior_mutable_const.stderr b/tests/ui/borrow_interior_mutable_const.stderr index 1e0b3e4d20a52..5800af7e960f4 100644 --- a/tests/ui/borrow_interior_mutable_const.stderr +++ b/tests/ui/borrow_interior_mutable_const.stderr @@ -1,5 +1,5 @@ error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:65:5 + --> $DIR/borrow_interior_mutable_const.rs:66:5 | LL | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^ @@ -8,7 +8,7 @@ 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:66:16 + --> $DIR/borrow_interior_mutable_const.rs:67:16 | LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability | ^^^^^^ @@ -16,7 +16,7 @@ LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutabi = 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:69:22 + --> $DIR/borrow_interior_mutable_const.rs:70:22 | LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -24,7 +24,7 @@ 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:70:25 + --> $DIR/borrow_interior_mutable_const.rs:71:25 | LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -32,7 +32,7 @@ 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:71:27 + --> $DIR/borrow_interior_mutable_const.rs:72:27 | LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -40,7 +40,7 @@ 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:72:26 + --> $DIR/borrow_interior_mutable_const.rs:73:26 | LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -48,7 +48,7 @@ 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:83:14 + --> $DIR/borrow_interior_mutable_const.rs:84:14 | LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -56,7 +56,7 @@ 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:84:14 + --> $DIR/borrow_interior_mutable_const.rs:85:14 | LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -64,7 +64,7 @@ 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:85:19 + --> $DIR/borrow_interior_mutable_const.rs:86:19 | LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -72,7 +72,7 @@ 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:86:14 + --> $DIR/borrow_interior_mutable_const.rs:87:14 | LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -80,7 +80,7 @@ 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:87:13 + --> $DIR/borrow_interior_mutable_const.rs:88:13 | LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mu = 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:93:13 + --> $DIR/borrow_interior_mutable_const.rs:94:13 | LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -96,7 +96,7 @@ 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:98:5 + --> $DIR/borrow_interior_mutable_const.rs:99:5 | LL | CELL.set(2); //~ ERROR interior mutability | ^^^^ @@ -104,7 +104,7 @@ 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:99:16 + --> $DIR/borrow_interior_mutable_const.rs:100:16 | LL | assert_eq!(CELL.get(), 6); //~ ERROR interior mutability | ^^^^ @@ -112,7 +112,7 @@ 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:112:5 + --> $DIR/borrow_interior_mutable_const.rs:113:5 | LL | u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^^^^^^ @@ -120,7 +120,7 @@ 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:113:16 + --> $DIR/borrow_interior_mutable_const.rs:114:16 | LL | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability | ^^^^^^^^^^^ diff --git a/tests/ui/temporary_assignment.rs b/tests/ui/temporary_assignment.rs index c6c315d5fab5d..d6f56d40c5d4e 100644 --- a/tests/ui/temporary_assignment.rs +++ b/tests/ui/temporary_assignment.rs @@ -1,4 +1,5 @@ #![warn(clippy::temporary_assignment)] +#![allow(const_item_mutation)] use std::ops::{Deref, DerefMut}; diff --git a/tests/ui/temporary_assignment.stderr b/tests/ui/temporary_assignment.stderr index 4efe2d4bb6713..4cc32c79f05ce 100644 --- a/tests/ui/temporary_assignment.stderr +++ b/tests/ui/temporary_assignment.stderr @@ -1,5 +1,5 @@ error: assignment to temporary - --> $DIR/temporary_assignment.rs:47:5 + --> $DIR/temporary_assignment.rs:48:5 | LL | Struct { field: 0 }.field = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | Struct { field: 0 }.field = 1; = note: `-D clippy::temporary-assignment` implied by `-D warnings` error: assignment to temporary - --> $DIR/temporary_assignment.rs:48:5 + --> $DIR/temporary_assignment.rs:49:5 | LL | / MultiStruct { LL | | structure: Struct { field: 0 }, @@ -17,40 +17,16 @@ LL | | .field = 1; | |______________^ error: assignment to temporary - --> $DIR/temporary_assignment.rs:53:5 + --> $DIR/temporary_assignment.rs:54:5 | LL | ArrayStruct { array: [0] }.array[0] = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: assignment to temporary - --> $DIR/temporary_assignment.rs:54:5 + --> $DIR/temporary_assignment.rs:55:5 | LL | (0, 0).0 = 1; | ^^^^^^^^^^^^ -error: assignment to temporary - --> $DIR/temporary_assignment.rs:56:5 - | -LL | A.0 = 2; - | ^^^^^^^ - -error: assignment to temporary - --> $DIR/temporary_assignment.rs:57:5 - | -LL | B.field = 2; - | ^^^^^^^^^^^ - -error: assignment to temporary - --> $DIR/temporary_assignment.rs:58:5 - | -LL | C.structure.field = 2; - | ^^^^^^^^^^^^^^^^^^^^^ - -error: assignment to temporary - --> $DIR/temporary_assignment.rs:59:5 - | -LL | D.array[0] = 2; - | ^^^^^^^^^^^^^^ - -error: aborting due to 8 previous errors +error: aborting due to 4 previous errors From 4434e8cefbec96e6928ea23769eb1a83d0f198b5 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 8 Sep 2020 17:59:43 -0400 Subject: [PATCH 0191/1052] Adjust Clippy for CONST_ITEM_MUTATION lint We no longer lint assignments to const item fields in the `temporary_assignment` lint, since this is now covered by the `CONST_ITEM_MUTATION` lint. Additionally, we `#![allow(const_item_mutation)]` in the `borrow_interior_mutable_const.rs` test. Clippy UI tests are run with `-D warnings`, which seems to cause builtin lints to prevent Clippy lints from running. --- .../clippy_lints/src/temporary_assignment.rs | 4 +-- .../tests/ui/borrow_interior_mutable_const.rs | 1 + .../ui/borrow_interior_mutable_const.stderr | 32 ++++++++--------- .../clippy/tests/ui/temporary_assignment.rs | 1 + .../tests/ui/temporary_assignment.stderr | 34 +++---------------- 5 files changed, 24 insertions(+), 48 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/temporary_assignment.rs b/src/tools/clippy/clippy_lints/src/temporary_assignment.rs index 1aeff1baa362e..2b6ddadd4c112 100644 --- a/src/tools/clippy/clippy_lints/src/temporary_assignment.rs +++ b/src/tools/clippy/clippy_lints/src/temporary_assignment.rs @@ -1,5 +1,4 @@ use crate::utils::{is_adjusted, span_lint}; -use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -22,10 +21,9 @@ declare_clippy_lint! { "assignments to temporaries" } -fn is_temporary(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { +fn is_temporary(_cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { match &expr.kind { ExprKind::Struct(..) | ExprKind::Tup(..) => true, - ExprKind::Path(qpath) => matches!(cx.qpath_res(qpath, expr.hir_id), Res::Def(DefKind::Const, ..)), _ => false, } } diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs index a414832bcd362..39f8751054850 100644 --- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs +++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs @@ -1,5 +1,6 @@ #![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}; diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const.stderr index 1e0b3e4d20a52..5800af7e960f4 100644 --- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const.stderr +++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const.stderr @@ -1,5 +1,5 @@ error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:65:5 + --> $DIR/borrow_interior_mutable_const.rs:66:5 | LL | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^ @@ -8,7 +8,7 @@ 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:66:16 + --> $DIR/borrow_interior_mutable_const.rs:67:16 | LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability | ^^^^^^ @@ -16,7 +16,7 @@ LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutabi = 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:69:22 + --> $DIR/borrow_interior_mutable_const.rs:70:22 | LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -24,7 +24,7 @@ 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:70:25 + --> $DIR/borrow_interior_mutable_const.rs:71:25 | LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -32,7 +32,7 @@ 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:71:27 + --> $DIR/borrow_interior_mutable_const.rs:72:27 | LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -40,7 +40,7 @@ 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:72:26 + --> $DIR/borrow_interior_mutable_const.rs:73:26 | LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -48,7 +48,7 @@ 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:83:14 + --> $DIR/borrow_interior_mutable_const.rs:84:14 | LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -56,7 +56,7 @@ 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:84:14 + --> $DIR/borrow_interior_mutable_const.rs:85:14 | LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -64,7 +64,7 @@ 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:85:19 + --> $DIR/borrow_interior_mutable_const.rs:86:19 | LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -72,7 +72,7 @@ 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:86:14 + --> $DIR/borrow_interior_mutable_const.rs:87:14 | LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -80,7 +80,7 @@ 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:87:13 + --> $DIR/borrow_interior_mutable_const.rs:88:13 | LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mu = 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:93:13 + --> $DIR/borrow_interior_mutable_const.rs:94:13 | LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -96,7 +96,7 @@ 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:98:5 + --> $DIR/borrow_interior_mutable_const.rs:99:5 | LL | CELL.set(2); //~ ERROR interior mutability | ^^^^ @@ -104,7 +104,7 @@ 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:99:16 + --> $DIR/borrow_interior_mutable_const.rs:100:16 | LL | assert_eq!(CELL.get(), 6); //~ ERROR interior mutability | ^^^^ @@ -112,7 +112,7 @@ 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:112:5 + --> $DIR/borrow_interior_mutable_const.rs:113:5 | LL | u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^^^^^^ @@ -120,7 +120,7 @@ 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:113:16 + --> $DIR/borrow_interior_mutable_const.rs:114:16 | LL | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability | ^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/temporary_assignment.rs b/src/tools/clippy/tests/ui/temporary_assignment.rs index c6c315d5fab5d..d6f56d40c5d4e 100644 --- a/src/tools/clippy/tests/ui/temporary_assignment.rs +++ b/src/tools/clippy/tests/ui/temporary_assignment.rs @@ -1,4 +1,5 @@ #![warn(clippy::temporary_assignment)] +#![allow(const_item_mutation)] use std::ops::{Deref, DerefMut}; diff --git a/src/tools/clippy/tests/ui/temporary_assignment.stderr b/src/tools/clippy/tests/ui/temporary_assignment.stderr index 4efe2d4bb6713..4cc32c79f05ce 100644 --- a/src/tools/clippy/tests/ui/temporary_assignment.stderr +++ b/src/tools/clippy/tests/ui/temporary_assignment.stderr @@ -1,5 +1,5 @@ error: assignment to temporary - --> $DIR/temporary_assignment.rs:47:5 + --> $DIR/temporary_assignment.rs:48:5 | LL | Struct { field: 0 }.field = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | Struct { field: 0 }.field = 1; = note: `-D clippy::temporary-assignment` implied by `-D warnings` error: assignment to temporary - --> $DIR/temporary_assignment.rs:48:5 + --> $DIR/temporary_assignment.rs:49:5 | LL | / MultiStruct { LL | | structure: Struct { field: 0 }, @@ -17,40 +17,16 @@ LL | | .field = 1; | |______________^ error: assignment to temporary - --> $DIR/temporary_assignment.rs:53:5 + --> $DIR/temporary_assignment.rs:54:5 | LL | ArrayStruct { array: [0] }.array[0] = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: assignment to temporary - --> $DIR/temporary_assignment.rs:54:5 + --> $DIR/temporary_assignment.rs:55:5 | LL | (0, 0).0 = 1; | ^^^^^^^^^^^^ -error: assignment to temporary - --> $DIR/temporary_assignment.rs:56:5 - | -LL | A.0 = 2; - | ^^^^^^^ - -error: assignment to temporary - --> $DIR/temporary_assignment.rs:57:5 - | -LL | B.field = 2; - | ^^^^^^^^^^^ - -error: assignment to temporary - --> $DIR/temporary_assignment.rs:58:5 - | -LL | C.structure.field = 2; - | ^^^^^^^^^^^^^^^^^^^^^ - -error: assignment to temporary - --> $DIR/temporary_assignment.rs:59:5 - | -LL | D.array[0] = 2; - | ^^^^^^^^^^^^^^ - -error: aborting due to 8 previous errors +error: aborting due to 4 previous errors From d719b485434eac557e65bf55cca79e63f7b83d5b Mon Sep 17 00:00:00 2001 From: Ricky Date: Tue, 8 Sep 2020 19:37:14 -0400 Subject: [PATCH 0192/1052] Move map_err_ignore from style to pedantic --- clippy_lints/src/lib.rs | 3 +-- clippy_lints/src/map_err_ignore.rs | 2 +- src/lintlist/mod.rs | 2 +- tests/ui/map_err.rs | 1 + tests/ui/map_err.stderr | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 3794cae091a42..797ab62cb5447 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1179,6 +1179,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP), LintId::of(&loops::EXPLICIT_ITER_LOOP), LintId::of(¯o_use::MACRO_USE_IMPORTS), + LintId::of(&map_err_ignore::MAP_ERR_IGNORE), LintId::of(&match_on_vec_items::MATCH_ON_VEC_ITEMS), LintId::of(&matches::MATCH_BOOL), LintId::of(&matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS), @@ -1330,7 +1331,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&manual_async_fn::MANUAL_ASYNC_FN), LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), LintId::of(&map_clone::MAP_CLONE), - LintId::of(&map_err_ignore::MAP_ERR_IGNORE), LintId::of(&map_identity::MAP_IDENTITY), LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN), LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN), @@ -1538,7 +1538,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&manual_async_fn::MANUAL_ASYNC_FN), LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), LintId::of(&map_clone::MAP_CLONE), - LintId::of(&map_err_ignore::MAP_ERR_IGNORE), LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH), LintId::of(&matches::MATCH_LIKE_MATCHES_MACRO), LintId::of(&matches::MATCH_OVERLAPPING_ARM), diff --git a/clippy_lints/src/map_err_ignore.rs b/clippy_lints/src/map_err_ignore.rs index fa59b6ec37061..5298e16a04d9b 100644 --- a/clippy_lints/src/map_err_ignore.rs +++ b/clippy_lints/src/map_err_ignore.rs @@ -99,7 +99,7 @@ declare_clippy_lint! { /// } /// ``` pub MAP_ERR_IGNORE, - style, + pedantic, "`map_err` should not ignore the original error" } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 6725c97f79383..5105e95316266 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1167,7 +1167,7 @@ pub static ref ALL_LINTS: Vec = vec![ }, Lint { name: "map_err_ignore", - group: "style", + group: "pedantic", desc: "`map_err` should not ignore the original error", deprecation: None, module: "map_err_ignore", diff --git a/tests/ui/map_err.rs b/tests/ui/map_err.rs index f3a74ad95cd29..617b642287264 100644 --- a/tests/ui/map_err.rs +++ b/tests/ui/map_err.rs @@ -1,3 +1,4 @@ +#![warn(clippy::map_err_ignore)] use std::convert::TryFrom; use std::error::Error; use std::fmt; diff --git a/tests/ui/map_err.stderr b/tests/ui/map_err.stderr index e4e6a289ba030..7273f46038078 100644 --- a/tests/ui/map_err.stderr +++ b/tests/ui/map_err.stderr @@ -1,5 +1,5 @@ error: `map_err(|_|...` ignores the original error - --> $DIR/map_err.rs:21:32 + --> $DIR/map_err.rs:22:32 | LL | println!("{:?}", x.map_err(|_| Errors::Ignored)); | ^^^ From c19b2370e419c0be7b46cc9ae7767773560a072c Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Tue, 8 Sep 2020 16:08:35 -0700 Subject: [PATCH 0193/1052] Add -Zgraphviz_dark_mode Many developers use a dark theme with editors and IDEs, but this typically doesn't extend to graphviz output. When I bring up a MIR graphviz document, the white background is strikingly bright. This new option changes the colors used for graphviz output to work better in dark-themed UIs. --- compiler/rustc_graphviz/src/lib.rs | 20 +++++++++++-- .../src/dataflow/framework/engine.rs | 6 +++- compiler/rustc_mir/src/util/graphviz.rs | 29 ++++++++++++++----- compiler/rustc_session/src/options.rs | 2 ++ 4 files changed, 46 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs index 4339092b63e85..252e341686541 100644 --- a/compiler/rustc_graphviz/src/lib.rs +++ b/compiler/rustc_graphviz/src/lib.rs @@ -599,6 +599,7 @@ pub enum RenderOption { NoNodeStyles, Monospace, + DarkTheme, } /// Returns vec holding all the default render options. @@ -630,10 +631,23 @@ where writeln!(w, "digraph {} {{", g.graph_id().as_slice())?; // Global graph properties + let mut graph_attrs = Vec::new(); + let mut content_attrs = Vec::new(); if options.contains(&RenderOption::Monospace) { - writeln!(w, r#" graph[fontname="monospace"];"#)?; - writeln!(w, r#" node[fontname="monospace"];"#)?; - writeln!(w, r#" edge[fontname="monospace"];"#)?; + let font = r#"fontname="monospace""#; + graph_attrs.push(font); + content_attrs.push(font); + }; + if options.contains(&RenderOption::DarkTheme) { + graph_attrs.push(r#"bgcolor="black""#); + content_attrs.push(r#"color="white""#); + content_attrs.push(r#"fontcolor="white""#); + } + if !(graph_attrs.is_empty() && content_attrs.is_empty()) { + writeln!(w, r#" graph[{}];"#, graph_attrs.join(" "))?; + let content_attrs_str = content_attrs.join(" "); + writeln!(w, r#" node[{}];"#, content_attrs_str)?; + writeln!(w, r#" edge[{}];"#, content_attrs_str)?; } for n in g.nodes().iter() { diff --git a/compiler/rustc_mir/src/dataflow/framework/engine.rs b/compiler/rustc_mir/src/dataflow/framework/engine.rs index d3ad42f6bbcce..0b5b437d186aa 100644 --- a/compiler/rustc_mir/src/dataflow/framework/engine.rs +++ b/compiler/rustc_mir/src/dataflow/framework/engine.rs @@ -306,7 +306,11 @@ where let mut buf = Vec::new(); let graphviz = graphviz::Formatter::new(body, def_id, results, style); - dot::render_opts(&graphviz, &mut buf, &[dot::RenderOption::Monospace])?; + let mut render_opts = vec![dot::RenderOption::Monospace]; + if tcx.sess.opts.debugging_opts.graphviz_dark_mode { + render_opts.push(dot::RenderOption::DarkTheme); + } + dot::render_opts(&graphviz, &mut buf, &render_opts)?; if let Some(parent) = path.parent() { fs::create_dir_all(parent)?; diff --git a/compiler/rustc_mir/src/util/graphviz.rs b/compiler/rustc_mir/src/util/graphviz.rs index 50193c4a0db7d..bc1e3fa8b2915 100644 --- a/compiler/rustc_mir/src/util/graphviz.rs +++ b/compiler/rustc_mir/src/util/graphviz.rs @@ -55,16 +55,28 @@ where writeln!(w, "{} {}Mir_{} {{", kind, cluster, def_name)?; // Global graph properties - writeln!(w, r#" graph [fontname="monospace"];"#)?; - writeln!(w, r#" node [fontname="monospace"];"#)?; - writeln!(w, r#" edge [fontname="monospace"];"#)?; + let font = r#"fontname="monospace""#; + let mut graph_attrs = vec![font]; + let mut content_attrs = vec![font]; + + let dark_mode = tcx.sess.opts.debugging_opts.graphviz_dark_mode; + if dark_mode { + graph_attrs.push(r#"bgcolor="black""#); + content_attrs.push(r#"color="white""#); + content_attrs.push(r#"fontcolor="white""#); + } + + writeln!(w, r#" graph [{}];"#, graph_attrs.join(" "))?; + let content_attrs_str = content_attrs.join(" "); + writeln!(w, r#" node [{}];"#, content_attrs_str)?; + writeln!(w, r#" edge [{}];"#, content_attrs_str)?; // Graph label write_graph_label(tcx, def_id, body, w)?; // Nodes for (block, _) in body.basic_blocks().iter_enumerated() { - write_node(def_id, block, body, w)?; + write_node(def_id, block, body, dark_mode, w)?; } // Edges @@ -84,6 +96,7 @@ where pub fn write_node_label( block: BasicBlock, body: &Body<'_>, + dark_mode: bool, w: &mut W, num_cols: u32, init: INIT, @@ -100,8 +113,9 @@ where // Basic block number at the top. write!( w, - r#"{blk}"#, - attrs = r#"bgcolor="gray" align="center""#, + r#"{blk}"#, + bgcolor = if dark_mode { "dimgray" } else { "gray" }, + attrs = r#"align="center""#, colspan = num_cols, blk = block.index() )?; @@ -134,11 +148,12 @@ fn write_node( def_id: DefId, block: BasicBlock, body: &Body<'_>, + dark_mode: bool, w: &mut W, ) -> io::Result<()> { // Start a new node with the label to follow, in one of DOT's pseudo-HTML tables. write!(w, r#" {} [shape="none", label=<"#, node(def_id, block))?; - write_node_label(block, body, w, 1, |_| Ok(()), |_| Ok(()))?; + write_node_label(block, body, dark_mode, w, 1, |_| Ok(()), |_| Ok(()))?; // Close the node label and the node itself. writeln!(w, ">];") } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index ad36fa7698621..f31e0431d0da7 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -907,6 +907,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "force all crates to be `rustc_private` unstable (default: no)"), fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED], "set the optimization fuel quota for a crate"), + graphviz_dark_mode: bool = (false, parse_bool, [UNTRACKED], + "use dark-themed colors in graphviz output (default: no)"), hir_stats: bool = (false, parse_bool, [UNTRACKED], "print some statistics about AST and HIR (default: no)"), human_readable_cgu_names: bool = (false, parse_bool, [TRACKED], From 15ccdeb2248f697c3873a60eea538110ed5b2f8f Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Thu, 3 Sep 2020 13:32:53 -0700 Subject: [PATCH 0194/1052] Update to hashbrown 0.9 --- Cargo.lock | 9 ++++----- library/std/Cargo.toml | 2 +- library/std/src/collections/hash/map.rs | 10 +++++----- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8deab1deee0d6..b687e714d4fa2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1259,11 +1259,10 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.8.2" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b62f79061a0bc2e046024cb7ba44b08419ed238ecbd9adbd787434b9e8c25" +checksum = "00d63df3d41950fb462ed38308eea019113ad1508da725bbedcd0fa5a85ef5f7" dependencies = [ - "autocfg", "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", @@ -1401,9 +1400,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b45e59b16c76b11bf9738fd5d38879d3bd28ad292d7b313608becb17ae2df9" +checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2" dependencies = [ "autocfg", "hashbrown", diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 9cc6928708008..bfd05db6b1bbe 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -20,7 +20,7 @@ libc = { version = "0.2.74", default-features = false, features = ['rustc-dep-of compiler_builtins = { version = "0.1.35" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } -hashbrown = { version = "0.8.1", default-features = false, features = ['rustc-dep-of-std'] } +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 } diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 57cb179a4244a..56176bc5856f3 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -1247,7 +1247,7 @@ pub struct RawEntryBuilderMut<'a, K: 'a, V: 'a, S: 'a> { #[unstable(feature = "hash_raw_entry", issue = "56167")] pub enum RawEntryMut<'a, K: 'a, V: 'a, S: 'a> { /// An occupied entry. - Occupied(RawOccupiedEntryMut<'a, K, V>), + Occupied(RawOccupiedEntryMut<'a, K, V, S>), /// A vacant entry. Vacant(RawVacantEntryMut<'a, K, V, S>), } @@ -1255,8 +1255,8 @@ pub enum RawEntryMut<'a, K: 'a, V: 'a, S: 'a> { /// A view into an occupied entry in a `HashMap`. /// It is part of the [`RawEntryMut`] enum. #[unstable(feature = "hash_raw_entry", issue = "56167")] -pub struct RawOccupiedEntryMut<'a, K: 'a, V: 'a> { - base: base::RawOccupiedEntryMut<'a, K, V>, +pub struct RawOccupiedEntryMut<'a, K: 'a, V: 'a, S: 'a> { + base: base::RawOccupiedEntryMut<'a, K, V, S>, } /// A view into a vacant entry in a `HashMap`. @@ -1457,7 +1457,7 @@ impl<'a, K, V, S> RawEntryMut<'a, K, V, S> { } } -impl<'a, K, V> RawOccupiedEntryMut<'a, K, V> { +impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> { /// Gets a reference to the key in the entry. #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] @@ -1597,7 +1597,7 @@ impl Debug for RawEntryMut<'_, K, V, S> { } #[unstable(feature = "hash_raw_entry", issue = "56167")] -impl Debug for RawOccupiedEntryMut<'_, K, V> { +impl Debug for RawOccupiedEntryMut<'_, K, V, S> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RawOccupiedEntryMut") .field("key", self.key()) From ebd15e790aceeaacb01bdd5c4361c5b4be2db237 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Mon, 10 Aug 2020 16:19:54 -0700 Subject: [PATCH 0195/1052] Implement HashSet in terms of hashbrown::HashSet --- library/std/src/collections/hash/map.rs | 2 +- library/std/src/collections/hash/set.rs | 109 +++++++++++------------- src/etc/gdb_lookup.py | 4 +- src/etc/gdb_providers.py | 14 ++- src/etc/lldb_lookup.py | 2 +- src/etc/lldb_providers.py | 13 ++- src/etc/natvis/libstd.natvis | 18 ++-- 7 files changed, 90 insertions(+), 72 deletions(-) diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 56176bc5856f3..fc0175332a769 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -2698,7 +2698,7 @@ fn map_entry<'a, K: 'a, V: 'a>(raw: base::RustcEntry<'a, K, V>) -> Entry<'a, K, } #[inline] -fn map_try_reserve_error(err: hashbrown::TryReserveError) -> TryReserveError { +pub(super) fn map_try_reserve_error(err: hashbrown::TryReserveError) -> TryReserveError { match err { hashbrown::TryReserveError::CapacityOverflow => TryReserveError::CapacityOverflow, hashbrown::TryReserveError::AllocError { layout } => { diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index 8c39725ef3550..f9bc2e933dcf9 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -1,6 +1,8 @@ #[cfg(test)] mod tests; +use hashbrown::hash_set as base; + use crate::borrow::Borrow; use crate::collections::TryReserveError; use crate::fmt; @@ -8,7 +10,7 @@ use crate::hash::{BuildHasher, Hash}; use crate::iter::{Chain, FromIterator, FusedIterator}; use crate::ops::{BitAnd, BitOr, BitXor, Sub}; -use super::map::{self, HashMap, Keys, RandomState}; +use super::map::{map_try_reserve_error, RandomState}; // Future Optimization (FIXME!) // ============================ @@ -101,13 +103,14 @@ use super::map::{self, HashMap, Keys, RandomState}; /// // use the values stored in the set /// ``` /// +/// [`HashMap`]: crate::collections::HashMap /// [`RefCell`]: crate::cell::RefCell /// [`Cell`]: crate::cell::Cell #[derive(Clone)] #[cfg_attr(not(test), rustc_diagnostic_item = "hashset_type")] #[stable(feature = "rust1", since = "1.0.0")] pub struct HashSet { - map: HashMap, + base: base::HashSet, } impl HashSet { @@ -125,7 +128,7 @@ impl HashSet { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> HashSet { - HashSet { map: HashMap::new() } + Default::default() } /// Creates an empty `HashSet` with the specified capacity. @@ -143,7 +146,7 @@ impl HashSet { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(capacity: usize) -> HashSet { - HashSet { map: HashMap::with_capacity(capacity) } + HashSet { base: base::HashSet::with_capacity_and_hasher(capacity, Default::default()) } } } @@ -160,7 +163,7 @@ impl HashSet { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn capacity(&self) -> usize { - self.map.capacity() + self.base.capacity() } /// An iterator visiting all elements in arbitrary order. @@ -182,7 +185,7 @@ impl HashSet { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn iter(&self) -> Iter<'_, T> { - Iter { iter: self.map.keys() } + Iter { base: self.base.iter() } } /// Returns the number of elements in the set. @@ -200,7 +203,7 @@ impl HashSet { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> usize { - self.map.len() + self.base.len() } /// Returns `true` if the set contains no elements. @@ -218,7 +221,7 @@ impl HashSet { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn is_empty(&self) -> bool { - self.map.is_empty() + self.base.is_empty() } /// Clears the set, returning all elements in an iterator. @@ -241,7 +244,7 @@ impl HashSet { #[inline] #[stable(feature = "drain", since = "1.6.0")] pub fn drain(&mut self) -> Drain<'_, T> { - Drain { iter: self.map.drain() } + Drain { base: self.base.drain() } } /// Clears the set, removing all values. @@ -259,7 +262,7 @@ impl HashSet { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn clear(&mut self) { - self.map.clear() + self.base.clear() } /// Creates a new empty hash set which will use the given hasher to hash @@ -288,7 +291,7 @@ impl HashSet { #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub fn with_hasher(hasher: S) -> HashSet { - HashSet { map: HashMap::with_hasher(hasher) } + HashSet { base: base::HashSet::with_hasher(hasher) } } /// Creates an empty `HashSet` with the specified capacity, using @@ -318,7 +321,7 @@ impl HashSet { #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashSet { - HashSet { map: HashMap::with_capacity_and_hasher(capacity, hasher) } + HashSet { base: base::HashSet::with_capacity_and_hasher(capacity, hasher) } } /// Returns a reference to the set's [`BuildHasher`]. @@ -336,7 +339,7 @@ impl HashSet { #[inline] #[stable(feature = "hashmap_public_hasher", since = "1.9.0")] pub fn hasher(&self) -> &S { - self.map.hasher() + self.base.hasher() } } @@ -364,7 +367,7 @@ where #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve(&mut self, additional: usize) { - self.map.reserve(additional) + self.base.reserve(additional) } /// Tries to reserve capacity for at least `additional` more elements to be inserted @@ -387,7 +390,7 @@ where #[inline] #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { - self.map.try_reserve(additional) + self.base.try_reserve(additional).map_err(map_try_reserve_error) } /// Shrinks the capacity of the set as much as possible. It will drop @@ -409,7 +412,7 @@ where #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn shrink_to_fit(&mut self) { - self.map.shrink_to_fit() + self.base.shrink_to_fit() } /// Shrinks the capacity of the set with a lower limit. It will drop @@ -437,7 +440,7 @@ where #[inline] #[unstable(feature = "shrink_to", reason = "new API", issue = "56431")] pub fn shrink_to(&mut self, min_capacity: usize) { - self.map.shrink_to(min_capacity) + self.base.shrink_to(min_capacity) } /// Visits the values representing the difference, @@ -577,7 +580,7 @@ where T: Borrow, Q: Hash + Eq, { - self.map.contains_key(value) + self.base.contains(value) } /// Returns a reference to the value in the set, if any, that is equal to the given value. @@ -602,7 +605,7 @@ where T: Borrow, Q: Hash + Eq, { - self.map.get_key_value(value).map(|(k, _)| k) + self.base.get(value) } /// Inserts the given `value` into the set if it is not present, then @@ -626,7 +629,7 @@ where pub fn get_or_insert(&mut self, value: T) -> &T { // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. - self.map.raw_entry_mut().from_key(&value).or_insert(value, ()).0 + self.base.get_or_insert(value) } /// Inserts an owned copy of the given `value` into the set if it is not @@ -658,7 +661,7 @@ where { // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. - self.map.raw_entry_mut().from_key(value).or_insert_with(|| (value.to_owned(), ())).0 + self.base.get_or_insert_owned(value) } /// Inserts a value computed from `f` into the set if the given `value` is @@ -691,7 +694,7 @@ where { // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. - self.map.raw_entry_mut().from_key(value).or_insert_with(|| (f(value), ())).0 + self.base.get_or_insert_with(value, f) } /// Returns `true` if `self` has no elements in common with `other`. @@ -788,7 +791,7 @@ where #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(&mut self, value: T) -> bool { - self.map.insert(value, ()).is_none() + self.base.insert(value) } /// Adds a value to the set, replacing the existing value, if any, that is equal to the given @@ -809,13 +812,7 @@ where #[inline] #[stable(feature = "set_recovery", since = "1.9.0")] pub fn replace(&mut self, value: T) -> Option { - match self.map.entry(value) { - map::Entry::Occupied(occupied) => Some(occupied.replace_key()), - map::Entry::Vacant(vacant) => { - vacant.insert(()); - None - } - } + self.base.replace(value) } /// Removes a value from the set. Returns whether the value was @@ -843,7 +840,7 @@ where T: Borrow, Q: Hash + Eq, { - self.map.remove(value).is_some() + self.base.remove(value) } /// Removes and returns the value in the set, if any, that is equal to the given one. @@ -868,7 +865,7 @@ where T: Borrow, Q: Hash + Eq, { - self.map.remove_entry(value).map(|(k, _)| k) + self.base.take(value) } /// Retains only the elements specified by the predicate. @@ -886,11 +883,11 @@ where /// assert_eq!(set.len(), 3); /// ``` #[stable(feature = "retain_hash_collection", since = "1.18.0")] - pub fn retain(&mut self, mut f: F) + pub fn retain(&mut self, f: F) where F: FnMut(&T) -> bool, { - self.map.retain(|k, _| f(k)); + self.base.retain(f) } } @@ -949,17 +946,17 @@ where { #[inline] fn extend>(&mut self, iter: I) { - self.map.extend(iter.into_iter().map(|k| (k, ()))); + self.base.extend(iter); } #[inline] fn extend_one(&mut self, item: T) { - self.map.insert(item, ()); + self.base.insert(item); } #[inline] fn extend_reserve(&mut self, additional: usize) { - self.map.extend_reserve(additional); + self.base.extend_reserve(additional); } } @@ -976,7 +973,7 @@ where #[inline] fn extend_one(&mut self, &item: &'a T) { - self.map.insert(item, ()); + self.base.insert(item); } #[inline] @@ -993,7 +990,7 @@ where /// Creates an empty `HashSet` with the `Default` value for the hasher. #[inline] fn default() -> HashSet { - HashSet { map: HashMap::default() } + HashSet { base: Default::default() } } } @@ -1137,7 +1134,7 @@ where /// [`iter`]: HashSet::iter #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, K: 'a> { - iter: Keys<'a, K, ()>, + base: base::Iter<'a, K>, } /// An owning iterator over the items of a `HashSet`. @@ -1148,7 +1145,7 @@ pub struct Iter<'a, K: 'a> { /// [`into_iter`]: IntoIterator::into_iter #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { - iter: map::IntoIter, + base: base::IntoIter, } /// A draining iterator over the items of a `HashSet`. @@ -1159,7 +1156,7 @@ pub struct IntoIter { /// [`drain`]: HashSet::drain #[stable(feature = "rust1", since = "1.0.0")] pub struct Drain<'a, K: 'a> { - iter: map::Drain<'a, K, ()>, + base: base::Drain<'a, K>, } /// A lazy iterator producing elements in the intersection of `HashSet`s. @@ -1250,7 +1247,7 @@ impl IntoIterator for HashSet { /// ``` #[inline] fn into_iter(self) -> IntoIter { - IntoIter { iter: self.map.into_iter() } + IntoIter { base: self.base.into_iter() } } } @@ -1258,7 +1255,7 @@ impl IntoIterator for HashSet { impl Clone for Iter<'_, K> { #[inline] fn clone(&self) -> Self { - Iter { iter: self.iter.clone() } + Iter { base: self.base.clone() } } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1267,18 +1264,18 @@ impl<'a, K> Iterator for Iter<'a, K> { #[inline] fn next(&mut self) -> Option<&'a K> { - self.iter.next() + self.base.next() } #[inline] fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() + self.base.size_hint() } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Iter<'_, K> { #[inline] fn len(&self) -> usize { - self.iter.len() + self.base.len() } } #[stable(feature = "fused", since = "1.26.0")] @@ -1297,18 +1294,18 @@ impl Iterator for IntoIter { #[inline] fn next(&mut self) -> Option { - self.iter.next().map(|(k, _)| k) + self.base.next() } #[inline] fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() + self.base.size_hint() } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter { #[inline] fn len(&self) -> usize { - self.iter.len() + self.base.len() } } #[stable(feature = "fused", since = "1.26.0")] @@ -1317,8 +1314,7 @@ impl FusedIterator for IntoIter {} #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for IntoIter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let entries_iter = self.iter.iter().map(|(k, _)| k); - f.debug_list().entries(entries_iter).finish() + fmt::Debug::fmt(&self.base, f) } } @@ -1328,18 +1324,18 @@ impl<'a, K> Iterator for Drain<'a, K> { #[inline] fn next(&mut self) -> Option { - self.iter.next().map(|(k, _)| k) + self.base.next() } #[inline] fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() + self.base.size_hint() } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Drain<'_, K> { #[inline] fn len(&self) -> usize { - self.iter.len() + self.base.len() } } #[stable(feature = "fused", since = "1.26.0")] @@ -1348,8 +1344,7 @@ impl FusedIterator for Drain<'_, K> {} #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Drain<'_, K> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let entries_iter = self.iter.iter().map(|(k, _)| k); - f.debug_list().entries(entries_iter).finish() + fmt::Debug::fmt(&self.base, f) } } diff --git a/src/etc/gdb_lookup.py b/src/etc/gdb_lookup.py index 2a46eaadad6f9..a5a1824c84e78 100644 --- a/src/etc/gdb_lookup.py +++ b/src/etc/gdb_lookup.py @@ -69,9 +69,9 @@ def lookup(valobj): else: return StdOldHashMapProvider(valobj) if rust_type == RustType.STD_HASH_SET: - hash_map = valobj["map"] + hash_map = valobj[valobj.type.fields()[0]] if is_hashbrown_hashmap(hash_map): - return StdHashMapProvider(hash_map, show_values=False) + return StdHashMapProvider(valobj, show_values=False) else: return StdOldHashMapProvider(hash_map, show_values=False) diff --git a/src/etc/gdb_providers.py b/src/etc/gdb_providers.py index 67f99ec4e40b9..bae51e6f9ee93 100644 --- a/src/etc/gdb_providers.py +++ b/src/etc/gdb_providers.py @@ -347,7 +347,7 @@ def __init__(self, valobj, show_values=True): self.valobj = valobj self.show_values = show_values - table = self.valobj["base"]["table"] + table = self.table() capacity = int(table["bucket_mask"]) + 1 ctrl = table["ctrl"]["pointer"] @@ -368,6 +368,18 @@ def __init__(self, valobj, show_values=True): if is_presented: self.valid_indices.append(idx) + def table(self): + if self.show_values: + hashbrown_hashmap = self.valobj["base"] + elif self.valobj.type.fields()[0].name == "map": + # BACKCOMPAT: rust 1.47 + # HashSet wraps std::collections::HashMap, which wraps hashbrown::HashMap + hashbrown_hashmap = self.valobj["map"]["base"] + else: + # HashSet wraps hashbrown::HashSet, which wraps hashbrown::HashMap + hashbrown_hashmap = self.valobj["base"]["map"] + return hashbrown_hashmap["table"] + def to_string(self): if self.show_values: return "HashMap(size={})".format(self.size) diff --git a/src/etc/lldb_lookup.py b/src/etc/lldb_lookup.py index 13420fbaf0a75..3cee51982ba9f 100644 --- a/src/etc/lldb_lookup.py +++ b/src/etc/lldb_lookup.py @@ -94,7 +94,7 @@ def synthetic_lookup(valobj, dict): if rust_type == RustType.STD_HASH_SET: hash_map = valobj.GetChildAtIndex(0) if is_hashbrown_hashmap(hash_map): - return StdHashMapSyntheticProvider(hash_map, dict, show_values=False) + return StdHashMapSyntheticProvider(valobj, dict, show_values=False) else: return StdOldHashMapSyntheticProvider(hash_map, dict, show_values=False) diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index 19da75c35b456..64cb9837943b9 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -526,7 +526,7 @@ def get_child_at_index(self, index): def update(self): # type: () -> None - table = self.valobj.GetChildMemberWithName("base").GetChildMemberWithName("table") + table = self.table() capacity = table.GetChildMemberWithName("bucket_mask").GetValueAsUnsigned() + 1 ctrl = table.GetChildMemberWithName("ctrl").GetChildAtIndex(0) @@ -552,6 +552,17 @@ def update(self): if is_present: self.valid_indices.append(idx) + def table(self): + # type: () -> SBValue + if self.show_values: + hashbrown_hashmap = self.valobj.GetChildMemberWithName("base") + else: + # BACKCOMPAT: rust 1.47 + # HashSet wraps either std HashMap or hashbrown::HashSet, which both + # wrap hashbrown::HashMap, so either way we "unwrap" twice. + hashbrown_hashmap = self.valobj.GetChildAtIndex(0).GetChildAtIndex(0) + return hashbrown_hashmap.GetChildMemberWithName("table") + def has_children(self): # type: () -> bool return True diff --git a/src/etc/natvis/libstd.natvis b/src/etc/natvis/libstd.natvis index f791979800f19..9550c25f2fcfe 100644 --- a/src/etc/natvis/libstd.natvis +++ b/src/etc/natvis/libstd.natvis @@ -5,7 +5,7 @@ Current std impls: std::collections::hash::set::HashSet is implemented in terms of... - std::collections::hash::map::HashMap is implemented in terms of... + hashbrown::set::HashSet is implemented in terms of... hashbrown::map::HashMap is implemented in terms of... hashbrown::raw::RawTable<(K, V)> @@ -50,22 +50,22 @@ - {{ size={map.base.table.items} }} + {{ size={base.map.table.items} }} - map.base.table.items - map.base.table.items + map.base.table.growth_left - map.base.hash_builder + base.map.table.items + base.map.table.items + base.map.table.growth_left + base.map.hash_builder - - map.base.table.items + + base.map.table.items - + n-- - (($T1*)map.base.table.ctrl.pointer)[-(i + 1)] + (($T1*)base.map.table.ctrl.pointer)[-(i + 1)] i++ From 49aef963d3fb50c6961077cc11c6ce93ee719d73 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Mon, 10 Aug 2020 13:06:48 -0700 Subject: [PATCH 0196/1052] Add HashMap::drain_filter and HashSet::drain_filter Implements #59618. --- library/std/src/collections/hash/map.rs | 87 +++++++++++++++++++++++++ library/std/src/collections/hash/set.rs | 84 ++++++++++++++++++++++++ 2 files changed, 171 insertions(+) diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index fc0175332a769..1a3a493fbb8f6 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -497,6 +497,50 @@ impl HashMap { Drain { base: self.base.drain() } } + /// Creates an iterator which uses a closure to determine if an element should be removed. + /// + /// If the closure returns true, the element is removed from the map and yielded. + /// If the closure returns false, or panics, the element remains in the map and will not be + /// yielded. + /// + /// Note that `drain_filter` lets you mutate every value in the filter closure, regardless of + /// whether you choose to keep or remove it. + /// + /// If the iterator is only partially consumed or not consumed at all, each of the remaining + /// elements will still be subjected to the closure and removed and dropped if it returns true. + /// + /// It is unspecified how many more elements will be subjected to the closure + /// if a panic occurs in the closure, or a panic occurs while dropping an element, + /// or if the `DrainFilter` value is leaked. + /// + /// # Examples + /// + /// Splitting a map into even and odd keys, reusing the original map: + /// + /// ``` + /// #![feature(hash_drain_filter)] + /// use std::collections::HashMap; + /// + /// let mut map: HashMap = (0..8).map(|x| (x, x)).collect(); + /// let drained: HashMap = map.drain_filter(|k, _v| k % 2 == 0).collect(); + /// + /// let mut evens = drained.keys().copied().collect::>(); + /// let mut odds = map.keys().copied().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// ``` + #[inline] + #[unstable(feature = "hash_drain_filter", issue = "59618")] + pub fn drain_filter(&mut self, pred: F) -> DrainFilter<'_, K, V, F> + where + F: FnMut(&K, &mut V) -> bool, + { + DrainFilter { base: self.base.drain_filter(pred) } + } + /// Clears the map, removing all key-value pairs. Keeps the allocated memory /// for reuse. /// @@ -1190,6 +1234,19 @@ impl<'a, K, V> Drain<'a, K, V> { } } +/// A draining, filtering iterator over the entries of a `HashMap`. +/// +/// This `struct` is created by the [`drain_filter`] method on [`HashMap`]. +/// +/// [`drain_filter`]: HashMap::drain_filter +#[unstable(feature = "hash_drain_filter", issue = "59618")] +pub struct DrainFilter<'a, K, V, F> +where + F: FnMut(&K, &mut V) -> bool, +{ + base: base::DrainFilter<'a, K, V, F>, +} + /// A mutable iterator over the values of a `HashMap`. /// /// This `struct` is created by the [`values_mut`] method on [`HashMap`]. See its @@ -1990,6 +2047,36 @@ where } } +#[unstable(feature = "hash_drain_filter", issue = "59618")] +impl Iterator for DrainFilter<'_, K, V, F> +where + F: FnMut(&K, &mut V) -> bool, +{ + type Item = (K, V); + + #[inline] + fn next(&mut self) -> Option<(K, V)> { + self.base.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.base.size_hint() + } +} + +#[unstable(feature = "hash_drain_filter", issue = "59618")] +impl FusedIterator for DrainFilter<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} + +#[unstable(feature = "hash_drain_filter", issue = "59618")] +impl<'a, K, V, F> fmt::Debug for DrainFilter<'a, K, V, F> +where + F: FnMut(&K, &mut V) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("DrainFilter { .. }") + } +} + impl<'a, K, V> Entry<'a, K, V> { #[stable(feature = "rust1", since = "1.0.0")] /// Ensures a value is in the entry by inserting the default if empty, and returns diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index f9bc2e933dcf9..72f4798b65d66 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -247,6 +247,47 @@ impl HashSet { Drain { base: self.base.drain() } } + /// Creates an iterator which uses a closure to determine if a value should be removed. + /// + /// If the closure returns true, then the value is removed and yielded. + /// If the closure returns false, the value will remain in the list and will not be yielded + /// by the iterator. + /// + /// If the iterator is only partially consumed or not consumed at all, each of the remaining + /// values will still be subjected to the closure and removed and dropped if it returns true. + /// + /// It is unspecified how many more values will be subjected to the closure + /// if a panic occurs in the closure, or if a panic occurs while dropping a value, or if the + /// `DrainFilter` itself is leaked. + /// + /// # Examples + /// + /// Splitting a set into even and odd values, reusing the original set: + /// + /// ``` + /// #![feature(hash_drain_filter)] + /// use std::collections::HashSet; + /// + /// let mut set: HashSet = (0..8).collect(); + /// let drained: HashSet = set.drain_filter(|v| v % 2 == 0).collect(); + /// + /// let mut evens = drained.into_iter().collect::>(); + /// let mut odds = set.into_iter().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// ``` + #[inline] + #[unstable(feature = "hash_drain_filter", issue = "59618")] + pub fn drain_filter(&mut self, pred: F) -> DrainFilter<'_, T, F> + where + F: FnMut(&T) -> bool, + { + DrainFilter { base: self.base.drain_filter(pred) } + } + /// Clears the set, removing all values. /// /// # Examples @@ -1159,6 +1200,19 @@ pub struct Drain<'a, K: 'a> { base: base::Drain<'a, K>, } +/// A draining, filtering iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`drain_filter`] method on [`HashSet`]. +/// +/// [`drain_filter`]: HashSet::drain_filter +#[unstable(feature = "hash_drain_filter", issue = "59618")] +pub struct DrainFilter<'a, K, F> +where + F: FnMut(&K) -> bool, +{ + base: base::DrainFilter<'a, K, F>, +} + /// A lazy iterator producing elements in the intersection of `HashSet`s. /// /// This `struct` is created by the [`intersection`] method on [`HashSet`]. @@ -1348,6 +1402,36 @@ impl fmt::Debug for Drain<'_, K> { } } +#[unstable(feature = "hash_drain_filter", issue = "59618")] +impl Iterator for DrainFilter<'_, K, F> +where + F: FnMut(&K) -> bool, +{ + type Item = K; + + #[inline] + fn next(&mut self) -> Option { + self.base.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.base.size_hint() + } +} + +#[unstable(feature = "hash_drain_filter", issue = "59618")] +impl FusedIterator for DrainFilter<'_, K, F> where F: FnMut(&K) -> bool {} + +#[unstable(feature = "hash_drain_filter", issue = "59618")] +impl<'a, K, F> fmt::Debug for DrainFilter<'a, K, F> +where + F: FnMut(&K) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("DrainFilter { .. }") + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Intersection<'_, T, S> { #[inline] From fb1fab5a67955240330038414c23d912766ddeaf Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Mon, 7 Sep 2020 10:07:15 -0700 Subject: [PATCH 0197/1052] Tests for HashMap/HashSet::drain_filter --- library/std/src/collections/hash/map/tests.rs | 161 ++++++++++++++++++ library/std/src/collections/hash/set/tests.rs | 71 ++++++++ 2 files changed, 232 insertions(+) diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs index 4283d80b78e64..467968354e25d 100644 --- a/library/std/src/collections/hash/map/tests.rs +++ b/library/std/src/collections/hash/map/tests.rs @@ -924,3 +924,164 @@ fn test_raw_entry() { } } } + +mod test_drain_filter { + use super::*; + + use crate::panic::{catch_unwind, AssertUnwindSafe}; + use crate::sync::atomic::{AtomicUsize, Ordering}; + + trait EqSorted: Iterator { + fn eq_sorted>(self, other: I) -> bool; + } + + impl EqSorted for T + where + T::Item: Eq + Ord, + { + fn eq_sorted>(self, other: I) -> bool { + let mut v: Vec<_> = self.collect(); + v.sort_unstable(); + v.into_iter().eq(other) + } + } + + #[test] + fn empty() { + let mut map: HashMap = HashMap::new(); + map.drain_filter(|_, _| unreachable!("there's nothing to decide on")); + assert!(map.is_empty()); + } + + #[test] + fn consuming_nothing() { + let pairs = (0..3).map(|i| (i, i)); + let mut map: HashMap<_, _> = pairs.collect(); + assert!(map.drain_filter(|_, _| false).eq_sorted(crate::iter::empty())); + assert_eq!(map.len(), 3); + } + + #[test] + fn consuming_all() { + let pairs = (0..3).map(|i| (i, i)); + let mut map: HashMap<_, _> = pairs.clone().collect(); + assert!(map.drain_filter(|_, _| true).eq_sorted(pairs)); + assert!(map.is_empty()); + } + + #[test] + fn mutating_and_keeping() { + let pairs = (0..3).map(|i| (i, i)); + let mut map: HashMap<_, _> = pairs.collect(); + assert!( + map.drain_filter(|_, v| { + *v += 6; + false + }) + .eq_sorted(crate::iter::empty()) + ); + assert!(map.keys().copied().eq_sorted(0..3)); + assert!(map.values().copied().eq_sorted(6..9)); + } + + #[test] + fn mutating_and_removing() { + let pairs = (0..3).map(|i| (i, i)); + let mut map: HashMap<_, _> = pairs.collect(); + assert!( + map.drain_filter(|_, v| { + *v += 6; + true + }) + .eq_sorted((0..3).map(|i| (i, i + 6))) + ); + assert!(map.is_empty()); + } + + #[test] + fn drop_panic_leak() { + static PREDS: AtomicUsize = AtomicUsize::new(0); + static DROPS: AtomicUsize = AtomicUsize::new(0); + + struct D; + impl Drop for D { + fn drop(&mut self) { + if DROPS.fetch_add(1, Ordering::SeqCst) == 1 { + panic!("panic in `drop`"); + } + } + } + + let mut map = (0..3).map(|i| (i, D)).collect::>(); + + catch_unwind(move || { + drop(map.drain_filter(|_, _| { + PREDS.fetch_add(1, Ordering::SeqCst); + true + })) + }) + .unwrap_err(); + + assert_eq!(PREDS.load(Ordering::SeqCst), 3); + assert_eq!(DROPS.load(Ordering::SeqCst), 3); + } + + #[test] + fn pred_panic_leak() { + static PREDS: AtomicUsize = AtomicUsize::new(0); + static DROPS: AtomicUsize = AtomicUsize::new(0); + + struct D; + impl Drop for D { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::SeqCst); + } + } + + let mut map = (0..3).map(|i| (i, D)).collect::>(); + + catch_unwind(AssertUnwindSafe(|| { + drop(map.drain_filter(|_, _| match PREDS.fetch_add(1, Ordering::SeqCst) { + 0 => true, + _ => panic!(), + })) + })) + .unwrap_err(); + + assert_eq!(PREDS.load(Ordering::SeqCst), 2); + assert_eq!(DROPS.load(Ordering::SeqCst), 1); + assert_eq!(map.len(), 2); + } + + // Same as above, but attempt to use the iterator again after the panic in the predicate + #[test] + fn pred_panic_reuse() { + static PREDS: AtomicUsize = AtomicUsize::new(0); + static DROPS: AtomicUsize = AtomicUsize::new(0); + + struct D; + impl Drop for D { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::SeqCst); + } + } + + let mut map = (0..3).map(|i| (i, D)).collect::>(); + + { + let mut it = map.drain_filter(|_, _| match PREDS.fetch_add(1, Ordering::SeqCst) { + 0 => true, + _ => panic!(), + }); + catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err(); + // Iterator behaviour after a panic is explicitly unspecified, + // so this is just the current implementation: + let result = catch_unwind(AssertUnwindSafe(|| it.next())); + assert!(result.is_err()); + } + + assert_eq!(PREDS.load(Ordering::SeqCst), 3); + assert_eq!(DROPS.load(Ordering::SeqCst), 1); + assert_eq!(map.len(), 2); + } +} diff --git a/library/std/src/collections/hash/set/tests.rs b/library/std/src/collections/hash/set/tests.rs index 3582390cee4bc..40f8467fd93fd 100644 --- a/library/std/src/collections/hash/set/tests.rs +++ b/library/std/src/collections/hash/set/tests.rs @@ -1,6 +1,9 @@ use super::super::map::RandomState; use super::HashSet; +use crate::panic::{catch_unwind, AssertUnwindSafe}; +use crate::sync::atomic::{AtomicU32, Ordering}; + #[test] fn test_zero_capacities() { type HS = HashSet; @@ -413,3 +416,71 @@ fn test_retain() { assert!(set.contains(&4)); assert!(set.contains(&6)); } + +#[test] +fn test_drain_filter() { + let mut x: HashSet<_> = [1].iter().copied().collect(); + let mut y: HashSet<_> = [1].iter().copied().collect(); + + x.drain_filter(|_| true); + y.drain_filter(|_| false); + assert_eq!(x.len(), 0); + assert_eq!(y.len(), 1); +} + +#[test] +fn test_drain_filter_drop_panic_leak() { + static PREDS: AtomicU32 = AtomicU32::new(0); + static DROPS: AtomicU32 = AtomicU32::new(0); + + #[derive(PartialEq, Eq, PartialOrd, Hash)] + struct D(i32); + impl Drop for D { + fn drop(&mut self) { + if DROPS.fetch_add(1, Ordering::SeqCst) == 1 { + panic!("panic in `drop`"); + } + } + } + + let mut set = (0..3).map(|i| D(i)).collect::>(); + + catch_unwind(move || { + drop(set.drain_filter(|_| { + PREDS.fetch_add(1, Ordering::SeqCst); + true + })) + }) + .ok(); + + assert_eq!(PREDS.load(Ordering::SeqCst), 3); + assert_eq!(DROPS.load(Ordering::SeqCst), 3); +} + +#[test] +fn test_drain_filter_pred_panic_leak() { + static PREDS: AtomicU32 = AtomicU32::new(0); + static DROPS: AtomicU32 = AtomicU32::new(0); + + #[derive(PartialEq, Eq, PartialOrd, Hash)] + struct D; + impl Drop for D { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::SeqCst); + } + } + + let mut set: HashSet<_> = (0..3).map(|_| D).collect(); + + catch_unwind(AssertUnwindSafe(|| { + drop(set.drain_filter(|_| match PREDS.fetch_add(1, Ordering::SeqCst) { + 0 => true, + _ => panic!(), + })) + })) + .ok(); + + assert_eq!(PREDS.load(Ordering::SeqCst), 1); + assert_eq!(DROPS.load(Ordering::SeqCst), 3); + assert_eq!(set.len(), 0); +} From d712d7f700977240ad9bd731fc3f76e05cc1c900 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Wed, 9 Sep 2020 14:18:19 +1200 Subject: [PATCH 0198/1052] Improve "known problems" of `interior_mutable_key` * Remove the mention to `Rc` and `Arc` as these are `Freeze` so the lint correctly handles already. * Instead, explain what could cause a false positive, and mention `bytes` as an example. --- clippy_lints/src/mut_key.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 7423107e8f945..fa3a99dad9d23 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -12,8 +12,10 @@ declare_clippy_lint! { /// `BtreeSet` rely on either the hash or the order of keys be unchanging, /// so having types with interior mutability is a bad idea. /// - /// **Known problems:** We don't currently account for `Rc` or `Arc`, so - /// this may yield false positives. + /// **Known problems:** It's correct to use a struct, that contains interior mutability, + /// as a key; when its `Hash` implementation doesn't access any these interior mutable types. + /// However, this lint is unable to recognise it so cause a false positive. + /// `bytes` ctate is a great example of this. /// /// **Example:** /// ```rust From d24026bb6dbf33f022b9dd1daffeeab2c9f7d117 Mon Sep 17 00:00:00 2001 From: Camelid Date: Tue, 8 Sep 2020 19:24:57 -0700 Subject: [PATCH 0199/1052] Fix broken link `write` is ambiguous because there's also a macro called `write`. Also removed unnecessary and potentially confusing link to a function in its own docs. --- library/core/src/ptr/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 219835bfae0f9..eb31c739e834e 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -129,7 +129,7 @@ mod mut_ptr; /// Additionally, if `T` is not [`Copy`], using the pointed-to value after /// calling `drop_in_place` can cause undefined behavior. Note that `*to_drop = /// foo` counts as a use because it will cause the value to be dropped -/// again. [`write`] can be used to overwrite data without causing it to be +/// again. [`write()`] can be used to overwrite data without causing it to be /// dropped. /// /// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. @@ -639,7 +639,7 @@ pub unsafe fn replace(dst: *mut T, mut src: T) -> T { /// `*src` can violate memory safety. Note that assigning to `*src` counts as a /// use because it will attempt to drop the value at `*src`. /// -/// [`write`] can be used to overwrite data without causing it to be dropped. +/// [`write()`] can be used to overwrite data without causing it to be dropped. /// /// ``` /// use std::ptr; @@ -878,7 +878,7 @@ pub unsafe fn write(dst: *mut T, src: T) { /// Overwrites a memory location with the given value without reading or /// dropping the old value. /// -/// Unlike [`write`], the pointer may be unaligned. +/// Unlike [`write()`], the pointer may be unaligned. /// /// `write_unaligned` does not drop the contents of `dst`. This is safe, but it /// could leak allocations or resources, so care should be taken not to overwrite @@ -1085,7 +1085,7 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// Just like in C, whether an operation is volatile has no bearing whatsoever /// on questions involving concurrent access from multiple threads. Volatile /// accesses behave exactly like non-atomic accesses in that regard. In particular, -/// a race between a [`write_volatile`] and any other operation (reading or writing) +/// a race between a `write_volatile` and any other operation (reading or writing) /// on the same location is undefined behavior. /// /// # Examples From c66789d572ab3d950bc187d3bca3bc0042023358 Mon Sep 17 00:00:00 2001 From: Flying-Toast <38232168+Flying-Toast@users.noreply.github.com> Date: Tue, 8 Sep 2020 22:26:44 -0400 Subject: [PATCH 0200/1052] Capitalize safety comments --- library/core/src/future/mod.rs | 2 +- library/core/src/iter/adapters/fuse.rs | 2 +- library/core/src/iter/adapters/mod.rs | 24 +++++++++++----------- library/core/src/iter/adapters/zip.rs | 2 +- library/core/src/lazy.rs | 8 ++++---- library/core/src/mem/maybe_uninit.rs | 4 ++-- library/core/src/num/mod.rs | 6 +++--- library/core/src/pin.rs | 2 +- library/core/src/slice/mod.rs | 2 +- library/std/src/alloc.rs | 2 +- library/std/src/ffi/c_str.rs | 4 ++-- library/std/src/ffi/os_str.rs | 4 ++-- library/std/src/lazy.rs | 6 +++--- library/std/src/sys/windows/os_str.rs | 4 ++-- library/std/src/sys_common/os_str_bytes.rs | 4 ++-- 15 files changed, 38 insertions(+), 38 deletions(-) diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs index 8b3df76f71fdd..ddce0fe4b7dc5 100644 --- a/library/core/src/future/mod.rs +++ b/library/core/src/future/mod.rs @@ -71,7 +71,7 @@ where impl> Future for GenFuture { type Output = T::Return; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - // Safety: Safe because we're !Unpin + !Drop, and this is just a field projection. + // SAFETY: Safe because we're !Unpin + !Drop, and this is just a field projection. let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) }; // Resume the generator, turning the `&mut Context` into a `NonNull` raw pointer. The diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index 4185453ac5ae3..409f202780ba6 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -530,7 +530,7 @@ where #[inline] unsafe fn as_inner(&mut self) -> &mut S { match self.iter { - // Safety: unsafe function forwarding to unsafe function with the same requirements + // SAFETY: unsafe function forwarding to unsafe function with the same requirements Some(ref mut iter) => unsafe { SourceIter::as_inner(iter) }, // SAFETY: the specialized iterator never sets `None` None => unsafe { intrinsics::unreachable() }, diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index b411222856edb..ab27fe15a8e2c 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -1019,7 +1019,7 @@ where #[inline] unsafe fn as_inner(&mut self) -> &mut S { - // Safety: unsafe function forwarding to unsafe function with the same requirements + // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } } @@ -1168,7 +1168,7 @@ where #[inline] unsafe fn as_inner(&mut self) -> &mut S { - // Safety: unsafe function forwarding to unsafe function with the same requirements + // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } } @@ -1312,7 +1312,7 @@ where #[inline] unsafe fn as_inner(&mut self) -> &mut S { - // Safety: unsafe function forwarding to unsafe function with the same requirements + // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } } @@ -1550,7 +1550,7 @@ where #[inline] unsafe fn as_inner(&mut self) -> &mut S { - // Safety: unsafe function forwarding to unsafe function with the same requirements + // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } } @@ -1848,7 +1848,7 @@ where #[inline] unsafe fn as_inner(&mut self) -> &mut S { - // Safety: unsafe function forwarding to unsafe function with the same requirements + // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } } @@ -1967,7 +1967,7 @@ where #[inline] unsafe fn as_inner(&mut self) -> &mut S { - // Safety: unsafe function forwarding to unsafe function with the same requirements + // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } } @@ -2102,7 +2102,7 @@ where #[inline] unsafe fn as_inner(&mut self) -> &mut S { - // Safety: unsafe function forwarding to unsafe function with the same requirements + // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } } @@ -2200,7 +2200,7 @@ where #[inline] unsafe fn as_inner(&mut self) -> &mut S { - // Safety: unsafe function forwarding to unsafe function with the same requirements + // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } } @@ -2403,7 +2403,7 @@ where #[inline] unsafe fn as_inner(&mut self) -> &mut S { - // Safety: unsafe function forwarding to unsafe function with the same requirements + // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } } @@ -2530,7 +2530,7 @@ where #[inline] unsafe fn as_inner(&mut self) -> &mut S { - // Safety: unsafe function forwarding to unsafe function with the same requirements + // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } } @@ -2712,7 +2712,7 @@ where #[inline] unsafe fn as_inner(&mut self) -> &mut S { - // Safety: unsafe function forwarding to unsafe function with the same requirements + // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } } @@ -2879,7 +2879,7 @@ where #[inline] unsafe fn as_inner(&mut self) -> &mut S { - // Safety: unsafe function forwarding to unsafe function with the same requirements + // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } } diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index c1c90ec9a836a..e02de0ce45dff 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -343,7 +343,7 @@ where #[inline] unsafe fn as_inner(&mut self) -> &mut S { - // Safety: unsafe function forwarding to unsafe function with the same requirements + // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.a) } } } diff --git a/library/core/src/lazy.rs b/library/core/src/lazy.rs index 5cf7217ef11e8..2c517371c2c9b 100644 --- a/library/core/src/lazy.rs +++ b/library/core/src/lazy.rs @@ -92,7 +92,7 @@ impl OnceCell { /// Returns `None` if the cell is empty. #[unstable(feature = "once_cell", issue = "74465")] pub fn get(&self) -> Option<&T> { - // Safety: Safe due to `inner`'s invariant + // SAFETY: Safe due to `inner`'s invariant unsafe { &*self.inner.get() }.as_ref() } @@ -101,7 +101,7 @@ impl OnceCell { /// Returns `None` if the cell is empty. #[unstable(feature = "once_cell", issue = "74465")] pub fn get_mut(&mut self) -> Option<&mut T> { - // Safety: Safe because we have unique access + // SAFETY: Safe because we have unique access unsafe { &mut *self.inner.get() }.as_mut() } @@ -129,13 +129,13 @@ impl OnceCell { /// ``` #[unstable(feature = "once_cell", issue = "74465")] pub fn set(&self, value: T) -> Result<(), T> { - // Safety: Safe because we cannot have overlapping mutable borrows + // SAFETY: Safe because we cannot have overlapping mutable borrows let slot = unsafe { &*self.inner.get() }; if slot.is_some() { return Err(value); } - // Safety: This is the only place where we set the slot, no races + // SAFETY: This is the only place where we set the slot, no races // due to reentrancy/concurrency are possible, and we've // checked that slot is currently `None`, so this write // maintains the `inner`'s invariant. diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index b64abf68c5e4a..3a7489aa27955 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -599,7 +599,7 @@ impl MaybeUninit { /// // Now that our `MaybeUninit<_>` is known to be initialized, it is okay to /// // create a shared reference to it: /// let x: &Vec = unsafe { - /// // Safety: `x` has been initialized. + /// // SAFETY: `x` has been initialized. /// x.assume_init_ref() /// }; /// assert_eq!(x, &vec![1, 2, 3]); @@ -676,7 +676,7 @@ impl MaybeUninit { /// // To assert our buffer has been initialized without copying it, we upgrade /// // the `&mut MaybeUninit<[u8; 2048]>` to a `&mut [u8; 2048]`: /// let buf: &mut [u8; 2048] = unsafe { - /// // Safety: `buf` has been initialized. + /// // SAFETY: `buf` has been initialized. /// buf.assume_init_mut() /// }; /// diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 757ad5252bab3..2a936c1867da0 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -124,7 +124,7 @@ assert_eq!(size_of::>(), size_of::<", s type Output = Self; #[inline] fn bitor(self, rhs: Self) -> Self::Output { - // Safety: since `self` and `rhs` are both nonzero, the + // SAFETY: since `self` and `rhs` are both nonzero, the // result of the bitwise-or will be nonzero. unsafe { $Ty::new_unchecked(self.get() | rhs.get()) } } @@ -135,7 +135,7 @@ assert_eq!(size_of::>(), size_of::<", s type Output = Self; #[inline] fn bitor(self, rhs: $Int) -> Self::Output { - // Safety: since `self` is nonzero, the result of the + // SAFETY: since `self` is nonzero, the result of the // bitwise-or will be nonzero regardless of the value of // `rhs`. unsafe { $Ty::new_unchecked(self.get() | rhs) } @@ -147,7 +147,7 @@ assert_eq!(size_of::>(), size_of::<", s type Output = $Ty; #[inline] fn bitor(self, rhs: $Ty) -> Self::Output { - // Safety: since `rhs` is nonzero, the result of the + // SAFETY: since `rhs` is nonzero, the result of the // bitwise-or will be nonzero regardless of the value of // `self`. unsafe { $Ty::new_unchecked(self | rhs.get()) } diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 3c3bb68c67144..1cc1dfb014335 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -474,7 +474,7 @@ impl> Pin

{ #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub fn new(pointer: P) -> Pin

{ - // Safety: the value pointed to is `Unpin`, and so has no requirements + // SAFETY: the value pointed to is `Unpin`, and so has no requirements // around pinning. unsafe { Pin::new_unchecked(pointer) } } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index c274ddf81bb8a..ce3a17a0d28e4 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3245,7 +3245,7 @@ fn is_ascii(s: &[u8]) -> bool { (word_ptr as usize) - (start as usize) == byte_pos ); - // Safety: We know `word_ptr` is properly aligned (because of + // SAFETY: We know `word_ptr` is properly aligned (because of // `align_offset`), and we know that we have enough bytes between `word_ptr` and the end let word = unsafe { word_ptr.read() }; if contains_nonascii(word) { diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index 64d8edf33bd3b..770c97899f002 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -149,7 +149,7 @@ impl System { } } - // Safety: Same as `AllocRef::grow` + // SAFETY: Same as `AllocRef::grow` #[inline] unsafe fn grow_impl( &mut self, diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs index 51deb217c7c29..13021738af139 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -881,13 +881,13 @@ impl From> for CString { unsafe { // Transmute `Vec` to `Vec`. let v: Vec = { - // Safety: + // SAFETY: // - transmuting between `NonZeroU8` and `u8` is sound; // - `alloc::Layout == alloc::Layout`. let (ptr, len, cap): (*mut NonZeroU8, _, _) = Vec::into_raw_parts(v); Vec::from_raw_parts(ptr.cast::(), len, cap) }; - // Safety: `v` cannot contain null bytes, given the type-level + // SAFETY: `v` cannot contain null bytes, given the type-level // invariant of `NonZeroU8`. CString::from_vec_unchecked(v) } diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index e0be6d1c836ae..c83e996634c8a 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -510,14 +510,14 @@ impl OsStr { #[inline] fn from_inner(inner: &Slice) -> &OsStr { - // Safety: OsStr is just a wrapper of Slice, + // SAFETY: OsStr is just a wrapper of Slice, // therefore converting &Slice to &OsStr is safe. unsafe { &*(inner as *const Slice as *const OsStr) } } #[inline] fn from_inner_mut(inner: &mut Slice) -> &mut OsStr { - // Safety: OsStr is just a wrapper of Slice, + // SAFETY: OsStr is just a wrapper of Slice, // therefore converting &mut Slice to &mut OsStr is safe. // Any method that mutates OsStr must be careful not to // break platform-specific encoding, in particular Wtf8 on Windows. diff --git a/library/std/src/lazy.rs b/library/std/src/lazy.rs index d171231b0f1e6..091e2091fb095 100644 --- a/library/std/src/lazy.rs +++ b/library/std/src/lazy.rs @@ -293,7 +293,7 @@ impl SyncOnceCell { debug_assert!(self.is_initialized()); - // Safety: The inner value has been initialized + // SAFETY: The inner value has been initialized Ok(unsafe { self.get_unchecked() }) } @@ -316,7 +316,7 @@ impl SyncOnceCell { /// ``` #[unstable(feature = "once_cell", issue = "74465")] pub fn into_inner(mut self) -> Option { - // Safety: Safe because we immediately free `self` without dropping + // SAFETY: Safe because we immediately free `self` without dropping let inner = unsafe { self.take_inner() }; // Don't drop this `SyncOnceCell`. We just moved out one of the fields, but didn't set @@ -416,7 +416,7 @@ impl SyncOnceCell { unsafe impl<#[may_dangle] T> Drop for SyncOnceCell { fn drop(&mut self) { - // Safety: The cell is being dropped, so it can't be accessed again. + // SAFETY: The cell is being dropped, so it can't be accessed again. // We also don't touch the `T`, which validates our usage of #[may_dangle]. unsafe { self.take_inner() }; } diff --git a/library/std/src/sys/windows/os_str.rs b/library/std/src/sys/windows/os_str.rs index 2f5fc72ab44c2..7e09a4fd56130 100644 --- a/library/std/src/sys/windows/os_str.rs +++ b/library/std/src/sys/windows/os_str.rs @@ -77,14 +77,14 @@ impl Buf { } pub fn as_slice(&self) -> &Slice { - // Safety: Slice is just a wrapper for Wtf8, + // SAFETY: Slice is just a wrapper for Wtf8, // and self.inner.as_slice() returns &Wtf8. // Therefore, transmuting &Wtf8 to &Slice is safe. unsafe { mem::transmute(self.inner.as_slice()) } } pub fn as_mut_slice(&mut self) -> &mut Slice { - // Safety: Slice is just a wrapper for Wtf8, + // SAFETY: Slice is just a wrapper for Wtf8, // and self.inner.as_mut_slice() returns &mut Wtf8. // Therefore, transmuting &mut Wtf8 to &mut Slice is safe. // Additionally, care should be taken to ensure the slice diff --git a/library/std/src/sys_common/os_str_bytes.rs b/library/std/src/sys_common/os_str_bytes.rs index 323165cda6bd5..497e5fc7bdd16 100644 --- a/library/std/src/sys_common/os_str_bytes.rs +++ b/library/std/src/sys_common/os_str_bytes.rs @@ -106,7 +106,7 @@ impl Buf { #[inline] pub fn as_slice(&self) -> &Slice { - // Safety: Slice just wraps [u8], + // SAFETY: Slice just wraps [u8], // and &*self.inner is &[u8], therefore // transmuting &[u8] to &Slice is safe. unsafe { mem::transmute(&*self.inner) } @@ -114,7 +114,7 @@ impl Buf { #[inline] pub fn as_mut_slice(&mut self) -> &mut Slice { - // Safety: Slice just wraps [u8], + // SAFETY: Slice just wraps [u8], // and &mut *self.inner is &mut [u8], therefore // transmuting &mut [u8] to &mut Slice is safe. unsafe { mem::transmute(&mut *self.inner) } From 2799aec6ab4ae35f1a2064f941a9f2a270953b63 Mon Sep 17 00:00:00 2001 From: Flying-Toast <38232168+Flying-Toast@users.noreply.github.com> Date: Tue, 8 Sep 2020 22:37:18 -0400 Subject: [PATCH 0201/1052] Capitalize safety comments --- compiler/rustc_data_structures/src/temp_dir.rs | 2 +- library/alloc/src/alloc.rs | 2 +- library/alloc/src/collections/vec_deque.rs | 2 +- src/test/ui/generator/static-generators.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_data_structures/src/temp_dir.rs b/compiler/rustc_data_structures/src/temp_dir.rs index 0d9b3e3ca25c0..a780d2386a63c 100644 --- a/compiler/rustc_data_structures/src/temp_dir.rs +++ b/compiler/rustc_data_structures/src/temp_dir.rs @@ -12,7 +12,7 @@ pub struct MaybeTempDir { impl Drop for MaybeTempDir { fn drop(&mut self) { - // Safety: We are in the destructor, and no further access will + // SAFETY: We are in the destructor, and no further access will // occur. let dir = unsafe { ManuallyDrop::take(&mut self.dir) }; if self.keep { diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 5f09f8def4d0a..341c6816197c7 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -157,7 +157,7 @@ impl Global { } } - // Safety: Same as `AllocRef::grow` + // SAFETY: Same as `AllocRef::grow` #[inline] unsafe fn grow_impl( &mut self, diff --git a/library/alloc/src/collections/vec_deque.rs b/library/alloc/src/collections/vec_deque.rs index cc2ef25a5a7d1..172b25b9d17f8 100644 --- a/library/alloc/src/collections/vec_deque.rs +++ b/library/alloc/src/collections/vec_deque.rs @@ -2392,7 +2392,7 @@ impl VecDeque { } } - // Safety: the following two methods require that the rotation amount + // SAFETY: the following two methods require that the rotation amount // be less than half the length of the deque. // // `wrap_copy` requires that `min(x, cap() - x) + copy_len <= cap()`, diff --git a/src/test/ui/generator/static-generators.rs b/src/test/ui/generator/static-generators.rs index 3980766c4287e..d098bf1e68812 100644 --- a/src/test/ui/generator/static-generators.rs +++ b/src/test/ui/generator/static-generators.rs @@ -12,7 +12,7 @@ fn main() { yield; assert_eq!(b as *const _, &a as *const _); }; - // Safety: We shadow the original generator variable so have no safe API to + // SAFETY: We shadow the original generator variable so have no safe API to // move it after this point. let mut generator = unsafe { Pin::new_unchecked(&mut generator) }; assert_eq!(generator.as_mut().resume(()), GeneratorState::Yielded(())); From c81b43d8ac0dd68a49c4c65771c3c65a4ca61f93 Mon Sep 17 00:00:00 2001 From: Victor Ding Date: Wed, 9 Sep 2020 14:51:16 +1000 Subject: [PATCH 0202/1052] Add `-Z combine_cgu` flag Introduce a compiler option to let rustc combines all regular CGUs into a single one at the end of compilation. Part of Issue #64191 --- compiler/rustc_codegen_llvm/src/back/lto.rs | 6 +- compiler/rustc_codegen_llvm/src/back/write.rs | 25 ++++++++ compiler/rustc_codegen_llvm/src/lib.rs | 7 +++ compiler/rustc_codegen_ssa/src/back/write.rs | 59 +++++++++++++++---- .../rustc_codegen_ssa/src/traits/write.rs | 6 ++ compiler/rustc_session/src/options.rs | 2 + 6 files changed, 90 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 7c710a1cb3d15..4b2d5907a02f4 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -346,14 +346,14 @@ fn fat_lto( Ok(LtoModuleCodegen::Fat { module: Some(module), _serialized_bitcode: serialized_bitcode }) } -struct Linker<'a>(&'a mut llvm::Linker<'a>); +crate struct Linker<'a>(&'a mut llvm::Linker<'a>); impl Linker<'a> { - fn new(llmod: &'a llvm::Module) -> Self { + crate fn new(llmod: &'a llvm::Module) -> Self { unsafe { Linker(llvm::LLVMRustLinkerNew(llmod)) } } - fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> { + crate fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> { unsafe { if llvm::LLVMRustLinkerAdd( self.0, diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 6f386c1287ca0..937821e9d4fb2 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -617,6 +617,31 @@ unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static } } +pub(crate) fn link( + cgcx: &CodegenContext, + diag_handler: &Handler, + mut modules: Vec>, +) -> Result, FatalError> { + use super::lto::{Linker, ModuleBuffer}; + // Sort the modules by name to ensure to ensure deterministic behavior. + modules.sort_by(|a, b| a.name.cmp(&b.name)); + let (first, elements) = + modules.split_first().expect("Bug! modules must contain at least one module."); + + let mut linker = Linker::new(first.module_llvm.llmod()); + for module in elements { + let _timer = + cgcx.prof.generic_activity_with_arg("LLVM_link_module", format!("{:?}", module.name)); + let buffer = ModuleBuffer::new(module.module_llvm.llmod()); + linker.add(&buffer.data()).map_err(|()| { + let msg = format!("failed to serialize module {:?}", module.name); + llvm_err(&diag_handler, &msg) + })?; + } + drop(linker); + Ok(modules.remove(0)) +} + pub(crate) unsafe fn codegen( cgcx: &CodegenContext, diag_handler: &Handler, diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 67d4b2642c058..2e2abe9fb30f8 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -130,6 +130,13 @@ impl WriteBackendMethods for LlvmCodegenBackend { llvm::LLVMRustPrintPassTimings(); } } + fn run_link( + cgcx: &CodegenContext, + diag_handler: &Handler, + modules: Vec>, + ) -> Result, FatalError> { + back::write::link(cgcx, diag_handler, modules) + } fn run_fat_lto( cgcx: &CodegenContext, modules: Vec>, diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 7d69bb983dd74..0edf0fcd1a264 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -702,6 +702,7 @@ impl WorkItem { enum WorkItemResult { Compiled(CompiledModule), + NeedsLink(ModuleCodegen), NeedsFatLTO(FatLTOInput), NeedsThinLTO(String, B::ThinBuffer), } @@ -801,11 +802,8 @@ fn execute_optimize_work_item( None }; - Ok(match lto_type { - ComputedLtoType::No => { - let module = unsafe { B::codegen(cgcx, &diag_handler, module, module_config)? }; - WorkItemResult::Compiled(module) - } + match lto_type { + ComputedLtoType::No => finish_intra_module_work(cgcx, module, module_config), ComputedLtoType::Thin => { let (name, thin_buffer) = B::prepare_thin(module); if let Some(path) = bitcode { @@ -813,7 +811,7 @@ fn execute_optimize_work_item( panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e); }); } - WorkItemResult::NeedsThinLTO(name, thin_buffer) + Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer)) } ComputedLtoType::Fat => match bitcode { Some(path) => { @@ -821,11 +819,11 @@ fn execute_optimize_work_item( fs::write(&path, buffer.data()).unwrap_or_else(|e| { panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e); }); - WorkItemResult::NeedsFatLTO(FatLTOInput::Serialized { name, buffer }) + Ok(WorkItemResult::NeedsFatLTO(FatLTOInput::Serialized { name, buffer })) } - None => WorkItemResult::NeedsFatLTO(FatLTOInput::InMemory(module)), + None => Ok(WorkItemResult::NeedsFatLTO(FatLTOInput::InMemory(module))), }, - }) + } } fn execute_copy_from_cache_work_item( @@ -870,13 +868,26 @@ fn execute_lto_work_item( cgcx: &CodegenContext, mut module: lto::LtoModuleCodegen, module_config: &ModuleConfig, +) -> Result, FatalError> { + let module = unsafe { module.optimize(cgcx)? }; + finish_intra_module_work(cgcx, module, module_config) +} + +fn finish_intra_module_work( + cgcx: &CodegenContext, + module: ModuleCodegen, + module_config: &ModuleConfig, ) -> Result, FatalError> { let diag_handler = cgcx.create_diag_handler(); - unsafe { - let module = module.optimize(cgcx)?; - let module = B::codegen(cgcx, &diag_handler, module, module_config)?; + if !cgcx.opts.debugging_opts.combine_cgu + || module.kind == ModuleKind::Metadata + || module.kind == ModuleKind::Allocator + { + let module = unsafe { B::codegen(cgcx, &diag_handler, module, module_config)? }; Ok(WorkItemResult::Compiled(module)) + } else { + Ok(WorkItemResult::NeedsLink(module)) } } @@ -891,6 +902,10 @@ pub enum Message { thin_buffer: B::ThinBuffer, worker_id: usize, }, + NeedsLink { + module: ModuleCodegen, + worker_id: usize, + }, Done { result: Result>, worker_id: usize, @@ -1178,6 +1193,7 @@ fn start_executing_work( let mut compiled_modules = vec![]; let mut compiled_metadata_module = None; let mut compiled_allocator_module = None; + let mut needs_link = Vec::new(); let mut needs_fat_lto = Vec::new(); let mut needs_thin_lto = Vec::new(); let mut lto_import_only_modules = Vec::new(); @@ -1434,6 +1450,10 @@ fn start_executing_work( } } } + Message::NeedsLink { module, worker_id } => { + free_worker(worker_id); + needs_link.push(module); + } Message::NeedsFatLTO { result, worker_id } => { assert!(!started_lto); free_worker(worker_id); @@ -1462,6 +1482,18 @@ fn start_executing_work( } } + let needs_link = mem::take(&mut needs_link); + if !needs_link.is_empty() { + assert!(compiled_modules.is_empty()); + let diag_handler = cgcx.create_diag_handler(); + let module = B::run_link(&cgcx, &diag_handler, needs_link).map_err(|_| ())?; + let module = unsafe { + B::codegen(&cgcx, &diag_handler, module, cgcx.config(ModuleKind::Regular)) + .map_err(|_| ())? + }; + compiled_modules.push(module); + } + // Drop to print timings drop(llvm_start_time); @@ -1521,6 +1553,9 @@ fn spawn_work(cgcx: CodegenContext, work: WorkItem Some(Ok(WorkItemResult::Compiled(m))) => { Message::Done:: { result: Ok(m), worker_id } } + Some(Ok(WorkItemResult::NeedsLink(m))) => { + Message::NeedsLink:: { module: m, worker_id } + } Some(Ok(WorkItemResult::NeedsFatLTO(m))) => { Message::NeedsFatLTO:: { result: m, worker_id } } diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index 27d52e9b9c53e..264e7c2aa92c0 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -13,6 +13,12 @@ pub trait WriteBackendMethods: 'static + Sized + Clone { type ThinData: Send + Sync; type ThinBuffer: ThinBufferMethods; + /// Merge all modules into main_module and returning it + fn run_link( + cgcx: &CodegenContext, + diag_handler: &Handler, + modules: Vec>, + ) -> Result, FatalError>; /// Performs fat LTO by merging all modules into a single one and returning it /// for further optimization. fn run_fat_lto( diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index ad36fa7698621..848c7cb7d7552 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -850,6 +850,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "enable the experimental Chalk-based trait solving engine"), codegen_backend: Option = (None, parse_opt_string, [TRACKED], "the backend to use"), + combine_cgu: bool = (false, parse_bool, [TRACKED], + "combine CGUs into a single one"), crate_attr: Vec = (Vec::new(), parse_string_push, [TRACKED], "inject the given attribute in the crate"), debug_macros: bool = (false, parse_bool, [TRACKED], From 7dad29d6868914484be04cb054863261903bba58 Mon Sep 17 00:00:00 2001 From: Bram van den Heuvel Date: Tue, 1 Sep 2020 17:58:34 +0200 Subject: [PATCH 0203/1052] Remove def_id field from ParamEnv --- .../rustc_infer/src/infer/outlives/mod.rs | 3 +- compiler/rustc_infer/src/traits/mod.rs | 2 +- compiler/rustc_infer/src/traits/util.rs | 3 + compiler/rustc_lint/src/builtin.rs | 3 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/traits/chalk.rs | 30 +--- compiler/rustc_middle/src/traits/mod.rs | 6 +- compiler/rustc_middle/src/ty/context.rs | 26 +--- compiler/rustc_middle/src/ty/flags.rs | 3 + compiler/rustc_middle/src/ty/mod.rs | 44 +++--- compiler/rustc_middle/src/ty/print/pretty.rs | 5 + .../rustc_middle/src/ty/structural_impls.rs | 8 +- .../src/transform/qualify_min_const_fn.rs | 3 +- .../rustc_trait_selection/src/opaque_types.rs | 3 +- .../src/traits/auto_trait.rs | 4 +- .../src/traits/chalk_fulfill.rs | 142 ++---------------- .../src/traits/error_reporting/mod.rs | 5 + .../src/traits/fulfill.rs | 8 +- .../rustc_trait_selection/src/traits/mod.rs | 15 +- .../src/traits/object_safety.rs | 12 +- .../src/traits/select/mod.rs | 3 + .../rustc_trait_selection/src/traits/wf.rs | 3 + compiler/rustc_traits/src/chalk/lowering.rs | 107 ++++++------- compiler/rustc_traits/src/chalk/mod.rs | 9 +- .../src/implied_outlives_bounds.rs | 3 +- .../src/normalize_erasing_regions.rs | 3 +- compiler/rustc_ty/src/ty.rs | 135 ++++++++++++++++- .../rustc_typeck/src/check/compare_method.rs | 16 +- .../rustc_typeck/src/check/method/probe.rs | 3 +- compiler/rustc_typeck/src/check/mod.rs | 1 + .../src/impl_wf_check/min_specialization.rs | 3 +- .../rustc_typeck/src/outlives/explicit.rs | 3 +- src/librustdoc/clean/mod.rs | 3 +- src/test/ui/chalkify/type_inference.stderr | 4 +- .../infinite-tag-type-recursion.stderr | 2 +- 35 files changed, 288 insertions(+), 337 deletions(-) diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index a1e7f1fa3e5e7..de98cccf25689 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -26,7 +26,8 @@ pub fn explicit_outlives_bounds<'tcx>( | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::TypeOutlives(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => None, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => { Some(OutlivesBound::RegionSubRegion(r_b, r_a)) } diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 7e7c8588ffb40..a3c4920fa8af3 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -57,7 +57,7 @@ pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; // `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -static_assert_size!(PredicateObligation<'_>, 40); +static_assert_size!(PredicateObligation<'_>, 32); pub type Obligations<'tcx, O> = Vec>; pub type PredicateObligations<'tcx> = Vec>; diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 93fc7f1f3b8a7..9c0d934a03529 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -236,6 +236,9 @@ impl Elaborator<'tcx> { .map(|predicate| predicate_obligation(predicate, None)), ); } + ty::PredicateAtom::TypeWellFormedFromEnv(..) => { + // Nothing to elaborate + } } } } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index d18d89ed641b2..61ecd13c30768 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1228,7 +1228,8 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { ClosureKind(..) | Subtype(..) | ConstEvaluatable(..) | - ConstEquate(..) => continue, + ConstEquate(..) | + TypeWellFormedFromEnv(..) => continue, }; if predicate.is_global() { cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 719f0322fd72c..15e3110bc851e 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1399,7 +1399,7 @@ rustc_queries! { } query evaluate_goal( - goal: traits::ChalkCanonicalGoal<'tcx> + goal: traits::CanonicalChalkEnvironmentAndGoal<'tcx> ) -> Result< &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, NoSolution diff --git a/compiler/rustc_middle/src/traits/chalk.rs b/compiler/rustc_middle/src/traits/chalk.rs index 763b078e7703e..d8507d08c1bc5 100644 --- a/compiler/rustc_middle/src/traits/chalk.rs +++ b/compiler/rustc_middle/src/traits/chalk.rs @@ -6,14 +6,11 @@ //! interned Chalk types. use rustc_middle::mir::interpret::ConstValue; -use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; -use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; +use rustc_middle::ty::{self, AdtDef, TyCtxt}; use rustc_hir::def_id::DefId; use rustc_target::spec::abi::Abi; -use smallvec::SmallVec; - use std::cmp::Ordering; use std::fmt; use std::hash::{Hash, Hasher}; @@ -376,31 +373,10 @@ impl<'tcx> chalk_ir::interner::HasInterner for RustInterner<'tcx> { type Interner = Self; } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)] -pub enum ChalkEnvironmentClause<'tcx> { - /// A normal rust `ty::Predicate` in the environment. - Predicate(ty::Predicate<'tcx>), - /// A special clause in the environment that gets lowered to - /// `chalk_ir::FromEnv::Ty`. - TypeFromEnv(Ty<'tcx>), -} - -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - let v = self.iter().map(|t| t.fold_with(folder)).collect::>(); - folder.tcx().intern_chalk_environment_clause_list(&v) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) - } -} -/// We have to elaborate the environment of a chalk goal *before* -/// canonicalization. This type wraps the predicate and the elaborated -/// environment. +/// A chalk environment and goal. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)] pub struct ChalkEnvironmentAndGoal<'tcx> { - pub environment: &'tcx ty::List>, + pub environment: &'tcx ty::List>, pub goal: ty::Predicate<'tcx>, } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index f86403fa502bb..ae89b68942c96 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -26,14 +26,12 @@ use std::rc::Rc; pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache}; -pub type ChalkCanonicalGoal<'tcx> = Canonical<'tcx, ChalkEnvironmentAndGoal<'tcx>>; +pub type CanonicalChalkEnvironmentAndGoal<'tcx> = Canonical<'tcx, ChalkEnvironmentAndGoal<'tcx>>; pub use self::ImplSource::*; pub use self::ObligationCauseCode::*; -pub use self::chalk::{ - ChalkEnvironmentAndGoal, ChalkEnvironmentClause, RustInterner as ChalkRustInterner, -}; +pub use self::chalk::{ChalkEnvironmentAndGoal, RustInterner as ChalkRustInterner}; /// Depending on the stage of compilation, we want projection to be /// more or less conservative. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index aa34dedc4b286..aacf61e5b425a 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -91,8 +91,6 @@ pub struct CtxtInterners<'tcx> { projs: InternedSet<'tcx, List>, place_elems: InternedSet<'tcx, List>>, const_: InternedSet<'tcx, Const<'tcx>>, - - chalk_environment_clause_list: InternedSet<'tcx, List>>, } impl<'tcx> CtxtInterners<'tcx> { @@ -110,7 +108,6 @@ impl<'tcx> CtxtInterners<'tcx> { projs: Default::default(), place_elems: Default::default(), const_: Default::default(), - chalk_environment_clause_list: Default::default(), } } @@ -2041,7 +2038,7 @@ direct_interners! { } macro_rules! slice_interners { - ($($field:ident: $method:ident($ty:ty)),+) => ( + ($($field:ident: $method:ident($ty:ty)),+ $(,)?) => ( $(impl<'tcx> TyCtxt<'tcx> { pub fn $method(self, v: &[$ty]) -> &'tcx List<$ty> { self.interners.$field.intern_ref(v, || { @@ -2060,8 +2057,6 @@ slice_interners!( predicates: _intern_predicates(Predicate<'tcx>), projs: _intern_projs(ProjectionKind), place_elems: _intern_place_elems(PlaceElem<'tcx>), - chalk_environment_clause_list: - _intern_chalk_environment_clause_list(traits::ChalkEnvironmentClause<'tcx>) ); impl<'tcx> TyCtxt<'tcx> { @@ -2460,13 +2455,6 @@ impl<'tcx> TyCtxt<'tcx> { if ts.is_empty() { List::empty() } else { self._intern_canonical_var_infos(ts) } } - pub fn intern_chalk_environment_clause_list( - self, - ts: &[traits::ChalkEnvironmentClause<'tcx>], - ) -> &'tcx List> { - if ts.is_empty() { List::empty() } else { self._intern_chalk_environment_clause_list(ts) } - } - pub fn mk_fn_sig( self, inputs: I, @@ -2524,18 +2512,6 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_substs(iter::once(self_ty.into()).chain(rest.iter().cloned())) } - pub fn mk_chalk_environment_clause_list< - I: InternAs< - [traits::ChalkEnvironmentClause<'tcx>], - &'tcx List>, - >, - >( - self, - iter: I, - ) -> I::Output { - iter.intern_with(|xs| self.intern_chalk_environment_clause_list(xs)) - } - /// Walks upwards from `id` to find a node which might change lint levels with attributes. /// It stops at `bound` and just returns it if reached. pub fn maybe_lint_level_root_bounded(self, mut id: HirId, bound: HirId) -> HirId { diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index f7871c4fffddb..c9a4022330a7a 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -249,6 +249,9 @@ impl FlagComputation { self.add_const(expected); self.add_const(found); } + ty::PredicateAtom::TypeWellFormedFromEnv(ty) => { + self.add_ty(ty); + } } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 29fa3f9bb65e0..8283deb3ecc24 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1155,6 +1155,11 @@ pub enum PredicateAtom<'tcx> { /// Constants must be equal. The first component is the const that is expected. ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>), + + /// Represents a type found in the environment that we can use for implied bounds. + /// + /// Only used for Chalk. + TypeWellFormedFromEnv(Ty<'tcx>), } impl<'tcx> PredicateAtom<'tcx> { @@ -1450,7 +1455,8 @@ impl<'tcx> Predicate<'tcx> { | PredicateAtom::ClosureKind(..) | PredicateAtom::TypeOutlives(..) | PredicateAtom::ConstEvaluatable(..) - | PredicateAtom::ConstEquate(..) => None, + | PredicateAtom::ConstEquate(..) + | PredicateAtom::TypeWellFormedFromEnv(..) => None, } } @@ -1465,7 +1471,8 @@ impl<'tcx> Predicate<'tcx> { | PredicateAtom::ObjectSafe(..) | PredicateAtom::ClosureKind(..) | PredicateAtom::ConstEvaluatable(..) - | PredicateAtom::ConstEquate(..) => None, + | PredicateAtom::ConstEquate(..) + | PredicateAtom::TypeWellFormedFromEnv(..) => None, } } } @@ -1738,11 +1745,6 @@ pub struct ParamEnv<'tcx> { /// /// Note: This is packed, use the reveal() method to access it. packed: CopyTaggedPtr<&'tcx List>, traits::Reveal, true>, - - /// If this `ParamEnv` comes from a call to `tcx.param_env(def_id)`, - /// register that `def_id` (useful for transitioning to the chalk trait - /// solver). - pub def_id: Option, } unsafe impl rustc_data_structures::tagged_ptr::Tag for traits::Reveal { @@ -1767,7 +1769,6 @@ impl<'tcx> fmt::Debug for ParamEnv<'tcx> { f.debug_struct("ParamEnv") .field("caller_bounds", &self.caller_bounds()) .field("reveal", &self.reveal()) - .field("def_id", &self.def_id) .finish() } } @@ -1776,23 +1777,16 @@ impl<'a, 'tcx> HashStable> for ParamEnv<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.caller_bounds().hash_stable(hcx, hasher); self.reveal().hash_stable(hcx, hasher); - self.def_id.hash_stable(hcx, hasher); } } impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { - ParamEnv::new( - self.caller_bounds().fold_with(folder), - self.reveal().fold_with(folder), - self.def_id.fold_with(folder), - ) + ParamEnv::new(self.caller_bounds().fold_with(folder), self.reveal().fold_with(folder)) } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.caller_bounds().visit_with(visitor) - || self.reveal().visit_with(visitor) - || self.def_id.visit_with(visitor) + self.caller_bounds().visit_with(visitor) || self.reveal().visit_with(visitor) } } @@ -1803,7 +1797,7 @@ impl<'tcx> ParamEnv<'tcx> { /// type-checking. #[inline] pub fn empty() -> Self { - Self::new(List::empty(), Reveal::UserFacing, None) + Self::new(List::empty(), Reveal::UserFacing) } #[inline] @@ -1825,17 +1819,13 @@ impl<'tcx> ParamEnv<'tcx> { /// or invoke `param_env.with_reveal_all()`. #[inline] pub fn reveal_all() -> Self { - Self::new(List::empty(), Reveal::All, None) + Self::new(List::empty(), Reveal::All) } /// Construct a trait environment with the given set of predicates. #[inline] - pub fn new( - caller_bounds: &'tcx List>, - reveal: Reveal, - def_id: Option, - ) -> Self { - ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, reveal), def_id } + pub fn new(caller_bounds: &'tcx List>, reveal: Reveal) -> Self { + ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, reveal) } } pub fn with_user_facing(mut self) -> Self { @@ -1857,12 +1847,12 @@ impl<'tcx> ParamEnv<'tcx> { return self; } - ParamEnv::new(tcx.normalize_opaque_types(self.caller_bounds()), Reveal::All, self.def_id) + ParamEnv::new(tcx.normalize_opaque_types(self.caller_bounds()), Reveal::All) } /// Returns this same environment but with no caller bounds. pub fn without_caller_bounds(self) -> Self { - Self::new(List::empty(), self.reveal(), self.def_id) + Self::new(List::empty(), self.reveal()) } /// Creates a suitable environment in which to perform trait diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 538c07b9bde5f..9562d43791493 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2096,6 +2096,11 @@ define_print_and_forward_display! { print(c2), write("`")) } + ty::PredicateAtom::TypeWellFormedFromEnv(ty) => { + p!(write("the type `"), + print(ty), + write("` is found in the environment")) + } } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index f8627e2f1b646..afbf805975ce7 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -260,6 +260,9 @@ impl fmt::Debug for ty::PredicateAtom<'tcx> { write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs) } ty::PredicateAtom::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2), + ty::PredicateAtom::TypeWellFormedFromEnv(ty) => { + write!(f, "TypeWellFormedFromEnv({:?})", ty) + } } } } @@ -536,6 +539,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateAtom<'a> { ty::PredicateAtom::ConstEquate(c1, c2) => { tcx.lift(&(c1, c2)).map(|(c1, c2)| ty::PredicateAtom::ConstEquate(c1, c2)) } + ty::PredicateAtom::TypeWellFormedFromEnv(ty) => { + tcx.lift(&ty).map(ty::PredicateAtom::TypeWellFormedFromEnv) + } } } } @@ -551,7 +557,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> { type Lifted = ty::ParamEnv<'tcx>; fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { tcx.lift(&self.caller_bounds()) - .map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal(), self.def_id)) + .map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal())) } } diff --git a/compiler/rustc_mir/src/transform/qualify_min_const_fn.rs b/compiler/rustc_mir/src/transform/qualify_min_const_fn.rs index 7d9611e07311d..5e102f5151d0c 100644 --- a/compiler/rustc_mir/src/transform/qualify_min_const_fn.rs +++ b/compiler/rustc_mir/src/transform/qualify_min_const_fn.rs @@ -30,7 +30,8 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - | ty::PredicateAtom::WellFormed(_) | ty::PredicateAtom::Projection(_) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => continue, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => continue, ty::PredicateAtom::ObjectSafe(_) => { bug!("object safe predicate on function: {:#?}", predicate) } diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 9cf3bbd94e03d..28697ec4e3b9f 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -1261,7 +1261,8 @@ crate fn required_region_bounds( | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::RegionOutlives(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => None, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => { // Search for a bound of the form `erased_self_ty // : 'a`, but be wary of something like `for<'a> diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index ad8e9d9faa6fc..6b87bc4f34ad4 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -373,14 +373,12 @@ impl AutoTraitFinder<'tcx> { computed_preds.clone().chain(user_computed_preds.iter().cloned()), ) .map(|o| o.predicate); - new_env = - ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal(), None); + new_env = ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal()); } let final_user_env = ty::ParamEnv::new( tcx.mk_predicates(user_computed_preds.into_iter()), user_env.reveal(), - None, ); debug!( "evaluate_nested_obligations(ty={:?}, trait_did={:?}): succeeded with '{:?}' \ diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs index 0097097707f32..adc8ae5908656 100644 --- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs @@ -4,12 +4,11 @@ use crate::infer::canonical::OriginalQueryValues; use crate::infer::InferCtxt; use crate::traits::query::NoSolution; use crate::traits::{ - ChalkEnvironmentAndGoal, ChalkEnvironmentClause, FulfillmentError, FulfillmentErrorCode, - ObligationCause, PredicateObligation, SelectionError, TraitEngine, + ChalkEnvironmentAndGoal, FulfillmentError, FulfillmentErrorCode, ObligationCause, + PredicateObligation, SelectionError, TraitEngine, }; use rustc_data_structures::fx::FxIndexSet; -use rustc_hir::def_id::DefId; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty}; pub struct FulfillmentContext<'tcx> { obligations: FxIndexSet>, @@ -21,132 +20,6 @@ impl FulfillmentContext<'tcx> { } } -fn environment<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: DefId, -) -> &'tcx ty::List> { - 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 environment(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().map(ChalkEnvironmentClause::Predicate); - - 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) => Some(ChalkEnvironmentClause::TypeFromEnv(ty)), - - // FIXME(eddyb) no WF conditions from lifetimes? - GenericArgKind::Lifetime(_) => None, - - // FIXME(eddyb) support const generics in Chalk - GenericArgKind::Const(_) => None, - } - }); - - tcx.mk_chalk_environment_clause_list(clauses.chain(input_clauses)) -} - -/// We need to wrap a `ty::Predicate` in an elaborated environment *before* we -/// canonicalize. This is due to the fact that we insert extra clauses into the -/// environment for all input types (`FromEnv`). -fn in_environment( - infcx: &InferCtxt<'_, 'tcx>, - obligation: &PredicateObligation<'tcx>, -) -> ChalkEnvironmentAndGoal<'tcx> { - assert!(!infcx.is_in_snapshot()); - let obligation = infcx.resolve_vars_if_possible(obligation); - - let environment = match obligation.param_env.def_id { - Some(def_id) => environment(infcx.tcx, def_id), - None if obligation.param_env.caller_bounds().is_empty() => ty::List::empty(), - // FIXME(chalk): this is hit in ui/where-clauses/where-clause-constraints-are-local-for-trait-impl - // and ui/generics/generic-static-methods - //_ => bug!("non-empty `ParamEnv` with no def-id"), - _ => ty::List::empty(), - }; - - ChalkEnvironmentAndGoal { environment, goal: obligation.predicate } -} - impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { fn normalize_projection_type( &mut self, @@ -195,6 +68,8 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { &mut self, infcx: &InferCtxt<'_, 'tcx>, ) -> Result<(), Vec>> { + assert!(!infcx.is_in_snapshot()); + let mut errors = Vec::new(); let mut next_round = FxIndexSet::default(); let mut making_progress; @@ -205,10 +80,11 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { // We iterate over all obligations, and record if we are able // to unambiguously prove at least one obligation. for obligation in self.obligations.drain(..) { - let goal_in_environment = in_environment(infcx, &obligation); + let obligation = infcx.resolve_vars_if_possible(&obligation); + let environment = obligation.param_env.caller_bounds(); + let goal = ChalkEnvironmentAndGoal { environment, goal: obligation.predicate }; let mut orig_values = OriginalQueryValues::default(); - let canonical_goal = - infcx.canonicalize_query(&goal_in_environment, &mut orig_values); + let canonical_goal = infcx.canonicalize_query(&goal, &mut orig_values); match infcx.tcx.evaluate_goal(canonical_goal) { Ok(response) => { 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 dcd8379803319..a9651144e597a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -663,6 +663,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { obligation ) } + + ty::PredicateAtom::TypeWellFormedFromEnv(..) => span_bug!( + span, + "TypeWellFormedFromEnv predicate should only exist in the environment" + ), } } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index a5c6dc042abc3..7e505e9c49125 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -86,7 +86,7 @@ pub struct PendingPredicateObligation<'tcx> { // `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -static_assert_size!(PendingPredicateObligation<'_>, 64); +static_assert_size!(PendingPredicateObligation<'_>, 56); impl<'a, 'tcx> FulfillmentContext<'tcx> { /// Creates a new fulfillment context. @@ -354,6 +354,9 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { obligation.with(pred.to_predicate(self.selcx.tcx())), ])) } + ty::PredicateAtom::TypeWellFormedFromEnv(..) => { + bug!("TypeWellFormedFromEnv is only used for Chalk") + } }, &ty::PredicateKind::Atom(atom) => match atom { ty::PredicateAtom::Trait(ref data, _) => { @@ -535,6 +538,9 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } } + ty::PredicateAtom::TypeWellFormedFromEnv(..) => { + bug!("TypeWellFormedFromEnv is only used for Chalk") + } }, } } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index fe406e88c5260..00ca1d0a74ac6 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -301,11 +301,8 @@ pub fn normalize_param_env_or_error<'tcx>( debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); - let elaborated_env = ty::ParamEnv::new( - tcx.intern_predicates(&predicates), - unnormalized_env.reveal(), - unnormalized_env.def_id, - ); + let elaborated_env = + ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal()); // HACK: we are trying to normalize the param-env inside *itself*. The problem is that // normalization expects its param-env to be already normalized, which means we have @@ -359,7 +356,7 @@ pub fn normalize_param_env_or_error<'tcx>( let outlives_env: Vec<_> = non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect(); let outlives_env = - ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal(), None); + ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal()); let outlives_predicates = match do_normalize_predicates( tcx, region_context, @@ -379,11 +376,7 @@ pub fn normalize_param_env_or_error<'tcx>( let mut predicates = non_outlives_predicates; predicates.extend(outlives_predicates); debug!("normalize_param_env_or_error: final predicates={:?}", predicates); - ty::ParamEnv::new( - tcx.intern_predicates(&predicates), - unnormalized_env.reveal(), - unnormalized_env.def_id, - ) + ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal()) } pub fn fully_normalize<'a, 'tcx, T>( diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 6c0c33d3dad2e..2f2ac9f094dc2 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -276,7 +276,8 @@ fn predicates_reference_self( | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::Subtype(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => None, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, } }) .collect() @@ -310,7 +311,8 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::TypeOutlives(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => false, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => false, } }) } @@ -654,11 +656,7 @@ fn receiver_is_dispatchable<'tcx>( .chain(iter::once(trait_predicate)) .collect(); - ty::ParamEnv::new( - tcx.intern_predicates(&caller_bounds), - param_env.reveal(), - param_env.def_id, - ) + ty::ParamEnv::new(tcx.intern_predicates(&caller_bounds), param_env.reveal()) }; // Receiver: DispatchFromDyn U]> diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 4258d8e3010a4..1e1ae78d57df7 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -592,6 +592,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } } + ty::PredicateAtom::TypeWellFormedFromEnv(..) => { + bug!("TypeWellFormedFromEnv is only used for chalk") + } } } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index eb9ee2868f93d..998990f374cb9 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -127,6 +127,9 @@ pub fn predicate_obligations<'a, 'tcx>( wf.compute(c1.into()); wf.compute(c2.into()); } + ty::PredicateAtom::TypeWellFormedFromEnv(..) => { + bug!("TypeWellFormedFromEnv is only used for Chalk") + } } wf.normalize() diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index e89a51a81768d..650404e8ca6dd 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -31,9 +31,7 @@ //! not. To lower anything wrapped in a `Binder`, we first deeply find any bound //! variables from the current `Binder`. -use rustc_middle::traits::{ - ChalkEnvironmentAndGoal, ChalkEnvironmentClause, ChalkRustInterner as RustInterner, -}; +use rustc_middle::traits::{ChalkEnvironmentAndGoal, ChalkRustInterner as RustInterner}; use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::{ @@ -43,8 +41,6 @@ use rustc_span::def_id::DefId; use std::collections::btree_map::{BTreeMap, Entry}; -use chalk_ir::fold::shift::Shift; - /// Essentially an `Into` with a `&RustInterner` parameter crate trait LowerInto<'tcx, T> { /// Lower a rustc construct (e.g., `ty::TraitPredicate`) to a chalk type, consuming `self`. @@ -82,60 +78,45 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment, ) -> chalk_ir::InEnvironment>> { - let clauses = self.environment.into_iter().map(|clause| match clause { - ChalkEnvironmentClause::Predicate(predicate) => { - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &predicate.bound_atom(interner.tcx)); - let consequence = match predicate { - ty::PredicateAtom::Trait(predicate, _) => chalk_ir::DomainGoal::FromEnv( - chalk_ir::FromEnv::Trait(predicate.trait_ref.lower_into(interner)), - ), - ty::PredicateAtom::RegionOutlives(predicate) => chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { - a: predicate.0.lower_into(interner), - b: predicate.1.lower_into(interner), - }), - ), - ty::PredicateAtom::TypeOutlives(predicate) => chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { - ty: predicate.0.lower_into(interner), - lifetime: predicate.1.lower_into(interner), - }), - ), - ty::PredicateAtom::Projection(predicate) => chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)), - ), - ty::PredicateAtom::WellFormed(..) - | ty::PredicateAtom::ObjectSafe(..) - | ty::PredicateAtom::ClosureKind(..) - | ty::PredicateAtom::Subtype(..) - | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => { - bug!("unexpected predicate {}", predicate) - } - }; - let value = chalk_ir::ProgramClauseImplication { - consequence, - conditions: chalk_ir::Goals::empty(interner), - priority: chalk_ir::ClausePriority::High, - constraints: chalk_ir::Constraints::empty(interner), - }; - chalk_ir::ProgramClauseData(chalk_ir::Binders::new(binders, value)).intern(interner) - } - ChalkEnvironmentClause::TypeFromEnv(ty) => { - chalk_ir::ProgramClauseData(chalk_ir::Binders::new( - chalk_ir::VariableKinds::empty(interner), - chalk_ir::ProgramClauseImplication { - consequence: chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty( - ty.lower_into(interner).shifted_in(interner), - )), - conditions: chalk_ir::Goals::empty(interner), - priority: chalk_ir::ClausePriority::High, - constraints: chalk_ir::Constraints::empty(interner), - }, - )) - .intern(interner) - } + let clauses = self.environment.into_iter().map(|predicate| { + let (predicate, binders, _named_regions) = + collect_bound_vars(interner, interner.tcx, &predicate.bound_atom(interner.tcx)); + let consequence = match predicate { + ty::PredicateAtom::TypeWellFormedFromEnv(ty) => { + chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(ty.lower_into(interner))) + } + ty::PredicateAtom::Trait(predicate, _) => chalk_ir::DomainGoal::FromEnv( + chalk_ir::FromEnv::Trait(predicate.trait_ref.lower_into(interner)), + ), + ty::PredicateAtom::RegionOutlives(predicate) => chalk_ir::DomainGoal::Holds( + chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { + a: predicate.0.lower_into(interner), + b: predicate.1.lower_into(interner), + }), + ), + ty::PredicateAtom::TypeOutlives(predicate) => chalk_ir::DomainGoal::Holds( + chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { + ty: predicate.0.lower_into(interner), + lifetime: predicate.1.lower_into(interner), + }), + ), + ty::PredicateAtom::Projection(predicate) => chalk_ir::DomainGoal::Holds( + chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)), + ), + ty::PredicateAtom::WellFormed(..) + | ty::PredicateAtom::ObjectSafe(..) + | ty::PredicateAtom::ClosureKind(..) + | ty::PredicateAtom::Subtype(..) + | ty::PredicateAtom::ConstEvaluatable(..) + | ty::PredicateAtom::ConstEquate(..) => bug!("unexpected predicate {}", predicate), + }; + let value = chalk_ir::ProgramClauseImplication { + consequence, + conditions: chalk_ir::Goals::empty(interner), + priority: chalk_ir::ClausePriority::High, + constraints: chalk_ir::Constraints::empty(interner), + }; + chalk_ir::ProgramClauseData(chalk_ir::Binders::new(binders, value)).intern(interner) }); let goal: chalk_ir::GoalData> = self.goal.lower_into(&interner); @@ -214,6 +195,9 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predi | ty::PredicateAtom::ConstEquate(..) => { chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner)) } + ty::PredicateAtom::TypeWellFormedFromEnv(ty) => chalk_ir::GoalData::DomainGoal( + chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(ty.lower_into(interner))), + ), }; chalk_ir::GoalData::Quantified( @@ -684,7 +668,10 @@ impl<'tcx> LowerInto<'tcx, Option bug!("unexpected predicate {}", &self), + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => { + bug!("unexpected predicate {}", &self) + } }; value.map(|value| chalk_ir::Binders::new(binders, value)) } diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs index c0d4a5d0e7e5c..63c5b884357b0 100644 --- a/compiler/rustc_traits/src/chalk/mod.rs +++ b/compiler/rustc_traits/src/chalk/mod.rs @@ -1,8 +1,7 @@ //! Calls `chalk-solve` to solve a `ty::Predicate` //! -//! In order to call `chalk-solve`, this file must convert a -//! `ChalkCanonicalGoal` into a Chalk ucanonical goal. It then calls Chalk, and -//! converts the answer back into rustc solution. +//! In order to call `chalk-solve`, this file must convert a `CanonicalChalkEnvironmentAndGoal` into +//! a Chalk uncanonical goal. It then calls Chalk, and converts the answer back into rustc solution. crate mod db; crate mod lowering; @@ -20,7 +19,7 @@ use rustc_middle::ty::{self, BoundVar, ParamTy, TyCtxt, TypeFoldable}; use rustc_infer::infer::canonical::{ Canonical, CanonicalVarValues, Certainty, QueryRegionConstraints, QueryResponse, }; -use rustc_infer::traits::{self, ChalkCanonicalGoal}; +use rustc_infer::traits::{self, CanonicalChalkEnvironmentAndGoal}; use crate::chalk::db::RustIrDatabase as ChalkRustIrDatabase; use crate::chalk::lowering::{ @@ -35,7 +34,7 @@ crate fn provide(p: &mut Providers) { crate fn evaluate_goal<'tcx>( tcx: TyCtxt<'tcx>, - obligation: ChalkCanonicalGoal<'tcx>, + obligation: CanonicalChalkEnvironmentAndGoal<'tcx>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, traits::query::NoSolution> { let interner = ChalkRustInterner { tcx }; diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index de3096eac9b19..79308b032eccd 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -103,7 +103,8 @@ fn compute_implied_outlives_bounds<'tcx>( | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::ObjectSafe(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => vec![], + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => vec![], ty::PredicateAtom::WellFormed(arg) => { wf_args.push(arg); vec![] diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 83aee31a39f3c..3e7c9ac62eb8e 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -49,6 +49,7 @@ fn not_outlives_predicate(p: &ty::Predicate<'tcx>) -> bool { | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::Subtype(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => true, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => true, } } diff --git a/compiler/rustc_ty/src/ty.rs b/compiler/rustc_ty/src/ty.rs index a0235444ac4fc..c4b6b64339a03 100644 --- a/compiler/rustc_ty/src/ty.rs +++ b/compiler/rustc_ty/src/ty.rs @@ -1,3 +1,4 @@ +use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::svh::Svh; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -5,7 +6,9 @@ use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_infer::traits::util; use rustc_middle::hir::map as hir_map; use rustc_middle::ty::subst::{InternalSubsts, Subst}; -use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; +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; @@ -245,7 +248,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { } // Compute the bounds on Self and the type parameters. - let ty::InstantiatedPredicates { predicates, .. } = + let ty::InstantiatedPredicates { mut predicates, .. } = tcx.predicates_of(def_id).instantiate_identity(tcx); // Finally, we have to normalize the bounds in the environment, in @@ -260,11 +263,13 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { // are any errors at that point, so after type checking you can be // sure that this will succeed without errors anyway. - let unnormalized_env = ty::ParamEnv::new( - tcx.intern_predicates(&predicates), - traits::Reveal::UserFacing, - tcx.sess.opts.debugging_opts.chalk.then_some(def_id), - ); + 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() @@ -276,6 +281,122 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { 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> { + 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) } diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index bbf5153d35d9b..7aa54e0ebcc6b 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -202,11 +202,8 @@ fn compare_predicate_entailment<'tcx>( // The key step here is to update the caller_bounds's predicates to be // the new hybrid bounds we computed. let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_hir_id); - let param_env = ty::ParamEnv::new( - tcx.intern_predicates(&hybrid_preds.predicates), - Reveal::UserFacing, - None, - ); + let param_env = + ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing); let param_env = traits::normalize_param_env_or_error( tcx, impl_m.def_id, @@ -1120,11 +1117,8 @@ fn compare_type_predicate_entailment<'tcx>( debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds); let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id); - let param_env = ty::ParamEnv::new( - tcx.intern_predicates(&hybrid_preds.predicates), - Reveal::UserFacing, - None, - ); + let param_env = + ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing); let param_env = traits::normalize_param_env_or_error( tcx, impl_ty.def_id, @@ -1227,7 +1221,7 @@ fn compare_projection_bounds<'tcx>( }) .to_predicate(tcx), ); - ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing, None) + ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing) }; tcx.infer_ctxt().enter(move |infcx| { diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index 14d80fded7122..ebe71b86c9221 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -814,7 +814,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::TypeOutlives(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => None, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, }, ); diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index cb5f5731aa611..b95034adb24d1 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -3918,6 +3918,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // code is looking for a self type of a unresolved // inference variable. ty::PredicateAtom::ClosureKind(..) => None, + ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, } }) .filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root)) diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs index 3746e5778aacd..60b9467fca8b3 100644 --- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs @@ -405,6 +405,7 @@ fn trait_predicate_kind<'tcx>( | ty::PredicateAtom::ObjectSafe(_) | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => None, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, } } diff --git a/compiler/rustc_typeck/src/outlives/explicit.rs b/compiler/rustc_typeck/src/outlives/explicit.rs index 135960a4c1114..ae336ccca457d 100644 --- a/compiler/rustc_typeck/src/outlives/explicit.rs +++ b/compiler/rustc_typeck/src/outlives/explicit.rs @@ -57,7 +57,8 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::Subtype(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => (), + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => (), } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1bdbad4675556..31d420c3a1854 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -508,7 +508,8 @@ impl<'a> Clean> for ty::Predicate<'a> { | ty::PredicateAtom::ObjectSafe(..) | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => panic!("not user writable"), + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => panic!("not user writable"), } } } diff --git a/src/test/ui/chalkify/type_inference.stderr b/src/test/ui/chalkify/type_inference.stderr index fb8ccbfc660bf..91c46b953159e 100644 --- a/src/test/ui/chalkify/type_inference.stderr +++ b/src/test/ui/chalkify/type_inference.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `{float}: Bar` is not satisfied - --> $DIR/type_inference.rs:27:5 + --> $DIR/type_inference.rs:27:14 | LL | fn only_bar(_x: T) { } | --- required by this bound in `only_bar` ... LL | only_bar(x); - | ^^^^^^^^ the trait `Bar` is not implemented for `{float}` + | ^ the trait `Bar` is not implemented for `{float}` | = help: the following implementations were found: diff --git a/src/test/ui/infinite/infinite-tag-type-recursion.stderr b/src/test/ui/infinite/infinite-tag-type-recursion.stderr index 6d1df4fda2eb0..45322ea96721d 100644 --- a/src/test/ui/infinite/infinite-tag-type-recursion.stderr +++ b/src/test/ui/infinite/infinite-tag-type-recursion.stderr @@ -18,7 +18,7 @@ LL | enum MList { Cons(isize, MList), Nil } | ^^^^^^^^^^ | = note: ...which again requires computing drop-check constraints for `MList`, completing the cycle - = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, def_id: None }, value: MList } }` + = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: MList } }` error: aborting due to 2 previous errors From 656a17b44d2e7ee8096f479ed8a04baab2200cae Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 9 Sep 2020 11:27:09 +0200 Subject: [PATCH 0204/1052] Rename MaybeUninit::drop to assume_init_drop. --- library/core/src/mem/maybe_uninit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 001ee0898d45e..8d19412e4c414 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -589,7 +589,7 @@ impl MaybeUninit { /// /// [`assume_init`]: MaybeUninit::assume_init #[unstable(feature = "maybe_uninit_extra", issue = "63567")] - pub unsafe fn drop(&mut self) { + pub unsafe fn assume_init_drop(&mut self) { // SAFETY: the caller must guarantee that `self` is initialized. // Dropping the value in place is safe if that is the case. unsafe { ptr::drop_in_place(self.as_mut_ptr()) } From a14efd1d0a2f0fa112e4359b9db1e9857589c796 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 9 Sep 2020 11:27:42 +0200 Subject: [PATCH 0205/1052] Rename MaybeUninit::read to assume_init_read. --- library/core/src/array/iter.rs | 4 ++-- library/core/src/mem/maybe_uninit.rs | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index 2e8b6419eea1e..cafb002c01a11 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -103,7 +103,7 @@ impl Iterator for IntoIter { // dead now (i.e. do not touch). As `idx` was the start of the // alive-zone, the alive zone is now `data[alive]` again, restoring // all invariants. - unsafe { self.data.get_unchecked(idx).read() } + unsafe { self.data.get_unchecked(idx).assume_init_read() } }) } @@ -136,7 +136,7 @@ impl DoubleEndedIterator for IntoIter { // dead now (i.e. do not touch). As `idx` was the end of the // alive-zone, the alive zone is now `data[alive]` again, restoring // all invariants. - unsafe { self.data.get_unchecked(idx).read() } + unsafe { self.data.get_unchecked(idx).assume_init_read() } }) } } diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 8d19412e4c414..38a006ce74ce0 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -520,8 +520,8 @@ impl MaybeUninit { /// this initialization invariant. /// /// Moreover, this leaves a copy of the same data behind in the `MaybeUninit`. When using - /// multiple copies of the data (by calling `read` multiple times, or first - /// calling `read` and then [`assume_init`]), it is your responsibility + /// multiple copies of the data (by calling `assume_init_read` multiple times, or first + /// calling `assume_init_read` and then [`assume_init`]), it is your responsibility /// to ensure that that data may indeed be duplicated. /// /// [inv]: #initialization-invariant @@ -537,16 +537,16 @@ impl MaybeUninit { /// /// let mut x = MaybeUninit::::uninit(); /// x.write(13); - /// let x1 = unsafe { x.read() }; + /// let x1 = unsafe { x.assume_init_read() }; /// // `u32` is `Copy`, so we may read multiple times. - /// let x2 = unsafe { x.read() }; + /// let x2 = unsafe { x.assume_init_read() }; /// assert_eq!(x1, x2); /// /// let mut x = MaybeUninit::>>::uninit(); /// x.write(None); - /// let x1 = unsafe { x.read() }; + /// let x1 = unsafe { x.assume_init_read() }; /// // Duplicating a `None` value is okay, so we may read multiple times. - /// let x2 = unsafe { x.read() }; + /// let x2 = unsafe { x.assume_init_read() }; /// assert_eq!(x1, x2); /// ``` /// @@ -558,14 +558,14 @@ impl MaybeUninit { /// /// let mut x = MaybeUninit::>>::uninit(); /// x.write(Some(vec![0,1,2])); - /// let x1 = unsafe { x.read() }; - /// let x2 = unsafe { x.read() }; + /// 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 /// // they both get dropped! /// ``` #[unstable(feature = "maybe_uninit_extra", issue = "63567")] #[inline(always)] - pub unsafe fn read(&self) -> T { + pub unsafe fn assume_init_read(&self) -> T { // SAFETY: the caller must guarantee that `self` is initialized. // Reading from `self.as_ptr()` is safe since `self` should be initialized. unsafe { From 46b164313288c4b5454ccdaa5ebee2412855f0fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Wed, 9 Sep 2020 11:57:30 +0200 Subject: [PATCH 0206/1052] update cargo dev ra-setup to changed rustc source paths --- clippy_dev/src/ra_setup.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_dev/src/ra_setup.rs b/clippy_dev/src/ra_setup.rs index f2bd651ab253c..c67efc10f1578 100644 --- a/clippy_dev/src/ra_setup.rs +++ b/clippy_dev/src/ra_setup.rs @@ -14,7 +14,7 @@ pub fn run(rustc_path: Option<&str>) { // we can unwrap here because the arg is required here let rustc_path = PathBuf::from(rustc_path.unwrap()); assert!(rustc_path.is_dir(), "path is not a directory"); - let rustc_source_basedir = rustc_path.join("src"); + let rustc_source_basedir = rustc_path.join("compiler"); assert!( rustc_source_basedir.is_dir(), "are you sure the path leads to a rustc repo?" @@ -61,7 +61,7 @@ fn inject_deps_into_manifest( let new_deps = extern_crates.map(|dep| { // format the dependencies that are going to be put inside the Cargo.toml format!( - "{dep} = {{ path = \"{source_path}/lib{dep}\" }}\n", + "{dep} = {{ path = \"{source_path}/{dep}\" }}\n", dep = dep, source_path = rustc_source_dir.display() ) From 8b392505ae8e5645f3f254caa8aff2a932df4d72 Mon Sep 17 00:00:00 2001 From: jumbatm <30644300+jumbatm@users.noreply.github.com> Date: Wed, 9 Sep 2020 21:23:25 +1000 Subject: [PATCH 0207/1052] Fix non-determinism in generated format string. --- compiler/rustc_macros/src/session_diagnostic.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_macros/src/session_diagnostic.rs b/compiler/rustc_macros/src/session_diagnostic.rs index 396de77d5eee0..610b9155cfc18 100644 --- a/compiler/rustc_macros/src/session_diagnostic.rs +++ b/compiler/rustc_macros/src/session_diagnostic.rs @@ -1,11 +1,9 @@ #![deny(unused_must_use)] -use quote::format_ident; -use quote::quote; - use proc_macro::Diagnostic; +use quote::{format_ident, quote}; use syn::spanned::Spanned; -use std::collections::{HashMap, HashSet}; +use std::collections::{BTreeSet, HashMap}; /// Implements #[derive(SessionDiagnostic)], which allows for errors to be specified as a struct, independent /// from the actual diagnostics emitting code. @@ -577,7 +575,10 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> { /// ``` /// This function builds the entire call to format!. fn build_format(&self, input: &String, span: proc_macro2::Span) -> proc_macro2::TokenStream { - let mut referenced_fields: HashSet = HashSet::new(); + // This set is used later to generate the final format string. To keep builds reproducible, + // the iteration order needs to be deterministic, hence why we use a BTreeSet here instead + // of a HashSet. + let mut referenced_fields: BTreeSet = BTreeSet::new(); // At this point, we can start parsing the format string. let mut it = input.chars().peekable(); From 5d7e7c25e4e6cea5b441227d5dc55b9defb170f1 Mon Sep 17 00:00:00 2001 From: Hameer Abbasi Date: Wed, 9 Sep 2020 13:28:41 +0200 Subject: [PATCH 0208/1052] Add revisions to const generic issue UI tests. --- .../auxiliary/const_generic_issues_lib.rs | 4 +- .../issues/issue-61935.full.stderr | 10 ++ .../issues/issue-61935.min.stderr | 10 ++ .../ui/const-generics/issues/issue-61935.rs | 9 +- .../const-generics/issues/issue-61935.stderr | 19 ---- ...-encountered-polymorphic-const.full.stderr | 10 ++ ...7-encountered-polymorphic-const.min.stderr | 10 ++ ...sue-62187-encountered-polymorphic-const.rs | 6 +- ...62187-encountered-polymorphic-const.stderr | 19 ---- ...e-62220.stderr => issue-62220.full.stderr} | 2 +- .../issues/issue-62220.min.stderr | 10 ++ .../ui/const-generics/issues/issue-62220.rs | 9 +- .../issues/issue-62456.full.stderr | 10 ++ .../issues/issue-62456.min.stderr | 10 ++ .../ui/const-generics/issues/issue-62456.rs | 9 +- .../const-generics/issues/issue-62456.stderr | 19 ---- ...e-62504.stderr => issue-62504.full.stderr} | 2 +- .../issues/issue-62504.min.stderr | 10 ++ .../ui/const-generics/issues/issue-62504.rs | 10 +- .../issues/issue-62579-no-match.min.stderr | 11 ++ .../issues/issue-62579-no-match.rs | 10 +- .../issues/issue-62579-no-match.stderr | 11 -- .../issues/issue-62878.full.stderr | 28 +++++ .../issues/issue-62878.min.stderr | 18 +++ .../ui/const-generics/issues/issue-62878.rs | 12 +- .../const-generics/issues/issue-62878.stderr | 33 ++++-- ...185-2.stderr => issue-67185-2.full.stderr} | 23 ++-- .../issues/issue-67185-2.min.stderr | 103 ++++++++++++++++++ .../ui/const-generics/issues/issue-67185-2.rs | 6 +- ...e-67739.stderr => issue-67739.full.stderr} | 0 .../issues/issue-67739.min.stderr | 10 ++ .../ui/const-generics/issues/issue-67739.rs | 11 +- ...e-68366.stderr => issue-68366.full.stderr} | 4 +- .../issues/issue-68366.min.stderr | 29 +++++ .../ui/const-generics/issues/issue-68366.rs | 7 +- ...e-72787.stderr => issue-72787.full.stderr} | 10 +- .../issues/issue-72787.min.stderr | 57 ++++++++++ .../ui/const-generics/issues/issue-72787.rs | 23 ++-- ...e-72819-generic-in-const-eval.full.stderr} | 2 +- ...sue-72819-generic-in-const-eval.min.stderr | 10 ++ .../issue-72819-generic-in-const-eval.rs | 9 +- .../ui/const-generics/issues/issue-73120.rs | 1 + 42 files changed, 467 insertions(+), 149 deletions(-) create mode 100644 src/test/ui/const-generics/issues/issue-61935.full.stderr create mode 100644 src/test/ui/const-generics/issues/issue-61935.min.stderr delete mode 100644 src/test/ui/const-generics/issues/issue-61935.stderr create mode 100644 src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.full.stderr create mode 100644 src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.min.stderr delete mode 100644 src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr rename src/test/ui/const-generics/issues/{issue-62220.stderr => issue-62220.full.stderr} (90%) create mode 100644 src/test/ui/const-generics/issues/issue-62220.min.stderr create mode 100644 src/test/ui/const-generics/issues/issue-62456.full.stderr create mode 100644 src/test/ui/const-generics/issues/issue-62456.min.stderr delete mode 100644 src/test/ui/const-generics/issues/issue-62456.stderr rename src/test/ui/const-generics/issues/{issue-62504.stderr => issue-62504.full.stderr} (89%) create mode 100644 src/test/ui/const-generics/issues/issue-62504.min.stderr create mode 100644 src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr delete mode 100644 src/test/ui/const-generics/issues/issue-62579-no-match.stderr create mode 100644 src/test/ui/const-generics/issues/issue-62878.full.stderr create mode 100644 src/test/ui/const-generics/issues/issue-62878.min.stderr rename src/test/ui/const-generics/issues/{issue-67185-2.stderr => issue-67185-2.full.stderr} (82%) create mode 100644 src/test/ui/const-generics/issues/issue-67185-2.min.stderr rename src/test/ui/const-generics/issues/{issue-67739.stderr => issue-67739.full.stderr} (100%) create mode 100644 src/test/ui/const-generics/issues/issue-67739.min.stderr rename src/test/ui/const-generics/issues/{issue-68366.stderr => issue-68366.full.stderr} (93%) create mode 100644 src/test/ui/const-generics/issues/issue-68366.min.stderr rename src/test/ui/const-generics/issues/{issue-72787.stderr => issue-72787.full.stderr} (88%) create mode 100644 src/test/ui/const-generics/issues/issue-72787.min.stderr rename src/test/ui/const-generics/issues/{issue-72819-generic-in-const-eval.stderr => issue-72819-generic-in-const-eval.full.stderr} (84%) create mode 100644 src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr diff --git a/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs b/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs index 59a4d345cbccb..7ea8d936d6141 100644 --- a/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs +++ b/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs @@ -1,4 +1,6 @@ -#![feature(const_generics)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] // All of these three items must be in `lib2` to reproduce the error diff --git a/src/test/ui/const-generics/issues/issue-61935.full.stderr b/src/test/ui/const-generics/issues/issue-61935.full.stderr new file mode 100644 index 0000000000000..b805bc0db7e55 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61935.full.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-61935.rs:10:14 + | +LL | Self:FooImpl<{N==0}> + | ^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-61935.min.stderr b/src/test/ui/const-generics/issues/issue-61935.min.stderr new file mode 100644 index 0000000000000..e5715ec658c5c --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61935.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-61935.rs:10:23 + | +LL | Self:FooImpl<{N==0}> + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-61935.rs b/src/test/ui/const-generics/issues/issue-61935.rs index 0d42ff1895cdb..64257da030943 100644 --- a/src/test/ui/const-generics/issues/issue-61935.rs +++ b/src/test/ui/const-generics/issues/issue-61935.rs @@ -1,12 +1,15 @@ -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait Foo {} impl Foo for [(); N] where Self:FooImpl<{N==0}> -//~^ERROR constant expression depends on a generic parameter +//[full]~^ERROR constant expression depends on a generic parameter +//[min]~^^ERROR generic parameters must not be used inside of non trivial constant values {} trait FooImpl{} diff --git a/src/test/ui/const-generics/issues/issue-61935.stderr b/src/test/ui/const-generics/issues/issue-61935.stderr deleted file mode 100644 index a785af5f008ea..0000000000000 --- a/src/test/ui/const-generics/issues/issue-61935.stderr +++ /dev/null @@ -1,19 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-61935.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -error: constant expression depends on a generic parameter - --> $DIR/issue-61935.rs:8:14 - | -LL | Self:FooImpl<{N==0}> - | ^^^^^^^^^^^^^^^ - | - = note: this may fail depending on what value the parameter takes - -error: aborting due to previous error; 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.full.stderr b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.full.stderr new file mode 100644 index 0000000000000..aada9c007256b --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.full.stderr @@ -0,0 +1,10 @@ +warning: unused variable: `foo` + --> $DIR/issue-62187-encountered-polymorphic-const.rs:17:9 + | +LL | let foo = <[u8; 2]>::BIT_LEN; + | ^^^ help: if this is intentional, prefix it with an underscore: `_foo` + | + = note: `#[warn(unused_variables)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.min.stderr b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.min.stderr new file mode 100644 index 0000000000000..aada9c007256b --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.min.stderr @@ -0,0 +1,10 @@ +warning: unused variable: `foo` + --> $DIR/issue-62187-encountered-polymorphic-const.rs:17:9 + | +LL | let foo = <[u8; 2]>::BIT_LEN; + | ^^^ help: if this is intentional, prefix it with an underscore: `_foo` + | + = note: `#[warn(unused_variables)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs index 2f3b5c5dc5b89..710fdbd9a11f3 100644 --- a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs +++ b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs @@ -1,7 +1,9 @@ // run-pass -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub trait BitLen: Sized { const BIT_LEN: usize; diff --git a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr deleted file mode 100644 index a9abb877c094c..0000000000000 --- a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr +++ /dev/null @@ -1,19 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-62187-encountered-polymorphic-const.rs:3:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -warning: unused variable: `foo` - --> $DIR/issue-62187-encountered-polymorphic-const.rs:15:9 - | -LL | let foo = <[u8; 2]>::BIT_LEN; - | ^^^ help: if this is intentional, prefix it with an underscore: `_foo` - | - = note: `#[warn(unused_variables)]` on by default - -warning: 2 warnings emitted - diff --git a/src/test/ui/const-generics/issues/issue-62220.stderr b/src/test/ui/const-generics/issues/issue-62220.full.stderr similarity index 90% rename from src/test/ui/const-generics/issues/issue-62220.stderr rename to src/test/ui/const-generics/issues/issue-62220.full.stderr index d91d2bb326fc5..120aa8e4af5d2 100644 --- a/src/test/ui/const-generics/issues/issue-62220.stderr +++ b/src/test/ui/const-generics/issues/issue-62220.full.stderr @@ -1,5 +1,5 @@ error: constant expression depends on a generic parameter - --> $DIR/issue-62220.rs:10:27 + --> $DIR/issue-62220.rs:13:27 | LL | pub fn trunc(self) -> (TruncatedVector, T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/const-generics/issues/issue-62220.min.stderr b/src/test/ui/const-generics/issues/issue-62220.min.stderr new file mode 100644 index 0000000000000..943b689bf61af --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62220.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-62220.rs:8:59 + | +LL | pub type TruncatedVector = Vector; + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-62220.rs b/src/test/ui/const-generics/issues/issue-62220.rs index 5c4a0d31a895d..acb13ad1170f2 100644 --- a/src/test/ui/const-generics/issues/issue-62220.rs +++ b/src/test/ui/const-generics/issues/issue-62220.rs @@ -1,14 +1,17 @@ -#![allow(incomplete_features)] -#![feature(const_generics)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub struct Vector([T; N]); pub type TruncatedVector = Vector; +//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values impl Vector { /// Drop the last component and return the vector with one fewer dimension. pub fn trunc(self) -> (TruncatedVector, T) { - //~^ ERROR constant expression depends on a generic parameter + //[full]~^ ERROR constant expression depends on a generic parameter unimplemented!() } } diff --git a/src/test/ui/const-generics/issues/issue-62456.full.stderr b/src/test/ui/const-generics/issues/issue-62456.full.stderr new file mode 100644 index 0000000000000..a8d44074db9d1 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62456.full.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-62456.rs:7:20 + | +LL | let _ = [0u64; N + 1]; + | ^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-62456.min.stderr b/src/test/ui/const-generics/issues/issue-62456.min.stderr new file mode 100644 index 0000000000000..335f0ead27871 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62456.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-62456.rs:7:20 + | +LL | let _ = [0u64; N + 1]; + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-62456.rs b/src/test/ui/const-generics/issues/issue-62456.rs index 37947ad1b331c..c96868c00a3d6 100644 --- a/src/test/ui/const-generics/issues/issue-62456.rs +++ b/src/test/ui/const-generics/issues/issue-62456.rs @@ -1,9 +1,12 @@ -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] fn foo() { let _ = [0u64; N + 1]; - //~^ ERROR constant expression depends on a generic parameter + //[full]~^ ERROR constant expression depends on a generic parameter + //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values } fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-62456.stderr b/src/test/ui/const-generics/issues/issue-62456.stderr deleted file mode 100644 index 0454fed670598..0000000000000 --- a/src/test/ui/const-generics/issues/issue-62456.stderr +++ /dev/null @@ -1,19 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-62456.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -error: constant expression depends on a generic parameter - --> $DIR/issue-62456.rs:5:20 - | -LL | let _ = [0u64; N + 1]; - | ^^^^^ - | - = note: this may fail depending on what value the parameter takes - -error: aborting due to previous error; 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-62504.stderr b/src/test/ui/const-generics/issues/issue-62504.full.stderr similarity index 89% rename from src/test/ui/const-generics/issues/issue-62504.stderr rename to src/test/ui/const-generics/issues/issue-62504.full.stderr index f09af76325e96..9c84f06ce9f74 100644 --- a/src/test/ui/const-generics/issues/issue-62504.stderr +++ b/src/test/ui/const-generics/issues/issue-62504.full.stderr @@ -1,5 +1,5 @@ error: constant expression depends on a generic parameter - --> $DIR/issue-62504.rs:18:25 + --> $DIR/issue-62504.rs:19:25 | LL | ArrayHolder([0; Self::SIZE]) | ^^^^^^^^^^ diff --git a/src/test/ui/const-generics/issues/issue-62504.min.stderr b/src/test/ui/const-generics/issues/issue-62504.min.stderr new file mode 100644 index 0000000000000..752df17aad614 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62504.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-62504.rs:19:25 + | +LL | ArrayHolder([0; Self::SIZE]) + | ^^^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `Self` + | + = help: it is currently only allowed to use either `Self` or `{ Self }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-62504.rs b/src/test/ui/const-generics/issues/issue-62504.rs index 4e05aadd3930f..b520dbe4e803b 100644 --- a/src/test/ui/const-generics/issues/issue-62504.rs +++ b/src/test/ui/const-generics/issues/issue-62504.rs @@ -1,7 +1,8 @@ -// Regression test for #62504 - -#![feature(const_generics)] +// revisions: full min #![allow(incomplete_features)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait HasSize { const SIZE: usize; @@ -16,7 +17,8 @@ struct ArrayHolder([u32; X]); impl ArrayHolder { pub const fn new() -> Self { ArrayHolder([0; Self::SIZE]) - //~^ ERROR constant expression depends on a generic parameter + //[full]~^ ERROR constant expression depends on a generic parameter + //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values } } diff --git a/src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr b/src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr new file mode 100644 index 0000000000000..6903b20fad63c --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr @@ -0,0 +1,11 @@ +error: `NoMatch` is forbidden as the type of a const generic parameter + --> $DIR/issue-62579-no-match.rs:10:17 + | +LL | fn foo() -> bool { + | ^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-62579-no-match.rs b/src/test/ui/const-generics/issues/issue-62579-no-match.rs index 7eaf5eea0787b..c9853aa9162e1 100644 --- a/src/test/ui/const-generics/issues/issue-62579-no-match.rs +++ b/src/test/ui/const-generics/issues/issue-62579-no-match.rs @@ -1,12 +1,14 @@ -// run-pass - -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// [full] run-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] #[derive(PartialEq, Eq)] struct NoMatch; fn foo() -> bool { + //[min]~^ ERROR `NoMatch` is forbidden as the type of a const generic parameter true } diff --git a/src/test/ui/const-generics/issues/issue-62579-no-match.stderr b/src/test/ui/const-generics/issues/issue-62579-no-match.stderr deleted file mode 100644 index 9fb9b5b13d8d5..0000000000000 --- a/src/test/ui/const-generics/issues/issue-62579-no-match.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-62579-no-match.rs:3:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-62878.full.stderr b/src/test/ui/const-generics/issues/issue-62878.full.stderr new file mode 100644 index 0000000000000..c8b9db8941098 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62878.full.stderr @@ -0,0 +1,28 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/issue-62878.rs:6:38 + | +LL | fn foo() {} + | ^ the type must not depend on the parameter `N` + +error[E0107]: wrong number of const arguments: expected 2, found 1 + --> $DIR/issue-62878.rs:11:5 + | +LL | foo::<_, {[1]}>(); + | ^^^^^^^^^^^^^^^ expected 2 const arguments + +error[E0107]: wrong number of type arguments: expected 0, found 1 + --> $DIR/issue-62878.rs:11:11 + | +LL | foo::<_, {[1]}>(); + | ^ unexpected type argument + +error[E0308]: mismatched types + --> $DIR/issue-62878.rs:11:15 + | +LL | foo::<_, {[1]}>(); + | ^^^ expected `usize`, found array `[{integer}; 1]` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0107, E0308, E0770. +For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/const-generics/issues/issue-62878.min.stderr b/src/test/ui/const-generics/issues/issue-62878.min.stderr new file mode 100644 index 0000000000000..34edd09b51565 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62878.min.stderr @@ -0,0 +1,18 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/issue-62878.rs:6:38 + | +LL | fn foo() {} + | ^ the type must not depend on the parameter `N` + +error: `[u8; _]` is forbidden as the type of a const generic parameter + --> $DIR/issue-62878.rs:6:33 + | +LL | fn foo() {} + | ^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0770`. diff --git a/src/test/ui/const-generics/issues/issue-62878.rs b/src/test/ui/const-generics/issues/issue-62878.rs index ccc05fdf100e7..0487dda2fe81d 100644 --- a/src/test/ui/const-generics/issues/issue-62878.rs +++ b/src/test/ui/const-generics/issues/issue-62878.rs @@ -1,11 +1,15 @@ -#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] fn foo() {} //~^ ERROR the type of const parameters must not +//[min]~| ERROR `[u8; _]` is forbidden as the type of a const generic parameter fn main() { foo::<_, {[1]}>(); - //~^ ERROR wrong number of const arguments - //~| ERROR wrong number of type arguments - //~| ERROR mismatched types + //[full]~^ ERROR wrong number of const arguments + //[full]~| ERROR wrong number of type arguments + //[full]~| ERROR mismatched types } diff --git a/src/test/ui/const-generics/issues/issue-62878.stderr b/src/test/ui/const-generics/issues/issue-62878.stderr index fe0990d8241fa..8f7fe000a8116 100644 --- a/src/test/ui/const-generics/issues/issue-62878.stderr +++ b/src/test/ui/const-generics/issues/issue-62878.stderr @@ -1,37 +1,46 @@ error[E0770]: the type of const parameters must not depend on other generic parameters - --> $DIR/issue-62878.rs:3:38 + --> $DIR/issue-62878.rs:5:38 | LL | fn foo() {} | ^ the type must not depend on the parameter `N` -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-62878.rs:1:12 +error[E0658]: const generics are unstable + --> $DIR/issue-62878.rs:5:14 | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ +LL | fn foo() {} + | ^ + | + = note: see issue #74878 for more information + = help: add `#![feature(min_const_generics)]` to the crate attributes to enable + +error[E0658]: const generics are unstable + --> $DIR/issue-62878.rs:5:30 + | +LL | fn foo() {} + | ^ | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information + = note: see issue #74878 for more information + = help: add `#![feature(min_const_generics)]` to the crate attributes to enable error[E0107]: wrong number of const arguments: expected 2, found 1 - --> $DIR/issue-62878.rs:7:5 + --> $DIR/issue-62878.rs:11:5 | LL | foo::<_, {[1]}>(); | ^^^^^^^^^^^^^^^ expected 2 const arguments error[E0107]: wrong number of type arguments: expected 0, found 1 - --> $DIR/issue-62878.rs:7:11 + --> $DIR/issue-62878.rs:11:11 | LL | foo::<_, {[1]}>(); | ^ unexpected type argument error[E0308]: mismatched types - --> $DIR/issue-62878.rs:7:15 + --> $DIR/issue-62878.rs:11:15 | LL | foo::<_, {[1]}>(); | ^^^ expected `usize`, found array `[{integer}; 1]` -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 6 previous errors -Some errors have detailed explanations: E0107, E0308, E0770. +Some errors have detailed explanations: E0107, E0308, E0658, E0770. For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/const-generics/issues/issue-67185-2.stderr b/src/test/ui/const-generics/issues/issue-67185-2.full.stderr similarity index 82% rename from src/test/ui/const-generics/issues/issue-67185-2.stderr rename to src/test/ui/const-generics/issues/issue-67185-2.full.stderr index 7d947a907a0ee..78c7ebff05985 100644 --- a/src/test/ui/const-generics/issues/issue-67185-2.stderr +++ b/src/test/ui/const-generics/issues/issue-67185-2.full.stderr @@ -1,14 +1,5 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-67185-2.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied - --> $DIR/issue-67185-2.rs:15:1 + --> $DIR/issue-67185-2.rs:17:1 | LL | / trait Foo LL | | @@ -26,7 +17,7 @@ LL | | } = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied - --> $DIR/issue-67185-2.rs:15:1 + --> $DIR/issue-67185-2.rs:17:1 | LL | / trait Foo LL | | @@ -44,7 +35,7 @@ LL | | } = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied - --> $DIR/issue-67185-2.rs:25:6 + --> $DIR/issue-67185-2.rs:27:6 | LL | trait Foo | --- required by a bound in this @@ -60,7 +51,7 @@ LL | impl Foo for FooImpl {} <[u16; 4] as Bar> error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied - --> $DIR/issue-67185-2.rs:25:6 + --> $DIR/issue-67185-2.rs:27:6 | LL | trait Foo | --- required by a bound in this @@ -76,7 +67,7 @@ LL | impl Foo for FooImpl {} <[u16; 4] as Bar> error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied - --> $DIR/issue-67185-2.rs:29:14 + --> $DIR/issue-67185-2.rs:31:14 | LL | trait Foo | --- required by a bound in this @@ -92,7 +83,7 @@ LL | fn f(_: impl Foo) {} <[u16; 4] as Bar> error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied - --> $DIR/issue-67185-2.rs:29:14 + --> $DIR/issue-67185-2.rs:31:14 | LL | trait Foo | --- required by a bound in this @@ -107,6 +98,6 @@ LL | fn f(_: impl Foo) {} <[[u16; 3]; 3] as Bar> <[u16; 4] as Bar> -error: aborting due to 6 previous errors; 1 warning emitted +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/issues/issue-67185-2.min.stderr b/src/test/ui/const-generics/issues/issue-67185-2.min.stderr new file mode 100644 index 0000000000000..78c7ebff05985 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-67185-2.min.stderr @@ -0,0 +1,103 @@ +error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:17:1 + | +LL | / trait Foo +LL | | +LL | | where +LL | | [::Quaks; 2]: Bar, +LL | | ::Quaks: Bar, +LL | | { +LL | | } + | |_^ the trait `Bar` is not implemented for `[u16; 3]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + +error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:17:1 + | +LL | / trait Foo +LL | | +LL | | where +LL | | [::Quaks; 2]: Bar, +LL | | ::Quaks: Bar, +LL | | { +LL | | } + | |_^ the trait `Bar` is not implemented for `[[u16; 3]; 2]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + +error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:27:6 + | +LL | trait Foo + | --- required by a bound in this +... +LL | ::Quaks: Bar, + | --- required by this bound in `Foo` +... +LL | impl Foo for FooImpl {} + | ^^^ the trait `Bar` is not implemented for `[u16; 3]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + +error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:27:6 + | +LL | trait Foo + | --- required by a bound in this +... +LL | [::Quaks; 2]: Bar, + | --- required by this bound in `Foo` +... +LL | impl Foo for FooImpl {} + | ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + +error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:31:14 + | +LL | trait Foo + | --- required by a bound in this +... +LL | [::Quaks; 2]: Bar, + | --- required by this bound in `Foo` +... +LL | fn f(_: impl Foo) {} + | ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + +error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:31:14 + | +LL | trait Foo + | --- required by a bound in this +... +LL | ::Quaks: Bar, + | --- required by this bound in `Foo` +... +LL | fn f(_: impl Foo) {} + | ^^^ the trait `Bar` is not implemented for `[u16; 3]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/issues/issue-67185-2.rs b/src/test/ui/const-generics/issues/issue-67185-2.rs index 111b718dd5efd..1176d0c690403 100644 --- a/src/test/ui/const-generics/issues/issue-67185-2.rs +++ b/src/test/ui/const-generics/issues/issue-67185-2.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait Baz { type Quaks; diff --git a/src/test/ui/const-generics/issues/issue-67739.stderr b/src/test/ui/const-generics/issues/issue-67739.full.stderr similarity index 100% rename from src/test/ui/const-generics/issues/issue-67739.stderr rename to src/test/ui/const-generics/issues/issue-67739.full.stderr diff --git a/src/test/ui/const-generics/issues/issue-67739.min.stderr b/src/test/ui/const-generics/issues/issue-67739.min.stderr new file mode 100644 index 0000000000000..1254ee7239dc7 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-67739.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-67739.rs:12:30 + | +LL | [0u8; mem::size_of::()]; + | ^^^^^^^^^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `Self` + | + = help: it is currently only allowed to use either `Self` or `{ Self }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-67739.rs b/src/test/ui/const-generics/issues/issue-67739.rs index c8ee182123985..72bf3ee9602fc 100644 --- a/src/test/ui/const-generics/issues/issue-67739.rs +++ b/src/test/ui/const-generics/issues/issue-67739.rs @@ -1,7 +1,7 @@ -// Regression test for #67739 - -#![allow(incomplete_features)] -#![feature(const_generics)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] use std::mem; @@ -10,7 +10,8 @@ pub trait Trait { fn associated_size(&self) -> usize { [0u8; mem::size_of::()]; - //~^ ERROR constant expression depends on a generic parameter + //[full]~^ ERROR constant expression depends on a generic parameter + //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values 0 } } diff --git a/src/test/ui/const-generics/issues/issue-68366.stderr b/src/test/ui/const-generics/issues/issue-68366.full.stderr similarity index 93% rename from src/test/ui/const-generics/issues/issue-68366.stderr rename to src/test/ui/const-generics/issues/issue-68366.full.stderr index bba16f421535a..ac774f50c7493 100644 --- a/src/test/ui/const-generics/issues/issue-68366.stderr +++ b/src/test/ui/const-generics/issues/issue-68366.full.stderr @@ -1,5 +1,5 @@ error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates - --> $DIR/issue-68366.rs:10:13 + --> $DIR/issue-68366.rs:12:13 | LL | impl Collatz<{Some(N)}> {} | ^ unconstrained const parameter @@ -8,7 +8,7 @@ LL | impl Collatz<{Some(N)}> {} = note: proving the result of expressions other than the parameter are unique is not supported error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates - --> $DIR/issue-68366.rs:15:12 + --> $DIR/issue-68366.rs:18:12 | LL | impl Foo {} | ^ unconstrained const parameter diff --git a/src/test/ui/const-generics/issues/issue-68366.min.stderr b/src/test/ui/const-generics/issues/issue-68366.min.stderr new file mode 100644 index 0000000000000..8d34bdc6ea0c8 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68366.min.stderr @@ -0,0 +1,29 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-68366.rs:12:37 + | +LL | impl Collatz<{Some(N)}> {} + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-68366.rs:12:13 + | +LL | impl Collatz<{Some(N)}> {} + | ^ unconstrained const parameter + | + = note: expressions using a const parameter must map each value to a distinct output value + = note: proving the result of expressions other than the parameter are unique is not supported + +error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-68366.rs:18:12 + | +LL | impl Foo {} + | ^ unconstrained const parameter + | + = note: expressions using a const parameter must map each value to a distinct output value + = note: proving the result of expressions other than the parameter are unique is not supported + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0207`. diff --git a/src/test/ui/const-generics/issues/issue-68366.rs b/src/test/ui/const-generics/issues/issue-68366.rs index a06b99d6645ec..819fcaffea18c 100644 --- a/src/test/ui/const-generics/issues/issue-68366.rs +++ b/src/test/ui/const-generics/issues/issue-68366.rs @@ -2,13 +2,16 @@ // The note should relate to the fact that it cannot be shown forall N that it maps 1-1 to a new // type. -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct Collatz>; impl Collatz<{Some(N)}> {} //~^ ERROR the const parameter +//[min]~^^ generic parameters must not be used inside of non trivial constant values struct Foo; diff --git a/src/test/ui/const-generics/issues/issue-72787.stderr b/src/test/ui/const-generics/issues/issue-72787.full.stderr similarity index 88% rename from src/test/ui/const-generics/issues/issue-72787.stderr rename to src/test/ui/const-generics/issues/issue-72787.full.stderr index ed892e46bbbed..29f975f566280 100644 --- a/src/test/ui/const-generics/issues/issue-72787.stderr +++ b/src/test/ui/const-generics/issues/issue-72787.full.stderr @@ -1,5 +1,5 @@ error: constant expression depends on a generic parameter - --> $DIR/issue-72787.rs:9:32 + --> $DIR/issue-72787.rs:11:32 | LL | Condition<{ LHS <= RHS }>: True | ^^^^ @@ -7,7 +7,7 @@ LL | Condition<{ LHS <= RHS }>: True = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/issue-72787.rs:20:42 + --> $DIR/issue-72787.rs:27:42 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^^^^ @@ -15,7 +15,7 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/issue-72787.rs:20:42 + --> $DIR/issue-72787.rs:27:42 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^^^^ @@ -23,7 +23,7 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/issue-72787.rs:20:42 + --> $DIR/issue-72787.rs:27:42 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^^^^ @@ -31,7 +31,7 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/issue-72787.rs:20:42 + --> $DIR/issue-72787.rs:27:42 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^^^^ diff --git a/src/test/ui/const-generics/issues/issue-72787.min.stderr b/src/test/ui/const-generics/issues/issue-72787.min.stderr new file mode 100644 index 0000000000000..d2c512898fe88 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-72787.min.stderr @@ -0,0 +1,57 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-72787.rs:11:17 + | +LL | Condition<{ LHS <= RHS }>: True + | ^^^ non-trivial anonymous constants must not depend on the parameter `LHS` + | + = help: it is currently only allowed to use either `LHS` or `{ LHS }` as generic constants + +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-72787.rs:11:24 + | +LL | Condition<{ LHS <= RHS }>: True + | ^^^ non-trivial anonymous constants must not depend on the parameter `RHS` + | + = help: it is currently only allowed to use either `RHS` or `{ RHS }` as generic constants + +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-72787.rs:27:25 + | +LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, + | ^ non-trivial anonymous constants must not depend on the parameter `I` + | + = help: it is currently only allowed to use either `I` or `{ I }` as generic constants + +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-72787.rs:27:36 + | +LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, + | ^ non-trivial anonymous constants must not depend on the parameter `J` + | + = help: it is currently only allowed to use either `J` or `{ J }` as generic constants + +error[E0283]: type annotations needed + --> $DIR/issue-72787.rs:22:26 + | +LL | pub trait True {} + | -------------- required by this bound in `True` +... +LL | IsLessOrEqual: True, + | ^^^^ cannot infer type for struct `IsLessOrEqual` + | + = note: cannot satisfy `IsLessOrEqual: True` + +error[E0283]: type annotations needed + --> $DIR/issue-72787.rs:22:26 + | +LL | pub trait True {} + | -------------- required by this bound in `True` +... +LL | IsLessOrEqual: True, + | ^^^^ cannot infer type for struct `IsLessOrEqual` + | + = note: cannot satisfy `IsLessOrEqual: True` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0283`. diff --git a/src/test/ui/const-generics/issues/issue-72787.rs b/src/test/ui/const-generics/issues/issue-72787.rs index a368c226ec338..e95976b5f0229 100644 --- a/src/test/ui/const-generics/issues/issue-72787.rs +++ b/src/test/ui/const-generics/issues/issue-72787.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub struct IsLessOrEqual; pub struct Condition; @@ -7,7 +9,9 @@ pub trait True {} impl True for IsLessOrEqual where Condition<{ LHS <= RHS }>: True -//~^ Error constant expression depends on a generic parameter +//[full]~^ Error constant expression depends on a generic parameter +//[min]~^^ Error generic parameters must not be used inside of non trivial constant values +//[min]~| Error generic parameters must not be used inside of non trivial constant values { } impl True for Condition {} @@ -16,12 +20,17 @@ struct S; impl S where IsLessOrEqual: True, +//[min]~^ Error type annotations needed [E0283] +//[min]~| Error type annotations needed [E0283] + // Condition<{ 8 - I <= 8 - J }>: True, IsLessOrEqual: True, IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, -//~^ Error constant expression depends on a generic parameter -//~| Error constant expression depends on a generic parameter -//~| Error constant expression depends on a generic parameter -//~| Error constant expression depends on a generic parameter +//[full]~^ constant expression depends on a generic parameter +//[full]~| constant expression depends on a generic parameter +//[full]~| constant expression depends on a generic parameter +//[full]~| constant expression depends on a generic parameter +//[min]~^^^^^ Error generic parameters must not be used inside of non trivial constant values +//[min]~| Error generic parameters must not be used inside of non trivial constant values // Condition<{ 8 - I <= 8 - J }>: True, { fn print() { diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.stderr b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.full.stderr similarity index 84% rename from src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.stderr rename to src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.full.stderr index a9f664d0ac8c5..e4105a3df1c88 100644 --- a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.stderr +++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.full.stderr @@ -1,5 +1,5 @@ error: constant expression depends on a generic parameter - --> $DIR/issue-72819-generic-in-const-eval.rs:7:47 + --> $DIR/issue-72819-generic-in-const-eval.rs:9:47 | LL | where Assert::<{N < usize::max_value() / 2}>: IsTrue, | ^^^^^^ diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr new file mode 100644 index 0000000000000..48a1f0bd19c0a --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-72819-generic-in-const-eval.rs:9:17 + | +LL | where Assert::<{N < usize::max_value() / 2}>: IsTrue, + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs index 225593c3178a5..b653b91d99d14 100644 --- a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs +++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs @@ -1,11 +1,14 @@ // Regression test for #72819: ICE due to failure in resolving the const generic in `Arr`'s type // bounds. +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] -#![feature(const_generics)] -#![allow(incomplete_features)] struct Arr where Assert::<{N < usize::max_value() / 2}>: IsTrue, -//~^ ERROR constant expression depends on a generic parameter +//[full]~^ ERROR constant expression depends on a generic parameter +//[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values { } diff --git a/src/test/ui/const-generics/issues/issue-73120.rs b/src/test/ui/const-generics/issues/issue-73120.rs index aea4de39f79ce..c153a93cdef4f 100644 --- a/src/test/ui/const-generics/issues/issue-73120.rs +++ b/src/test/ui/const-generics/issues/issue-73120.rs @@ -1,3 +1,4 @@ +// revisions: full min // check-pass // aux-build:const_generic_issues_lib.rs extern crate const_generic_issues_lib as lib2; From 7889373730343f9f7cebc5d649907a3003692280 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Jul 2020 10:36:56 +0200 Subject: [PATCH 0209/1052] make as_leaf return a raw pointer, to reduce aliasing assumptions --- library/alloc/src/collections/btree/node.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 1346ad19fe20a..ce4a7e1bdd7da 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -316,7 +316,9 @@ impl NodeRef { /// Note that, despite being safe, calling this function can have the side effect /// of invalidating mutable references that unsafe code has created. pub fn len(&self) -> usize { - self.as_leaf().len as usize + // Crucially, we only access the `len` field here. There might be outstanding mutable references + // to keys/values that we must not invalidate. + unsafe { (*self.as_leaf()).len as usize } } /// Returns the height of this node in the whole tree. Zero height denotes the @@ -334,11 +336,14 @@ impl NodeRef { /// If the node is a leaf, this function simply opens up its data. /// If the node is an internal node, so not a leaf, it does have all the data a leaf has /// (header, keys and values), and this function exposes that. - fn as_leaf(&self) -> &LeafNode { + /// + /// Returns a raw ptr to avoid invalidating other references to this node + /// (such as during iteration). + fn as_leaf(&self) -> *const LeafNode { // The node must be valid for at least the LeafNode portion. // This is not a reference in the NodeRef type because we don't know if // it should be unique or shared. - unsafe { self.node.as_ref() } + self.node.as_ptr() } /// Borrows a view into the keys stored in the node. @@ -361,7 +366,7 @@ impl NodeRef { pub fn ascend( self, ) -> Result, marker::Edge>, Self> { - let parent_as_leaf = self.as_leaf().parent as *const LeafNode; + let parent_as_leaf = unsafe { (*self.as_leaf()).parent as *const LeafNode }; if let Some(non_zero) = NonNull::new(parent_as_leaf as *mut _) { Ok(Handle { node: NodeRef { @@ -370,7 +375,7 @@ impl NodeRef { root: self.root, _marker: PhantomData, }, - idx: unsafe { usize::from(*self.as_leaf().parent_idx.as_ptr()) }, + idx: unsafe { usize::from(*(*self.as_leaf()).parent_idx.as_ptr()) }, _marker: PhantomData, }) } else { @@ -475,13 +480,13 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { fn into_key_slice(self) -> &'a [K] { unsafe { - slice::from_raw_parts(MaybeUninit::slice_as_ptr(&self.as_leaf().keys), self.len()) + slice::from_raw_parts(MaybeUninit::slice_as_ptr(&(*self.as_leaf()).keys), self.len()) } } fn into_val_slice(self) -> &'a [V] { unsafe { - slice::from_raw_parts(MaybeUninit::slice_as_ptr(&self.as_leaf().vals), self.len()) + slice::from_raw_parts(MaybeUninit::slice_as_ptr(&(*self.as_leaf()).vals), self.len()) } } } From 8158d5623eb565c6354b6dda987efe3c384c41c5 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Sun, 16 Aug 2020 19:07:30 +0200 Subject: [PATCH 0210/1052] BTreeMap: avoid aliasing by avoiding slices --- library/alloc/src/collections/btree/map.rs | 4 +- .../alloc/src/collections/btree/map/tests.rs | 15 +- .../alloc/src/collections/btree/navigate.rs | 8 +- library/alloc/src/collections/btree/node.rs | 337 ++++++++++-------- library/alloc/src/collections/btree/search.rs | 6 +- library/alloc/src/lib.rs | 1 + 6 files changed, 204 insertions(+), 167 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 92f02fb60168b..674cdaaa012d9 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -2796,8 +2796,8 @@ enum UnderflowResult<'a, K, V> { Stole(bool), } -fn handle_underfull_node( - node: NodeRef, K, V, marker::LeafOrInternal>, +fn handle_underfull_node<'a, K: 'a, V: 'a>( + node: NodeRef, K, V, marker::LeafOrInternal>, ) -> UnderflowResult<'_, K, V> { let parent = match node.ascend() { Ok(parent) => parent, diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index eb8d86b9693fd..af5cf7d7d875c 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -77,7 +77,8 @@ impl<'a, K: 'a, V: 'a> BTreeMap { let min_len = if is_root { 0 } else { node::MIN_LEN }; assert!(node.len() >= min_len, "{} < {}", node.len(), min_len); - for &key in node.keys() { + for idx in 0..node.len() { + let key = *unsafe { node.key_at(idx) }; checker.is_ascending(key); } leaf_length += node.len(); @@ -120,7 +121,13 @@ impl<'a, K: 'a, V: 'a> BTreeMap { Position::Leaf(leaf) => { let depth = root_node.height(); let indent = " ".repeat(depth); - result += &format!("\n{}{:?}", indent, leaf.keys()) + result += &format!("\n{}", indent); + for idx in 0..leaf.len() { + if idx > 0 { + result += ", "; + } + result += &format!("{:?}", unsafe { leaf.key_at(idx) }); + } } Position::Internal(_) => {} Position::InternalKV(kv) => { @@ -432,7 +439,6 @@ fn test_iter_mut_mutation() { } #[test] -#[cfg_attr(miri, ignore)] // FIXME: fails in Miri fn test_values_mut() { let mut a: BTreeMap<_, _> = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i)).collect(); test_all_refs(&mut 13, a.values_mut()); @@ -455,7 +461,6 @@ fn test_values_mut_mutation() { } #[test] -#[cfg_attr(miri, ignore)] // FIXME: fails in Miri fn test_iter_entering_root_twice() { let mut map: BTreeMap<_, _> = (0..2).map(|i| (i, i)).collect(); let mut it = map.iter_mut(); @@ -471,7 +476,6 @@ fn test_iter_entering_root_twice() { } #[test] -#[cfg_attr(miri, ignore)] // FIXME: fails in Miri fn test_iter_descending_to_same_node_twice() { let mut map: BTreeMap<_, _> = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i)).collect(); let mut it = map.iter_mut(); @@ -515,7 +519,6 @@ fn test_iter_mixed() { } #[test] -#[cfg_attr(miri, ignore)] // FIXME: fails in Miri fn test_iter_min_max() { let mut a = BTreeMap::new(); assert_eq!(a.iter().min(), None); diff --git a/library/alloc/src/collections/btree/navigate.rs b/library/alloc/src/collections/btree/navigate.rs index 376060b3143de..69f7ef57218df 100644 --- a/library/alloc/src/collections/btree/navigate.rs +++ b/library/alloc/src/collections/btree/navigate.rs @@ -366,7 +366,6 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Ed impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge> { /// Moves the leaf edge handle to the next leaf edge and returns references to the /// key and value in between. - /// The returned references might be invalidated when the updated handle is used again. /// /// # Safety /// There must be another KV in the direction travelled. @@ -376,14 +375,12 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::E let kv = unsafe { unwrap_unchecked(kv.ok()) }; (unsafe { ptr::read(&kv) }.next_leaf_edge(), kv) }); - // Doing the descend (and perhaps another move) invalidates the references - // returned by `into_kv_valmut`, so we have to do this last. + // Doing this last is faster, according to benchmarks. kv.into_kv_valmut() } /// Moves the leaf edge handle to the previous leaf and returns references to the /// key and value in between. - /// The returned references might be invalidated when the updated handle is used again. /// /// # Safety /// There must be another KV in the direction travelled. @@ -393,8 +390,7 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::E let kv = unsafe { unwrap_unchecked(kv.ok()) }; (unsafe { ptr::read(&kv) }.next_back_leaf_edge(), kv) }); - // Doing the descend (and perhaps another move) invalidates the references - // returned by `into_kv_valmut`, so we have to do this last. + // Doing this last is faster, according to benchmarks. kv.into_kv_valmut() } } diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index ce4a7e1bdd7da..f9de88e4c13c8 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -244,9 +244,7 @@ impl Root { ) }; self.height -= 1; - unsafe { - (*self.node_as_mut().as_leaf_mut()).parent = ptr::null(); - } + self.node_as_mut().as_leaf_mut().parent = ptr::null(); unsafe { Global.dealloc(NonNull::from(top).cast(), Layout::new::>()); @@ -298,12 +296,27 @@ unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send for NodeRef Send for NodeRef {} impl NodeRef { - fn as_internal(&self) -> &InternalNode { - unsafe { &*(self.node.as_ptr() as *mut InternalNode) } + /// Exposes the data of an internal node for reading. + /// + /// Returns a raw ptr to avoid invalidating other references to this node, + /// which is possible when BorrowType is marker::ValMut. + fn as_internal_ptr(&self) -> *const InternalNode { + self.node.as_ptr() as *const InternalNode + } +} + +impl<'a, K, V> NodeRef, K, V, marker::Internal> { + /// Exposes the data of an internal node for reading, + /// when we know we have exclusive access. + fn as_internal(&mut self) -> &InternalNode { + unsafe { &*self.as_internal_ptr() } } } impl<'a, K, V> NodeRef, K, V, marker::Internal> { + /// Exposes the data of an internal node for writing. + /// + /// We don't need to return a raw ptr because we have unique access to the entire node. fn as_internal_mut(&mut self) -> &mut InternalNode { unsafe { &mut *(self.node.as_ptr() as *mut InternalNode) } } @@ -316,9 +329,9 @@ impl NodeRef { /// Note that, despite being safe, calling this function can have the side effect /// of invalidating mutable references that unsafe code has created. pub fn len(&self) -> usize { - // Crucially, we only access the `len` field here. There might be outstanding mutable references - // to keys/values that we must not invalidate. - unsafe { (*self.as_leaf()).len as usize } + // Crucially, we only access the `len` field here. If BorrowType is marker::ValMut, + // there might be outstanding mutable references to values that we must not invalidate. + unsafe { (*self.as_leaf_ptr()).len as usize } } /// Returns the height of this node in the whole tree. Zero height denotes the @@ -337,23 +350,29 @@ impl NodeRef { /// If the node is an internal node, so not a leaf, it does have all the data a leaf has /// (header, keys and values), and this function exposes that. /// - /// Returns a raw ptr to avoid invalidating other references to this node - /// (such as during iteration). - fn as_leaf(&self) -> *const LeafNode { + /// Returns a raw ptr to avoid invalidating other references to this node, + /// which is possible when BorrowType is marker::ValMut. + fn as_leaf_ptr(&self) -> *const LeafNode { // The node must be valid for at least the LeafNode portion. // This is not a reference in the NodeRef type because we don't know if // it should be unique or shared. self.node.as_ptr() } - /// Borrows a view into the keys stored in the node. - pub fn keys(&self) -> &[K] { - self.reborrow().into_key_slice() + /// Borrows a reference to one of the keys stored in the node. + /// + /// # Safety + /// The node has more than `idx` initialized elements. + pub unsafe fn key_at(&self, idx: usize) -> &K { + unsafe { self.reborrow().into_key_at(idx) } } - /// Borrows a view into the values stored in the node. - fn vals(&self) -> &[V] { - self.reborrow().into_val_slice() + /// Borrows a reference to one of the values stored in the node. + /// + /// # Safety + /// The node has more than `idx` initialized elements. + unsafe fn val_at(&self, idx: usize) -> &V { + unsafe { self.reborrow().into_val_at(idx) } } /// Finds the parent of the current node. Returns `Ok(handle)` if the current @@ -366,7 +385,9 @@ impl NodeRef { pub fn ascend( self, ) -> Result, marker::Edge>, Self> { - let parent_as_leaf = unsafe { (*self.as_leaf()).parent as *const LeafNode }; + // We need to use raw pointers to nodes because, if BorrowType is marker::ValMut, + // there might be outstanding mutable references to values that we must not invalidate. + let parent_as_leaf = unsafe { (*self.as_leaf_ptr()).parent as *const LeafNode }; if let Some(non_zero) = NonNull::new(parent_as_leaf as *mut _) { Ok(Handle { node: NodeRef { @@ -375,7 +396,7 @@ impl NodeRef { root: self.root, _marker: PhantomData, }, - idx: unsafe { usize::from(*(*self.as_leaf()).parent_idx.as_ptr()) }, + idx: unsafe { usize::from(*(*self.as_leaf_ptr()).parent_idx.as_ptr()) }, _marker: PhantomData, }) } else { @@ -407,6 +428,15 @@ impl NodeRef { } } +impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { + /// Exposes the data of a leaf node for reading in an immutable tree. + fn into_leaf(self) -> &'a LeafNode { + // SAFETY: we can access the entire node freely and do no need raw pointers, + // because there can be no mutable references to this Immut tree. + unsafe { &(*self.as_leaf_ptr()) } + } +} + impl NodeRef { /// Similar to `ascend`, gets a reference to a node's parent node, but also /// deallocate the current node in the process. This is unsafe because the @@ -457,9 +487,9 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { /// If the node is an internal node, so not a leaf, it does have all the data a leaf has /// (header, keys and values), and this function exposes that. /// - /// Returns a raw ptr to avoid asserting exclusive access to the entire node. - fn as_leaf_mut(&mut self) -> *mut LeafNode { - self.node.as_ptr() + /// We don't need to return a raw ptr because we have unique access to the entire node. + fn as_leaf_mut(&mut self) -> &'a mut LeafNode { + unsafe { &mut (*self.node.as_ptr()) } } fn keys_mut(&mut self) -> &mut [K] { @@ -478,16 +508,16 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { } impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { - fn into_key_slice(self) -> &'a [K] { - unsafe { - slice::from_raw_parts(MaybeUninit::slice_as_ptr(&(*self.as_leaf()).keys), self.len()) - } + /// # Safety + /// The node has more than `idx` initialized elements. + unsafe fn into_key_at(self, idx: usize) -> &'a K { + unsafe { self.into_leaf().keys.get_unchecked(idx).assume_init_ref() } } - fn into_val_slice(self) -> &'a [V] { - unsafe { - slice::from_raw_parts(MaybeUninit::slice_as_ptr(&(*self.as_leaf()).vals), self.len()) - } + /// # Safety + /// The node has more than `idx` initialized elements. + unsafe fn into_val_at(self, idx: usize) -> &'a V { + unsafe { self.into_leaf().vals.get_unchecked(idx).assume_init_ref() } } } @@ -502,7 +532,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { // SAFETY: The keys of a node must always be initialized up to length. unsafe { slice::from_raw_parts_mut( - MaybeUninit::slice_as_mut_ptr(&mut (*self.as_leaf_mut()).keys), + MaybeUninit::slice_as_mut_ptr(&mut self.as_leaf_mut().keys), self.len(), ) } @@ -512,48 +542,50 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { // SAFETY: The values of a node must always be initialized up to length. unsafe { slice::from_raw_parts_mut( - MaybeUninit::slice_as_mut_ptr(&mut (*self.as_leaf_mut()).vals), + MaybeUninit::slice_as_mut_ptr(&mut self.as_leaf_mut().vals), self.len(), ) } } - fn into_slices_mut(mut self) -> (&'a mut [K], &'a mut [V]) { - // We cannot use the getters here, because calling the second one - // invalidates the reference returned by the first. - // More precisely, it is the call to `len` that is the culprit, - // because that creates a shared reference to the header, which *can* - // overlap with the keys (and even the values, for ZST keys). - let len = self.len(); + /// # Safety + /// The node has more than `idx` initialized elements. + unsafe fn into_key_mut_at(mut self, idx: usize) -> &'a mut K { + debug_assert!(idx < self.len()); + let leaf = self.as_leaf_mut(); - // SAFETY: The keys and values of a node must always be initialized up to length. - let keys = unsafe { - slice::from_raw_parts_mut(MaybeUninit::slice_as_mut_ptr(&mut (*leaf).keys), len) - }; - let vals = unsafe { - slice::from_raw_parts_mut(MaybeUninit::slice_as_mut_ptr(&mut (*leaf).vals), len) - }; - (keys, vals) + unsafe { leaf.keys.get_unchecked_mut(idx).assume_init_mut() } + } + + /// # Safety + /// The node has more than `idx` initialized elements. + unsafe fn into_val_mut_at(mut self, idx: usize) -> &'a mut V { + debug_assert!(idx < self.len()); + + let leaf = self.as_leaf_mut(); + unsafe { leaf.vals.get_unchecked_mut(idx).assume_init_mut() } } } -impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { - /// Same as the marker::Mut method, but far more dangerous because ValMut-based iterators: - /// - have front and back handles often refering to the same node, so `self` is not unique; - /// - hand out mutable references to parts of these slices to the public. - fn into_slices_mut(self) -> (&'a [K], &'a mut [V]) { - let len = self.len(); +impl<'a, K, V, Type> NodeRef, K, V, Type> { + /// # Safety + /// The node has more than `idx` initialized elements. + unsafe fn into_key_val_mut_at(self, idx: usize) -> (&'a K, &'a mut V) { + // We only create a reference to the one element we are interested in, + // to avoid aliasing with outstanding references to other elements, + // in particular, those returned to the caller in earlier iterations. let leaf = self.node.as_ptr(); + // We must coerce to unsized array pointers because of Rust issue #74679. + let keys: *const [_] = unsafe { &raw const (*leaf).keys }; + let vals: *mut [_] = unsafe { &raw mut (*leaf).vals }; // SAFETY: The keys and values of a node must always be initialized up to length. - let keys = unsafe { slice::from_raw_parts(MaybeUninit::slice_as_ptr(&(*leaf).keys), len) }; - let vals = unsafe { - slice::from_raw_parts_mut(MaybeUninit::slice_as_mut_ptr(&mut (*leaf).vals), len) - }; - (keys, vals) + let key = unsafe { (&*keys.get_unchecked(idx)).assume_init_ref() }; + let val = unsafe { (&mut *vals.get_unchecked_mut(idx)).assume_init_mut() }; + (key, val) } } -impl<'a, K, V> NodeRef, K, V, marker::Leaf> { +impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Leaf> { /// Adds a key/value pair to the end of the node. pub fn push(&mut self, key: K, val: V) { assert!(self.len() < CAPACITY); @@ -563,9 +595,8 @@ impl<'a, K, V> NodeRef, K, V, marker::Leaf> { unsafe { ptr::write(self.keys_mut().get_unchecked_mut(idx), key); ptr::write(self.vals_mut().get_unchecked_mut(idx), val); - - (*self.as_leaf_mut()).len += 1; } + self.as_leaf_mut().len += 1; } /// Adds a key/value pair to the beginning of the node. @@ -575,13 +606,29 @@ impl<'a, K, V> NodeRef, K, V, marker::Leaf> { unsafe { slice_insert(self.keys_mut(), 0, key); slice_insert(self.vals_mut(), 0, val); - - (*self.as_leaf_mut()).len += 1; } + self.as_leaf_mut().len += 1; } } impl<'a, K, V> NodeRef, K, V, marker::Internal> { + /// # Safety + /// 'first' and 'after_last' must be in range. + unsafe fn correct_childrens_parent_links(&mut self, first: usize, after_last: usize) { + debug_assert!(first <= self.len()); + debug_assert!(after_last <= self.len() + 1); + for i in first..after_last { + unsafe { Handle::new_edge(self.reborrow_mut(), i) }.correct_parent_link(); + } + } + + fn correct_all_childrens_parent_links(&mut self) { + let len = self.len(); + unsafe { self.correct_childrens_parent_links(0, len + 1) }; + } +} + +impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { /// Adds a key/value pair and an edge to go to the right of that pair to /// the end of the node. pub fn push(&mut self, key: K, val: V, edge: Root) { @@ -595,26 +642,12 @@ impl<'a, K, V> NodeRef, K, V, marker::Internal> { ptr::write(self.vals_mut().get_unchecked_mut(idx), val); self.as_internal_mut().edges.get_unchecked_mut(idx + 1).write(edge.node); - (*self.as_leaf_mut()).len += 1; + self.as_leaf_mut().len += 1; Handle::new_edge(self.reborrow_mut(), idx + 1).correct_parent_link(); } } - // Unsafe because 'first' and 'after_last' must be in range - unsafe fn correct_childrens_parent_links(&mut self, first: usize, after_last: usize) { - debug_assert!(first <= self.len()); - debug_assert!(after_last <= self.len() + 1); - for i in first..after_last { - unsafe { Handle::new_edge(self.reborrow_mut(), i) }.correct_parent_link(); - } - } - - fn correct_all_childrens_parent_links(&mut self) { - let len = self.len(); - unsafe { self.correct_childrens_parent_links(0, len + 1) }; - } - /// Adds a key/value pair and an edge to go to the left of that pair to /// the beginning of the node. pub fn push_front(&mut self, key: K, val: V, edge: Root) { @@ -632,15 +665,15 @@ impl<'a, K, V> NodeRef, K, V, marker::Internal> { 0, edge.node, ); + } - (*self.as_leaf_mut()).len += 1; + self.as_leaf_mut().len += 1; - self.correct_all_childrens_parent_links(); - } + self.correct_all_childrens_parent_links(); } } -impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { +impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { /// Removes a key/value pair from the end of this node and returns the pair. /// If this is an internal node, also removes the edge that was to the right /// of that pair and returns the orphaned node that this edge owned with its @@ -651,20 +684,20 @@ impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { let idx = self.len() - 1; unsafe { - let key = ptr::read(self.keys().get_unchecked(idx)); - let val = ptr::read(self.vals().get_unchecked(idx)); + let key = ptr::read(self.key_at(idx)); + let val = ptr::read(self.val_at(idx)); let edge = match self.reborrow_mut().force() { ForceResult::Leaf(_) => None, - ForceResult::Internal(internal) => { + ForceResult::Internal(mut internal) => { let edge = ptr::read(internal.as_internal().edges.get_unchecked(idx + 1).as_ptr()); let mut new_root = Root { node: edge, height: internal.height - 1 }; - (*new_root.node_as_mut().as_leaf_mut()).parent = ptr::null(); + new_root.node_as_mut().as_leaf_mut().parent = ptr::null(); Some(new_root) } }; - (*self.as_leaf_mut()).len -= 1; + self.as_leaf_mut().len -= 1; (key, val, edge) } } @@ -691,7 +724,7 @@ impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { ); let mut new_root = Root { node: edge, height: internal.height - 1 }; - (*new_root.node_as_mut().as_leaf_mut()).parent = ptr::null(); + new_root.node_as_mut().as_leaf_mut().parent = ptr::null(); for i in 0..old_len { Handle::new_edge(internal.reborrow_mut(), i).correct_parent_link(); @@ -701,7 +734,7 @@ impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { } }; - (*self.as_leaf_mut()).len -= 1; + self.as_leaf_mut().len -= 1; (key, val, edge) } @@ -883,7 +916,7 @@ fn splitpoint(edge_idx: usize) -> (usize, InsertionPlace) { } } -impl<'a, K, V, NodeType> Handle, K, V, NodeType>, marker::Edge> { +impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::Edge> { /// Helps implementations of `insert_fit` for a particular `NodeType`, /// by taking care of leaf data. /// Inserts a new key/value pair between the key/value pairs to the right and left of @@ -897,12 +930,12 @@ impl<'a, K, V, NodeType> Handle, K, V, NodeType>, marker slice_insert(self.node.keys_mut(), self.idx, key); slice_insert(self.node.vals_mut(), self.idx, val); - (*self.node.as_leaf_mut()).len += 1; + self.node.as_leaf_mut().len += 1; } } } -impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge> { +impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, marker::Edge> { /// Inserts a new key/value pair between the key/value pairs to the right and left of /// this edge. This method assumes that there is enough space in the node for the new /// pair to fit. @@ -914,7 +947,7 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge } } -impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge> { +impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, marker::Edge> { /// Inserts a new key/value pair between the key/value pairs to the right and left of /// this edge. This method splits the node if there isn't enough room. /// @@ -952,12 +985,12 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: let idx = self.idx as u16; let ptr = self.node.as_internal_mut() as *mut _; let mut child = self.descend(); - unsafe { - (*child.as_leaf_mut()).parent = ptr; - (*child.as_leaf_mut()).parent_idx.write(idx); - } + child.as_leaf_mut().parent = ptr; + child.as_leaf_mut().parent_idx.write(idx); } +} +impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, marker::Edge> { /// Inserts a new key/value pair and an edge that will go to the right of that new pair /// between this edge and the key/value pair to the right of this edge. This method assumes /// that there is enough space in the node for the new pair to fit. @@ -1020,7 +1053,7 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: } } -impl<'a, K: 'a, V> Handle, K, V, marker::Leaf>, marker::Edge> { +impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, marker::Edge> { /// Inserts a new key/value pair between the key/value pairs to the right and left of /// this edge. This method splits the node if there isn't enough room, and tries to /// insert the split off portion into the parent node recursively, until the root is reached. @@ -1062,11 +1095,17 @@ impl Handle, marke /// `edge.descend().ascend().unwrap()` and `node.ascend().unwrap().descend()` should /// both, upon success, do nothing. pub fn descend(self) -> NodeRef { + // We need to use raw pointers to nodes because, if BorrowType is + // marker::ValMut, there might be outstanding mutable references to + // values that we must not invalidate. There's no worry accessing the + // height field because that value is copied. Beware that, once the + // node pointer is dereferenced, we access the edges array with a + // reference (Rust issue #73987) and invalidate any other references + // to or inside the array, should any be around. + let internal_node = self.node.as_internal_ptr(); NodeRef { height: self.node.height - 1, - node: unsafe { - (&*self.node.as_internal().edges.get_unchecked(self.idx).as_ptr()).as_ptr() - }, + node: unsafe { (&*(*internal_node).edges.get_unchecked(self.idx).as_ptr()).as_ptr() }, root: self.node.root, _marker: PhantomData, } @@ -1075,71 +1114,66 @@ impl Handle, marke impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::KV> { pub fn into_kv(self) -> (&'a K, &'a V) { - let keys = self.node.into_key_slice(); - let vals = self.node.into_val_slice(); - unsafe { (keys.get_unchecked(self.idx), vals.get_unchecked(self.idx)) } + (unsafe { self.node.into_key_at(self.idx) }, unsafe { self.node.into_val_at(self.idx) }) } } impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::KV> { pub fn into_key_mut(self) -> &'a mut K { - let keys = self.node.into_key_slice_mut(); - unsafe { keys.get_unchecked_mut(self.idx) } + unsafe { self.node.into_key_mut_at(self.idx) } } pub fn into_val_mut(self) -> &'a mut V { - let vals = self.node.into_val_slice_mut(); - unsafe { vals.get_unchecked_mut(self.idx) } + unsafe { self.node.into_val_mut_at(self.idx) } } } impl<'a, K, V, NodeType> Handle, K, V, NodeType>, marker::KV> { pub fn into_kv_valmut(self) -> (&'a K, &'a mut V) { - unsafe { - let (keys, vals) = self.node.into_slices_mut(); - (keys.get_unchecked(self.idx), vals.get_unchecked_mut(self.idx)) - } + unsafe { self.node.into_key_val_mut_at(self.idx) } } } -impl<'a, K, V, NodeType> Handle, K, V, NodeType>, marker::KV> { +impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::KV> { pub fn kv_mut(&mut self) -> (&mut K, &mut V) { - unsafe { - let (keys, vals) = self.node.reborrow_mut().into_slices_mut(); - (keys.get_unchecked_mut(self.idx), vals.get_unchecked_mut(self.idx)) - } + // We cannot call into_key_mut_at and into_val_mut_at, because calling the second one + // invalidates the reference returned by the first. + let leaf = self.node.as_leaf_mut(); + let key = unsafe { leaf.keys.get_unchecked_mut(self.idx).assume_init_mut() }; + let val = unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() }; + (key, val) } } -impl<'a, K, V, NodeType> Handle, K, V, NodeType>, marker::KV> { +impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::KV> { /// Helps implementations of `split` for a particular `NodeType`, /// by taking care of leaf data. fn leafy_split(&mut self, new_node: &mut LeafNode) -> (K, V, usize) { unsafe { - let k = ptr::read(self.node.keys().get_unchecked(self.idx)); - let v = ptr::read(self.node.vals().get_unchecked(self.idx)); + let k = ptr::read(self.node.key_at(self.idx)); + let v = ptr::read(self.node.val_at(self.idx)); let new_len = self.node.len() - self.idx - 1; ptr::copy_nonoverlapping( - self.node.keys().as_ptr().add(self.idx + 1), + self.node.key_at(self.idx + 1), new_node.keys.as_mut_ptr() as *mut K, new_len, ); ptr::copy_nonoverlapping( - self.node.vals().as_ptr().add(self.idx + 1), + self.node.val_at(self.idx + 1), new_node.vals.as_mut_ptr() as *mut V, new_len, ); - (*self.node.as_leaf_mut()).len = self.idx as u16; + self.node.as_leaf_mut().len = self.idx as u16; new_node.len = new_len as u16; (k, v, new_len) } } } -impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::KV> { +impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, marker::KV> { /// Splits the underlying node into three parts: /// /// - The node is truncated to only contain the key/value pairs to the right of @@ -1165,13 +1199,25 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::KV> unsafe { let k = slice_remove(self.node.keys_mut(), self.idx); let v = slice_remove(self.node.vals_mut(), self.idx); - (*self.node.as_leaf_mut()).len -= 1; + self.node.as_leaf_mut().len -= 1; ((k, v), self.left_edge()) } } } impl<'a, K, V> Handle, K, V, marker::Internal>, marker::KV> { + /// Returns `true` if it is valid to call `.merge()`, i.e., whether there is enough room in + /// a node to hold the combination of the nodes to the left and right of this handle along + /// with the key/value pair at this handle. + pub fn can_merge(&self) -> bool { + (self.reborrow().left_edge().descend().len() + + self.reborrow().right_edge().descend().len() + + 1) + <= CAPACITY + } +} + +impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, marker::KV> { /// Splits the underlying node into three parts: /// /// - The node is truncated to only contain the edges and key/value pairs to the @@ -1185,9 +1231,10 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: let (k, v, new_len) = self.leafy_split(&mut new_node.data); let height = self.node.height; + let old_node = &*self.node.as_internal_ptr(); ptr::copy_nonoverlapping( - self.node.as_internal().edges.as_ptr().add(self.idx + 1), + old_node.edges.as_ptr().add(self.idx + 1), new_node.edges.as_mut_ptr(), new_len + 1, ); @@ -1202,16 +1249,6 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: } } - /// Returns `true` if it is valid to call `.merge()`, i.e., whether there is enough room in - /// a node to hold the combination of the nodes to the left and right of this handle along - /// with the key/value pair at this handle. - pub fn can_merge(&self) -> bool { - (self.reborrow().left_edge().descend().len() - + self.reborrow().right_edge().descend().len() - + 1) - <= CAPACITY - } - /// Combines the node immediately to the left of this handle, the key/value pair pointed /// to by this handle, and the node immediately to the right of this handle into one new /// child of the underlying node, returning an edge referencing that new child. @@ -1235,7 +1272,7 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: slice_remove(self.node.keys_mut(), self.idx), ); ptr::copy_nonoverlapping( - right_node.keys().as_ptr(), + right_node.key_at(0), left_node.keys_mut().as_mut_ptr().add(left_len + 1), right_len, ); @@ -1244,7 +1281,7 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: slice_remove(self.node.vals_mut(), self.idx), ); ptr::copy_nonoverlapping( - right_node.vals().as_ptr(), + right_node.val_at(0), left_node.vals_mut().as_mut_ptr().add(left_len + 1), right_len, ); @@ -1253,18 +1290,18 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: for i in self.idx + 1..self.node.len() { Handle::new_edge(self.node.reborrow_mut(), i).correct_parent_link(); } - (*self.node.as_leaf_mut()).len -= 1; + self.node.as_leaf_mut().len -= 1; - (*left_node.as_leaf_mut()).len += right_len as u16 + 1; + left_node.as_leaf_mut().len += right_len as u16 + 1; if self.node.height > 1 { // SAFETY: the height of the nodes being merged is one below the height // of the node of this edge, thus above zero, so they are internal. let mut left_node = left_node.cast_unchecked(); - let right_node = right_node.cast_unchecked(); + let mut right_node = right_node.cast_unchecked(); ptr::copy_nonoverlapping( - right_node.reborrow().as_internal().edges.as_ptr(), - left_node.reborrow_mut().as_internal_mut().edges.as_mut_ptr().add(left_len + 1), + right_node.as_internal().edges.as_ptr(), + left_node.as_internal_mut().edges.as_mut_ptr().add(left_len + 1), right_len + 1, ); @@ -1352,8 +1389,8 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: move_kv(left_kv, new_left_len, parent_kv, 0, 1); } - (*left_node.reborrow_mut().as_leaf_mut()).len -= count as u16; - (*right_node.reborrow_mut().as_leaf_mut()).len += count as u16; + left_node.as_leaf_mut().len -= count as u16; + right_node.as_leaf_mut().len += count as u16; match (left_node.force(), right_node.force()) { (ForceResult::Internal(left), ForceResult::Internal(mut right)) => { @@ -1409,8 +1446,8 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: ptr::copy(right_kv.1.add(count), right_kv.1, new_right_len); } - (*left_node.reborrow_mut().as_leaf_mut()).len += count as u16; - (*right_node.reborrow_mut().as_leaf_mut()).len -= count as u16; + left_node.as_leaf_mut().len += count as u16; + right_node.as_leaf_mut().len -= count as u16; match (left_node.force(), right_node.force()) { (ForceResult::Internal(left), ForceResult::Internal(mut right)) => { @@ -1451,7 +1488,7 @@ unsafe fn move_edges( dest_offset: usize, count: usize, ) { - let source_ptr = source.as_internal_mut().edges.as_mut_ptr(); + let source_ptr = source.as_internal().edges.as_ptr(); let dest_ptr = dest.as_internal_mut().edges.as_mut_ptr(); unsafe { ptr::copy_nonoverlapping(source_ptr.add(source_offset), dest_ptr.add(dest_offset), count); @@ -1549,8 +1586,8 @@ impl<'a, K, V> Handle, K, V, marker::LeafOrInternal>, ma move_kv(left_kv, left_new_len, right_kv, 0, right_new_len); - (*left_node.reborrow_mut().as_leaf_mut()).len = left_new_len as u16; - (*right_node.reborrow_mut().as_leaf_mut()).len = right_new_len as u16; + left_node.as_leaf_mut().len = left_new_len as u16; + right_node.as_leaf_mut().len = right_new_len as u16; match (left_node.force(), right_node.force()) { (ForceResult::Internal(left), ForceResult::Internal(right)) => { diff --git a/library/alloc/src/collections/btree/search.rs b/library/alloc/src/collections/btree/search.rs index 4e80f7f21ebff..1526c0673c691 100644 --- a/library/alloc/src/collections/btree/search.rs +++ b/library/alloc/src/collections/btree/search.rs @@ -68,11 +68,11 @@ where K: Borrow, { // This function is defined over all borrow types (immutable, mutable, owned). - // Using `keys()` is fine here even if BorrowType is mutable, as all we return + // Using `keys_at()` is fine here even if BorrowType is mutable, as all we return // is an index -- not a reference. let len = node.len(); - let keys = node.keys(); - for (i, k) in keys.iter().enumerate() { + for i in 0..len { + let k = unsafe { node.key_at(i) }; match key.cmp(k.borrow()) { Ordering::Greater => {} Ordering::Equal => return (i, true), diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 2ced10831e75c..48313f9af98e6 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -106,6 +106,7 @@ #![feature(libc)] #![feature(map_first_last)] #![feature(map_into_keys_values)] +#![feature(maybe_uninit_ref)] #![feature(negative_impls)] #![feature(never_type)] #![feature(new_uninit)] From a06edda3ad9abd4f07d07bbe46cb488efeebbbd0 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 9 Sep 2020 10:16:03 -0400 Subject: [PATCH 0211/1052] Fix segfault if pthread_getattr_np fails glibc destroys[1] the passed pthread_attr_t if pthread_getattr_np() fails. Destroying it again leads to a segfault. Fix it by only destroying it on success for glibc. [1]: https://sourceware.org/git/?p=glibc.git;a=blob;f=nptl/pthread_getattr_np.c;h=ce437205e41dc05653e435f6188768cccdd91c99;hb=HEAD#l205 --- library/std/src/sys/unix/thread.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 04da9812ddc45..569aedd741192 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -305,7 +305,9 @@ pub mod guard { assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0); ret = Some(stackaddr); } - assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); + if e == 0 || cfg!(not(target_env = "gnu")) { + assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); + } ret } @@ -446,7 +448,9 @@ pub mod guard { Some(stackaddr..stackaddr + guardsize) }; } - assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); + if e == 0 || cfg!(not(target_env = "gnu")) { + assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); + } ret } } From be28b6235e64e0f662b96b710bf3af9de169215c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Wed, 9 Sep 2020 16:32:55 +0200 Subject: [PATCH 0212/1052] remove redundant clones (clippy::redundant_clone) --- compiler/rustc_resolve/src/late/diagnostics.rs | 2 +- compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 8cb6b6553ffe0..a10754f2c0c78 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1387,7 +1387,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { } } } - introduce_suggestion.push((*for_span, for_sugg.to_string())); + introduce_suggestion.push((*for_span, for_sugg)); introduce_suggestion.push((span, formatter(<_name))); err.multipart_suggestion(&msg, introduce_suggestion, Applicability::MaybeIncorrect); } diff --git a/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs b/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs index fd55a0fc6a15e..fcb2af0005f28 100644 --- a/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs +++ b/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs @@ -22,7 +22,7 @@ pub fn opts() -> TargetOptions { "-lmingw32".to_string(), ]; late_link_args.insert(LinkerFlavor::Gcc, mingw_libs.clone()); - late_link_args.insert(LinkerFlavor::Lld(LldFlavor::Ld), mingw_libs.clone()); + late_link_args.insert(LinkerFlavor::Lld(LldFlavor::Ld), mingw_libs); TargetOptions { executables: false, From 4db10297c1dcd2fc368bd61a24aa0291a6b6c61a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Wed, 9 Sep 2020 16:53:45 +0200 Subject: [PATCH 0213/1052] link to the Box docs in related lint documentation. --- clippy_lints/src/types.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index c82deaa43b266..550ae2927a828 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -37,6 +37,7 @@ use crate::utils::{ declare_clippy_lint! { /// **What it does:** Checks for use of `Box>` anywhere in the code. + /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. /// /// **Why is this bad?** `Vec` already keeps its contents in a separate area on /// the heap. So if you `Box` it, you just add another level of indirection @@ -65,6 +66,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** Checks for use of `Vec>` where T: Sized anywhere in the code. + /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. /// /// **Why is this bad?** `Vec` already keeps its contents in a separate area on /// the heap. So if you `Box` its contents, you just add another level of indirection. @@ -167,6 +169,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** Checks for use of `&Box` anywhere in the code. + /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. /// /// **Why is this bad?** Any `&Box` can also be a `&T`, which is more /// general. From 001640507374be965d1bfc3def758752464a474f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Wed, 9 Sep 2020 00:00:00 +0000 Subject: [PATCH 0214/1052] Remove unused PlaceContext::NonUse(NonUseContext::Coverage) --- compiler/rustc_middle/src/mir/visit.rs | 2 -- compiler/rustc_mir/src/borrow_check/def_use.rs | 3 +-- compiler/rustc_mir/src/dataflow/impls/init_locals.rs | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 6515ae31b46ff..a008bd5f75fa0 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -1150,8 +1150,6 @@ pub enum NonUseContext { StorageDead, /// User type annotation assertions for NLL. AscribeUserTy, - /// Coverage code region and counter metadata. - Coverage, /// The data of an user variable, for debug info. VarDebugInfo, } diff --git a/compiler/rustc_mir/src/borrow_check/def_use.rs b/compiler/rustc_mir/src/borrow_check/def_use.rs index 6574e584406f0..689ec249a2fb4 100644 --- a/compiler/rustc_mir/src/borrow_check/def_use.rs +++ b/compiler/rustc_mir/src/borrow_check/def_use.rs @@ -72,8 +72,7 @@ pub fn categorize(context: PlaceContext) -> Option { PlaceContext::MutatingUse(MutatingUseContext::Drop) => Some(DefUse::Drop), - // Coverage and debug info are neither def nor use. - PlaceContext::NonUse(NonUseContext::Coverage) | + // Debug info is neither def nor use. PlaceContext::NonUse(NonUseContext::VarDebugInfo) => None, } } diff --git a/compiler/rustc_mir/src/dataflow/impls/init_locals.rs b/compiler/rustc_mir/src/dataflow/impls/init_locals.rs index 5da302cd1fd4a..bb7292cd0337a 100644 --- a/compiler/rustc_mir/src/dataflow/impls/init_locals.rs +++ b/compiler/rustc_mir/src/dataflow/impls/init_locals.rs @@ -97,7 +97,6 @@ where PlaceContext::NonUse( NonUseContext::StorageLive | NonUseContext::AscribeUserTy - | NonUseContext::Coverage | NonUseContext::VarDebugInfo, ) | PlaceContext::NonMutatingUse( From a684153f2920729f9fc3ea27ddb77d7cc3543214 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 9 Sep 2020 11:10:43 -0400 Subject: [PATCH 0215/1052] Only call pthread_attr_destroy() after getattr_np() succeeds on all libcs The calling convention of pthread_getattr_np() is to initialize the pthread_attr_t, so _destroy() is only necessary on success (and _init() isn't necessary beforehand). On the other hand, FreeBSD wants the attr_t to be initialized before pthread_attr_get_np(), and therefore it should always be destroyed afterwards. --- library/std/src/sys/unix/thread.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 569aedd741192..652219e28f6e0 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -294,6 +294,7 @@ pub mod guard { unsafe fn get_stack_start() -> Option<*mut libc::c_void> { let mut ret = None; let mut attr: libc::pthread_attr_t = crate::mem::zeroed(); + #[cfg(target_os = "freebsd")] assert_eq!(libc::pthread_attr_init(&mut attr), 0); #[cfg(target_os = "freebsd")] let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr); @@ -305,7 +306,7 @@ pub mod guard { assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0); ret = Some(stackaddr); } - if e == 0 || cfg!(not(target_env = "gnu")) { + if e == 0 || cfg!(target_os = "freebsd") { assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); } ret @@ -405,6 +406,7 @@ pub mod guard { pub unsafe fn current() -> Option { let mut ret = None; let mut attr: libc::pthread_attr_t = crate::mem::zeroed(); + #[cfg(target_os = "freebsd")] assert_eq!(libc::pthread_attr_init(&mut attr), 0); #[cfg(target_os = "freebsd")] let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr); @@ -448,7 +450,7 @@ pub mod guard { Some(stackaddr..stackaddr + guardsize) }; } - if e == 0 || cfg!(not(target_env = "gnu")) { + if e == 0 || cfg!(target_os = "freebsd") { assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); } ret From daa62d9081bfeeb0f438f88eb69082c227a5c221 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 9 Sep 2020 17:40:15 +0200 Subject: [PATCH 0216/1052] Add as_str() and AsRef to string::Drain. --- library/alloc/src/string.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index e1724bf3c9a90..d27dd9c93402c 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2462,6 +2462,32 @@ impl Drop for Drain<'_> { } } +impl<'a> Drain<'a> { + /// Returns the remaining (sub)string of this iterator as a slice. + /// + /// # Examples + /// + /// ``` + /// #![feature(string_drain_as_str)] + /// let mut s = String::from("abc"); + /// let mut drain = s.drain(..); + /// assert_eq!(drain.as_str(), "abc"); + /// let _ = drain.next().unwrap(); + /// assert_eq!(drain.as_str(), "bc"); + /// ``` + #[unstable(feature = "string_drain_as_str", issue = "none")] + pub fn as_str(&self) -> &str { + self.iter.as_str() + } +} + +#[unstable(feature = "string_drain_as_str", issue = "none")] +impl<'a> AsRef for Drain<'a> { + fn as_ref(&self) -> &str { + self.as_str() + } +} + #[stable(feature = "drain", since = "1.6.0")] impl Iterator for Drain<'_> { type Item = char; From 673284058b53992cfd66c04b9db8e551a0dc9996 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 9 Sep 2020 17:40:44 +0200 Subject: [PATCH 0217/1052] Show remaining data in string::Drain's Debug impl. --- library/alloc/src/string.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index d27dd9c93402c..14ffd06e9bdfd 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2439,7 +2439,7 @@ pub struct Drain<'a> { #[stable(feature = "collection_debug", since = "1.17.0")] impl fmt::Debug for Drain<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Drain { .. }") + f.debug_tuple("Drain").field(&self.as_str()).finish() } } From de195f2d3d3a2039cb8c4141aa37d060780beaa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Wed, 9 Sep 2020 17:59:13 +0200 Subject: [PATCH 0218/1052] print the unit type `()` in related lint messages. --- clippy_lints/src/map_unit_fn.rs | 6 ++-- tests/ui/option_map_unit_fn_fixable.stderr | 36 ++++++++++---------- tests/ui/result_map_unit_fn_fixable.stderr | 34 +++++++++--------- tests/ui/result_map_unit_fn_unfixable.stderr | 12 +++---- 4 files changed, 44 insertions(+), 44 deletions(-) diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 1f9ae8c931a1e..076ef235b8bd8 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -9,7 +9,7 @@ use rustc_span::source_map::Span; declare_clippy_lint! { /// **What it does:** Checks for usage of `option.map(f)` where f is a function - /// or closure that returns the unit type. + /// or closure that returns the unit type `()`. /// /// **Why is this bad?** Readability, this can be written more clearly with /// an if let statement @@ -51,7 +51,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** Checks for usage of `result.map(f)` where f is a function - /// or closure that returns the unit type. + /// or closure that returns the unit type `()`. /// /// **Why is this bad?** Readability, this can be written more clearly with /// an if let statement @@ -197,7 +197,7 @@ fn let_binding_name(cx: &LateContext<'_>, var_arg: &hir::Expr<'_>) -> String { #[must_use] fn suggestion_msg(function_type: &str, map_type: &str) -> String { format!( - "called `map(f)` on an `{0}` value where `f` is a {1} that returns the unit type", + "called `map(f)` on an `{0}` value where `f` is a {1} that returns the unit type `()`", map_type, function_type ) } diff --git a/tests/ui/option_map_unit_fn_fixable.stderr b/tests/ui/option_map_unit_fn_fixable.stderr index 1312c70b6d592..d7d45ef9b0b33 100644 --- a/tests/ui/option_map_unit_fn_fixable.stderr +++ b/tests/ui/option_map_unit_fn_fixable.stderr @@ -1,4 +1,4 @@ -error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type +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 | LL | x.field.map(do_nothing); @@ -8,7 +8,7 @@ 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 +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 | LL | x.field.map(do_nothing); @@ -16,7 +16,7 @@ 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 +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 | LL | x.field.map(diverge); @@ -24,7 +24,7 @@ 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 +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 | LL | x.field.map(|value| x.do_option_nothing(value + captured)); @@ -32,7 +32,7 @@ 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 +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 | LL | x.field.map(|value| { x.do_option_plus_one(value + captured); }); @@ -40,7 +40,7 @@ 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 +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 | LL | x.field.map(|value| do_nothing(value + captured)); @@ -48,7 +48,7 @@ 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 +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 | LL | x.field.map(|value| { do_nothing(value + captured) }); @@ -56,7 +56,7 @@ 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 +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 | LL | x.field.map(|value| { do_nothing(value + captured); }); @@ -64,7 +64,7 @@ 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 +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 | LL | x.field.map(|value| { { do_nothing(value + captured); } }); @@ -72,7 +72,7 @@ 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 +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 | LL | x.field.map(|value| diverge(value + captured)); @@ -80,7 +80,7 @@ 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 +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 | LL | x.field.map(|value| { diverge(value + captured) }); @@ -88,7 +88,7 @@ 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 +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 | LL | x.field.map(|value| { diverge(value + captured); }); @@ -96,7 +96,7 @@ 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 +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 | LL | x.field.map(|value| { { diverge(value + captured); } }); @@ -104,7 +104,7 @@ 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 +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 | LL | x.field.map(|value| { let y = plus_one(value + captured); }); @@ -112,7 +112,7 @@ 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 +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 | LL | x.field.map(|value| { plus_one(value + captured); }); @@ -120,7 +120,7 @@ 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 +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 | LL | x.field.map(|value| { { plus_one(value + captured); } }); @@ -128,7 +128,7 @@ 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 +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 | LL | x.field.map(|ref value| { do_nothing(value + captured) }); @@ -136,7 +136,7 @@ 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 +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 | LL | option().map(do_nothing);} diff --git a/tests/ui/result_map_unit_fn_fixable.stderr b/tests/ui/result_map_unit_fn_fixable.stderr index 467e00263cd3a..4f3a8c6b79239 100644 --- a/tests/ui/result_map_unit_fn_fixable.stderr +++ b/tests/ui/result_map_unit_fn_fixable.stderr @@ -1,4 +1,4 @@ -error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:35:5 | LL | x.field.map(do_nothing); @@ -8,7 +8,7 @@ LL | x.field.map(do_nothing); | = note: `-D clippy::result-map-unit-fn` implied by `-D warnings` -error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:37:5 | LL | x.field.map(do_nothing); @@ -16,7 +16,7 @@ LL | x.field.map(do_nothing); | | | help: try this: `if let Ok(x_field) = x.field { do_nothing(x_field) }` -error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:39:5 | LL | x.field.map(diverge); @@ -24,7 +24,7 @@ LL | x.field.map(diverge); | | | help: try this: `if let Ok(x_field) = x.field { diverge(x_field) }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:45:5 | LL | x.field.map(|value| x.do_result_nothing(value + captured)); @@ -32,7 +32,7 @@ LL | x.field.map(|value| x.do_result_nothing(value + captured)); | | | help: try this: `if let Ok(value) = x.field { x.do_result_nothing(value + captured) }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:47:5 | LL | x.field.map(|value| { x.do_result_plus_one(value + captured); }); @@ -40,7 +40,7 @@ LL | x.field.map(|value| { x.do_result_plus_one(value + captured); }); | | | help: try this: `if let Ok(value) = x.field { x.do_result_plus_one(value + captured); }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:50:5 | LL | x.field.map(|value| do_nothing(value + captured)); @@ -48,7 +48,7 @@ LL | x.field.map(|value| do_nothing(value + captured)); | | | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured) }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:52:5 | LL | x.field.map(|value| { do_nothing(value + captured) }); @@ -56,7 +56,7 @@ LL | x.field.map(|value| { do_nothing(value + captured) }); | | | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured) }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:54:5 | LL | x.field.map(|value| { do_nothing(value + captured); }); @@ -64,7 +64,7 @@ LL | x.field.map(|value| { do_nothing(value + captured); }); | | | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured); }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:56:5 | LL | x.field.map(|value| { { do_nothing(value + captured); } }); @@ -72,7 +72,7 @@ LL | x.field.map(|value| { { do_nothing(value + captured); } }); | | | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured); }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:59:5 | LL | x.field.map(|value| diverge(value + captured)); @@ -80,7 +80,7 @@ LL | x.field.map(|value| diverge(value + captured)); | | | help: try this: `if let Ok(value) = x.field { diverge(value + captured) }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:61:5 | LL | x.field.map(|value| { diverge(value + captured) }); @@ -88,7 +88,7 @@ LL | x.field.map(|value| { diverge(value + captured) }); | | | help: try this: `if let Ok(value) = x.field { diverge(value + captured) }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:63:5 | LL | x.field.map(|value| { diverge(value + captured); }); @@ -96,7 +96,7 @@ LL | x.field.map(|value| { diverge(value + captured); }); | | | help: try this: `if let Ok(value) = x.field { diverge(value + captured); }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:65:5 | LL | x.field.map(|value| { { diverge(value + captured); } }); @@ -104,7 +104,7 @@ LL | x.field.map(|value| { { diverge(value + captured); } }); | | | help: try this: `if let Ok(value) = x.field { diverge(value + captured); }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:70:5 | LL | x.field.map(|value| { let y = plus_one(value + captured); }); @@ -112,7 +112,7 @@ LL | x.field.map(|value| { let y = plus_one(value + captured); }); | | | help: try this: `if let Ok(value) = x.field { let y = plus_one(value + captured); }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:72:5 | LL | x.field.map(|value| { plus_one(value + captured); }); @@ -120,7 +120,7 @@ LL | x.field.map(|value| { plus_one(value + captured); }); | | | help: try this: `if let Ok(value) = x.field { plus_one(value + captured); }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:74:5 | LL | x.field.map(|value| { { plus_one(value + captured); } }); @@ -128,7 +128,7 @@ LL | x.field.map(|value| { { plus_one(value + captured); } }); | | | help: try this: `if let Ok(value) = x.field { plus_one(value + captured); }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:77:5 | LL | x.field.map(|ref value| { do_nothing(value + captured) }); diff --git a/tests/ui/result_map_unit_fn_unfixable.stderr b/tests/ui/result_map_unit_fn_unfixable.stderr index b23cc608621d0..88e4efdb0f054 100644 --- a/tests/ui/result_map_unit_fn_unfixable.stderr +++ b/tests/ui/result_map_unit_fn_unfixable.stderr @@ -1,4 +1,4 @@ -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_unfixable.rs:23:5 | LL | x.field.map(|value| { do_nothing(value); do_nothing(value) }); @@ -8,7 +8,7 @@ LL | x.field.map(|value| { do_nothing(value); do_nothing(value) }); | = note: `-D clippy::result-map-unit-fn` implied by `-D warnings` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_unfixable.rs:25:5 | LL | x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) }); @@ -16,7 +16,7 @@ LL | x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) | | | help: try this: `if let Ok(value) = x.field { ... }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_unfixable.rs:29:5 | LL | x.field.map(|value| { @@ -30,7 +30,7 @@ LL | || }); | |_______| | -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_unfixable.rs:33:5 | LL | x.field.map(|value| { do_nothing(value); do_nothing(value); }); @@ -38,7 +38,7 @@ LL | x.field.map(|value| { do_nothing(value); do_nothing(value); }); | | | help: try this: `if let Ok(value) = x.field { ... }` -error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` --> $DIR/result_map_unit_fn_unfixable.rs:37:5 | LL | "12".parse::().map(diverge); @@ -46,7 +46,7 @@ LL | "12".parse::().map(diverge); | | | help: try this: `if let Ok(a) = "12".parse::() { diverge(a) }` -error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` --> $DIR/result_map_unit_fn_unfixable.rs:43:5 | LL | y.map(do_nothing); From f5bb523e94b431c35b495b6ad6ae94495b653a5f Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 9 Sep 2020 17:59:43 +0200 Subject: [PATCH 0219/1052] Add AsRef<[u8]> for String's Drain. --- library/alloc/src/string.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 14ffd06e9bdfd..a164de8b4d387 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2488,6 +2488,13 @@ impl<'a> AsRef for Drain<'a> { } } +#[unstable(feature = "string_drain_as_str", issue = "none")] +impl<'a> AsRef<[u8]> for Drain<'a> { + fn as_ref(&self) -> &[u8] { + self.as_str().as_bytes() + } +} + #[stable(feature = "drain", since = "1.6.0")] impl Iterator for Drain<'_> { type Item = char; From 4506d26cf39dcde786d4853af133bf26799bf65d Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 9 Sep 2020 18:38:10 +0200 Subject: [PATCH 0220/1052] Remove internal and unstable MaybeUninit::UNINIT. Looks like it is no longer necessary, as uninit_array() can be used instead in the few cases where it was needed. --- library/alloc/src/collections/btree/node.rs | 6 +++--- library/alloc/src/lib.rs | 3 +-- library/core/src/mem/maybe_uninit.rs | 8 -------- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 1346ad19fe20a..04d2b205a272d 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -78,8 +78,8 @@ impl LeafNode { LeafNode { // As a general policy, we leave fields uninitialized if they can be, as this should // be both slightly faster and easier to track in Valgrind. - keys: [MaybeUninit::UNINIT; CAPACITY], - vals: [MaybeUninit::UNINIT; CAPACITY], + keys: MaybeUninit::uninit_array(), + vals: MaybeUninit::uninit_array(), parent: ptr::null(), parent_idx: MaybeUninit::uninit(), len: 0, @@ -111,7 +111,7 @@ impl InternalNode { /// `len` of 0), there must be one initialized and valid edge. This function does not set up /// such an edge. unsafe fn new() -> Self { - InternalNode { data: unsafe { LeafNode::new() }, edges: [MaybeUninit::UNINIT; 2 * B] } + InternalNode { data: unsafe { LeafNode::new() }, edges: MaybeUninit::uninit_array() } } } diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 2ced10831e75c..b338e5b2de7a4 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -100,7 +100,6 @@ #![feature(fn_traits)] #![feature(fundamental)] #![feature(inplace_iteration)] -#![feature(internal_uninit_const)] #![feature(lang_items)] #![feature(layout_for_ptr)] #![feature(libc)] @@ -134,7 +133,7 @@ #![feature(unsized_locals)] #![feature(allocator_internals)] #![feature(slice_partition_dedup)] -#![feature(maybe_uninit_extra, maybe_uninit_slice)] +#![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_uninit_array)] #![feature(alloc_layout_extra)] #![feature(trusted_random_access)] #![feature(try_trait)] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index b64abf68c5e4a..2a353670a91fa 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -305,14 +305,6 @@ impl MaybeUninit { unsafe { MaybeUninit::<[MaybeUninit; LEN]>::uninit().assume_init() } } - /// A promotable constant, equivalent to `uninit()`. - #[unstable( - feature = "internal_uninit_const", - issue = "none", - reason = "hack to work around promotability" - )] - pub const UNINIT: Self = Self::uninit(); - /// Creates a new `MaybeUninit` in an uninitialized state, with the memory being /// filled with `0` bytes. It depends on `T` whether that already makes for /// proper initialization. For example, `MaybeUninit::zeroed()` is initialized, From a94b2cb034c2521d52e54632b775e181eb7e0bc7 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 9 Sep 2020 18:54:17 +0200 Subject: [PATCH 0221/1052] Add safety docs about T's invariants in MaybeUninit::assume_init_drop. --- library/core/src/mem/maybe_uninit.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 38a006ce74ce0..0d1d563b5ceec 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -580,17 +580,23 @@ impl MaybeUninit { /// /// # Safety /// - /// Calling this when the content is not yet fully initialized causes undefined - /// behavior: it is up to the caller to guarantee that the `MaybeUninit` really - /// is in an initialized state. - /// - /// This function runs the destructor of the contained value in place. - /// Afterwards, the memory is considered uninitialized again, but remains unmodified. + /// It is up to the caller to guarantee that the `MaybeUninit` really is + /// in an initialized state. Calling this when the content is not yet fully + /// initialized causes undefined behavior. + /// + /// On top of that, all additional invariants of the type `T` must be + /// satisfied, as the `Drop` implementation of `T` (or its members) may + /// rely on this. For example, a `1`-initialized [`Vec`] is considered + /// initialized (under the current implementation; this does not constitute + /// a stable guarantee) because the only requirement the compiler knows + /// about it is that the data pointer must be non-null. Dropping such a + /// `Vec` however will cause undefined behaviour. /// /// [`assume_init`]: MaybeUninit::assume_init #[unstable(feature = "maybe_uninit_extra", issue = "63567")] pub unsafe fn assume_init_drop(&mut self) { - // SAFETY: the caller must guarantee that `self` is initialized. + // SAFETY: the caller must guarantee that `self` is initialized and + // satisfies all invariants of `T`. // Dropping the value in place is safe if that is the case. unsafe { ptr::drop_in_place(self.as_mut_ptr()) } } From 43c7a9b72b284bee6ce8517550cb6ee7903c639e Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 9 Sep 2020 18:56:16 +0200 Subject: [PATCH 0222/1052] Fix broken doc links in MaybeUninit. --- library/core/src/mem/maybe_uninit.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 0d1d563b5ceec..f68e2b8208982 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -472,6 +472,8 @@ impl MaybeUninit { /// *immediate* undefined behavior, but will cause undefined behavior with most /// safe operations (including dropping it). /// + /// [`Vec`]: ../../std/vec/struct.Vec.html + /// /// # Examples /// /// Correct usage of this method: @@ -593,6 +595,7 @@ impl MaybeUninit { /// `Vec` however will cause undefined behaviour. /// /// [`assume_init`]: MaybeUninit::assume_init + /// [`Vec`]: ../../std/vec/struct.Vec.html #[unstable(feature = "maybe_uninit_extra", issue = "63567")] pub unsafe fn assume_init_drop(&mut self) { // SAFETY: the caller must guarantee that `self` is initialized and From f2a32909e0649eb589406ddac63597ba34273c95 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 9 Sep 2020 19:10:06 +0200 Subject: [PATCH 0223/1052] Mark AsRef impls for String's Drain as stable. Trait implementations effectively can't be #[unstable]. --- library/alloc/src/string.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index a164de8b4d387..047ae942cd9a2 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2481,14 +2481,14 @@ impl<'a> Drain<'a> { } } -#[unstable(feature = "string_drain_as_str", issue = "none")] +#[stable(feature = "string_drain_as_ref", since = "1.48.0")] impl<'a> AsRef for Drain<'a> { fn as_ref(&self) -> &str { self.as_str() } } -#[unstable(feature = "string_drain_as_str", issue = "none")] +#[stable(feature = "string_drain_as_ref", since = "1.48.0")] impl<'a> AsRef<[u8]> for Drain<'a> { fn as_ref(&self) -> &[u8] { self.as_str().as_bytes() From 493c037699603388a00010d96339d84e84e361c6 Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Wed, 9 Sep 2020 12:11:44 -0500 Subject: [PATCH 0224/1052] Eliminate mut reference UB in Drop impl for Rc This changes `self.ptr.as_mut()` with `get_mut_unchecked` which does not use an intermediate reference. Arc already handled this case properly. --- library/alloc/src/rc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index a9b293856e57b..fe429e6e9464c 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1195,7 +1195,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc { self.dec_strong(); if self.strong() == 0 { // destroy the contained object - ptr::drop_in_place(self.ptr.as_mut()); + ptr::drop_in_place(Self::get_mut_unchecked(self)); // remove the implicit "strong weak" pointer now that we've // destroyed the contents. From 829019d4043a6e9dd1305113f43b30fc8415893d Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 9 Sep 2020 19:38:51 +0200 Subject: [PATCH 0225/1052] Disable AsRef implementations for String's Drain. Since trait implementations cannot be unstable, we should only add them when the as_str feature gets stabilized. Until then, only `.as_str()` is available (behind a feature gate). --- library/alloc/src/string.rs | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 047ae942cd9a2..b9506281ed629 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2475,25 +2475,26 @@ impl<'a> Drain<'a> { /// let _ = drain.next().unwrap(); /// assert_eq!(drain.as_str(), "bc"); /// ``` - #[unstable(feature = "string_drain_as_str", issue = "none")] + #[unstable(feature = "string_drain_as_str", issue = "none")] // Note: uncomment AsRef impls below when stabilizing. pub fn as_str(&self) -> &str { self.iter.as_str() } } -#[stable(feature = "string_drain_as_ref", since = "1.48.0")] -impl<'a> AsRef for Drain<'a> { - fn as_ref(&self) -> &str { - self.as_str() - } -} - -#[stable(feature = "string_drain_as_ref", since = "1.48.0")] -impl<'a> AsRef<[u8]> for Drain<'a> { - fn as_ref(&self) -> &[u8] { - self.as_str().as_bytes() - } -} +// Uncomment when stabilizing `string_drain_as_str`. +// #[unstable(feature = "string_drain_as_str", issue = "none")] +// impl<'a> AsRef for Drain<'a> { +// fn as_ref(&self) -> &str { +// self.as_str() +// } +// } +// +// #[unstable(feature = "string_drain_as_str", issue = "none")] +// impl<'a> AsRef<[u8]> for Drain<'a> { +// fn as_ref(&self) -> &[u8] { +// self.as_str().as_bytes() +// } +// } #[stable(feature = "drain", since = "1.6.0")] impl Iterator for Drain<'_> { From 74e07198a08fea62ab2fba9ae258f4d118d7dffe Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Wed, 9 Sep 2020 20:10:23 +0200 Subject: [PATCH 0226/1052] fix test on 32 bit systems --- src/test/ui/const_evaluatable/function-call.rs | 5 +++-- src/test/ui/const_evaluatable/function-call.stderr | 8 ++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/test/ui/const_evaluatable/function-call.rs b/src/test/ui/const_evaluatable/function-call.rs index 9b54a541e6906..b5de66621c50e 100644 --- a/src/test/ui/const_evaluatable/function-call.rs +++ b/src/test/ui/const_evaluatable/function-call.rs @@ -1,8 +1,9 @@ // check-pass -#![warn(const_evaluatable_unchecked)] const fn foo() -> usize { - if std::mem::size_of::<*mut T>() < 8 { // size of *mut T does not depend on T + // We might instead branch on `std::mem::size_of::<*mut T>() < 8` here, + // which would cause this function to fail on 32 bit systems. + if false { std::mem::size_of::() } else { 8 diff --git a/src/test/ui/const_evaluatable/function-call.stderr b/src/test/ui/const_evaluatable/function-call.stderr index a63a2643ad2c2..0d8463714e8df 100644 --- a/src/test/ui/const_evaluatable/function-call.stderr +++ b/src/test/ui/const_evaluatable/function-call.stderr @@ -1,14 +1,10 @@ warning: cannot use constants which depend on generic parameters in types - --> $DIR/function-call.rs:13:17 + --> $DIR/function-call.rs:14:17 | LL | let _ = [0; foo::()]; | ^^^^^^^^^^ | -note: the lint level is defined here - --> $DIR/function-call.rs:2:9 - | -LL | #![warn(const_evaluatable_unchecked)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(const_evaluatable_unchecked)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #76200 From 8f43fa09893b664e4ceb4cc8c7815fa5ab20c10e Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Wed, 9 Sep 2020 13:39:48 -0500 Subject: [PATCH 0227/1052] Add WeakInner<'_> and have Weak::inner() return it This avoids overlapping a reference covering the data field, which may be changed due in concurrent conditions. This fully fixed the UB mainfested with `new_cyclic`. --- library/alloc/src/rc.rs | 109 ++++++++++++++++++++++++++-------------- 1 file changed, 70 insertions(+), 39 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index fe429e6e9464c..43cf3fe6fb6ac 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -469,7 +469,7 @@ impl Rc { // the strong count, and then remove the implicit "strong weak" // pointer while also handling drop logic by just crafting a // fake Weak. - this.dec_strong(); + this.inner().dec_strong(); let _weak = Weak { ptr: this.ptr }; forget(this); Ok(val) @@ -735,7 +735,7 @@ impl Rc { /// ``` #[stable(feature = "rc_weak", since = "1.4.0")] pub fn downgrade(this: &Self) -> Weak { - this.inc_weak(); + this.inner().inc_weak(); // Make sure we do not create a dangling Weak debug_assert!(!is_dangling(this.ptr)); Weak { ptr: this.ptr } @@ -756,7 +756,7 @@ impl Rc { #[inline] #[stable(feature = "rc_counts", since = "1.15.0")] pub fn weak_count(this: &Self) -> usize { - this.weak() - 1 + this.inner().weak() - 1 } /// Gets the number of strong (`Rc`) pointers to this allocation. @@ -774,7 +774,7 @@ impl Rc { #[inline] #[stable(feature = "rc_counts", since = "1.15.0")] pub fn strong_count(this: &Self) -> usize { - this.strong() + this.inner().strong() } /// Returns `true` if there are no other `Rc` or [`Weak`] pointers to @@ -844,7 +844,16 @@ impl Rc { #[inline] #[unstable(feature = "get_mut_unchecked", issue = "63292")] pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T { - unsafe { &mut this.ptr.as_mut().value } + // We are careful to *not* create a reference covering the "count" fields, as + // this would alias with reenterant access to the reference counts (e.g. by `Weak`). + unsafe { &mut (*this.ptr.as_ptr()).value } + } + + #[inline] + fn inner(&self) -> &RcBox { + // This unsafety is ok because while this Rc is alive we're guaranteed + // that the inner pointer is valid. + unsafe { self.ptr.as_ref() } } #[inline] @@ -931,10 +940,10 @@ impl Rc { unsafe { let mut swap = Rc::new(ptr::read(&this.ptr.as_ref().value)); mem::swap(this, &mut swap); - swap.dec_strong(); + swap.inner().dec_strong(); // Remove implicit strong-weak ref (no need to craft a fake // Weak here -- we know other Weaks can clean up for us) - swap.dec_weak(); + swap.inner().dec_weak(); forget(swap); } } @@ -1192,16 +1201,16 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc { /// ``` fn drop(&mut self) { unsafe { - self.dec_strong(); - if self.strong() == 0 { + self.inner().dec_strong(); + if self.inner().strong() == 0 { // destroy the contained object ptr::drop_in_place(Self::get_mut_unchecked(self)); // remove the implicit "strong weak" pointer now that we've // destroyed the contents. - self.dec_weak(); + self.inner().dec_weak(); - if self.weak() == 0 { + if self.inner().weak() == 0 { Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); } } @@ -1227,7 +1236,7 @@ impl Clone for Rc { /// ``` #[inline] fn clone(&self) -> Rc { - self.inc_strong(); + self.inner().inc_strong(); Self::from_inner(self.ptr) } } @@ -1851,6 +1860,13 @@ pub(crate) fn is_dangling(ptr: NonNull) -> bool { address == usize::MAX } +/// Helper type to allow accessing the reference counts without +/// making any assertions about the data field. +struct WeakInner<'a> { + weak: &'a Cell, + strong: &'a Cell, +} + impl Weak { /// Attempts to upgrade the `Weak` pointer to an [`Rc`], delaying /// dropping of the inner value if successful. @@ -1910,11 +1926,21 @@ impl Weak { .unwrap_or(0) } - /// Returns `None` when the pointer is dangling and there is no allocated `RcBox` + /// Returns `None` when the pointer is dangling and there is no allocated `RcBox`, /// (i.e., when this `Weak` was created by `Weak::new`). #[inline] - fn inner(&self) -> Option<&RcBox> { - if is_dangling(self.ptr) { None } else { Some(unsafe { self.ptr.as_ref() }) } + fn inner(&self) -> Option> { + if is_dangling(self.ptr) { + None + } else { + // We are careful to *not* create a reference covering the "data" field, as + // the field may be mutated concurrently (for example, if the last `Rc` + // is dropped, the data field will be dropped in-place). + Some(unsafe { + let ptr = self.ptr.as_ptr(); + WeakInner { strong: &(*ptr).strong, weak: &(*ptr).weak } + }) + } } /// Returns `true` if the two `Weak`s point to the same allocation (similar to @@ -1992,14 +2018,14 @@ impl Drop for Weak { /// assert!(other_weak_foo.upgrade().is_none()); /// ``` fn drop(&mut self) { - if let Some(inner) = self.inner() { - inner.dec_weak(); - // the weak count starts at 1, and will only go to zero if all - // the strong pointers have disappeared. - if inner.weak() == 0 { - unsafe { - Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); - } + let inner = if let Some(inner) = self.inner() { inner } else { return }; + + inner.dec_weak(); + // the weak count starts at 1, and will only go to zero if all + // the strong pointers have disappeared. + if inner.weak() == 0 { + unsafe { + Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); } } } @@ -2065,12 +2091,13 @@ impl Default for Weak { // clone these much in Rust thanks to ownership and move-semantics. #[doc(hidden)] -trait RcBoxPtr { - fn inner(&self) -> &RcBox; +trait RcInnerPtr { + fn weak_ref(&self) -> &Cell; + fn strong_ref(&self) -> &Cell; #[inline] fn strong(&self) -> usize { - self.inner().strong.get() + self.strong_ref().get() } #[inline] @@ -2084,17 +2111,17 @@ trait RcBoxPtr { if strong == 0 || strong == usize::MAX { abort(); } - self.inner().strong.set(strong + 1); + self.strong_ref().set(strong + 1); } #[inline] fn dec_strong(&self) { - self.inner().strong.set(self.strong() - 1); + self.strong_ref().set(self.strong() - 1); } #[inline] fn weak(&self) -> usize { - self.inner().weak.get() + self.weak_ref().get() } #[inline] @@ -2108,26 +2135,30 @@ trait RcBoxPtr { if weak == 0 || weak == usize::MAX { abort(); } - self.inner().weak.set(weak + 1); + self.weak_ref().set(weak + 1); } #[inline] fn dec_weak(&self) { - self.inner().weak.set(self.weak() - 1); + self.weak_ref().set(self.weak() - 1); } } -impl RcBoxPtr for Rc { - #[inline(always)] - fn inner(&self) -> &RcBox { - unsafe { self.ptr.as_ref() } +impl RcInnerPtr for RcBox { + fn weak_ref(&self) -> &Cell { + &self.weak + } + fn strong_ref(&self) -> &Cell { + &self.strong } } -impl RcBoxPtr for RcBox { - #[inline(always)] - fn inner(&self) -> &RcBox { - self +impl<'a> RcInnerPtr for WeakInner<'a> { + fn weak_ref(&self) -> &Cell { + self.weak + } + fn strong_ref(&self) -> &Cell { + self.strong } } From bb57c9f91c920a8b1533fb92aa50be342e11f675 Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Wed, 9 Sep 2020 13:44:22 -0500 Subject: [PATCH 0228/1052] Format --- library/alloc/src/rc.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 43cf3fe6fb6ac..4821c8f567626 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -845,7 +845,7 @@ impl Rc { #[unstable(feature = "get_mut_unchecked", issue = "63292")] pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T { // We are careful to *not* create a reference covering the "count" fields, as - // this would alias with reenterant access to the reference counts (e.g. by `Weak`). + // this would alias with concurrent access to the reference counts (e.g. by `Weak`). unsafe { &mut (*this.ptr.as_ptr()).value } } @@ -2019,7 +2019,7 @@ impl Drop for Weak { /// ``` fn drop(&mut self) { let inner = if let Some(inner) = self.inner() { inner } else { return }; - + inner.dec_weak(); // the weak count starts at 1, and will only go to zero if all // the strong pointers have disappeared. @@ -2144,7 +2144,7 @@ trait RcInnerPtr { } } -impl RcInnerPtr for RcBox { +impl RcInnerPtr for RcBox { fn weak_ref(&self) -> &Cell { &self.weak } From d85db82960db80132a10d25e0fe7dfd5f4736d0f Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 8 Sep 2020 23:38:24 -0700 Subject: [PATCH 0229/1052] Add documentation for `impl From for Poll` --- library/core/src/task/poll.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index 9383e7c45fa55..4e987a53b2cb2 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -112,6 +112,14 @@ impl Poll>> { #[stable(feature = "futures_api", since = "1.36.0")] impl From for Poll { + /// Convert to a `Ready` variant. + /// + /// # Example + /// + /// ``` + /// # use core::task::Poll; + /// assert_eq!(Poll::from(true), Poll::Ready(true)); + /// ``` fn from(t: T) -> Poll { Poll::Ready(t) } From 8b0d0a0cadbaaf0e7f4114e289a71981872c8587 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 9 Sep 2020 11:53:24 -0700 Subject: [PATCH 0230/1052] Add documentation for `impl From> for Vec` --- library/alloc/src/collections/binary_heap.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index 40aa4d850f59d..24d17fdd880ba 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -1343,6 +1343,10 @@ impl From> for BinaryHeap { #[stable(feature = "binary_heap_extras_15", since = "1.5.0")] impl From> for Vec { + /// Converts a `BinaryHeap` into a `Vec`. + /// + /// This conversion requires no data movement or allocation, and has + /// constant time complexity. fn from(heap: BinaryHeap) -> Vec { heap.data } From 10d3f8a484a812db995198f17b17462718f477bc Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 26 Jul 2020 20:11:30 +0300 Subject: [PATCH 0231/1052] Move `rustllvm` into `rustc_llvm` --- .gitignore | 1 - compiler/rustc_codegen_llvm/Cargo.toml | 2 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 4 ++-- .../rustc_llvm}/Cargo.toml | 5 +---- .../rustc_llvm}/build.rs | 16 ++++++++-------- .../rustc_llvm/llvm-wrapper}/.editorconfig | 0 .../rustc_llvm/llvm-wrapper}/ArchiveWrapper.cpp | 2 +- .../llvm-wrapper}/CoverageMappingWrapper.cpp | 2 +- .../rustc_llvm/llvm-wrapper/LLVMWrapper.h | 0 .../rustc_llvm/llvm-wrapper}/Linker.cpp | 2 +- .../rustc_llvm/llvm-wrapper}/PassWrapper.cpp | 2 +- .../rustc_llvm/llvm-wrapper}/README | 0 .../rustc_llvm/llvm-wrapper}/RustWrapper.cpp | 2 +- .../rustc_llvm/src}/lib.rs | 0 config.toml.example | 2 +- src/bootstrap/builder.rs | 6 +++--- src/bootstrap/compile.rs | 4 ++-- 17 files changed, 23 insertions(+), 27 deletions(-) rename {src/librustc_llvm => compiler/rustc_llvm}/Cargo.toml (77%) rename {src/librustc_llvm => compiler/rustc_llvm}/build.rs (96%) rename {src/rustllvm => compiler/rustc_llvm/llvm-wrapper}/.editorconfig (100%) rename {src/rustllvm => compiler/rustc_llvm/llvm-wrapper}/ArchiveWrapper.cpp (99%) rename {src/rustllvm => compiler/rustc_llvm/llvm-wrapper}/CoverageMappingWrapper.cpp (98%) rename src/rustllvm/rustllvm.h => compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h (100%) rename {src/rustllvm => compiler/rustc_llvm/llvm-wrapper}/Linker.cpp (97%) rename {src/rustllvm => compiler/rustc_llvm/llvm-wrapper}/PassWrapper.cpp (99%) rename {src/rustllvm => compiler/rustc_llvm/llvm-wrapper}/README (100%) rename {src/rustllvm => compiler/rustc_llvm/llvm-wrapper}/RustWrapper.cpp (99%) rename {src/librustc_llvm => compiler/rustc_llvm/src}/lib.rs (100%) diff --git a/.gitignore b/.gitignore index 856ff7dbb0f33..1c50d9b054ddc 100644 --- a/.gitignore +++ b/.gitignore @@ -33,7 +33,6 @@ __pycache__/ /mingw-build/ # Created by default with `src/ci/docker/run.sh`: /obj/ -/rustllvm/ /unicode-downloads /target # Generated by compiletest for incremental: diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 38f552558c839..04792b334d553 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -25,7 +25,7 @@ rustc_fs_util = { path = "../rustc_fs_util" } rustc_hir = { path = "../rustc_hir" } rustc_incremental = { path = "../rustc_incremental" } rustc_index = { path = "../rustc_index" } -rustc_llvm = { path = "../../src/librustc_llvm" } +rustc_llvm = { path = "../rustc_llvm" } rustc_session = { path = "../rustc_session" } rustc_serialize = { path = "../rustc_serialize" } rustc_target = { path = "../rustc_target" } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 32822eba930c6..4942c997682d8 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -96,7 +96,7 @@ pub enum DLLStorageClass { DllExport = 2, // Function to be accessible from DLL. } -/// Matches LLVMRustAttribute in rustllvm.h +/// Matches LLVMRustAttribute in LLVMWrapper.h /// Semantically a subset of the C++ enum llvm::Attribute::AttrKind, /// though it is not ABI compatible (since it's a C++ enum) #[repr(C)] @@ -1705,7 +1705,7 @@ extern "C" { PM: &PassManager<'_>, ); - // Stuff that's in rustllvm/ because it's not upstream yet. + // Stuff that's in llvm-wrapper/ because it's not upstream yet. /// Opens an object file. pub fn LLVMCreateObjectFile( diff --git a/src/librustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml similarity index 77% rename from src/librustc_llvm/Cargo.toml rename to compiler/rustc_llvm/Cargo.toml index 7120f2e991acd..ee83689f0a469 100644 --- a/src/librustc_llvm/Cargo.toml +++ b/compiler/rustc_llvm/Cargo.toml @@ -4,9 +4,6 @@ name = "rustc_llvm" version = "0.0.0" edition = "2018" -[lib] -path = "lib.rs" - [features] static-libstdcpp = [] emscripten = [] @@ -15,5 +12,5 @@ emscripten = [] libc = "0.2.73" [build-dependencies] -build_helper = { path = "../build_helper" } +build_helper = { path = "../../src/build_helper" } cc = "1.0.58" diff --git a/src/librustc_llvm/build.rs b/compiler/rustc_llvm/build.rs similarity index 96% rename from src/librustc_llvm/build.rs rename to compiler/rustc_llvm/build.rs index 306ffbf5daab4..7f1e5cf336ac4 100644 --- a/src/librustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -175,15 +175,15 @@ fn main() { cfg.debug(false); } - build_helper::rerun_if_changed_anything_in_dir(Path::new("../rustllvm")); - cfg.file("../rustllvm/PassWrapper.cpp") - .file("../rustllvm/RustWrapper.cpp") - .file("../rustllvm/ArchiveWrapper.cpp") - .file("../rustllvm/CoverageMappingWrapper.cpp") - .file("../rustllvm/Linker.cpp") + build_helper::rerun_if_changed_anything_in_dir(Path::new("llvm-wrapper")); + cfg.file("llvm-wrapper/PassWrapper.cpp") + .file("llvm-wrapper/RustWrapper.cpp") + .file("llvm-wrapper/ArchiveWrapper.cpp") + .file("llvm-wrapper/CoverageMappingWrapper.cpp") + .file("llvm-wrapper/Linker.cpp") .cpp(true) .cpp_link_stdlib(None) // we handle this below - .compile("rustllvm"); + .compile("llvm-wrapper"); let (llvm_kind, llvm_link_arg) = detect_llvm_link(); @@ -259,7 +259,7 @@ fn main() { } // Some LLVM linker flags (-L and -l) may be needed even when linking - // librustc_llvm, for example when using static libc++, we may need to + // rustc_llvm, for example when using static libc++, we may need to // manually specify the library search path and -ldl -lpthread as link // dependencies. let llvm_linker_flags = tracked_env_var_os("LLVM_LINKER_FLAGS"); diff --git a/src/rustllvm/.editorconfig b/compiler/rustc_llvm/llvm-wrapper/.editorconfig similarity index 100% rename from src/rustllvm/.editorconfig rename to compiler/rustc_llvm/llvm-wrapper/.editorconfig diff --git a/src/rustllvm/ArchiveWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp similarity index 99% rename from src/rustllvm/ArchiveWrapper.cpp rename to compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp index 9ce614fda5752..2797fe8df4a8e 100644 --- a/src/rustllvm/ArchiveWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp @@ -1,4 +1,4 @@ -#include "rustllvm.h" +#include "LLVMWrapper.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ArchiveWriter.h" diff --git a/src/rustllvm/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp similarity index 98% rename from src/rustllvm/CoverageMappingWrapper.cpp rename to compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp index 81aba0cbf7d42..2b1143a4ecff5 100644 --- a/src/rustllvm/CoverageMappingWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp @@ -1,4 +1,4 @@ -#include "rustllvm.h" +#include "LLVMWrapper.h" #include "llvm/ProfileData/Coverage/CoverageMapping.h" #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h" #include "llvm/ProfileData/InstrProf.h" diff --git a/src/rustllvm/rustllvm.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h similarity index 100% rename from src/rustllvm/rustllvm.h rename to compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h diff --git a/src/rustllvm/Linker.cpp b/compiler/rustc_llvm/llvm-wrapper/Linker.cpp similarity index 97% rename from src/rustllvm/Linker.cpp rename to compiler/rustc_llvm/llvm-wrapper/Linker.cpp index 69176f9cb1f6d..8766e96f086d2 100644 --- a/src/rustllvm/Linker.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/Linker.cpp @@ -1,6 +1,6 @@ #include "llvm/Linker/Linker.h" -#include "rustllvm.h" +#include "LLVMWrapper.h" using namespace llvm; diff --git a/src/rustllvm/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp similarity index 99% rename from src/rustllvm/PassWrapper.cpp rename to compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 76fe5e7f769f7..7b1c3f9ba2c68 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -3,7 +3,7 @@ #include #include -#include "rustllvm.h" +#include "LLVMWrapper.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" diff --git a/src/rustllvm/README b/compiler/rustc_llvm/llvm-wrapper/README similarity index 100% rename from src/rustllvm/README rename to compiler/rustc_llvm/llvm-wrapper/README diff --git a/src/rustllvm/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp similarity index 99% rename from src/rustllvm/RustWrapper.cpp rename to compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 9d90b0dfe0702..e85a9b7638004 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1,4 +1,4 @@ -#include "rustllvm.h" +#include "LLVMWrapper.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" diff --git a/src/librustc_llvm/lib.rs b/compiler/rustc_llvm/src/lib.rs similarity index 100% rename from src/librustc_llvm/lib.rs rename to compiler/rustc_llvm/src/lib.rs diff --git a/config.toml.example b/config.toml.example index 9abb8add785a9..0f25d311ec5d2 100644 --- a/config.toml.example +++ b/config.toml.example @@ -45,7 +45,7 @@ # this flag will indicate that this version check should not be done. #version-check = true -# Link libstdc++ statically into the librustc_llvm instead of relying on a +# Link libstdc++ statically into the rustc_llvm instead of relying on a # dynamic version to be available. #static-libstdcpp = false diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 01dbb48354825..d2baf4a1d1e6a 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -812,7 +812,7 @@ impl<'a> Builder<'a> { format!("CARGO_PROFILE_{}_{}", profile, name) }; - // See comment in librustc_llvm/build.rs for why this is necessary, largely llvm-config + // See comment in rustc_llvm/build.rs for why this is necessary, largely llvm-config // needs to not accidentally link to libLLVM in stage0/lib. cargo.env("REAL_LIBRARY_PATH_VAR", &util::dylib_path_var()); if let Some(e) = env::var_os(util::dylib_path_var()) { @@ -829,9 +829,9 @@ impl<'a> Builder<'a> { // scripts can do less work (i.e. not building/requiring LLVM). if cmd == "check" || cmd == "clippy" || cmd == "fix" { // If we've not yet built LLVM, or it's stale, then bust - // the librustc_llvm cache. That will always work, even though it + // the rustc_llvm cache. That will always work, even though it // may mean that on the next non-check build we'll need to rebuild - // librustc_llvm. But if LLVM is stale, that'll be a tiny amount + // rustc_llvm. But if LLVM is stale, that'll be a tiny amount // of work comparitively, and we'd likely need to rebuild it anyway, // so that's okay. if crate::native::prebuilt_llvm_config(self, target).is_err() { diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 7814ca8e5bbce..9d314e8452b9c 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -560,7 +560,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS } // Pass down configuration from the LLVM build into the build of - // librustc_llvm and librustc_codegen_llvm. + // rustc_llvm and rustc_codegen_llvm. // // Note that this is disabled if LLVM itself is disabled or we're in a check // build. If we are in a check build we still go ahead here presuming we've @@ -579,7 +579,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { cargo.env("CFG_LLVM_ROOT", s); } - // Some LLVM linker flags (-L and -l) may be needed to link librustc_llvm. + // Some LLVM linker flags (-L and -l) may be needed to link rustc_llvm. if let Some(ref s) = builder.config.llvm_ldflags { cargo.env("LLVM_LINKER_FLAGS", s); } From 884a1b4b9b358fcb2c12dab0aac5671c8534b29d Mon Sep 17 00:00:00 2001 From: Camelid Date: Wed, 9 Sep 2020 13:42:57 -0700 Subject: [PATCH 0232/1052] Fix anchor links #safety -> self#safety --- library/core/src/ptr/mod.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index eb31c739e834e..92c4f2ccfe8a0 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -134,7 +134,7 @@ mod mut_ptr; /// /// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// -/// [valid]: #safety +/// [valid]: self#safety /// /// # Examples /// @@ -316,7 +316,7 @@ pub const fn slice_from_raw_parts_mut(data: *mut T, len: usize) -> *mut [T] { /// /// Note that even if `T` has size `0`, the pointers must be non-NULL and properly aligned. /// -/// [valid]: #safety +/// [valid]: self#safety /// /// # Examples /// @@ -394,7 +394,7 @@ pub unsafe fn swap(x: *mut T, y: *mut T) { /// Note that even if the effectively copied size (`count * size_of::()`) is `0`, /// the pointers must be non-NULL and properly aligned. /// -/// [valid]: #safety +/// [valid]: self#safety /// /// # Examples /// @@ -533,7 +533,7 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// /// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// -/// [valid]: #safety +/// [valid]: self#safety /// /// # Examples /// @@ -668,7 +668,7 @@ pub unsafe fn replace(dst: *mut T, mut src: T) -> T { /// assert_eq!(s, "bar"); /// ``` /// -/// [valid]: #safety +/// [valid]: self#safety #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn read(src: *const T) -> T { @@ -706,7 +706,7 @@ pub unsafe fn read(src: *const T) -> T { /// Note that even if `T` has size `0`, the pointer must be non-NULL. /// /// [read-ownership]: read#ownership-of-the-returned-value -/// [valid]: #safety +/// [valid]: self#safety /// /// ## On `packed` structs /// @@ -809,7 +809,7 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// /// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// -/// [valid]: #safety +/// [valid]: self#safety /// /// # Examples /// @@ -898,7 +898,7 @@ pub unsafe fn write(dst: *mut T, src: T) { /// /// Note that even if `T` has size `0`, the pointer must be non-NULL. /// -/// [valid]: #safety +/// [valid]: self#safety /// /// ## On `packed` structs /// @@ -1010,7 +1010,7 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// /// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// -/// [valid]: #safety +/// [valid]: self#safety /// [read-ownership]: read#ownership-of-the-returned-value /// /// Just like in C, whether an operation is volatile has no bearing whatsoever @@ -1080,7 +1080,7 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// -/// [valid]: #safety +/// [valid]: self#safety /// /// Just like in C, whether an operation is volatile has no bearing whatsoever /// on questions involving concurrent access from multiple threads. Volatile From 3550568a548091ec4ae738827b50a84e9ddf0b8f Mon Sep 17 00:00:00 2001 From: Vali Schneider Date: Wed, 9 Sep 2020 14:02:34 -0700 Subject: [PATCH 0233/1052] removing if chain and renaming lint --- CHANGELOG.md | 2 +- clippy_lints/src/lib.rs | 8 ++--- ...nic_in_result.rs => panic_in_result_fn.rs} | 29 +++++++------------ src/lintlist/mod.rs | 4 +-- ...nic_in_result.rs => panic_in_result_fn.rs} | 2 +- ...esult.stderr => panic_in_result_fn.stderr} | 26 ++++++++--------- 6 files changed, 32 insertions(+), 39 deletions(-) rename clippy_lints/src/{panic_in_result.rs => panic_in_result_fn.rs} (79%) rename tests/ui/{panic_in_result.rs => panic_in_result_fn.rs} (97%) rename tests/ui/{panic_in_result.stderr => panic_in_result_fn.stderr} (88%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7af3b666cca00..d4f0ff4ba78d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1651,7 +1651,7 @@ Released 2018-09-13 [`out_of_bounds_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#out_of_bounds_indexing [`overflow_check_conditional`]: https://rust-lang.github.io/rust-clippy/master/index.html#overflow_check_conditional [`panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic -[`panic_in_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result +[`panic_in_result_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result [`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params [`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index b70d126af5bf8..dbe17e6bbfe03 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -267,7 +267,7 @@ mod open_options; mod option_env_unwrap; mod option_if_let_else; mod overflow_check_conditional; -mod panic_in_result; +mod panic_in_result_fn; mod panic_unimplemented; mod partialeq_ne_impl; mod path_buf_push_overwrite; @@ -748,7 +748,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &option_env_unwrap::OPTION_ENV_UNWRAP, &option_if_let_else::OPTION_IF_LET_ELSE, &overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, - &panic_in_result::PANIC_IN_RESULT, + &panic_in_result_fn::PANIC_IN_RESULT_FN, &panic_unimplemented::PANIC, &panic_unimplemented::PANIC_PARAMS, &panic_unimplemented::TODO, @@ -1088,7 +1088,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box manual_async_fn::ManualAsyncFn); store.register_early_pass(|| box redundant_field_names::RedundantFieldNames); store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero); - store.register_late_pass(|| box panic_in_result::PanicInResult); + store.register_late_pass(|| box panic_in_result_fn::PanicInResultFn); let single_char_binding_names_threshold = conf.single_char_binding_names_threshold; store.register_early_pass(move || box non_expressive_names::NonExpressiveNames { @@ -1132,7 +1132,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS), LintId::of(&missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS), LintId::of(&modulo_arithmetic::MODULO_ARITHMETIC), - LintId::of(&panic_in_result::PANIC_IN_RESULT), + LintId::of(&panic_in_result_fn::PANIC_IN_RESULT_FN), LintId::of(&panic_unimplemented::PANIC), LintId::of(&panic_unimplemented::TODO), LintId::of(&panic_unimplemented::UNIMPLEMENTED), diff --git a/clippy_lints/src/panic_in_result.rs b/clippy_lints/src/panic_in_result_fn.rs similarity index 79% rename from clippy_lints/src/panic_in_result.rs rename to clippy_lints/src/panic_in_result_fn.rs index 8b8e211cb723a..4077aba6ef17d 100644 --- a/clippy_lints/src/panic_in_result.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -1,5 +1,4 @@ use crate::utils::{is_expn_of, is_type_diagnostic_item, return_ty, span_lint_and_then}; -use if_chain::if_chain; use rustc_hir as hir; use rustc_hir::intravisit::{self, FnKind, NestedVisitorMap, Visitor}; use rustc_hir::Expr; @@ -23,14 +22,14 @@ declare_clippy_lint! { /// panic!("error"); /// } /// ``` - pub PANIC_IN_RESULT, + pub PANIC_IN_RESULT_FN, restriction, "functions of type `Result<..>` that contain `panic!()`, `todo!()` or `unreachable()` or `unimplemented()` " } -declare_lint_pass!(PanicInResult => [PANIC_IN_RESULT]); +declare_lint_pass!(PanicInResultFn => [PANIC_IN_RESULT_FN]); -impl<'tcx> LateLintPass<'tcx> for PanicInResult { +impl<'tcx> LateLintPass<'tcx> for PanicInResultFn { fn check_fn( &mut self, cx: &LateContext<'tcx>, @@ -40,15 +39,10 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResult { span: Span, hir_id: hir::HirId, ) { - if let FnKind::Closure(_) = fn_kind { - return; - } - if_chain! { - if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)); - then - { - lint_impl_body(cx, span, body); - } + if !matches!(fn_kind, FnKind::Closure(_)) + && is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) + { + lint_impl_body(cx, span, body); } } } @@ -61,10 +55,9 @@ impl<'tcx> Visitor<'tcx> for FindPanicUnimplementedUnreachable { type Map = Map<'tcx>; fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if is_expn_of(expr.span, "unimplemented").is_some() - || is_expn_of(expr.span, "unreachable").is_some() - || is_expn_of(expr.span, "panic").is_some() - || is_expn_of(expr.span, "todo").is_some() + if ["unimplemented", "unreachable", "panic", "todo"] + .iter() + .any(|fun| is_expn_of(expr.span, fun).is_some()) { self.result.push(expr.span); } @@ -83,7 +76,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir if !panics.result.is_empty() { span_lint_and_then( cx, - PANIC_IN_RESULT, + PANIC_IN_RESULT_FN, impl_span, "used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result`", move |diag| { diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 1f56c56f081d3..4d6c45761e66e 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1705,11 +1705,11 @@ pub static ref ALL_LINTS: Vec = vec![ module: "panic_unimplemented", }, Lint { - name: "panic_in_result", + 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", + module: "panic_in_result_fn", }, Lint { name: "panic_params", diff --git a/tests/ui/panic_in_result.rs b/tests/ui/panic_in_result_fn.rs similarity index 97% rename from tests/ui/panic_in_result.rs rename to tests/ui/panic_in_result_fn.rs index f6fb2f1ab6120..287726f7a2d4e 100644 --- a/tests/ui/panic_in_result.rs +++ b/tests/ui/panic_in_result_fn.rs @@ -1,4 +1,4 @@ -#![warn(clippy::panic_in_result)] +#![warn(clippy::panic_in_result_fn)] struct A; diff --git a/tests/ui/panic_in_result.stderr b/tests/ui/panic_in_result_fn.stderr similarity index 88% rename from tests/ui/panic_in_result.stderr rename to tests/ui/panic_in_result_fn.stderr index 9faedf8298603..c6936fd86923c 100644 --- a/tests/ui/panic_in_result.stderr +++ b/tests/ui/panic_in_result_fn.stderr @@ -1,5 +1,5 @@ error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` - --> $DIR/panic_in_result.rs:6:5 + --> $DIR/panic_in_result_fn.rs:6:5 | LL | / fn result_with_panic() -> Result // should emit lint LL | | { @@ -7,17 +7,17 @@ LL | | panic!("error"); LL | | } | |_____^ | - = note: `-D clippy::panic-in-result` implied by `-D warnings` + = 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.rs:8:9 + --> $DIR/panic_in_result_fn.rs:8: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.rs:11:5 + --> $DIR/panic_in_result_fn.rs:11:5 | LL | / fn result_with_unimplemented() -> Result // should emit lint LL | | { @@ -27,14 +27,14 @@ 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.rs:13:9 + --> $DIR/panic_in_result_fn.rs:13: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.rs:16:5 + --> $DIR/panic_in_result_fn.rs:16:5 | LL | / fn result_with_unreachable() -> Result // should emit lint LL | | { @@ -44,14 +44,14 @@ 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.rs:18:9 + --> $DIR/panic_in_result_fn.rs:18: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.rs:21:5 + --> $DIR/panic_in_result_fn.rs:21:5 | LL | / fn result_with_todo() -> Result // should emit lint LL | | { @@ -61,14 +61,14 @@ 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.rs:23:9 + --> $DIR/panic_in_result_fn.rs:23: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.rs:52:1 + --> $DIR/panic_in_result_fn.rs:52:1 | LL | / fn function_result_with_panic() -> Result // should emit lint LL | | { @@ -78,14 +78,14 @@ 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.rs:54:5 + --> $DIR/panic_in_result_fn.rs:54: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.rs:67:1 + --> $DIR/panic_in_result_fn.rs:67:1 | LL | / fn main() -> Result<(), String> { LL | | todo!("finish main method"); @@ -95,7 +95,7 @@ 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.rs:68:5 + --> $DIR/panic_in_result_fn.rs:68:5 | LL | todo!("finish main method"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From f90b1fc0636cb50bd225caeb20d6a1309d7b966f Mon Sep 17 00:00:00 2001 From: Vali Schneider Date: Wed, 9 Sep 2020 14:06:11 -0700 Subject: [PATCH 0234/1052] cargo dev update-lints --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4f0ff4ba78d6..6b6be50065cd6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1651,7 +1651,7 @@ Released 2018-09-13 [`out_of_bounds_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#out_of_bounds_indexing [`overflow_check_conditional`]: https://rust-lang.github.io/rust-clippy/master/index.html#overflow_check_conditional [`panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic -[`panic_in_result_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result +[`panic_in_result_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result_fn [`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params [`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl From 6211599ccafee5b2429bfb1bbeb48ead32a48484 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Wed, 9 Sep 2020 14:00:31 -0700 Subject: [PATCH 0235/1052] Extend invalid_atomic_ordering to detect misuse of compare_exchange{,_weak} --- clippy_lints/src/atomic_ordering.rs | 82 ++++++- tests/ui/atomic_ordering_exchange.rs | 84 ++++++++ tests/ui/atomic_ordering_exchange.stderr | 259 +++++++++++++++++++++++ 3 files changed, 423 insertions(+), 2 deletions(-) create mode 100644 tests/ui/atomic_ordering_exchange.rs create mode 100644 tests/ui/atomic_ordering_exchange.stderr diff --git a/clippy_lints/src/atomic_ordering.rs b/clippy_lints/src/atomic_ordering.rs index 2d964ac2b9f64..748f45f47c2ad 100644 --- a/clippy_lints/src/atomic_ordering.rs +++ b/clippy_lints/src/atomic_ordering.rs @@ -8,7 +8,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { /// **What it does:** Checks for usage of invalid atomic - /// ordering in atomic loads/stores and memory fences. + /// ordering in atomic loads/stores/exchanges and memory fences /// /// **Why is this bad?** Using an invalid atomic ordering /// will cause a panic at run-time. @@ -29,10 +29,13 @@ declare_clippy_lint! { /// /// atomic::fence(Ordering::Relaxed); /// atomic::compiler_fence(Ordering::Relaxed); + /// + /// let _ = x.compare_exchange(false, false, Ordering::Relaxed, Ordering::SeqCst); + /// let _ = x.compare_exchange_weak(false, true, Ordering::SeqCst, Ordering::Release); /// ``` pub INVALID_ATOMIC_ORDERING, correctness, - "usage of invalid atomic ordering in atomic loads/stores and memory fences" + "usage of invalid atomic ordering in atomic loads/stores/exchanges ane memory fences" } declare_lint_pass!(AtomicOrdering => [INVALID_ATOMIC_ORDERING]); @@ -127,9 +130,84 @@ fn check_memory_fence(cx: &LateContext<'_>, expr: &Expr<'_>) { } } +fn opt_ordering_defid(cx: &LateContext<'_>, ord_arg: &Expr<'_>) -> Option { + if let ExprKind::Path(ref ord_qpath) = ord_arg.kind { + cx.qpath_res(ord_qpath, ord_arg.hir_id).opt_def_id() + } else { + None + } +} +fn check_atomic_compare_exchange(cx: &LateContext<'_>, expr: &Expr<'_>) { + if_chain! { + if let ExprKind::MethodCall(ref method_path, _, args, _) = &expr.kind; + let method = method_path.ident.name.as_str(); + if type_is_atomic(cx, &args[0]); + if method == "compare_exchange" || method == "compare_exchange_weak"; + let failure_order_arg = &args[4]; + if let Some(fail_ordering_def_id) = opt_ordering_defid(cx, failure_order_arg); + then { + // Helper type holding on to some checking and error reporting data. Has + // - (success ordering name, + // - list of failure orderings forbidden by the success order, + // - suggestion message) + type OrdLintInfo = (&'static str, &'static [&'static str], &'static str); + let relaxed: OrdLintInfo = ("Relaxed", &["SeqCst", "Acquire"], "ordering mode `Relaxed`"); + let acquire: OrdLintInfo = ("Acquire", &["SeqCst"], "ordering modes `Acquire` or `Relaxed`"); + let seq_cst: OrdLintInfo = ("SeqCst", &[], "ordering modes `Acquire`, `SeqCst` or `Relaxed`"); + let release = ("Release", relaxed.1, relaxed.2); + let acqrel = ("AcqRel", acquire.1, acquire.2); + let search = [relaxed, acquire, seq_cst, release, acqrel]; + + let success_lint_info = opt_ordering_defid(cx, &args[3]) + .and_then(|success_ord_def_id| -> Option { + search + .iter() + .find(|(ordering, ..)| { + match_def_path(cx, success_ord_def_id, + &["core", "sync", "atomic", "Ordering", ordering]) + }) + .copied() + }); + + if match_ordering_def_path(cx, fail_ordering_def_id, &["Release", "AcqRel"]) { + // If we don't know the success order is, use what we'd suggest + // if it were maximally permissive. + let suggested = success_lint_info.unwrap_or(seq_cst).2; + span_lint_and_help( + cx, + INVALID_ATOMIC_ORDERING, + failure_order_arg.span, + &format!( + "{}'s failure ordering may not be `Release` or `AcqRel`", + method, + ), + None, + &format!("consider using {} instead", suggested), + ); + } else if let Some((success_ord_name, bad_ords_given_success, suggested)) = success_lint_info { + if match_ordering_def_path(cx, fail_ordering_def_id, bad_ords_given_success) { + span_lint_and_help( + cx, + INVALID_ATOMIC_ORDERING, + failure_order_arg.span, + &format!( + "{}'s failure ordering may not stronger than the success ordering of `{}`", + method, + success_ord_name, + ), + None, + &format!("consider using {} instead", suggested), + ); + } + } + } + } +} + impl<'tcx> LateLintPass<'tcx> for AtomicOrdering { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { check_atomic_load_store(cx, expr); check_memory_fence(cx, expr); + check_atomic_compare_exchange(cx, expr); } } diff --git a/tests/ui/atomic_ordering_exchange.rs b/tests/ui/atomic_ordering_exchange.rs new file mode 100644 index 0000000000000..2f60a98f037b4 --- /dev/null +++ b/tests/ui/atomic_ordering_exchange.rs @@ -0,0 +1,84 @@ +#![warn(clippy::invalid_atomic_ordering)] + +use std::sync::atomic::{AtomicUsize, Ordering}; + +fn main() { + // `compare_exchange` (not weak) testing + let x = AtomicUsize::new(0); + + // Allowed ordering combos + let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::Relaxed); + let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::Acquire); + let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::Relaxed); + let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::Relaxed); + let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::Acquire); + let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::Relaxed); + let _ = x.compare_exchange(0, 0, Ordering::SeqCst, Ordering::Relaxed); + let _ = x.compare_exchange(0, 0, Ordering::SeqCst, Ordering::Acquire); + let _ = x.compare_exchange(0, 0, Ordering::SeqCst, Ordering::SeqCst); + + // AcqRel is always forbidden as a failure ordering + let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::AcqRel); + let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::AcqRel); + let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::AcqRel); + let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::AcqRel); + let _ = x.compare_exchange(0, 0, Ordering::SeqCst, Ordering::AcqRel); + + // Release is always forbidden as a failure ordering + let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::Release); + let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::Release); + let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::Release); + let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::Release); + let _ = x.compare_exchange(0, 0, Ordering::SeqCst, Ordering::Release); + + // Release success order forbids failure order of Acquire or SeqCst + let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::Acquire); + let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::SeqCst); + + // Relaxed success order also forbids failure order of Acquire or SeqCst + let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::SeqCst); + let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::Acquire); + + // Acquire/AcqRel forbids failure order of SeqCst + let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::SeqCst); + let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::SeqCst); + + // compare_exchange_weak tests + + // Allowed ordering combos + let _ = x.compare_exchange_weak(0, 0, Ordering::Relaxed, Ordering::Relaxed); + let _ = x.compare_exchange_weak(0, 0, Ordering::Acquire, Ordering::Acquire); + let _ = x.compare_exchange_weak(0, 0, Ordering::Acquire, Ordering::Relaxed); + let _ = x.compare_exchange_weak(0, 0, Ordering::Release, Ordering::Relaxed); + let _ = x.compare_exchange_weak(0, 0, Ordering::AcqRel, Ordering::Acquire); + let _ = x.compare_exchange_weak(0, 0, Ordering::AcqRel, Ordering::Relaxed); + let _ = x.compare_exchange_weak(0, 0, Ordering::SeqCst, Ordering::Relaxed); + let _ = x.compare_exchange_weak(0, 0, Ordering::SeqCst, Ordering::Acquire); + let _ = x.compare_exchange_weak(0, 0, Ordering::SeqCst, Ordering::SeqCst); + + // AcqRel is always forbidden as a failure ordering + let _ = x.compare_exchange_weak(0, 0, Ordering::Relaxed, Ordering::AcqRel); + let _ = x.compare_exchange_weak(0, 0, Ordering::Acquire, Ordering::AcqRel); + let _ = x.compare_exchange_weak(0, 0, Ordering::Release, Ordering::AcqRel); + let _ = x.compare_exchange_weak(0, 0, Ordering::AcqRel, Ordering::AcqRel); + let _ = x.compare_exchange_weak(0, 0, Ordering::SeqCst, Ordering::AcqRel); + + // Release is always forbidden as a failure ordering + let _ = x.compare_exchange_weak(0, 0, Ordering::Relaxed, Ordering::Release); + let _ = x.compare_exchange_weak(0, 0, Ordering::Acquire, Ordering::Release); + let _ = x.compare_exchange_weak(0, 0, Ordering::Release, Ordering::Release); + let _ = x.compare_exchange_weak(0, 0, Ordering::AcqRel, Ordering::Release); + let _ = x.compare_exchange_weak(0, 0, Ordering::SeqCst, Ordering::Release); + + // Release success order forbids failure order of Acquire or SeqCst + let _ = x.compare_exchange_weak(0, 0, Ordering::Release, Ordering::Acquire); + let _ = x.compare_exchange_weak(0, 0, Ordering::Release, Ordering::SeqCst); + + // Relaxed success order also forbids failure order of Acquire or SeqCst + let _ = x.compare_exchange_weak(0, 0, Ordering::Relaxed, Ordering::SeqCst); + let _ = x.compare_exchange_weak(0, 0, Ordering::Relaxed, Ordering::Acquire); + + // Acquire/AcqRel forbids failure order of SeqCst + let _ = x.compare_exchange_weak(0, 0, Ordering::Acquire, Ordering::SeqCst); + let _ = x.compare_exchange_weak(0, 0, Ordering::AcqRel, Ordering::SeqCst); +} diff --git a/tests/ui/atomic_ordering_exchange.stderr b/tests/ui/atomic_ordering_exchange.stderr new file mode 100644 index 0000000000000..26ec15be518c5 --- /dev/null +++ b/tests/ui/atomic_ordering_exchange.stderr @@ -0,0 +1,259 @@ +error: compare_exchange's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange.rs:21:57 + | +LL | let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::invalid-atomic-ordering` implied by `-D warnings` + = help: consider using ordering mode `Relaxed` instead + +error: compare_exchange's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange.rs:22:57 + | +LL | let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire` or `Relaxed` instead + +error: compare_exchange's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange.rs:23:57 + | +LL | let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: compare_exchange's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange.rs:24:56 + | +LL | let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire` or `Relaxed` instead + +error: compare_exchange's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange.rs:25:56 + | +LL | let _ = x.compare_exchange(0, 0, Ordering::SeqCst, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead + +error: compare_exchange's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange.rs:28:57 + | +LL | let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: compare_exchange's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange.rs:29:57 + | +LL | let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire` or `Relaxed` instead + +error: compare_exchange's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange.rs:30:57 + | +LL | let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: compare_exchange's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange.rs:31:56 + | +LL | let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire` or `Relaxed` instead + +error: compare_exchange's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange.rs:32:56 + | +LL | let _ = x.compare_exchange(0, 0, Ordering::SeqCst, Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead + +error: compare_exchange's failure ordering may not stronger than the success ordering of `Release` + --> $DIR/atomic_ordering_exchange.rs:35:57 + | +LL | let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::Acquire); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: compare_exchange's failure ordering may not stronger than the success ordering of `Release` + --> $DIR/atomic_ordering_exchange.rs:36:57 + | +LL | let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: compare_exchange's failure ordering may not stronger than the success ordering of `Relaxed` + --> $DIR/atomic_ordering_exchange.rs:39:57 + | +LL | let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: compare_exchange's failure ordering may not stronger than the success ordering of `Relaxed` + --> $DIR/atomic_ordering_exchange.rs:40:57 + | +LL | let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::Acquire); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: compare_exchange's failure ordering may not stronger than the success ordering of `Acquire` + --> $DIR/atomic_ordering_exchange.rs:43:57 + | +LL | let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire` or `Relaxed` instead + +error: compare_exchange's failure ordering may not stronger than the success ordering of `AcqRel` + --> $DIR/atomic_ordering_exchange.rs:44:56 + | +LL | let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire` or `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange.rs:60:62 + | +LL | let _ = x.compare_exchange_weak(0, 0, Ordering::Relaxed, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange.rs:61:62 + | +LL | let _ = x.compare_exchange_weak(0, 0, Ordering::Acquire, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire` or `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange.rs:62:62 + | +LL | let _ = x.compare_exchange_weak(0, 0, Ordering::Release, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange.rs:63:61 + | +LL | let _ = x.compare_exchange_weak(0, 0, Ordering::AcqRel, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire` or `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange.rs:64:61 + | +LL | let _ = x.compare_exchange_weak(0, 0, Ordering::SeqCst, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange.rs:67:62 + | +LL | let _ = x.compare_exchange_weak(0, 0, Ordering::Relaxed, Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange.rs:68:62 + | +LL | let _ = x.compare_exchange_weak(0, 0, Ordering::Acquire, Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire` or `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange.rs:69:62 + | +LL | let _ = x.compare_exchange_weak(0, 0, Ordering::Release, Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange.rs:70:61 + | +LL | let _ = x.compare_exchange_weak(0, 0, Ordering::AcqRel, Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire` or `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange.rs:71:61 + | +LL | let _ = x.compare_exchange_weak(0, 0, Ordering::SeqCst, Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not stronger than the success ordering of `Release` + --> $DIR/atomic_ordering_exchange.rs:74:62 + | +LL | let _ = x.compare_exchange_weak(0, 0, Ordering::Release, Ordering::Acquire); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not stronger than the success ordering of `Release` + --> $DIR/atomic_ordering_exchange.rs:75:62 + | +LL | let _ = x.compare_exchange_weak(0, 0, Ordering::Release, Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not stronger than the success ordering of `Relaxed` + --> $DIR/atomic_ordering_exchange.rs:78:62 + | +LL | let _ = x.compare_exchange_weak(0, 0, Ordering::Relaxed, Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not stronger than the success ordering of `Relaxed` + --> $DIR/atomic_ordering_exchange.rs:79:62 + | +LL | let _ = x.compare_exchange_weak(0, 0, Ordering::Relaxed, Ordering::Acquire); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not stronger than the success ordering of `Acquire` + --> $DIR/atomic_ordering_exchange.rs:82:62 + | +LL | let _ = x.compare_exchange_weak(0, 0, Ordering::Acquire, Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire` or `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not stronger than the success ordering of `AcqRel` + --> $DIR/atomic_ordering_exchange.rs:83:61 + | +LL | let _ = x.compare_exchange_weak(0, 0, Ordering::AcqRel, Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire` or `Relaxed` instead + +error: aborting due to 32 previous errors + From 61671a2268903e1b5c28fcb3c713c27e84ea3e9b Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Wed, 9 Sep 2020 14:12:14 -0700 Subject: [PATCH 0236/1052] Detect fetch_update misuse in invalid_atomic_ordering too --- clippy_lints/src/atomic_ordering.rs | 16 ++- src/lintlist/mod.rs | 2 +- tests/ui/atomic_ordering_fetch_update.rs | 45 +++++++ tests/ui/atomic_ordering_fetch_update.stderr | 131 +++++++++++++++++++ 4 files changed, 188 insertions(+), 6 deletions(-) create mode 100644 tests/ui/atomic_ordering_fetch_update.rs create mode 100644 tests/ui/atomic_ordering_fetch_update.stderr diff --git a/clippy_lints/src/atomic_ordering.rs b/clippy_lints/src/atomic_ordering.rs index 748f45f47c2ad..ff2c281ec9d73 100644 --- a/clippy_lints/src/atomic_ordering.rs +++ b/clippy_lints/src/atomic_ordering.rs @@ -8,7 +8,8 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { /// **What it does:** Checks for usage of invalid atomic - /// ordering in atomic loads/stores/exchanges and memory fences + /// ordering in atomic loads/stores/exchanges/updates and + /// memory fences. /// /// **Why is this bad?** Using an invalid atomic ordering /// will cause a panic at run-time. @@ -32,10 +33,11 @@ declare_clippy_lint! { /// /// let _ = x.compare_exchange(false, false, Ordering::Relaxed, Ordering::SeqCst); /// let _ = x.compare_exchange_weak(false, true, Ordering::SeqCst, Ordering::Release); + /// let _ = x.fetch_update(Ordering::AcqRel, Ordering::AcqRel, |val| Some(val ^ val)); /// ``` pub INVALID_ATOMIC_ORDERING, correctness, - "usage of invalid atomic ordering in atomic loads/stores/exchanges ane memory fences" + "usage of invalid atomic ordering in atomic operations and memory fences" } declare_lint_pass!(AtomicOrdering => [INVALID_ATOMIC_ORDERING]); @@ -142,8 +144,12 @@ fn check_atomic_compare_exchange(cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::MethodCall(ref method_path, _, args, _) = &expr.kind; let method = method_path.ident.name.as_str(); if type_is_atomic(cx, &args[0]); - if method == "compare_exchange" || method == "compare_exchange_weak"; - let failure_order_arg = &args[4]; + if method == "compare_exchange" || method == "compare_exchange_weak" || method == "fetch_update"; + let (success_order_arg, failure_order_arg) = if method == "fetch_update" { + (&args[1], &args[2]) + } else { + (&args[3], &args[4]) + }; if let Some(fail_ordering_def_id) = opt_ordering_defid(cx, failure_order_arg); then { // Helper type holding on to some checking and error reporting data. Has @@ -158,7 +164,7 @@ fn check_atomic_compare_exchange(cx: &LateContext<'_>, expr: &Expr<'_>) { let acqrel = ("AcqRel", acquire.1, acquire.2); let search = [relaxed, acquire, seq_cst, release, acqrel]; - let success_lint_info = opt_ordering_defid(cx, &args[3]) + let success_lint_info = opt_ordering_defid(cx, success_order_arg) .and_then(|success_ord_def_id| -> Option { search .iter() diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index dff19ef440f31..5dead1b9b6915 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -923,7 +923,7 @@ pub static ref ALL_LINTS: Vec = vec![ Lint { name: "invalid_atomic_ordering", group: "correctness", - desc: "usage of invalid atomic ordering in atomic loads/stores and memory fences", + desc: "usage of invalid atomic ordering in atomic operations and memory fences", deprecation: None, module: "atomic_ordering", }, diff --git a/tests/ui/atomic_ordering_fetch_update.rs b/tests/ui/atomic_ordering_fetch_update.rs new file mode 100644 index 0000000000000..550bdb001e4cd --- /dev/null +++ b/tests/ui/atomic_ordering_fetch_update.rs @@ -0,0 +1,45 @@ +#![warn(clippy::invalid_atomic_ordering)] + +use std::sync::atomic::{AtomicIsize, Ordering}; + +fn main() { + // `fetch_update` testing + let x = AtomicIsize::new(0); + + // Allowed ordering combos + let _ = x.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |old| Some(old + 1)); + let _ = x.fetch_update(Ordering::Acquire, Ordering::Acquire, |old| Some(old + 1)); + let _ = x.fetch_update(Ordering::Acquire, Ordering::Relaxed, |old| Some(old + 1)); + let _ = x.fetch_update(Ordering::Release, Ordering::Relaxed, |old| Some(old + 1)); + let _ = x.fetch_update(Ordering::AcqRel, Ordering::Acquire, |old| Some(old + 1)); + let _ = x.fetch_update(Ordering::AcqRel, Ordering::Relaxed, |old| Some(old + 1)); + let _ = x.fetch_update(Ordering::SeqCst, Ordering::Relaxed, |old| Some(old + 1)); + let _ = x.fetch_update(Ordering::SeqCst, Ordering::Acquire, |old| Some(old + 1)); + let _ = x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |old| Some(old + 1)); + + // AcqRel is always forbidden as a failure ordering + let _ = x.fetch_update(Ordering::Relaxed, Ordering::AcqRel, |old| Some(old + 1)); + let _ = x.fetch_update(Ordering::Acquire, Ordering::AcqRel, |old| Some(old + 1)); + let _ = x.fetch_update(Ordering::Release, Ordering::AcqRel, |old| Some(old + 1)); + let _ = x.fetch_update(Ordering::AcqRel, Ordering::AcqRel, |old| Some(old + 1)); + let _ = x.fetch_update(Ordering::SeqCst, Ordering::AcqRel, |old| Some(old + 1)); + + // Release is always forbidden as a failure ordering + let _ = x.fetch_update(Ordering::Relaxed, Ordering::Release, |old| Some(old + 1)); + let _ = x.fetch_update(Ordering::Acquire, Ordering::Release, |old| Some(old + 1)); + let _ = x.fetch_update(Ordering::Release, Ordering::Release, |old| Some(old + 1)); + let _ = x.fetch_update(Ordering::AcqRel, Ordering::Release, |old| Some(old + 1)); + let _ = x.fetch_update(Ordering::SeqCst, Ordering::Release, |old| Some(old + 1)); + + // Release success order forbids failure order of Acquire or SeqCst + let _ = x.fetch_update(Ordering::Release, Ordering::Acquire, |old| Some(old + 1)); + let _ = x.fetch_update(Ordering::Release, Ordering::SeqCst, |old| Some(old + 1)); + + // Relaxed success order also forbids failure order of Acquire or SeqCst + let _ = x.fetch_update(Ordering::Relaxed, Ordering::SeqCst, |old| Some(old + 1)); + let _ = x.fetch_update(Ordering::Relaxed, Ordering::Acquire, |old| Some(old + 1)); + + // Acquire/AcqRel forbids failure order of SeqCst + let _ = x.fetch_update(Ordering::Acquire, Ordering::SeqCst, |old| Some(old + 1)); + let _ = x.fetch_update(Ordering::AcqRel, Ordering::SeqCst, |old| Some(old + 1)); +} diff --git a/tests/ui/atomic_ordering_fetch_update.stderr b/tests/ui/atomic_ordering_fetch_update.stderr new file mode 100644 index 0000000000000..362e104a24482 --- /dev/null +++ b/tests/ui/atomic_ordering_fetch_update.stderr @@ -0,0 +1,131 @@ +error: fetch_update's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_fetch_update.rs:21:47 + | +LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::AcqRel, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::invalid-atomic-ordering` implied by `-D warnings` + = help: consider using ordering mode `Relaxed` instead + +error: fetch_update's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_fetch_update.rs:22:47 + | +LL | let _ = x.fetch_update(Ordering::Acquire, Ordering::AcqRel, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire` or `Relaxed` instead + +error: fetch_update's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_fetch_update.rs:23:47 + | +LL | let _ = x.fetch_update(Ordering::Release, Ordering::AcqRel, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: fetch_update's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_fetch_update.rs:24:46 + | +LL | let _ = x.fetch_update(Ordering::AcqRel, Ordering::AcqRel, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire` or `Relaxed` instead + +error: fetch_update's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_fetch_update.rs:25:46 + | +LL | let _ = x.fetch_update(Ordering::SeqCst, Ordering::AcqRel, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead + +error: fetch_update's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_fetch_update.rs:28:47 + | +LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::Release, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: fetch_update's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_fetch_update.rs:29:47 + | +LL | let _ = x.fetch_update(Ordering::Acquire, Ordering::Release, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire` or `Relaxed` instead + +error: fetch_update's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_fetch_update.rs:30:47 + | +LL | let _ = x.fetch_update(Ordering::Release, Ordering::Release, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: fetch_update's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_fetch_update.rs:31:46 + | +LL | let _ = x.fetch_update(Ordering::AcqRel, Ordering::Release, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire` or `Relaxed` instead + +error: fetch_update's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_fetch_update.rs:32:46 + | +LL | let _ = x.fetch_update(Ordering::SeqCst, Ordering::Release, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead + +error: fetch_update's failure ordering may not stronger than the success ordering of `Release` + --> $DIR/atomic_ordering_fetch_update.rs:35:47 + | +LL | let _ = x.fetch_update(Ordering::Release, Ordering::Acquire, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: fetch_update's failure ordering may not stronger than the success ordering of `Release` + --> $DIR/atomic_ordering_fetch_update.rs:36:47 + | +LL | let _ = x.fetch_update(Ordering::Release, Ordering::SeqCst, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: fetch_update's failure ordering may not stronger than the success ordering of `Relaxed` + --> $DIR/atomic_ordering_fetch_update.rs:39:47 + | +LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::SeqCst, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: fetch_update's failure ordering may not stronger than the success ordering of `Relaxed` + --> $DIR/atomic_ordering_fetch_update.rs:40:47 + | +LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::Acquire, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: fetch_update's failure ordering may not stronger than the success ordering of `Acquire` + --> $DIR/atomic_ordering_fetch_update.rs:43:47 + | +LL | let _ = x.fetch_update(Ordering::Acquire, Ordering::SeqCst, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire` or `Relaxed` instead + +error: fetch_update's failure ordering may not stronger than the success ordering of `AcqRel` + --> $DIR/atomic_ordering_fetch_update.rs:44:46 + | +LL | let _ = x.fetch_update(Ordering::AcqRel, Ordering::SeqCst, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire` or `Relaxed` instead + +error: aborting due to 16 previous errors + From 159178e5d4a023f3945b504b49d3742b40453fee Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Wed, 9 Sep 2020 14:32:38 -0700 Subject: [PATCH 0237/1052] Separate compare_exchange and compare_exchange_weak uitests --- tests/ui/atomic_ordering_exchange.rs | 39 ------ tests/ui/atomic_ordering_exchange.stderr | 130 +---------------- tests/ui/atomic_ordering_exchange_weak.rs | 47 +++++++ tests/ui/atomic_ordering_exchange_weak.stderr | 131 ++++++++++++++++++ 4 files changed, 179 insertions(+), 168 deletions(-) create mode 100644 tests/ui/atomic_ordering_exchange_weak.rs create mode 100644 tests/ui/atomic_ordering_exchange_weak.stderr diff --git a/tests/ui/atomic_ordering_exchange.rs b/tests/ui/atomic_ordering_exchange.rs index 2f60a98f037b4..1ddc12f9ab213 100644 --- a/tests/ui/atomic_ordering_exchange.rs +++ b/tests/ui/atomic_ordering_exchange.rs @@ -42,43 +42,4 @@ fn main() { // Acquire/AcqRel forbids failure order of SeqCst let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::SeqCst); let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::SeqCst); - - // compare_exchange_weak tests - - // Allowed ordering combos - let _ = x.compare_exchange_weak(0, 0, Ordering::Relaxed, Ordering::Relaxed); - let _ = x.compare_exchange_weak(0, 0, Ordering::Acquire, Ordering::Acquire); - let _ = x.compare_exchange_weak(0, 0, Ordering::Acquire, Ordering::Relaxed); - let _ = x.compare_exchange_weak(0, 0, Ordering::Release, Ordering::Relaxed); - let _ = x.compare_exchange_weak(0, 0, Ordering::AcqRel, Ordering::Acquire); - let _ = x.compare_exchange_weak(0, 0, Ordering::AcqRel, Ordering::Relaxed); - let _ = x.compare_exchange_weak(0, 0, Ordering::SeqCst, Ordering::Relaxed); - let _ = x.compare_exchange_weak(0, 0, Ordering::SeqCst, Ordering::Acquire); - let _ = x.compare_exchange_weak(0, 0, Ordering::SeqCst, Ordering::SeqCst); - - // AcqRel is always forbidden as a failure ordering - let _ = x.compare_exchange_weak(0, 0, Ordering::Relaxed, Ordering::AcqRel); - let _ = x.compare_exchange_weak(0, 0, Ordering::Acquire, Ordering::AcqRel); - let _ = x.compare_exchange_weak(0, 0, Ordering::Release, Ordering::AcqRel); - let _ = x.compare_exchange_weak(0, 0, Ordering::AcqRel, Ordering::AcqRel); - let _ = x.compare_exchange_weak(0, 0, Ordering::SeqCst, Ordering::AcqRel); - - // Release is always forbidden as a failure ordering - let _ = x.compare_exchange_weak(0, 0, Ordering::Relaxed, Ordering::Release); - let _ = x.compare_exchange_weak(0, 0, Ordering::Acquire, Ordering::Release); - let _ = x.compare_exchange_weak(0, 0, Ordering::Release, Ordering::Release); - let _ = x.compare_exchange_weak(0, 0, Ordering::AcqRel, Ordering::Release); - let _ = x.compare_exchange_weak(0, 0, Ordering::SeqCst, Ordering::Release); - - // Release success order forbids failure order of Acquire or SeqCst - let _ = x.compare_exchange_weak(0, 0, Ordering::Release, Ordering::Acquire); - let _ = x.compare_exchange_weak(0, 0, Ordering::Release, Ordering::SeqCst); - - // Relaxed success order also forbids failure order of Acquire or SeqCst - let _ = x.compare_exchange_weak(0, 0, Ordering::Relaxed, Ordering::SeqCst); - let _ = x.compare_exchange_weak(0, 0, Ordering::Relaxed, Ordering::Acquire); - - // Acquire/AcqRel forbids failure order of SeqCst - let _ = x.compare_exchange_weak(0, 0, Ordering::Acquire, Ordering::SeqCst); - let _ = x.compare_exchange_weak(0, 0, Ordering::AcqRel, Ordering::SeqCst); } diff --git a/tests/ui/atomic_ordering_exchange.stderr b/tests/ui/atomic_ordering_exchange.stderr index 26ec15be518c5..c09d2d6ab21ae 100644 --- a/tests/ui/atomic_ordering_exchange.stderr +++ b/tests/ui/atomic_ordering_exchange.stderr @@ -127,133 +127,5 @@ LL | let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::SeqCst); | = help: consider using ordering modes `Acquire` or `Relaxed` instead -error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` - --> $DIR/atomic_ordering_exchange.rs:60:62 - | -LL | let _ = x.compare_exchange_weak(0, 0, Ordering::Relaxed, Ordering::AcqRel); - | ^^^^^^^^^^^^^^^^ - | - = help: consider using ordering mode `Relaxed` instead - -error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` - --> $DIR/atomic_ordering_exchange.rs:61:62 - | -LL | let _ = x.compare_exchange_weak(0, 0, Ordering::Acquire, Ordering::AcqRel); - | ^^^^^^^^^^^^^^^^ - | - = help: consider using ordering modes `Acquire` or `Relaxed` instead - -error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` - --> $DIR/atomic_ordering_exchange.rs:62:62 - | -LL | let _ = x.compare_exchange_weak(0, 0, Ordering::Release, Ordering::AcqRel); - | ^^^^^^^^^^^^^^^^ - | - = help: consider using ordering mode `Relaxed` instead - -error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` - --> $DIR/atomic_ordering_exchange.rs:63:61 - | -LL | let _ = x.compare_exchange_weak(0, 0, Ordering::AcqRel, Ordering::AcqRel); - | ^^^^^^^^^^^^^^^^ - | - = help: consider using ordering modes `Acquire` or `Relaxed` instead - -error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` - --> $DIR/atomic_ordering_exchange.rs:64:61 - | -LL | let _ = x.compare_exchange_weak(0, 0, Ordering::SeqCst, Ordering::AcqRel); - | ^^^^^^^^^^^^^^^^ - | - = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead - -error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` - --> $DIR/atomic_ordering_exchange.rs:67:62 - | -LL | let _ = x.compare_exchange_weak(0, 0, Ordering::Relaxed, Ordering::Release); - | ^^^^^^^^^^^^^^^^^ - | - = help: consider using ordering mode `Relaxed` instead - -error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` - --> $DIR/atomic_ordering_exchange.rs:68:62 - | -LL | let _ = x.compare_exchange_weak(0, 0, Ordering::Acquire, Ordering::Release); - | ^^^^^^^^^^^^^^^^^ - | - = help: consider using ordering modes `Acquire` or `Relaxed` instead - -error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` - --> $DIR/atomic_ordering_exchange.rs:69:62 - | -LL | let _ = x.compare_exchange_weak(0, 0, Ordering::Release, Ordering::Release); - | ^^^^^^^^^^^^^^^^^ - | - = help: consider using ordering mode `Relaxed` instead - -error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` - --> $DIR/atomic_ordering_exchange.rs:70:61 - | -LL | let _ = x.compare_exchange_weak(0, 0, Ordering::AcqRel, Ordering::Release); - | ^^^^^^^^^^^^^^^^^ - | - = help: consider using ordering modes `Acquire` or `Relaxed` instead - -error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` - --> $DIR/atomic_ordering_exchange.rs:71:61 - | -LL | let _ = x.compare_exchange_weak(0, 0, Ordering::SeqCst, Ordering::Release); - | ^^^^^^^^^^^^^^^^^ - | - = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead - -error: compare_exchange_weak's failure ordering may not stronger than the success ordering of `Release` - --> $DIR/atomic_ordering_exchange.rs:74:62 - | -LL | let _ = x.compare_exchange_weak(0, 0, Ordering::Release, Ordering::Acquire); - | ^^^^^^^^^^^^^^^^^ - | - = help: consider using ordering mode `Relaxed` instead - -error: compare_exchange_weak's failure ordering may not stronger than the success ordering of `Release` - --> $DIR/atomic_ordering_exchange.rs:75:62 - | -LL | let _ = x.compare_exchange_weak(0, 0, Ordering::Release, Ordering::SeqCst); - | ^^^^^^^^^^^^^^^^ - | - = help: consider using ordering mode `Relaxed` instead - -error: compare_exchange_weak's failure ordering may not stronger than the success ordering of `Relaxed` - --> $DIR/atomic_ordering_exchange.rs:78:62 - | -LL | let _ = x.compare_exchange_weak(0, 0, Ordering::Relaxed, Ordering::SeqCst); - | ^^^^^^^^^^^^^^^^ - | - = help: consider using ordering mode `Relaxed` instead - -error: compare_exchange_weak's failure ordering may not stronger than the success ordering of `Relaxed` - --> $DIR/atomic_ordering_exchange.rs:79:62 - | -LL | let _ = x.compare_exchange_weak(0, 0, Ordering::Relaxed, Ordering::Acquire); - | ^^^^^^^^^^^^^^^^^ - | - = help: consider using ordering mode `Relaxed` instead - -error: compare_exchange_weak's failure ordering may not stronger than the success ordering of `Acquire` - --> $DIR/atomic_ordering_exchange.rs:82:62 - | -LL | let _ = x.compare_exchange_weak(0, 0, Ordering::Acquire, Ordering::SeqCst); - | ^^^^^^^^^^^^^^^^ - | - = help: consider using ordering modes `Acquire` or `Relaxed` instead - -error: compare_exchange_weak's failure ordering may not stronger than the success ordering of `AcqRel` - --> $DIR/atomic_ordering_exchange.rs:83:61 - | -LL | let _ = x.compare_exchange_weak(0, 0, Ordering::AcqRel, Ordering::SeqCst); - | ^^^^^^^^^^^^^^^^ - | - = help: consider using ordering modes `Acquire` or `Relaxed` instead - -error: aborting due to 32 previous errors +error: aborting due to 16 previous errors diff --git a/tests/ui/atomic_ordering_exchange_weak.rs b/tests/ui/atomic_ordering_exchange_weak.rs new file mode 100644 index 0000000000000..5906990250728 --- /dev/null +++ b/tests/ui/atomic_ordering_exchange_weak.rs @@ -0,0 +1,47 @@ +#![warn(clippy::invalid_atomic_ordering)] + +use std::sync::atomic::{AtomicPtr, Ordering}; + +fn main() { + let ptr = &mut 5; + let ptr2 = &mut 10; + // `compare_exchange_weak` testing + let x = AtomicPtr::new(ptr); + + // Allowed ordering combos + let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::Relaxed); + let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Acquire, Ordering::Acquire); + let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Acquire, Ordering::Relaxed); + let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Release, Ordering::Relaxed); + let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::AcqRel, Ordering::Acquire); + let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::AcqRel, Ordering::Relaxed); + let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::SeqCst, Ordering::Relaxed); + let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::SeqCst, Ordering::Acquire); + let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::SeqCst, Ordering::SeqCst); + + // AcqRel is always forbidden as a failure ordering + let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Relaxed, Ordering::AcqRel); + let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Acquire, Ordering::AcqRel); + let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering::AcqRel); + let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::AcqRel, Ordering::AcqRel); + let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::SeqCst, Ordering::AcqRel); + + // Release is always forbidden as a failure ordering + let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::Release); + let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Acquire, Ordering::Release); + let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Release, Ordering::Release); + let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::AcqRel, Ordering::Release); + let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::SeqCst, Ordering::Release); + + // Release success order forbids failure order of Acquire or SeqCst + let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering::Acquire); + let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering::SeqCst); + + // Relaxed success order also forbids failure order of Acquire or SeqCst + let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::SeqCst); + let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::Acquire); + + // Acquire/AcqRel forbids failure order of SeqCst + let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Acquire, Ordering::SeqCst); + let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::AcqRel, Ordering::SeqCst); +} diff --git a/tests/ui/atomic_ordering_exchange_weak.stderr b/tests/ui/atomic_ordering_exchange_weak.stderr new file mode 100644 index 0000000000000..7210431bd1bdf --- /dev/null +++ b/tests/ui/atomic_ordering_exchange_weak.stderr @@ -0,0 +1,131 @@ +error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange_weak.rs:23:67 + | +LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Relaxed, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::invalid-atomic-ordering` implied by `-D warnings` + = help: consider using ordering mode `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange_weak.rs:24:67 + | +LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Acquire, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire` or `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange_weak.rs:25:67 + | +LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange_weak.rs:26:66 + | +LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::AcqRel, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire` or `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange_weak.rs:27:66 + | +LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::SeqCst, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange_weak.rs:30:67 + | +LL | let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange_weak.rs:31:67 + | +LL | let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Acquire, Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire` or `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange_weak.rs:32:67 + | +LL | let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Release, Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange_weak.rs:33:66 + | +LL | let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::AcqRel, Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire` or `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + --> $DIR/atomic_ordering_exchange_weak.rs:34:66 + | +LL | let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::SeqCst, Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not stronger than the success ordering of `Release` + --> $DIR/atomic_ordering_exchange_weak.rs:37:67 + | +LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering::Acquire); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not stronger than the success ordering of `Release` + --> $DIR/atomic_ordering_exchange_weak.rs:38:67 + | +LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not stronger than the success ordering of `Relaxed` + --> $DIR/atomic_ordering_exchange_weak.rs:41:67 + | +LL | let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not stronger than the success ordering of `Relaxed` + --> $DIR/atomic_ordering_exchange_weak.rs:42:67 + | +LL | let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::Acquire); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering mode `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not stronger than the success ordering of `Acquire` + --> $DIR/atomic_ordering_exchange_weak.rs:45:67 + | +LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Acquire, Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire` or `Relaxed` instead + +error: compare_exchange_weak's failure ordering may not stronger than the success ordering of `AcqRel` + --> $DIR/atomic_ordering_exchange_weak.rs:46:66 + | +LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::AcqRel, Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire` or `Relaxed` instead + +error: aborting due to 16 previous errors + From b65745545f410b31c5ecdd33a8299a65da578af2 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Wed, 9 Sep 2020 14:40:43 -0700 Subject: [PATCH 0238/1052] Use AtomicU8 in ordering example so all operations can be demonstrated --- clippy_lints/src/atomic_ordering.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/atomic_ordering.rs b/clippy_lints/src/atomic_ordering.rs index ff2c281ec9d73..d4e070b0c24bd 100644 --- a/clippy_lints/src/atomic_ordering.rs +++ b/clippy_lints/src/atomic_ordering.rs @@ -18,22 +18,22 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust,no_run - /// # use std::sync::atomic::{self, AtomicBool, Ordering}; + /// # use std::sync::atomic::{self, AtomicU8, Ordering}; /// - /// let x = AtomicBool::new(true); + /// let x = AtomicU8::new(0); /// /// let _ = x.load(Ordering::Release); /// let _ = x.load(Ordering::AcqRel); /// - /// x.store(false, Ordering::Acquire); - /// x.store(false, Ordering::AcqRel); + /// x.store(1, Ordering::Acquire); + /// x.store(2, Ordering::AcqRel); /// /// atomic::fence(Ordering::Relaxed); /// atomic::compiler_fence(Ordering::Relaxed); /// - /// let _ = x.compare_exchange(false, false, Ordering::Relaxed, Ordering::SeqCst); - /// let _ = x.compare_exchange_weak(false, true, Ordering::SeqCst, Ordering::Release); - /// let _ = x.fetch_update(Ordering::AcqRel, Ordering::AcqRel, |val| Some(val ^ val)); + /// let _ = x.compare_exchange(1, 2, Ordering::Relaxed, Ordering::SeqCst); + /// let _ = x.compare_exchange_weak(2, 3, Ordering::SeqCst, Ordering::Release); + /// let _ = x.fetch_update(Ordering::AcqRel, Ordering::AcqRel, |val| Some(val + val)); /// ``` pub INVALID_ATOMIC_ORDERING, correctness, From f7aee330c70ef787d2224adb49804343978dd145 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Wed, 9 Sep 2020 14:49:32 -0700 Subject: [PATCH 0239/1052] Also fixed monospace font for d3-graphviz engine VS code graphviz extensions use d3-graphviz, which supports `Courier` fontname but does not support `monospace`. This caused graphs to render poorly because the text sizes were wrong. --- compiler/rustc_graphviz/src/lib.rs | 2 +- compiler/rustc_mir/src/util/graphviz.rs | 2 +- src/test/mir-opt/graphviz.main.mir_map.0.dot | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs index 252e341686541..29ec3572016d7 100644 --- a/compiler/rustc_graphviz/src/lib.rs +++ b/compiler/rustc_graphviz/src/lib.rs @@ -634,7 +634,7 @@ where let mut graph_attrs = Vec::new(); let mut content_attrs = Vec::new(); if options.contains(&RenderOption::Monospace) { - let font = r#"fontname="monospace""#; + let font = r#"fontname="Courier, monospace""#; graph_attrs.push(font); content_attrs.push(font); }; diff --git a/compiler/rustc_mir/src/util/graphviz.rs b/compiler/rustc_mir/src/util/graphviz.rs index bc1e3fa8b2915..e89c943770638 100644 --- a/compiler/rustc_mir/src/util/graphviz.rs +++ b/compiler/rustc_mir/src/util/graphviz.rs @@ -55,7 +55,7 @@ where writeln!(w, "{} {}Mir_{} {{", kind, cluster, def_name)?; // Global graph properties - let font = r#"fontname="monospace""#; + let font = r#"fontname="Courier, monospace""#; let mut graph_attrs = vec![font]; let mut content_attrs = vec![font]; diff --git a/src/test/mir-opt/graphviz.main.mir_map.0.dot b/src/test/mir-opt/graphviz.main.mir_map.0.dot index f5d8b84812a3e..df4f11f0f2169 100644 --- a/src/test/mir-opt/graphviz.main.mir_map.0.dot +++ b/src/test/mir-opt/graphviz.main.mir_map.0.dot @@ -1,7 +1,7 @@ digraph Mir_0_3 { - graph [fontname="monospace"]; - node [fontname="monospace"]; - edge [fontname="monospace"]; + graph [fontname="Courier, monospace"]; + node [fontname="Courier, monospace"]; + edge [fontname="Courier, monospace"]; label=>; bb0__0_3 [shape="none", label=<
0
_0 = const ()
goto
>]; bb1__0_3 [shape="none", label=<
1
resume
>]; From 2b54ab880c1803ff1178205b9b0a1c02238c37bf Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Sun, 16 Aug 2020 22:32:50 +0200 Subject: [PATCH 0240/1052] BTreeMap: pull the map's root out of NodeRef --- library/alloc/src/collections/btree/borrow.rs | 44 +++++++ .../src/collections/btree/borrow/tests.rs | 19 +++ library/alloc/src/collections/btree/map.rs | 121 +++++++++++------- library/alloc/src/collections/btree/mod.rs | 1 + library/alloc/src/collections/btree/node.rs | 95 ++++---------- 5 files changed, 163 insertions(+), 117 deletions(-) create mode 100644 library/alloc/src/collections/btree/borrow.rs create mode 100644 library/alloc/src/collections/btree/borrow/tests.rs diff --git a/library/alloc/src/collections/btree/borrow.rs b/library/alloc/src/collections/btree/borrow.rs new file mode 100644 index 0000000000000..5c95acfbe9c20 --- /dev/null +++ b/library/alloc/src/collections/btree/borrow.rs @@ -0,0 +1,44 @@ +use core::marker::PhantomData; +use core::ptr::NonNull; + +/// Models a reborrow of some unique reference, when you know that the reborrow +/// and all its descendants (i.e., all pointers and references derived from it) +/// will not be used any more at some point, after which you want to use the +/// original unique reference again. +/// +/// The borrow checker usually handles this stacking of borrows for you, but +/// some control flows that accomplish this stacking are too complicated for +/// the compiler to follow. A `DormantMutRef` allows you to check borrowing +/// yourself, while still expressing its stacked nature, and encapsulating +/// the raw pointer code needed to do this without undefined behavior. +pub struct DormantMutRef<'a, T> { + ptr: NonNull, + _marker: PhantomData<&'a mut T>, +} + +impl<'a, T> DormantMutRef<'a, T> { + /// Capture a unique borrow, and immediately reborrow it. For the compiler, + /// the lifetime of the new reference is the same as the lifetime of the + /// original reference, but you promise to use it for a shorter period. + pub fn new(t: &'a mut T) -> (&'a mut T, Self) { + let ptr = NonNull::from(t); + // SAFETY: we hold the borrow throughout 'a via `_marker`, and we expose + // only this reference, so it is unique. + let new_ref = unsafe { &mut *ptr.as_ptr() }; + (new_ref, Self { ptr, _marker: PhantomData }) + } + + /// Revert to the unique borrow initially captured. + /// + /// # Safety + /// + /// The reborrow must have ended, i.e., the reference returned by `new` and + /// all pointers and references derived from it, must not be used anymore. + pub unsafe fn awaken(self) -> &'a mut T { + // SAFETY: our own safety conditions imply this reference is again unique. + unsafe { &mut *self.ptr.as_ptr() } + } +} + +#[cfg(test)] +mod tests; diff --git a/library/alloc/src/collections/btree/borrow/tests.rs b/library/alloc/src/collections/btree/borrow/tests.rs new file mode 100644 index 0000000000000..56a8434fc71e6 --- /dev/null +++ b/library/alloc/src/collections/btree/borrow/tests.rs @@ -0,0 +1,19 @@ +use super::DormantMutRef; + +#[test] +fn test_borrow() { + let mut data = 1; + let mut stack = vec![]; + let mut rr = &mut data; + for factor in [2, 3, 7].iter() { + let (r, dormant_r) = DormantMutRef::new(rr); + rr = r; + assert_eq!(*rr, 1); + stack.push((factor, dormant_r)); + } + while let Some((factor, dormant_r)) = stack.pop() { + let r = unsafe { dormant_r.awaken() }; + *r *= factor; + } + assert_eq!(data, 42); +} diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 674cdaaa012d9..aed898be08fb6 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -8,6 +8,7 @@ use core::mem::{self, ManuallyDrop}; use core::ops::{Index, RangeBounds}; use core::ptr; +use super::borrow::DormantMutRef; use super::node::{self, marker, ForceResult::*, Handle, InsertResult::*, NodeRef}; use super::search::{self, SearchResult::*}; use super::unwrap_unchecked; @@ -228,24 +229,23 @@ where } fn take(&mut self, key: &Q) -> Option { - let root_node = self.root.as_mut()?.node_as_mut(); + let (map, dormant_map) = DormantMutRef::new(self); + let root_node = map.root.as_mut()?.node_as_mut(); match search::search_tree(root_node, key) { - Found(handle) => Some( - OccupiedEntry { handle, length: &mut self.length, _marker: PhantomData } - .remove_kv() - .0, - ), + Found(handle) => { + Some(OccupiedEntry { handle, dormant_map, _marker: PhantomData }.remove_kv().0) + } GoDown(_) => None, } } fn replace(&mut self, key: K) -> Option { - let root = Self::ensure_is_owned(&mut self.root); - match search::search_tree::, K, (), K>(root.node_as_mut(), &key) { + let (map, dormant_map) = DormantMutRef::new(self); + let root_node = Self::ensure_is_owned(&mut map.root).node_as_mut(); + match search::search_tree::, K, (), K>(root_node, &key) { Found(handle) => Some(mem::replace(handle.into_key_mut(), key)), GoDown(handle) => { - VacantEntry { key, handle, length: &mut self.length, _marker: PhantomData } - .insert(()); + VacantEntry { key, handle, dormant_map, _marker: PhantomData }.insert(()); None } } @@ -459,7 +459,7 @@ impl Debug for Entry<'_, K, V> { pub struct VacantEntry<'a, K: 'a, V: 'a> { key: K, handle: Handle, K, V, marker::Leaf>, marker::Edge>, - length: &'a mut usize, + dormant_map: DormantMutRef<'a, BTreeMap>, // Be invariant in `K` and `V` _marker: PhantomData<&'a mut (K, V)>, @@ -479,8 +479,7 @@ impl Debug for VacantEntry<'_, K, V> { #[stable(feature = "rust1", since = "1.0.0")] pub struct OccupiedEntry<'a, K: 'a, V: 'a> { handle: Handle, K, V, marker::LeafOrInternal>, marker::KV>, - - length: &'a mut usize, + dormant_map: DormantMutRef<'a, BTreeMap>, // Be invariant in `K` and `V` _marker: PhantomData<&'a mut (K, V)>, @@ -644,13 +643,10 @@ impl BTreeMap { /// ``` #[unstable(feature = "map_first_last", issue = "62924")] pub fn first_entry(&mut self) -> Option> { - let root_node = self.root.as_mut()?.node_as_mut(); + let (map, dormant_map) = DormantMutRef::new(self); + let root_node = map.root.as_mut()?.node_as_mut(); let kv = root_node.first_leaf_edge().right_kv().ok()?; - Some(OccupiedEntry { - handle: kv.forget_node_type(), - length: &mut self.length, - _marker: PhantomData, - }) + Some(OccupiedEntry { handle: kv.forget_node_type(), dormant_map, _marker: PhantomData }) } /// Removes and returns the first element in the map. @@ -721,13 +717,10 @@ impl BTreeMap { /// ``` #[unstable(feature = "map_first_last", issue = "62924")] pub fn last_entry(&mut self) -> Option> { - let root_node = self.root.as_mut()?.node_as_mut(); + let (map, dormant_map) = DormantMutRef::new(self); + let root_node = map.root.as_mut()?.node_as_mut(); let kv = root_node.last_leaf_edge().left_kv().ok()?; - Some(OccupiedEntry { - handle: kv.forget_node_type(), - length: &mut self.length, - _marker: PhantomData, - }) + Some(OccupiedEntry { handle: kv.forget_node_type(), dormant_map, _marker: PhantomData }) } /// Removes and returns the last element in the map. @@ -901,12 +894,12 @@ impl BTreeMap { K: Borrow, Q: Ord, { - let root_node = self.root.as_mut()?.node_as_mut(); + let (map, dormant_map) = DormantMutRef::new(self); + let root_node = map.root.as_mut()?.node_as_mut(); match search::search_tree(root_node, key) { - Found(handle) => Some( - OccupiedEntry { handle, length: &mut self.length, _marker: PhantomData } - .remove_entry(), - ), + Found(handle) => { + Some(OccupiedEntry { handle, dormant_map, _marker: PhantomData }.remove_entry()) + } GoDown(_) => None, } } @@ -1073,13 +1066,12 @@ impl BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] pub fn entry(&mut self, key: K) -> Entry<'_, K, V> { // FIXME(@porglezomp) Avoid allocating if we don't insert - let root = Self::ensure_is_owned(&mut self.root); - match search::search_tree(root.node_as_mut(), &key) { - Found(handle) => { - Occupied(OccupiedEntry { handle, length: &mut self.length, _marker: PhantomData }) - } + let (map, dormant_map) = DormantMutRef::new(self); + let root_node = Self::ensure_is_owned(&mut map.root).node_as_mut(); + match search::search_tree(root_node, &key) { + Found(handle) => Occupied(OccupiedEntry { handle, dormant_map, _marker: PhantomData }), GoDown(handle) => { - Vacant(VacantEntry { key, handle, length: &mut self.length, _marker: PhantomData }) + Vacant(VacantEntry { key, handle, dormant_map, _marker: PhantomData }) } } } @@ -1284,9 +1276,17 @@ impl BTreeMap { } pub(super) fn drain_filter_inner(&mut self) -> DrainFilterInner<'_, K, V> { - let root_node = self.root.as_mut().map(|r| r.node_as_mut()); - let front = root_node.map(|rn| rn.first_leaf_edge()); - DrainFilterInner { length: &mut self.length, cur_leaf_edge: front } + if let Some(root) = self.root.as_mut() { + let (root, dormant_root) = DormantMutRef::new(root); + let front = root.node_as_mut().first_leaf_edge(); + DrainFilterInner { + length: &mut self.length, + dormant_root: Some(dormant_root), + cur_leaf_edge: Some(front), + } + } else { + DrainFilterInner { length: &mut self.length, dormant_root: None, cur_leaf_edge: None } + } } /// Creates a consuming iterator visiting all the keys, in sorted order. @@ -1671,6 +1671,9 @@ where /// of the predicate, thus also serving for BTreeSet::DrainFilter. pub(super) struct DrainFilterInner<'a, K: 'a, V: 'a> { length: &'a mut usize, + // dormant_root is wrapped in an Option to be able to `take` it. + dormant_root: Option>>, + // cur_leaf_edge is wrapped in an Option because maps without root lack a leaf edge. cur_leaf_edge: Option, K, V, marker::Leaf>, marker::Edge>>, } @@ -1728,7 +1731,13 @@ impl<'a, K: 'a, V: 'a> DrainFilterInner<'a, K, V> { let (k, v) = kv.kv_mut(); if pred(k, v) { *self.length -= 1; - let (kv, pos) = kv.remove_kv_tracking(); + let (kv, pos) = kv.remove_kv_tracking(|| { + // SAFETY: we will touch the root in a way that will not + // invalidate the position returned. + let root = unsafe { self.dormant_root.take().unwrap().awaken() }; + root.pop_internal_level(); + self.dormant_root = Some(DormantMutRef::new(root).1); + }); self.cur_leaf_edge = Some(pos); return Some(kv); } @@ -2456,13 +2465,20 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(self, value: V) -> &'a mut V { - *self.length += 1; - let out_ptr = match self.handle.insert_recursing(self.key, value) { - (Fit(_), val_ptr) => val_ptr, + (Fit(_), val_ptr) => { + // Safety: We have consumed self.handle and the handle returned. + let map = unsafe { self.dormant_map.awaken() }; + map.length += 1; + val_ptr + } (Split(ins), val_ptr) => { - let root = ins.left.into_root_mut(); + drop(ins.left); + // 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); + map.length += 1; val_ptr } }; @@ -2636,9 +2652,15 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { // Body of `remove_entry`, separate to keep the above implementations short. fn remove_kv(self) -> (K, V) { - *self.length -= 1; - - let (old_kv, _) = self.handle.remove_kv_tracking(); + let mut emptied_internal_root = false; + let (old_kv, _) = self.handle.remove_kv_tracking(|| emptied_internal_root = true); + // SAFETY: we consumed the intermediate root borrow, `self.handle`. + let map = unsafe { self.dormant_map.awaken() }; + map.length -= 1; + if emptied_internal_root { + let root = map.root.as_mut().unwrap(); + root.pop_internal_level(); + } old_kv } } @@ -2646,8 +2668,9 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { impl<'a, K: 'a, V: 'a> Handle, K, V, marker::LeafOrInternal>, marker::KV> { /// Removes a key/value-pair from the map, and returns that pair, as well as /// the leaf edge corresponding to that former pair. - fn remove_kv_tracking( + fn remove_kv_tracking( self, + handle_emptied_internal_root: F, ) -> ((K, V), Handle, K, V, marker::Leaf>, marker::Edge>) { let (old_kv, mut pos, was_internal) = match self.force() { Leaf(leaf) => { @@ -2700,7 +2723,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::LeafOrInter // The parent that was just emptied must be the root, // because nodes on a lower level would not have been // left with a single child. - parent.into_root_mut().pop_internal_level(); + handle_emptied_internal_root(); break; } else { cur_node = parent.forget_type(); diff --git a/library/alloc/src/collections/btree/mod.rs b/library/alloc/src/collections/btree/mod.rs index 6c8a588eb58f3..1f85c44b185ed 100644 --- a/library/alloc/src/collections/btree/mod.rs +++ b/library/alloc/src/collections/btree/mod.rs @@ -1,3 +1,4 @@ +mod borrow; pub mod map; mod navigate; mod node; diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index f9de88e4c13c8..8832619a404cb 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -168,40 +168,20 @@ impl Root { /// Borrows and returns an immutable reference to the node owned by the root. pub fn node_as_ref(&self) -> NodeRef, K, V, marker::LeafOrInternal> { - NodeRef { - height: self.height, - node: self.node.as_ptr(), - root: ptr::null(), - _marker: PhantomData, - } + NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } } /// Borrows and returns a mutable reference to the node owned by the root. pub fn node_as_mut(&mut self) -> NodeRef, K, V, marker::LeafOrInternal> { - NodeRef { - height: self.height, - node: self.node.as_ptr(), - root: self as *mut _, - _marker: PhantomData, - } + NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } } pub fn node_as_valmut(&mut self) -> NodeRef, K, V, marker::LeafOrInternal> { - NodeRef { - height: self.height, - node: self.node.as_ptr(), - root: ptr::null(), - _marker: PhantomData, - } + NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } } pub fn into_ref(self) -> NodeRef { - NodeRef { - height: self.height, - node: self.node.as_ptr(), - root: ptr::null(), - _marker: PhantomData, - } + NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } } /// Adds a new internal node with a single edge, pointing to the previous root, and make that @@ -214,12 +194,8 @@ impl Root { self.node = BoxedNode::from_internal(new_node); self.height += 1; - let mut ret = NodeRef { - height: self.height, - node: self.node.as_ptr(), - root: self as *mut _, - _marker: PhantomData, - }; + let mut ret = + NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData }; unsafe { ret.reborrow_mut().first_edge().correct_parent_link(); @@ -228,11 +204,15 @@ impl Root { ret } - /// Removes the internal root node, using its first child as the new root. - /// As it is intended only to be called when the root has only one child, - /// no cleanup is done on any of the other children of the root. + /// Removes the internal root node, using its first child as the new root node. + /// As it is intended only to be called when the root node has only one child, + /// no cleanup is done on any of the other children. /// This decreases the height by 1 and is the opposite of `push_internal_level`. - /// Panics if there is no internal level, i.e. if the root is a leaf. + /// + /// 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. + /// + /// 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); @@ -276,8 +256,6 @@ pub struct NodeRef { /// The number of levels below the node. height: usize, node: NonNull>, - // `root` is null unless the borrow type is `Mut` - root: *const Root, _marker: PhantomData<(BorrowType, Type)>, } @@ -342,7 +320,7 @@ impl NodeRef { /// Temporarily takes out another, immutable reference to the same node. fn reborrow(&self) -> NodeRef, K, V, Type> { - NodeRef { height: self.height, node: self.node, root: self.root, _marker: PhantomData } + NodeRef { height: self.height, node: self.node, _marker: PhantomData } } /// Exposes the leaf "portion" of any leaf or internal node. @@ -390,12 +368,7 @@ impl NodeRef { let parent_as_leaf = unsafe { (*self.as_leaf_ptr()).parent as *const LeafNode }; if let Some(non_zero) = NonNull::new(parent_as_leaf as *mut _) { Ok(Handle { - node: NodeRef { - height: self.height + 1, - node: non_zero, - root: self.root, - _marker: PhantomData, - }, + node: NodeRef { height: self.height + 1, node: non_zero, _marker: PhantomData }, idx: unsafe { usize::from(*(*self.as_leaf_ptr()).parent_idx.as_ptr()) }, _marker: PhantomData, }) @@ -465,21 +438,21 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { /// Unsafely asserts to the compiler some static information about whether this /// node is a `Leaf` or an `Internal`. unsafe fn cast_unchecked(self) -> NodeRef, K, V, NewType> { - NodeRef { height: self.height, node: self.node, root: self.root, _marker: PhantomData } + NodeRef { height: self.height, node: self.node, _marker: PhantomData } } /// Temporarily takes out another, mutable reference to the same node. Beware, as /// this method is very dangerous, doubly so since it may not immediately appear /// dangerous. /// - /// Because mutable pointers can roam anywhere around the tree and can even (through - /// `into_root_mut`) mess with the root of the tree, the result of `reborrow_mut` - /// can easily be used to make the original mutable pointer dangling, or, in the case - /// of a reborrowed handle, out of bounds. - // FIXME(@gereeter) consider adding yet another type parameter to `NodeRef` that restricts - // the use of `ascend` and `into_root_mut` on reborrowed pointers, preventing this unsafety. + /// Because mutable pointers can roam anywhere around the tree, the returned + /// pointer can easily be used to make the original pointer dangling, out of + /// bounds, or invalid under stacked borrow rules. + // FIXME(@gereeter) consider adding yet another type parameter to `NodeRef` + // that restricts the use of navigation methods on reborrowed pointers, + // preventing this unsafety. unsafe fn reborrow_mut(&mut self) -> NodeRef, K, V, Type> { - NodeRef { height: self.height, node: self.node, root: self.root, _marker: PhantomData } + NodeRef { height: self.height, node: self.node, _marker: PhantomData } } /// Exposes the leaf "portion" of any leaf or internal node for writing. @@ -522,12 +495,6 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { } impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { - /// Gets a mutable reference to the root itself. This is useful primarily when the - /// height of the tree needs to be adjusted. Never call this on a reborrowed pointer. - pub fn into_root_mut(self) -> &'a mut Root { - unsafe { &mut *(self.root as *mut Root) } - } - fn into_key_slice_mut(mut self) -> &'a mut [K] { // SAFETY: The keys of a node must always be initialized up to length. unsafe { @@ -757,14 +724,12 @@ impl NodeRef { ForceResult::Leaf(NodeRef { height: self.height, node: self.node, - root: self.root, _marker: PhantomData, }) } else { ForceResult::Internal(NodeRef { height: self.height, node: self.node, - root: self.root, _marker: PhantomData, }) } @@ -855,12 +820,7 @@ impl<'a, K, V, NodeType, HandleType> Handle, K, V, NodeT /// this method is very dangerous, doubly so since it may not immediately appear /// dangerous. /// - /// Because mutable pointers can roam anywhere around the tree and can even (through - /// `into_root_mut`) mess with the root of the tree, the result of `reborrow_mut` - /// can easily be used to make the original mutable pointer dangling, or, in the case - /// of a reborrowed handle, out of bounds. - // FIXME(@gereeter) consider adding yet another type parameter to `NodeRef` that restricts - // the use of `ascend` and `into_root_mut` on reborrowed pointers, preventing this unsafety. + /// For details, see `NodeRef::reborrow_mut`. pub unsafe fn reborrow_mut( &mut self, ) -> Handle, K, V, NodeType>, HandleType> { @@ -1106,7 +1066,6 @@ impl Handle, marke NodeRef { height: self.node.height - 1, node: unsafe { (&*(*internal_node).edges.get_unchecked(self.idx).as_ptr()).as_ptr() }, - root: self.node.root, _marker: PhantomData, } } @@ -1499,14 +1458,14 @@ unsafe fn move_edges( impl NodeRef { /// Removes any static information asserting that this node is a `Leaf` node. pub fn forget_type(self) -> NodeRef { - NodeRef { height: self.height, node: self.node, root: self.root, _marker: PhantomData } + NodeRef { height: self.height, node: self.node, _marker: PhantomData } } } impl NodeRef { /// Removes any static information asserting that this node is an `Internal` node. pub fn forget_type(self) -> NodeRef { - NodeRef { height: self.height, node: self.node, root: self.root, _marker: PhantomData } + NodeRef { height: self.height, node: self.node, _marker: PhantomData } } } From b4935e07269429e04abe0d6d25f7e3211f4fa3f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Thu, 10 Sep 2020 00:03:58 +0200 Subject: [PATCH 0241/1052] use sort_unstable to sort primitive types It's not important to retain original order if we have &[1, 1, 2, 3] for example. clippy::stable_sort_primitive --- compiler/rustc_ast/src/util/lev_distance.rs | 3 ++- compiler/rustc_ast_lowering/src/expr.rs | 5 +++-- compiler/rustc_lint/src/non_ascii_idents.rs | 3 ++- compiler/rustc_mir/src/monomorphize/partitioning/merging.rs | 4 +++- compiler/rustc_mir/src/transform/simplify_try.rs | 4 ++-- compiler/rustc_typeck/src/check/mod.rs | 6 ++++-- 6 files changed, 16 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_ast/src/util/lev_distance.rs b/compiler/rustc_ast/src/util/lev_distance.rs index d4e0e3ba051c9..754b1f13381cb 100644 --- a/compiler/rustc_ast/src/util/lev_distance.rs +++ b/compiler/rustc_ast/src/util/lev_distance.rs @@ -103,6 +103,7 @@ fn find_match_by_sorted_words<'a>(iter_names: Vec<&'a Symbol>, lookup: &str) -> fn sort_by_words(name: &str) -> String { let mut split_words: Vec<&str> = name.split('_').collect(); - split_words.sort(); + // We are sorting primitive &strs and can use unstable sort here + split_words.sort_unstable(); split_words.join("_") } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index df452825bba55..c97f80cf09ba1 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1121,7 +1121,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // features. We check that at least one type is available for // the current target. let reg_class = reg.reg_class(); - let mut required_features = vec![]; + let mut required_features: Vec<&str> = vec![]; for &(_, feature) in reg_class.supported_types(asm_arch) { if let Some(feature) = feature { if self.sess.target_features.contains(&Symbol::intern(feature)) { @@ -1135,7 +1135,8 @@ impl<'hir> LoweringContext<'_, 'hir> { break; } } - required_features.sort(); + // We are sorting primitive strs here and can use unstable sort here + required_features.sort_unstable(); required_features.dedup(); match &required_features[..] { [] => {} diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs index 2f0b2a8d68028..717ccce35b61d 100644 --- a/compiler/rustc_lint/src/non_ascii_idents.rs +++ b/compiler/rustc_lint/src/non_ascii_idents.rs @@ -212,7 +212,8 @@ impl EarlyLintPass for NonAsciiIdents { } } - ch_list.sort(); + // We sort primitive chars here and can use unstable sort + ch_list.sort_unstable(); ch_list.dedup(); lint_reports.insert((sp, ch_list), augment_script_set); } diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/merging.rs b/compiler/rustc_mir/src/monomorphize/partitioning/merging.rs index 1787e6df1b9c7..d92f1367e7d67 100644 --- a/compiler/rustc_mir/src/monomorphize/partitioning/merging.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/merging.rs @@ -74,7 +74,9 @@ pub fn merge_codegen_units<'tcx>( // Sort the names, so things are deterministic and easy to // predict. - cgu_contents.sort(); + + // We are sorting primitive &strs here so we can use unstable sort + cgu_contents.sort_unstable(); (current_cgu_name, cgu_contents.join("--")) }) diff --git a/compiler/rustc_mir/src/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs index a7a3548189e1c..d7188f05ff6b1 100644 --- a/compiler/rustc_mir/src/transform/simplify_try.rs +++ b/compiler/rustc_mir/src/transform/simplify_try.rs @@ -230,8 +230,8 @@ fn get_arm_identity_info<'a, 'tcx>( } } } - - nop_stmts.sort(); + // We sort primitive usize here so we can use unstable sort + nop_stmts.sort_unstable(); // Use one of the statements we're going to discard between the point // where the storage location for the variant field becomes live and diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index cb5f5731aa611..af0878b93dde4 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -4266,11 +4266,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None } }) - .collect::>(); + .collect::>(); // Both checked and coerced types could have matched, thus we need to remove // duplicates. - referenced_in.sort(); + + // We sort primitive type usize here and can use unstable sort + referenced_in.sort_unstable(); referenced_in.dedup(); if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) { From f42dac0ce04e372d413dcc374f2e0cf1e40dff6a Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Thu, 23 Jul 2020 20:15:47 +0200 Subject: [PATCH 0242/1052] Document btree's unwrap_unchecked --- library/alloc/src/collections/btree/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/alloc/src/collections/btree/mod.rs b/library/alloc/src/collections/btree/mod.rs index 6c8a588eb58f3..1a836f11499ec 100644 --- a/library/alloc/src/collections/btree/mod.rs +++ b/library/alloc/src/collections/btree/mod.rs @@ -13,6 +13,9 @@ trait Recover { fn replace(&mut self, key: Self::Key) -> Option; } +/// Same purpose as `Option::unwrap` but doesn't always guarantee a panic +/// if the option contains no value. +/// SAFETY: the caller must ensure that the option contains a value. #[inline(always)] pub unsafe fn unwrap_unchecked(val: Option) -> T { val.unwrap_or_else(|| { From 00e64ba476fa5bbc515bd6ff11151f8064748e88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Thu, 10 Sep 2020 00:00:00 +0000 Subject: [PATCH 0243/1052] Validate removal of AscribeUserType, FakeRead, and Shallow borrow Those statements are removed by CleanupNonCodegenStatements pass in drop lowering phase, and should not occur afterwards. --- compiler/rustc_mir/src/transform/validate.rs | 28 ++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir/src/transform/validate.rs b/compiler/rustc_mir/src/transform/validate.rs index 8f01e94280116..d3ca14abdcab2 100644 --- a/compiler/rustc_mir/src/transform/validate.rs +++ b/compiler/rustc_mir/src/transform/validate.rs @@ -4,8 +4,8 @@ use super::{MirPass, MirSource}; use rustc_middle::mir::visit::Visitor; use rustc_middle::{ mir::{ - AggregateKind, BasicBlock, Body, Location, MirPhase, Operand, Rvalue, Statement, - StatementKind, Terminator, TerminatorKind, + AggregateKind, BasicBlock, Body, BorrowKind, Location, MirPhase, Operand, Rvalue, + Statement, StatementKind, Terminator, TerminatorKind, }, ty::{ self, @@ -274,9 +274,33 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ) } } + Rvalue::Ref(_, BorrowKind::Shallow, _) => { + if self.mir_phase > MirPhase::DropLowering { + self.fail( + location, + "`Assign` statement with a `Shallow` borrow should have been removed after drop lowering phase", + ); + } + } _ => {} } } + StatementKind::AscribeUserType(..) => { + if self.mir_phase > MirPhase::DropLowering { + self.fail( + location, + "`AscribeUserType` should have been removed after drop lowering phase", + ); + } + } + StatementKind::FakeRead(..) => { + if self.mir_phase > MirPhase::DropLowering { + self.fail( + location, + "`FakeRead` should have been removed after drop lowering phase", + ); + } + } _ => {} } } From fdff7defc9a21fc63a1586efab87694723144793 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Thu, 10 Sep 2020 02:18:46 +0000 Subject: [PATCH 0244/1052] Revert "Rollup merge of #76285 - matklad:censor-spacing, r=petrochenkov" This reverts commit 85cee57fd791d670d92dc61e0ad71594128dd45a, reversing changes made to b4d387302416c90a3f70211770292d8d8ab5e07d. --- compiler/rustc_ast/src/tokenstream.rs | 4 ++-- .../rustc_expand/src/proc_macro_server.rs | 22 +++++-------------- compiler/rustc_parse/src/lexer/tokentrees.rs | 5 ++++- compiler/rustc_parse/src/parser/mod.rs | 10 ++++----- 4 files changed, 16 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index fb98f55a2154a..151acddae840e 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -403,8 +403,8 @@ impl Cursor { self.index = index; } - pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> { - self.stream.0[self.index..].get(n).map(|(tree, _)| tree) + pub fn look_ahead(&self, n: usize) -> Option { + self.stream.0[self.index..].get(n).map(|(tree, _)| tree.clone()) } } diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 765871a6396f3..39c82f97e0a39 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -47,26 +47,15 @@ impl ToInternal for Delimiter { } } -impl - FromInternal<( - TreeAndJoint, - Option<&'_ tokenstream::TokenTree>, - &'_ ParseSess, - &'_ mut Vec, - )> for TokenTree +impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec)> + for TokenTree { fn from_internal( - ((tree, is_joint), look_ahead, sess, stack): ( - TreeAndJoint, - Option<&tokenstream::TokenTree>, - &ParseSess, - &mut Vec, - ), + ((tree, is_joint), sess, stack): (TreeAndJoint, &ParseSess, &mut Vec), ) -> Self { use rustc_ast::token::*; - let joint = is_joint == Joint - && matches!(look_ahead, Some(tokenstream::TokenTree::Token(t)) if t.is_op()); + let joint = is_joint == Joint; let Token { kind, span } = match tree { tokenstream::TokenTree::Delimited(span, delim, tts) => { let delimiter = Delimiter::from_internal(delim); @@ -456,8 +445,7 @@ impl server::TokenStreamIter for Rustc<'_> { loop { let tree = iter.stack.pop().or_else(|| { let next = iter.cursor.next_with_joint()?; - let lookahead = iter.cursor.look_ahead(0); - Some(TokenTree::from_internal((next, lookahead, self.sess, &mut iter.stack))) + Some(TokenTree::from_internal((next, self.sess, &mut iter.stack))) })?; // A hack used to pass AST fragments to attribute and derive macros // as a single nonterminal token instead of a token stream. diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index fb27ccfbd9429..d5977ca3c7d2f 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -262,7 +262,10 @@ impl<'a> TokenTreesReader<'a> { } _ => { let tt = TokenTree::Token(self.token.take()); - let is_joint = self.bump(); + let mut is_joint = self.bump(); + if !self.token.is_op() { + is_joint = NonJoint; + } Ok((tt, is_joint)) } } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 1b2067f8f256b..84edfecad192f 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -822,15 +822,15 @@ impl<'a> Parser<'a> { } let frame = &self.token_cursor.frame; - match frame.tree_cursor.look_ahead(dist - 1) { + looker(&match frame.tree_cursor.look_ahead(dist - 1) { Some(tree) => match tree { - TokenTree::Token(token) => looker(token), + TokenTree::Token(token) => token, TokenTree::Delimited(dspan, delim, _) => { - looker(&Token::new(token::OpenDelim(delim.clone()), dspan.open)) + Token::new(token::OpenDelim(delim), dspan.open) } }, - None => looker(&Token::new(token::CloseDelim(frame.delim), frame.span.close)), - } + None => Token::new(token::CloseDelim(frame.delim), frame.span.close), + }) } /// Returns whether any of the given keywords are `dist` tokens ahead of the current one. From 01bf35010fb76154475fb722773731073fb50fa3 Mon Sep 17 00:00:00 2001 From: Andrew Lilley Brinker Date: Wed, 9 Sep 2020 19:36:15 -0700 Subject: [PATCH 0245/1052] Reword `trivial_casts` lint to better explain. The current description of the trivial casts lint under the "allowed by default" listing in the rustc book indicates the lint is for lints which may be removed, which is less clear than saying it's for lints which may be replaced by coercion (which is the wording used by the error message included in the doc). This commit changes the wording slightly to better describe what the lint does. --- src/doc/rustc/src/lints/listing/allowed-by-default.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc/src/lints/listing/allowed-by-default.md b/src/doc/rustc/src/lints/listing/allowed-by-default.md index d3dfc3197e2f6..d2d8c471efc96 100644 --- a/src/doc/rustc/src/lints/listing/allowed-by-default.md +++ b/src/doc/rustc/src/lints/listing/allowed-by-default.md @@ -232,7 +232,8 @@ error: lifetime name `'x` only used once ## trivial-casts -This lint detects trivial casts which could be removed. Some example code +This lint detects trivial casts which could be replaced with coercion, which may require +type ascription or a temporary variable. Some example code that triggers this lint: ```rust From 82cb37911124a608986961f819b60291965ead3f Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Thu, 10 Sep 2020 00:19:06 -0400 Subject: [PATCH 0246/1052] Fix broken test on MSVC --- src/test/ui/issues/issue-2214.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/ui/issues/issue-2214.rs b/src/test/ui/issues/issue-2214.rs index e04eff7cc4d89..9b7c448541853 100644 --- a/src/test/ui/issues/issue-2214.rs +++ b/src/test/ui/issues/issue-2214.rs @@ -23,7 +23,6 @@ fn lgamma(n: c_double, value: &mut isize) -> c_double { mod m { use libc::{c_double, c_int}; - #[link(name = "m")] extern { #[cfg(any(all(unix, not(target_os = "vxworks")), target_os = "cloudabi"))] #[link_name="lgamma_r"] From 4b5326b0d62104801f0b33c4d8f3749d93eebc02 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Wed, 9 Sep 2020 23:12:57 -0700 Subject: [PATCH 0247/1052] Address small review comments --- clippy_lints/src/atomic_ordering.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/atomic_ordering.rs b/clippy_lints/src/atomic_ordering.rs index d4e070b0c24bd..614e33a06da34 100644 --- a/clippy_lints/src/atomic_ordering.rs +++ b/clippy_lints/src/atomic_ordering.rs @@ -139,6 +139,7 @@ fn opt_ordering_defid(cx: &LateContext<'_>, ord_arg: &Expr<'_>) -> Option None } } + fn check_atomic_compare_exchange(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { if let ExprKind::MethodCall(ref method_path, _, args, _) = &expr.kind; @@ -197,7 +198,7 @@ fn check_atomic_compare_exchange(cx: &LateContext<'_>, expr: &Expr<'_>) { INVALID_ATOMIC_ORDERING, failure_order_arg.span, &format!( - "{}'s failure ordering may not stronger than the success ordering of `{}`", + "{}'s failure ordering may not be stronger than the success ordering of `{}`", method, success_ord_name, ), From 3a072131da2e574e914073af6d72360ead735781 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Wed, 9 Sep 2020 23:22:01 -0700 Subject: [PATCH 0248/1052] Ah, right, rerun the scripts --- tests/ui/atomic_ordering_exchange.stderr | 12 ++++++------ tests/ui/atomic_ordering_exchange_weak.stderr | 12 ++++++------ tests/ui/atomic_ordering_fetch_update.stderr | 12 ++++++------ 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/ui/atomic_ordering_exchange.stderr b/tests/ui/atomic_ordering_exchange.stderr index c09d2d6ab21ae..4b9bfef79748c 100644 --- a/tests/ui/atomic_ordering_exchange.stderr +++ b/tests/ui/atomic_ordering_exchange.stderr @@ -79,7 +79,7 @@ LL | let _ = x.compare_exchange(0, 0, Ordering::SeqCst, Ordering::Release); | = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead -error: compare_exchange's failure ordering may not stronger than the success ordering of `Release` +error: compare_exchange's failure ordering may not be stronger than the success ordering of `Release` --> $DIR/atomic_ordering_exchange.rs:35:57 | LL | let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::Acquire); @@ -87,7 +87,7 @@ LL | let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::Acquire); | = help: consider using ordering mode `Relaxed` instead -error: compare_exchange's failure ordering may not stronger than the success ordering of `Release` +error: compare_exchange's failure ordering may not be stronger than the success ordering of `Release` --> $DIR/atomic_ordering_exchange.rs:36:57 | LL | let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::SeqCst); @@ -95,7 +95,7 @@ LL | let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::SeqCst); | = help: consider using ordering mode `Relaxed` instead -error: compare_exchange's failure ordering may not stronger than the success ordering of `Relaxed` +error: compare_exchange's failure ordering may not be stronger than the success ordering of `Relaxed` --> $DIR/atomic_ordering_exchange.rs:39:57 | LL | let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::SeqCst); @@ -103,7 +103,7 @@ LL | let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::SeqCst); | = help: consider using ordering mode `Relaxed` instead -error: compare_exchange's failure ordering may not stronger than the success ordering of `Relaxed` +error: compare_exchange's failure ordering may not be stronger than the success ordering of `Relaxed` --> $DIR/atomic_ordering_exchange.rs:40:57 | LL | let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::Acquire); @@ -111,7 +111,7 @@ LL | let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::Acquire); | = help: consider using ordering mode `Relaxed` instead -error: compare_exchange's failure ordering may not stronger than the success ordering of `Acquire` +error: compare_exchange's failure ordering may not be stronger than the success ordering of `Acquire` --> $DIR/atomic_ordering_exchange.rs:43:57 | LL | let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::SeqCst); @@ -119,7 +119,7 @@ LL | let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::SeqCst); | = help: consider using ordering modes `Acquire` or `Relaxed` instead -error: compare_exchange's failure ordering may not stronger than the success ordering of `AcqRel` +error: compare_exchange's failure ordering may not be stronger than the success ordering of `AcqRel` --> $DIR/atomic_ordering_exchange.rs:44:56 | LL | let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::SeqCst); diff --git a/tests/ui/atomic_ordering_exchange_weak.stderr b/tests/ui/atomic_ordering_exchange_weak.stderr index 7210431bd1bdf..de7026f3ffafa 100644 --- a/tests/ui/atomic_ordering_exchange_weak.stderr +++ b/tests/ui/atomic_ordering_exchange_weak.stderr @@ -79,7 +79,7 @@ LL | let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::SeqCst, Ordering:: | = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead -error: compare_exchange_weak's failure ordering may not stronger than the success ordering of `Release` +error: compare_exchange_weak's failure ordering may not be stronger than the success ordering of `Release` --> $DIR/atomic_ordering_exchange_weak.rs:37:67 | LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering::Acquire); @@ -87,7 +87,7 @@ LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering: | = help: consider using ordering mode `Relaxed` instead -error: compare_exchange_weak's failure ordering may not stronger than the success ordering of `Release` +error: compare_exchange_weak's failure ordering may not be stronger than the success ordering of `Release` --> $DIR/atomic_ordering_exchange_weak.rs:38:67 | LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering::SeqCst); @@ -95,7 +95,7 @@ LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering: | = help: consider using ordering mode `Relaxed` instead -error: compare_exchange_weak's failure ordering may not stronger than the success ordering of `Relaxed` +error: compare_exchange_weak's failure ordering may not be stronger than the success ordering of `Relaxed` --> $DIR/atomic_ordering_exchange_weak.rs:41:67 | LL | let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::SeqCst); @@ -103,7 +103,7 @@ LL | let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering: | = help: consider using ordering mode `Relaxed` instead -error: compare_exchange_weak's failure ordering may not stronger than the success ordering of `Relaxed` +error: compare_exchange_weak's failure ordering may not be stronger than the success ordering of `Relaxed` --> $DIR/atomic_ordering_exchange_weak.rs:42:67 | LL | let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::Acquire); @@ -111,7 +111,7 @@ LL | let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering: | = help: consider using ordering mode `Relaxed` instead -error: compare_exchange_weak's failure ordering may not stronger than the success ordering of `Acquire` +error: compare_exchange_weak's failure ordering may not be stronger than the success ordering of `Acquire` --> $DIR/atomic_ordering_exchange_weak.rs:45:67 | LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Acquire, Ordering::SeqCst); @@ -119,7 +119,7 @@ LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Acquire, Ordering: | = help: consider using ordering modes `Acquire` or `Relaxed` instead -error: compare_exchange_weak's failure ordering may not stronger than the success ordering of `AcqRel` +error: compare_exchange_weak's failure ordering may not be stronger than the success ordering of `AcqRel` --> $DIR/atomic_ordering_exchange_weak.rs:46:66 | LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::AcqRel, Ordering::SeqCst); diff --git a/tests/ui/atomic_ordering_fetch_update.stderr b/tests/ui/atomic_ordering_fetch_update.stderr index 362e104a24482..694548ece97b2 100644 --- a/tests/ui/atomic_ordering_fetch_update.stderr +++ b/tests/ui/atomic_ordering_fetch_update.stderr @@ -79,7 +79,7 @@ LL | let _ = x.fetch_update(Ordering::SeqCst, Ordering::Release, |old| Some( | = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead -error: fetch_update's failure ordering may not stronger than the success ordering of `Release` +error: fetch_update's failure ordering may not be stronger than the success ordering of `Release` --> $DIR/atomic_ordering_fetch_update.rs:35:47 | LL | let _ = x.fetch_update(Ordering::Release, Ordering::Acquire, |old| Some(old + 1)); @@ -87,7 +87,7 @@ LL | let _ = x.fetch_update(Ordering::Release, Ordering::Acquire, |old| Some | = help: consider using ordering mode `Relaxed` instead -error: fetch_update's failure ordering may not stronger than the success ordering of `Release` +error: fetch_update's failure ordering may not be stronger than the success ordering of `Release` --> $DIR/atomic_ordering_fetch_update.rs:36:47 | LL | let _ = x.fetch_update(Ordering::Release, Ordering::SeqCst, |old| Some(old + 1)); @@ -95,7 +95,7 @@ LL | let _ = x.fetch_update(Ordering::Release, Ordering::SeqCst, |old| Some( | = help: consider using ordering mode `Relaxed` instead -error: fetch_update's failure ordering may not stronger than the success ordering of `Relaxed` +error: fetch_update's failure ordering may not be stronger than the success ordering of `Relaxed` --> $DIR/atomic_ordering_fetch_update.rs:39:47 | LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::SeqCst, |old| Some(old + 1)); @@ -103,7 +103,7 @@ LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::SeqCst, |old| Some( | = help: consider using ordering mode `Relaxed` instead -error: fetch_update's failure ordering may not stronger than the success ordering of `Relaxed` +error: fetch_update's failure ordering may not be stronger than the success ordering of `Relaxed` --> $DIR/atomic_ordering_fetch_update.rs:40:47 | LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::Acquire, |old| Some(old + 1)); @@ -111,7 +111,7 @@ LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::Acquire, |old| Some | = help: consider using ordering mode `Relaxed` instead -error: fetch_update's failure ordering may not stronger than the success ordering of `Acquire` +error: fetch_update's failure ordering may not be stronger than the success ordering of `Acquire` --> $DIR/atomic_ordering_fetch_update.rs:43:47 | LL | let _ = x.fetch_update(Ordering::Acquire, Ordering::SeqCst, |old| Some(old + 1)); @@ -119,7 +119,7 @@ LL | let _ = x.fetch_update(Ordering::Acquire, Ordering::SeqCst, |old| Some( | = help: consider using ordering modes `Acquire` or `Relaxed` instead -error: fetch_update's failure ordering may not stronger than the success ordering of `AcqRel` +error: fetch_update's failure ordering may not be stronger than the success ordering of `AcqRel` --> $DIR/atomic_ordering_fetch_update.rs:44:46 | LL | let _ = x.fetch_update(Ordering::AcqRel, Ordering::SeqCst, |old| Some(old + 1)); From 8667f93040cf539c469e3a64b9ed82c5f13bf938 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 10 Sep 2020 08:52:02 +0200 Subject: [PATCH 0249/1052] implement `const_evaluatable_checked` feature MVP --- compiler/rustc_feature/src/active.rs | 6 ++- compiler/rustc_span/src/symbol.rs | 1 + .../src/traits/const_evaluatable.rs | 51 +++++++++++++------ compiler/rustc_typeck/src/collect.rs | 46 ++++++++++++++++- .../const_evaluatable_checked/simple.rs | 14 +++++ .../const_evaluatable_checked/simple_fail.rs | 12 +++++ .../simple_fail.stderr | 9 ++++ 7 files changed, 122 insertions(+), 17 deletions(-) create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/simple.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/simple_fail.stderr diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 3d7b3da45ccb9..d7adf1cdb6d24 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -585,6 +585,9 @@ declare_features! ( /// Allows `if let` guard in match arms. (active, if_let_guard, "1.47.0", Some(51114), None), + /// Allows non trivial generic constants which have to be manually propageted upwards. + (active, const_evaluatable_checked, "1.48.0", Some(0), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- @@ -600,6 +603,7 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[ sym::const_generics, sym::let_chains, sym::raw_dylib, + sym::const_evaluatable_checked, sym::const_trait_impl, sym::const_trait_bound_opt_out, sym::lazy_normalization_consts, @@ -607,6 +611,6 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[ ]; /// Some features are not allowed to be used together at the same time, if -/// the two are present, produce an error +/// the two are present, produce an error. pub const INCOMPATIBLE_FEATURES: &[(Symbol, Symbol)] = &[(sym::const_generics, sym::min_const_generics)]; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 5092b945f72c4..407663e57577a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -348,6 +348,7 @@ symbols! { const_compare_raw_pointers, const_constructor, const_eval_limit, + const_evaluatable_checked, const_extern_fn, const_fn, const_fn_transmute, diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 013cd71ea305d..74f7b1b352caf 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -14,6 +14,24 @@ pub fn is_const_evaluatable<'cx, 'tcx>( param_env: ty::ParamEnv<'tcx>, span: Span, ) -> Result<(), ErrorHandled> { + debug!("is_const_evaluatable({:?}, {:?})", def, substs); + if infcx.tcx.features().const_evaluatable_checked { + // FIXME(const_evaluatable_checked): Actually look into generic constants to + // implement const equality. + for pred in param_env.caller_bounds() { + match pred.skip_binders() { + ty::PredicateAtom::ConstEvaluatable(b_def, b_substs) => { + debug!("is_const_evaluatable: caller_bound={:?}, {:?}", b_def, b_substs); + if b_def == def && b_substs == substs { + debug!("is_const_evaluatable: caller_bound ~~> ok"); + return Ok(()); + } + } + _ => {} // don't care + } + } + } + let future_compat_lint = || { if let Some(local_def_id) = def.did.as_local() { infcx.tcx.struct_span_lint_hir( @@ -38,24 +56,27 @@ pub fn is_const_evaluatable<'cx, 'tcx>( // See #74595 for more details about this. let concrete = infcx.const_eval_resolve(param_env, def, substs, None, Some(span)); - let def_kind = infcx.tcx.def_kind(def.did); - match def_kind { - DefKind::AnonConst => { - let mir_body = if let Some(def) = def.as_const_arg() { - infcx.tcx.optimized_mir_of_const_arg(def) - } else { - infcx.tcx.optimized_mir(def.did) - }; - if mir_body.is_polymorphic && concrete.is_ok() { - future_compat_lint(); - } - } - _ => { - if substs.has_param_types_or_consts() && concrete.is_ok() { - future_compat_lint(); + if concrete.is_ok() && substs.has_param_types_or_consts() { + match infcx.tcx.def_kind(def.did) { + DefKind::AnonConst => { + let mir_body = if let Some(def) = def.as_const_arg() { + infcx.tcx.optimized_mir_of_const_arg(def) + } else { + infcx.tcx.optimized_mir(def.did) + }; + + if mir_body.is_polymorphic { + future_compat_lint(); + } } + _ => future_compat_lint(), } } + if concrete.is_ok() { + debug!("is_const_evaluatable: concrete ~~> ok"); + } else { + debug!("is_const_evaluatable: concrete ~~> err"); + } concrete.map(drop) } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index ea59375bad736..0bba8b821a70c 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -37,11 +37,12 @@ use rustc_middle::hir::map::Map; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::mono::Linkage; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::subst::InternalSubsts; +use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; use rustc_middle::ty::util::Discr; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, AdtKind, Const, ToPolyTraitRef, Ty, TyCtxt}; use rustc_middle::ty::{ReprOptions, ToPredicate, WithConstness}; +use rustc_middle::ty::{TypeFoldable, TypeVisitor}; use rustc_session::config::SanitizerSet; use rustc_session::lint; use rustc_session::parse::feature_err; @@ -50,6 +51,8 @@ use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::abi; use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName; +use smallvec::SmallVec; + mod type_of; struct OnlySelfBounds(bool); @@ -1672,10 +1675,51 @@ fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicate .alloc_from_iter(result.predicates.iter().chain(inferred_outlives).copied()); } } + + if tcx.features().const_evaluatable_checked { + let const_evaluatable = const_evaluatable_predicates_of(tcx, def_id, &result); + if result.predicates.is_empty() { + result.predicates = tcx.arena.alloc_from_iter(const_evaluatable); + } else { + result.predicates = tcx + .arena + .alloc_from_iter(result.predicates.iter().copied().chain(const_evaluatable)); + } + } + debug!("predicates_defined_on({:?}) = {:?}", def_id, result); result } +pub fn const_evaluatable_predicates_of<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + predicates: &ty::GenericPredicates<'tcx>, +) -> impl Iterator, Span)> { + #[derive(Default)] + struct ConstCollector<'tcx> { + ct: SmallVec<[(ty::WithOptConstParam, SubstsRef<'tcx>); 4]>, + } + + impl<'tcx> TypeVisitor<'tcx> for ConstCollector<'tcx> { + fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> bool { + if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val { + self.ct.push((def, substs)); + } + false + } + } + + let mut collector = ConstCollector::default(); + for (pred, _span) in predicates.predicates.iter() { + pred.visit_with(&mut collector); + } + warn!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.ct); + collector.ct.into_iter().map(move |(def_id, subst)| { + (ty::PredicateAtom::ConstEvaluatable(def_id, subst).to_predicate(tcx), DUMMY_SP) + }) +} + /// Returns a list of all type predicates (explicit and implicit) for the definition with /// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus /// `Self: Trait` predicates for traits. diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple.rs new file mode 100644 index 0000000000000..a7ead78b97bae --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple.rs @@ -0,0 +1,14 @@ +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +type Arr = [u8; N - 1]; + +fn test() -> Arr where Arr: Default { + Default::default() +} + +fn main() { + let x = test::<33>(); + assert_eq!(x, [0; 32]); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs new file mode 100644 index 0000000000000..1edf1885dd281 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs @@ -0,0 +1,12 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +type Arr = [u8; N - 1]; //~ ERROR evaluation of constant + +fn test() -> Arr where Arr: Sized { + todo!() +} + +fn main() { + test::<0>(); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.stderr new file mode 100644 index 0000000000000..1ac5e1d95537a --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/simple_fail.rs:4:33 + | +LL | type Arr = [u8; N - 1]; + | ^^^^^ attempt to compute `0_usize - 1_usize` which would overflow + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. From 2815db1844824def6183ac2ec5b8ad82ce1888db Mon Sep 17 00:00:00 2001 From: Hameer Abbasi Date: Thu, 10 Sep 2020 09:04:14 +0200 Subject: [PATCH 0250/1052] Respond to review comments. --- ...-encountered-polymorphic-const.full.stderr | 10 ---- ...7-encountered-polymorphic-const.min.stderr | 10 ---- ...sue-62187-encountered-polymorphic-const.rs | 2 +- .../const-generics/issues/issue-62878.stderr | 46 ------------------- .../issues/issue-72787.full.stderr | 8 ++-- .../issues/issue-72787.min.stderr | 4 +- .../ui/const-generics/issues/issue-72787.rs | 1 - 7 files changed, 7 insertions(+), 74 deletions(-) delete mode 100644 src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.full.stderr delete mode 100644 src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.min.stderr delete mode 100644 src/test/ui/const-generics/issues/issue-62878.stderr diff --git a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.full.stderr b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.full.stderr deleted file mode 100644 index aada9c007256b..0000000000000 --- a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.full.stderr +++ /dev/null @@ -1,10 +0,0 @@ -warning: unused variable: `foo` - --> $DIR/issue-62187-encountered-polymorphic-const.rs:17:9 - | -LL | let foo = <[u8; 2]>::BIT_LEN; - | ^^^ help: if this is intentional, prefix it with an underscore: `_foo` - | - = note: `#[warn(unused_variables)]` on by default - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.min.stderr b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.min.stderr deleted file mode 100644 index aada9c007256b..0000000000000 --- a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.min.stderr +++ /dev/null @@ -1,10 +0,0 @@ -warning: unused variable: `foo` - --> $DIR/issue-62187-encountered-polymorphic-const.rs:17:9 - | -LL | let foo = <[u8; 2]>::BIT_LEN; - | ^^^ help: if this is intentional, prefix it with an underscore: `_foo` - | - = note: `#[warn(unused_variables)]` on by default - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs index 710fdbd9a11f3..a8fa378035660 100644 --- a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs +++ b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs @@ -14,5 +14,5 @@ impl BitLen for [u8; L] { } fn main() { - let foo = <[u8; 2]>::BIT_LEN; //~ WARN unused variable + let _foo = <[u8; 2]>::BIT_LEN; } diff --git a/src/test/ui/const-generics/issues/issue-62878.stderr b/src/test/ui/const-generics/issues/issue-62878.stderr deleted file mode 100644 index 8f7fe000a8116..0000000000000 --- a/src/test/ui/const-generics/issues/issue-62878.stderr +++ /dev/null @@ -1,46 +0,0 @@ -error[E0770]: the type of const parameters must not depend on other generic parameters - --> $DIR/issue-62878.rs:5:38 - | -LL | fn foo() {} - | ^ the type must not depend on the parameter `N` - -error[E0658]: const generics are unstable - --> $DIR/issue-62878.rs:5:14 - | -LL | fn foo() {} - | ^ - | - = note: see issue #74878 for more information - = help: add `#![feature(min_const_generics)]` to the crate attributes to enable - -error[E0658]: const generics are unstable - --> $DIR/issue-62878.rs:5:30 - | -LL | fn foo() {} - | ^ - | - = note: see issue #74878 for more information - = help: add `#![feature(min_const_generics)]` to the crate attributes to enable - -error[E0107]: wrong number of const arguments: expected 2, found 1 - --> $DIR/issue-62878.rs:11:5 - | -LL | foo::<_, {[1]}>(); - | ^^^^^^^^^^^^^^^ expected 2 const arguments - -error[E0107]: wrong number of type arguments: expected 0, found 1 - --> $DIR/issue-62878.rs:11:11 - | -LL | foo::<_, {[1]}>(); - | ^ unexpected type argument - -error[E0308]: mismatched types - --> $DIR/issue-62878.rs:11:15 - | -LL | foo::<_, {[1]}>(); - | ^^^ expected `usize`, found array `[{integer}; 1]` - -error: aborting due to 6 previous errors - -Some errors have detailed explanations: E0107, E0308, E0658, E0770. -For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/const-generics/issues/issue-72787.full.stderr b/src/test/ui/const-generics/issues/issue-72787.full.stderr index 29f975f566280..b4c79d4171b7a 100644 --- a/src/test/ui/const-generics/issues/issue-72787.full.stderr +++ b/src/test/ui/const-generics/issues/issue-72787.full.stderr @@ -7,7 +7,7 @@ LL | Condition<{ LHS <= RHS }>: True = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/issue-72787.rs:27:42 + --> $DIR/issue-72787.rs:26:42 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^^^^ @@ -15,7 +15,7 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/issue-72787.rs:27:42 + --> $DIR/issue-72787.rs:26:42 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^^^^ @@ -23,7 +23,7 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/issue-72787.rs:27:42 + --> $DIR/issue-72787.rs:26:42 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^^^^ @@ -31,7 +31,7 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/issue-72787.rs:27:42 + --> $DIR/issue-72787.rs:26:42 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^^^^ diff --git a/src/test/ui/const-generics/issues/issue-72787.min.stderr b/src/test/ui/const-generics/issues/issue-72787.min.stderr index d2c512898fe88..d3e9887fe209c 100644 --- a/src/test/ui/const-generics/issues/issue-72787.min.stderr +++ b/src/test/ui/const-generics/issues/issue-72787.min.stderr @@ -15,7 +15,7 @@ LL | Condition<{ LHS <= RHS }>: True = help: it is currently only allowed to use either `RHS` or `{ RHS }` as generic constants error: generic parameters must not be used inside of non trivial constant values - --> $DIR/issue-72787.rs:27:25 + --> $DIR/issue-72787.rs:26:25 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^ non-trivial anonymous constants must not depend on the parameter `I` @@ -23,7 +23,7 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, = help: it is currently only allowed to use either `I` or `{ I }` as generic constants error: generic parameters must not be used inside of non trivial constant values - --> $DIR/issue-72787.rs:27:36 + --> $DIR/issue-72787.rs:26:36 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^ non-trivial anonymous constants must not depend on the parameter `J` diff --git a/src/test/ui/const-generics/issues/issue-72787.rs b/src/test/ui/const-generics/issues/issue-72787.rs index e95976b5f0229..45c20191c8848 100644 --- a/src/test/ui/const-generics/issues/issue-72787.rs +++ b/src/test/ui/const-generics/issues/issue-72787.rs @@ -22,7 +22,6 @@ where IsLessOrEqual: True, //[min]~^ Error type annotations needed [E0283] //[min]~| Error type annotations needed [E0283] - // Condition<{ 8 - I <= 8 - J }>: True, IsLessOrEqual: True, IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, //[full]~^ constant expression depends on a generic parameter From 36903d79c8d61f1909bb430d9b09c2cb4a0d9db1 Mon Sep 17 00:00:00 2001 From: Hameer Abbasi Date: Thu, 10 Sep 2020 09:18:40 +0200 Subject: [PATCH 0251/1052] Add revisions to const generic default UI tests. --- .../defaults/complex-unord-param.min.stderr | 8 ++++++ .../defaults/complex-unord-param.rs | 10 ++++--- ...stderr => intermixed-lifetime.full.stderr} | 4 +-- .../defaults/intermixed-lifetime.min.stderr | 26 +++++++++++++++++++ .../defaults/intermixed-lifetime.rs | 12 ++++++--- .../defaults/simple-defaults.min.stderr | 8 ++++++ .../defaults/simple-defaults.rs | 9 ++++--- 7 files changed, 64 insertions(+), 13 deletions(-) create mode 100644 src/test/ui/const-generics/defaults/complex-unord-param.min.stderr rename src/test/ui/const-generics/defaults/{intermixed-lifetime.stderr => intermixed-lifetime.full.stderr} (87%) create mode 100644 src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr create mode 100644 src/test/ui/const-generics/defaults/simple-defaults.min.stderr diff --git a/src/test/ui/const-generics/defaults/complex-unord-param.min.stderr b/src/test/ui/const-generics/defaults/complex-unord-param.min.stderr new file mode 100644 index 0000000000000..0574ddfb2557a --- /dev/null +++ b/src/test/ui/const-generics/defaults/complex-unord-param.min.stderr @@ -0,0 +1,8 @@ +error: type parameters must be declared prior to const parameters + --> $DIR/complex-unord-param.rs:9:41 + | +LL | struct NestedArrays<'a, const N: usize, A: 'a, const M: usize, T:'a =u32> { + | ---------------------^----------------------^--------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, A: 'a, T: 'a, const N: usize, const M: usize>` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/defaults/complex-unord-param.rs b/src/test/ui/const-generics/defaults/complex-unord-param.rs index 72967640a8e62..e83a96388c190 100644 --- a/src/test/ui/const-generics/defaults/complex-unord-param.rs +++ b/src/test/ui/const-generics/defaults/complex-unord-param.rs @@ -1,11 +1,13 @@ -// run-pass +// [full] run-pass +// revisions: full min // Checks a complicated usage of unordered params - -#![feature(const_generics)] -#![allow(incomplete_features)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] #![allow(dead_code)] struct NestedArrays<'a, const N: usize, A: 'a, const M: usize, T:'a =u32> { + //[min]~^ ERROR type parameters must be declared prior to const parameters args: &'a [&'a [T; M]; N], specifier: A, } diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr b/src/test/ui/const-generics/defaults/intermixed-lifetime.full.stderr similarity index 87% rename from src/test/ui/const-generics/defaults/intermixed-lifetime.stderr rename to src/test/ui/const-generics/defaults/intermixed-lifetime.full.stderr index 0f6d7f1065af8..9cc3e9c0da665 100644 --- a/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr +++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.full.stderr @@ -1,11 +1,11 @@ error: lifetime parameters must be declared prior to const parameters - --> $DIR/intermixed-lifetime.rs:6:28 + --> $DIR/intermixed-lifetime.rs:7:28 | LL | struct Foo(&'a (), T); | -----------------^^---------- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T>` error: lifetime parameters must be declared prior to type parameters - --> $DIR/intermixed-lifetime.rs:9:37 + --> $DIR/intermixed-lifetime.rs:11:37 | LL | struct Bar(&'a (), T); | --------------------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T>` diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr b/src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr new file mode 100644 index 0000000000000..4d80fdb5bcbc2 --- /dev/null +++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr @@ -0,0 +1,26 @@ +error: lifetime parameters must be declared prior to const parameters + --> $DIR/intermixed-lifetime.rs:7:28 + | +LL | struct Foo(&'a (), T); + | -----------------^^---------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>` + +error: type parameters must be declared prior to const parameters + --> $DIR/intermixed-lifetime.rs:7:32 + | +LL | struct Foo(&'a (), T); + | ---------------------^------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>` + +error: lifetime parameters must be declared prior to const parameters + --> $DIR/intermixed-lifetime.rs:11:37 + | +LL | struct Bar(&'a (), T); + | --------------------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>` + +error: type parameters must be declared prior to const parameters + --> $DIR/intermixed-lifetime.rs:11:28 + | +LL | struct Bar(&'a (), T); + | -----------------^----------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.rs b/src/test/ui/const-generics/defaults/intermixed-lifetime.rs index ea3a8c14b98cb..cc0d1c6c0c97c 100644 --- a/src/test/ui/const-generics/defaults/intermixed-lifetime.rs +++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.rs @@ -1,12 +1,16 @@ +// revisions: full min // Checks that lifetimes cannot be interspersed between consts and types. - -#![feature(const_generics)] -#![allow(incomplete_features)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct Foo(&'a (), T); //~^ Error lifetime parameters must be declared prior to const parameters +//[min]~^^ Error type parameters must be declared prior to const parameters struct Bar(&'a (), T); -//~^ Error lifetime parameters must be declared prior to type parameters +//[full]~^ Error lifetime parameters must be declared prior to type parameters +//[min]~^^ Error type parameters must be declared prior to const parameters +//[min]~| Error lifetime parameters must be declared prior to const parameters fn main() {} diff --git a/src/test/ui/const-generics/defaults/simple-defaults.min.stderr b/src/test/ui/const-generics/defaults/simple-defaults.min.stderr new file mode 100644 index 0000000000000..59cc6f28af857 --- /dev/null +++ b/src/test/ui/const-generics/defaults/simple-defaults.min.stderr @@ -0,0 +1,8 @@ +error: type parameters must be declared prior to const parameters + --> $DIR/simple-defaults.rs:9:40 + | +LL | struct FixedOutput<'a, const N: usize, T=u32> { + | ---------------------^----- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/defaults/simple-defaults.rs b/src/test/ui/const-generics/defaults/simple-defaults.rs index b282dfd37cc4a..78abe3519985b 100644 --- a/src/test/ui/const-generics/defaults/simple-defaults.rs +++ b/src/test/ui/const-generics/defaults/simple-defaults.rs @@ -1,10 +1,13 @@ -// run-pass +// [full] run-pass +// revisions: min full // Checks some basic test cases for defaults. -#![feature(const_generics)] -#![allow(incomplete_features)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] #![allow(dead_code)] struct FixedOutput<'a, const N: usize, T=u32> { + //[min]~^ ERROR type parameters must be declared prior to const parameters out: &'a [T; N], } From f3489d4a5ed944b3f62238c13cda6097dfbed0c8 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Wed, 9 Sep 2020 11:04:29 +1200 Subject: [PATCH 0252/1052] fix some use of `snippet` in `types.rs` --- clippy_lints/src/types.rs | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 6c6188d61ad52..b6d405cca770d 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -321,14 +321,15 @@ impl Types { if let Some(def_id) = res.opt_def_id() { if Some(def_id) == cx.tcx.lang_items().owned_box() { if let Some(span) = match_borrows_parameter(cx, qpath) { + let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, REDUNDANT_ALLOCATION, hir_ty.span, "usage of `Box<&T>`", "try", - snippet(cx, span, "..").to_string(), - Applicability::MachineApplicable, + snippet_with_applicability(cx, span, "..", &mut applicability).to_string(), + applicability, ); return; // don't recurse into the type } @@ -345,14 +346,15 @@ impl Types { } } else if cx.tcx.is_diagnostic_item(sym::Rc, def_id) { if let Some(span) = match_type_parameter(cx, qpath, &paths::RC) { + let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, REDUNDANT_ALLOCATION, hir_ty.span, "usage of `Rc>`", "try", - snippet(cx, span, "..").to_string(), - Applicability::MachineApplicable, + snippet_with_applicability(cx, span, "..", &mut applicability).to_string(), + applicability, ); return; // don't recurse into the type } @@ -368,26 +370,31 @@ impl Types { GenericArg::Type(ty) => ty.span, _ => return, }; + let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, REDUNDANT_ALLOCATION, hir_ty.span, "usage of `Rc>`", "try", - format!("Rc<{}>", snippet(cx, inner_span, "..")), - Applicability::MachineApplicable, + format!( + "Rc<{}>", + snippet_with_applicability(cx, inner_span, "..", &mut applicability) + ), + applicability, ); return; // don't recurse into the type } if let Some(span) = match_borrows_parameter(cx, qpath) { + let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, REDUNDANT_ALLOCATION, hir_ty.span, "usage of `Rc<&T>`", "try", - snippet(cx, span, "..").to_string(), - Applicability::MachineApplicable, + snippet_with_applicability(cx, span, "..", &mut applicability).to_string(), + applicability, ); return; // don't recurse into the type } @@ -546,7 +553,6 @@ impl Types { // details. return; } - let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, BORROWED_BOX, @@ -556,8 +562,12 @@ impl Types { format!( "&{}{}", ltopt, - &snippet_with_applicability(cx, inner.span, "..", &mut applicability) + &snippet(cx, inner.span, "..") ), + // To make this `MachineApplicable`, at least one needs to check if it isn't a trait item + // because the trait impls of it will break otherwise; + // and there may be other cases that result in invalid code. + // For example, type coercion doesn't work nicely. Applicability::Unspecified, ); return; // don't recurse into the type From bec8e5fc145a2958c303fd276303f529e759b07c Mon Sep 17 00:00:00 2001 From: Hameer Abbasi Date: Thu, 10 Sep 2020 09:30:05 +0200 Subject: [PATCH 0253/1052] Add revisions to const generic UI tests. --- .../const-generics/auxiliary/const_generic_lib.rs | 4 +++- .../ui/const-generics/auxiliary/impl-const.rs | 4 +++- ...nst-argument-cross-crate-mismatch.full.stderr} | 4 ++-- ...const-argument-cross-crate-mismatch.min.stderr | 15 +++++++++++++++ .../const-argument-cross-crate-mismatch.rs | 1 + .../const-generics/const-argument-cross-crate.rs | 1 + 6 files changed, 25 insertions(+), 4 deletions(-) rename src/test/ui/const-generics/{const-argument-cross-crate-mismatch.stderr => const-argument-cross-crate-mismatch.full.stderr} (86%) create mode 100644 src/test/ui/const-generics/const-argument-cross-crate-mismatch.min.stderr diff --git a/src/test/ui/const-generics/auxiliary/const_generic_lib.rs b/src/test/ui/const-generics/auxiliary/const_generic_lib.rs index 901fb5dd054e2..899a5a1836c33 100644 --- a/src/test/ui/const-generics/auxiliary/const_generic_lib.rs +++ b/src/test/ui/const-generics/auxiliary/const_generic_lib.rs @@ -1,4 +1,6 @@ -#![feature(const_generics)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub struct Struct(pub [u8; N]); diff --git a/src/test/ui/const-generics/auxiliary/impl-const.rs b/src/test/ui/const-generics/auxiliary/impl-const.rs index fc993d63927c3..2e25dadf119c4 100644 --- a/src/test/ui/const-generics/auxiliary/impl-const.rs +++ b/src/test/ui/const-generics/auxiliary/impl-const.rs @@ -1,4 +1,6 @@ -#![feature(const_generics)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub struct Num; diff --git a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.full.stderr similarity index 86% rename from src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr rename to src/test/ui/const-generics/const-argument-cross-crate-mismatch.full.stderr index aefd514f7a68e..a35c3abc113b9 100644 --- a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr +++ b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.full.stderr @@ -1,11 +1,11 @@ error[E0308]: mismatched types - --> $DIR/const-argument-cross-crate-mismatch.rs:6:67 + --> $DIR/const-argument-cross-crate-mismatch.rs:7:67 | LL | let _ = const_generic_lib::function(const_generic_lib::Struct([0u8, 1u8])); | ^^^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements error[E0308]: mismatched types - --> $DIR/const-argument-cross-crate-mismatch.rs:8:65 + --> $DIR/const-argument-cross-crate-mismatch.rs:9:65 | LL | let _: const_generic_lib::Alias = const_generic_lib::Struct([0u8, 1u8, 2u8]); | ^^^^^^^^^^^^^^^ expected an array with a fixed size of 2 elements, found one with 3 elements diff --git a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.min.stderr b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.min.stderr new file mode 100644 index 0000000000000..a35c3abc113b9 --- /dev/null +++ b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.min.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/const-argument-cross-crate-mismatch.rs:7:67 + | +LL | let _ = const_generic_lib::function(const_generic_lib::Struct([0u8, 1u8])); + | ^^^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements + +error[E0308]: mismatched types + --> $DIR/const-argument-cross-crate-mismatch.rs:9:65 + | +LL | let _: const_generic_lib::Alias = const_generic_lib::Struct([0u8, 1u8, 2u8]); + | ^^^^^^^^^^^^^^^ expected an array with a fixed size of 2 elements, found one with 3 elements + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.rs b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.rs index d863d097d5caf..9ae2ae50ba0ab 100644 --- a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.rs +++ b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.rs @@ -1,4 +1,5 @@ // aux-build:const_generic_lib.rs +// revisions: full min extern crate const_generic_lib; diff --git a/src/test/ui/const-generics/const-argument-cross-crate.rs b/src/test/ui/const-generics/const-argument-cross-crate.rs index 98cf39a7ee11c..fda3ec3eef799 100644 --- a/src/test/ui/const-generics/const-argument-cross-crate.rs +++ b/src/test/ui/const-generics/const-argument-cross-crate.rs @@ -1,4 +1,5 @@ // run-pass +// revisions: full min // aux-build:const_generic_lib.rs extern crate const_generic_lib; From 300b0acb85e41a19b518715147968f177679ebc1 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 10 Sep 2020 09:48:02 +0200 Subject: [PATCH 0254/1052] fix tidy, small cleanup --- compiler/rustc_feature/src/active.rs | 2 +- .../src/traits/const_evaluatable.rs | 6 +----- compiler/rustc_typeck/src/collect.rs | 9 ++------- .../feature-gate-const_evaluatable_checked.rs | 14 ++++++++++++++ .../feature-gate-const_evaluatable_checked.stderr | 10 ++++++++++ 5 files changed, 28 insertions(+), 13 deletions(-) create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.stderr diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index d7adf1cdb6d24..1aeb0bd5ad9aa 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -586,7 +586,7 @@ declare_features! ( (active, if_let_guard, "1.47.0", Some(51114), None), /// Allows non trivial generic constants which have to be manually propageted upwards. - (active, const_evaluatable_checked, "1.48.0", Some(0), None), + (active, const_evaluatable_checked, "1.48.0", Some(76560), None), // ------------------------------------------------------------------------- // feature-group-end: actual feature gates diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 74f7b1b352caf..fdb87c085b54e 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -73,10 +73,6 @@ pub fn is_const_evaluatable<'cx, 'tcx>( } } - if concrete.is_ok() { - debug!("is_const_evaluatable: concrete ~~> ok"); - } else { - debug!("is_const_evaluatable: concrete ~~> err"); - } + debug!(?concrete, "is_const_evaluatable"); concrete.map(drop) } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 0bba8b821a70c..7d6b3df03b064 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1678,13 +1678,8 @@ fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicate if tcx.features().const_evaluatable_checked { let const_evaluatable = const_evaluatable_predicates_of(tcx, def_id, &result); - if result.predicates.is_empty() { - result.predicates = tcx.arena.alloc_from_iter(const_evaluatable); - } else { - result.predicates = tcx - .arena - .alloc_from_iter(result.predicates.iter().copied().chain(const_evaluatable)); - } + result.predicates = + tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(const_evaluatable)); } debug!("predicates_defined_on({:?}) = {:?}", def_id, result); diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs new file mode 100644 index 0000000000000..941bd5e9e5d0a --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs @@ -0,0 +1,14 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +type Arr = [u8; N - 1]; + +fn test() -> Arr where Arr: Default { + //~^ ERROR constant expression depends + Default::default() +} + +fn main() { + let x = test::<33>(); + assert_eq!(x, [0; 32]); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.stderr b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.stderr new file mode 100644 index 0000000000000..6e4a22a38b17c --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/feature-gate-const_evaluatable_checked.rs:6:30 + | +LL | fn test() -> Arr where Arr: Default { + | ^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + From 8b059980d71765270b637b2fce7f13f728ca24b4 Mon Sep 17 00:00:00 2001 From: Nanami <12036195+yokodake@users.noreply.github.com> Date: Thu, 10 Sep 2020 11:56:11 +0200 Subject: [PATCH 0255/1052] small typo fix in rustc_parse docs --- compiler/rustc_parse/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 462279b0a9e03..8e1e4c1b4513b 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -109,7 +109,7 @@ pub fn maybe_new_parser_from_source_str( } /// Creates a new parser, handling errors as appropriate if the file doesn't exist. -/// If a span is given, that is used on an error as the as the source of the problem. +/// If a span is given, that is used on an error as the source of the problem. pub fn new_parser_from_file<'a>(sess: &'a ParseSess, path: &Path, sp: Option) -> Parser<'a> { source_file_to_parser(sess, file_to_source_file(sess, path, sp)) } From a5cdc06db88d9a9d41dd18353fedb6467260437a Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 10 Sep 2020 12:54:29 +0200 Subject: [PATCH 0256/1052] ci: avoid moving the build directory on GHA While waiting for a PR job to start testing my code, I noticed the symlink-build-dir step took 10 minutes to complete, so I investigated what caused that. It seems like something changed in the build environment between version 20200901.1 (where the step took 45 seconds) and version 20200908.1 (where the step took 10 minutes). At the time of writing this commit, the rust-lang organization is on vertsion 20200908.1, while the rust-lang-ci organization is at version 20200901.1 (and is not affected by this yet). There is no need for this step anymore on GHA, as our XL builders got an increase in the root paritition size, so this commit removes the code that moved stuff around on GHA (while keeping it on Azure). For the record, at the time of writing this, the disk situation is: Filesystem Size Used Avail Use% Mounted on /dev/sda1 667G 60G 607G 9% / /dev/sdb1 110G 4.1G 101G 4% /mnt --- src/ci/scripts/symlink-build-dir.sh | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/ci/scripts/symlink-build-dir.sh b/src/ci/scripts/symlink-build-dir.sh index 28d8aa3b6e71a..23849f7047c54 100755 --- a/src/ci/scripts/symlink-build-dir.sh +++ b/src/ci/scripts/symlink-build-dir.sh @@ -12,22 +12,4 @@ source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" if isWindows && isAzurePipelines; then cmd //c "mkdir c:\\MORE_SPACE" cmd //c "mklink /J build c:\\MORE_SPACE" -elif isLinux && isGitHubActions && ! isSelfHostedGitHubActions; then - sudo mkdir -p /mnt/more-space - sudo chown -R "$(whoami):" /mnt/more-space - - # Switch the whole workspace to the /mnt partition, which has more space. - # We don't just symlink the `obj` directory as doing that creates problems - # with the docker container. - current_dir="$(readlink -f "$(pwd)")" - cd /tmp - mv "${current_dir}" /mnt/more-space/workspace - ln -s /mnt/more-space/workspace "${current_dir}" - cd "${current_dir}" - - # Move the Docker data directory to /mnt - sudo systemctl stop docker.service - sudo mv /var/lib/docker /mnt/docker - sudo ln -s /mnt/docker /var/lib/docker - sudo systemctl start docker.service fi From 6bfe132067890abba67b6710060a88d4ad91abfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Thu, 10 Sep 2020 13:08:28 +0200 Subject: [PATCH 0257/1052] take reference to Place directly instead of taking reference to Box clippy::borrowed_box --- compiler/rustc_mir/src/transform/simplify_try.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs index a7a3548189e1c..a320d00614d40 100644 --- a/compiler/rustc_mir/src/transform/simplify_try.rs +++ b/compiler/rustc_mir/src/transform/simplify_try.rs @@ -674,7 +674,7 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { y_bb_idx: BasicBlock, ) -> StatementEquality { let helper = |rhs: &Rvalue<'tcx>, - place: &Box>, + place: &Place<'tcx>, variant_index: &VariantIdx, side_to_choose| { let place_type = place.ty(self.body, self.tcx).ty; From e2a511fe2059f7e64137aa893550b37195e96209 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Thu, 10 Sep 2020 13:16:35 +0200 Subject: [PATCH 0258/1052] use String::from instead of format!() macro to craft string clippy::useless_format --- compiler/rustc_mir/src/transform/instrument_coverage.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/transform/instrument_coverage.rs b/compiler/rustc_mir/src/transform/instrument_coverage.rs index 8f43df8a6cbd1..a5b30a25a9bdf 100644 --- a/compiler/rustc_mir/src/transform/instrument_coverage.rs +++ b/compiler/rustc_mir/src/transform/instrument_coverage.rs @@ -353,7 +353,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { if !INCLUDE_COVERAGE_STATEMENTS { continue; } - format!("unreachable") + String::from("unreachable") } }, _ => format!("{:?}", statement), From e11c667e4af17ddebc47df803d6ea641cef7359b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Thu, 10 Sep 2020 13:20:33 +0200 Subject: [PATCH 0259/1052] don't clone types that are copy (clippy::clone_on_copy) --- compiler/rustc_infer/src/infer/lub.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs index 3e2ea3d0f8fbf..9f43fac0916b5 100644 --- a/compiler/rustc_infer/src/infer/lub.rs +++ b/compiler/rustc_infer/src/infer/lub.rs @@ -50,7 +50,7 @@ impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> { ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), ty::Covariant => self.relate(a, b), // FIXME(#41044) -- not correct, need test - ty::Bivariant => Ok(a.clone()), + ty::Bivariant => Ok(a), ty::Contravariant => self.fields.glb(self.a_is_expected).relate(a, b), } } From 9bb10cc90741fada64ec633122835cb821d0c89c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Thu, 10 Sep 2020 13:57:40 +0200 Subject: [PATCH 0260/1052] use push(char) instead of push_str(&str) to add single chars to strings clippy::single-char-push-str --- .../src/format_foreign.rs | 12 +++++----- compiler/rustc_codegen_ssa/src/back/link.rs | 2 +- .../src/debuginfo/type_names.rs | 2 +- .../src/infer/error_reporting/mod.rs | 2 +- .../src/borrow_check/diagnostics/mod.rs | 22 ++++++++++--------- .../src/borrow_check/region_infer/values.rs | 4 ++-- .../src/monomorphize/partitioning/mod.rs | 6 ++--- compiler/rustc_mir/src/util/pretty.rs | 2 +- compiler/rustc_save_analysis/src/lib.rs | 2 +- compiler/rustc_save_analysis/src/sig.rs | 2 +- compiler/rustc_session/src/config.rs | 4 ++-- 11 files changed, 31 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs index 85cf4c42e9435..b39423b86e7b5 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -166,14 +166,14 @@ pub mod printf { let cap = self.span.len() + if has_options { 2 } else { 0 }; let mut s = String::with_capacity(cap); - s.push_str("{"); + s.push('{'); if let Some(arg) = self.parameter { write!(s, "{}", arg.checked_sub(1)?).ok()?; } if has_options { - s.push_str(":"); + s.push(':'); let align = if let Some(fill) = fill { s.push_str(fill); @@ -191,11 +191,11 @@ pub mod printf { } if alt { - s.push_str("#"); + s.push('#'); } if zero_fill { - s.push_str("0"); + s.push('0'); } if let Some(width) = width { @@ -203,7 +203,7 @@ pub mod printf { } if let Some(precision) = precision { - s.push_str("."); + s.push('.'); precision.translate(&mut s).ok()?; } @@ -212,7 +212,7 @@ pub mod printf { } } - s.push_str("}"); + s.push('}'); Some(s) } } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index c044020d9301b..faeb727202cd6 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1076,7 +1076,7 @@ fn exec_linker( } .to_string(), ); - args.push_str("\n"); + args.push('\n'); } let file = tmpdir.join("linker-arguments"); let bytes = if sess.target.target.options.is_like_msvc { diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 54e5d4d00f6e4..0c0f1bc681cf8 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -37,7 +37,7 @@ pub fn push_debuginfo_type_name<'tcx>( ty::Bool => output.push_str("bool"), ty::Char => output.push_str("char"), ty::Str => output.push_str("str"), - ty::Never => output.push_str("!"), + ty::Never => output.push('!'), ty::Int(int_ty) => output.push_str(int_ty.name_str()), ty::Uint(uint_ty) => output.push_str(uint_ty.name_str()), ty::Float(float_ty) => output.push_str(float_ty.name_str()), diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index b53605b0796c9..1225776db4590 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2093,7 +2093,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => String::new(), }; if !s.is_empty() { - s.push_str(" "); + s.push(' '); } s }; diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs index f51bf7730ea09..3cee32834beb7 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs @@ -150,8 +150,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Some(mut descr) => { // Surround descr with `backticks`. descr.reserve(2); - descr.insert_str(0, "`"); - descr.push_str("`"); + descr.insert(0, '`'); + descr.push('`'); descr } None => "value".to_string(), @@ -222,7 +222,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if self.upvars[var_index].by_ref { buf.push_str(&name); } else { - buf.push_str(&format!("*{}", &name)); + buf.push('*'); + buf.push_str(&name); } } else { if autoderef { @@ -234,7 +235,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &including_downcast, )?; } else { - buf.push_str(&"*"); + buf.push('*'); self.append_place_to_string( PlaceRef { local, projection: proj_base }, buf, @@ -272,7 +273,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { autoderef, &including_downcast, )?; - buf.push_str(&format!(".{}", field_name)); + buf.push('.'); + buf.push_str(&field_name); } } ProjectionElem::Index(index) => { @@ -284,11 +286,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { autoderef, &including_downcast, )?; - buf.push_str("["); + buf.push('['); if self.append_local_to_string(*index, buf).is_err() { - buf.push_str("_"); + buf.push('_'); } - buf.push_str("]"); + buf.push(']'); } ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { autoderef = true; @@ -301,7 +303,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { autoderef, &including_downcast, )?; - buf.push_str(&"[..]"); + buf.push_str("[..]"); } }; } @@ -648,7 +650,7 @@ impl UseSpans { " in closure".to_string() } } - _ => "".to_string(), + _ => String::new(), } } diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/values.rs b/compiler/rustc_mir/src/borrow_check/region_infer/values.rs index 8a5a600cfdd8a..f247d07e1f05e 100644 --- a/compiler/rustc_mir/src/borrow_check/region_infer/values.rs +++ b/compiler/rustc_mir/src/borrow_check/region_infer/values.rs @@ -417,7 +417,7 @@ crate fn location_set_str( fn region_value_str(elements: impl IntoIterator) -> String { let mut result = String::new(); - result.push_str("{"); + result.push('{'); // Set to Some(l1, l2) when we have observed all the locations // from l1..=l2 (inclusive) but not yet printed them. This @@ -478,7 +478,7 @@ fn region_value_str(elements: impl IntoIterator) -> String push_location_range(&mut result, location1, location2); } - result.push_str("}"); + result.push('}'); return result; diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs index e96af77bbb8e0..0f6f078d9686f 100644 --- a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs @@ -382,7 +382,7 @@ fn collect_and_partition_mono_items<'tcx>( cgus.sort_by_key(|(name, _)| *name); cgus.dedup(); for &(ref cgu_name, (linkage, _)) in cgus.iter() { - output.push_str(" "); + output.push(' '); output.push_str(&cgu_name.as_str()); let linkage_abbrev = match linkage { @@ -399,9 +399,9 @@ fn collect_and_partition_mono_items<'tcx>( Linkage::Common => "Common", }; - output.push_str("["); + output.push('['); output.push_str(linkage_abbrev); - output.push_str("]"); + output.push(']'); } output }) diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index 54bc248bc5b4a..75567181b6916 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -514,7 +514,7 @@ fn write_scope_tree( write!(indented_decl, " as {:?}", user_ty).unwrap(); } } - indented_decl.push_str(";"); + indented_decl.push(';'); let local_name = if local == RETURN_PLACE { " return place".to_string() } else { String::new() }; diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index c95e7e193be30..032d7cb3ed6b7 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -438,7 +438,7 @@ impl<'tcx> SaveContext<'tcx> { .next() .map(|item| item.def_id); } - qualname.push_str(">"); + qualname.push('>'); (qualname, trait_id, decl_id, docs, attrs) } diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs index 6dd7f89d59486..747e198cd9324 100644 --- a/compiler/rustc_save_analysis/src/sig.rs +++ b/compiler/rustc_save_analysis/src/sig.rs @@ -497,7 +497,7 @@ impl<'hir> Sig for hir::Item<'hir> { sig.text.push_str(&bounds_to_string(bounds)); } // FIXME where clause - sig.text.push_str(";"); + sig.text.push(';'); Ok(sig) } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 19cd238599210..4aecb35294a07 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -581,9 +581,9 @@ impl OutputFilenames { if !ext.is_empty() { if !extension.is_empty() { - extension.push_str("."); + extension.push('.'); extension.push_str(RUST_CGU_EXT); - extension.push_str("."); + extension.push('.'); } extension.push_str(ext); From d7a97070517f20fa6533ff29fdc2945908fc58d7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 10 Sep 2020 14:11:25 +0200 Subject: [PATCH 0261/1052] Add missing examples on core traits' method --- library/core/src/ops/arith.rs | 77 +++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs index 622a138abe9d1..bdf93baa1b8f9 100644 --- a/library/core/src/ops/arith.rs +++ b/library/core/src/ops/arith.rs @@ -78,6 +78,12 @@ pub trait Add { type Output; /// Performs the `+` operation. + /// + /// # Example + /// + /// ``` + /// assert_eq!(12 + 1, 13); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn add(self, rhs: Rhs) -> Self::Output; @@ -178,6 +184,12 @@ pub trait Sub { type Output; /// Performs the `-` operation. + /// + /// # Example + /// + /// ``` + /// assert_eq!(12 - 1, 11); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn sub(self, rhs: Rhs) -> Self::Output; @@ -300,6 +312,12 @@ pub trait Mul { type Output; /// Performs the `*` operation. + /// + /// # Example + /// + /// ``` + /// assert_eq!(12 * 2, 24); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn mul(self, rhs: Rhs) -> Self::Output; @@ -426,6 +444,12 @@ pub trait Div { type Output; /// Performs the `/` operation. + /// + /// # Example + /// + /// ``` + /// assert_eq!(12 / 2, 6); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn div(self, rhs: Rhs) -> Self::Output; @@ -513,6 +537,12 @@ pub trait Rem { type Output; /// Performs the `%` operation. + /// + /// # Example + /// + /// ``` + /// assert_eq!(12 % 10, 2); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn rem(self, rhs: Rhs) -> Self::Output; @@ -612,6 +642,13 @@ pub trait Neg { type Output; /// Performs the unary `-` operation. + /// + /// # Example + /// + /// ``` + /// let x: i32 = 12; + /// assert_eq!(-x, -12); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn neg(self) -> Self::Output; @@ -673,6 +710,14 @@ neg_impl! { isize i8 i16 i32 i64 i128 f32 f64 } #[doc(alias = "+=")] pub trait AddAssign { /// Performs the `+=` operation. + /// + /// # Example + /// + /// ``` + /// let mut x: u32 = 12; + /// x += 1; + /// assert_eq!(x, 13); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn add_assign(&mut self, rhs: Rhs); } @@ -731,6 +776,14 @@ add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[doc(alias = "-=")] pub trait SubAssign { /// Performs the `-=` operation. + /// + /// # Example + /// + /// ``` + /// let mut x: u32 = 12; + /// x -= 1; + /// assert_eq!(x, 11); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn sub_assign(&mut self, rhs: Rhs); } @@ -780,6 +833,14 @@ sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[doc(alias = "*=")] pub trait MulAssign { /// Performs the `*=` operation. + /// + /// # Example + /// + /// ``` + /// let mut x: u32 = 12; + /// x *= 2; + /// assert_eq!(x, 24); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn mul_assign(&mut self, rhs: Rhs); } @@ -829,6 +890,14 @@ mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[doc(alias = "/=")] pub trait DivAssign { /// Performs the `/=` operation. + /// + /// # Example + /// + /// ``` + /// let mut x: u32 = 12; + /// x /= 2; + /// assert_eq!(x, 6); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn div_assign(&mut self, rhs: Rhs); } @@ -881,6 +950,14 @@ div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[doc(alias = "%=")] pub trait RemAssign { /// Performs the `%=` operation. + /// + /// # Example + /// + /// ``` + /// let mut x: u32 = 12; + /// x %= 10; + /// assert_eq!(x, 2); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn rem_assign(&mut self, rhs: Rhs); } From 2d56512580919483268c3e3bf2e028c8614805f2 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 10 Sep 2020 14:18:05 +0200 Subject: [PATCH 0262/1052] Cleanup of rustup --- clippy_lints/src/temporary_assignment.rs | 9 +++------ tests/ui/temporary_assignment.rs | 6 ------ tests/ui/temporary_assignment.stderr | 8 ++++---- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/clippy_lints/src/temporary_assignment.rs b/clippy_lints/src/temporary_assignment.rs index 2b6ddadd4c112..fb891866364cc 100644 --- a/clippy_lints/src/temporary_assignment.rs +++ b/clippy_lints/src/temporary_assignment.rs @@ -21,11 +21,8 @@ declare_clippy_lint! { "assignments to temporaries" } -fn is_temporary(_cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - match &expr.kind { - ExprKind::Struct(..) | ExprKind::Tup(..) => true, - _ => false, - } +fn is_temporary(expr: &Expr<'_>) -> bool { + matches!(&expr.kind, ExprKind::Struct(..) | ExprKind::Tup(..)) } declare_lint_pass!(TemporaryAssignment => [TEMPORARY_ASSIGNMENT]); @@ -37,7 +34,7 @@ impl<'tcx> LateLintPass<'tcx> for TemporaryAssignment { while let ExprKind::Field(f, _) | ExprKind::Index(f, _) = &base.kind { base = f; } - if is_temporary(cx, base) && !is_adjusted(cx, base) { + if is_temporary(base) && !is_adjusted(cx, base) { span_lint(cx, TEMPORARY_ASSIGNMENT, expr.span, "assignment to temporary"); } } diff --git a/tests/ui/temporary_assignment.rs b/tests/ui/temporary_assignment.rs index d6f56d40c5d4e..ac4c1bc65979f 100644 --- a/tests/ui/temporary_assignment.rs +++ b/tests/ui/temporary_assignment.rs @@ -1,5 +1,4 @@ #![warn(clippy::temporary_assignment)] -#![allow(const_item_mutation)] use std::ops::{Deref, DerefMut}; @@ -54,11 +53,6 @@ fn main() { ArrayStruct { array: [0] }.array[0] = 1; (0, 0).0 = 1; - A.0 = 2; - B.field = 2; - C.structure.field = 2; - D.array[0] = 2; - // no error s.field = 1; t.0 = 1; diff --git a/tests/ui/temporary_assignment.stderr b/tests/ui/temporary_assignment.stderr index 4cc32c79f05ce..7d79901a28d1b 100644 --- a/tests/ui/temporary_assignment.stderr +++ b/tests/ui/temporary_assignment.stderr @@ -1,5 +1,5 @@ error: assignment to temporary - --> $DIR/temporary_assignment.rs:48:5 + --> $DIR/temporary_assignment.rs:47:5 | LL | Struct { field: 0 }.field = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | Struct { field: 0 }.field = 1; = note: `-D clippy::temporary-assignment` implied by `-D warnings` error: assignment to temporary - --> $DIR/temporary_assignment.rs:49:5 + --> $DIR/temporary_assignment.rs:48:5 | LL | / MultiStruct { LL | | structure: Struct { field: 0 }, @@ -17,13 +17,13 @@ LL | | .field = 1; | |______________^ error: assignment to temporary - --> $DIR/temporary_assignment.rs:54:5 + --> $DIR/temporary_assignment.rs:53:5 | LL | ArrayStruct { array: [0] }.array[0] = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: assignment to temporary - --> $DIR/temporary_assignment.rs:55:5 + --> $DIR/temporary_assignment.rs:54:5 | LL | (0, 0).0 = 1; | ^^^^^^^^^^^^ From f1775f05b7a20c83dd018bc716e1eb5578cfceb0 Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Thu, 10 Sep 2020 22:39:08 +0900 Subject: [PATCH 0263/1052] Fix typo --- clippy_lints/src/await_holding_lock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/await_holding_lock.rs b/clippy_lints/src/await_holding_lock.rs index f18e7e5d99755..367534499fd02 100644 --- a/clippy_lints/src/await_holding_lock.rs +++ b/clippy_lints/src/await_holding_lock.rs @@ -10,7 +10,7 @@ declare_clippy_lint! { /// **What it does:** Checks for calls to await while holding a /// non-async-aware MutexGuard. /// - /// **Why is this bad?** The Mutex types found in syd::sync and parking_lot + /// **Why is this bad?** The Mutex types found in std::sync and parking_lot /// are not designed to operate in an async context across await points. /// /// There are two potential solutions. One is to use an asynx-aware Mutex From fd4dd00ddef578aa01744e4146c1dfe3fbca4866 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 23 Aug 2020 03:42:19 -0700 Subject: [PATCH 0264/1052] Syntactically permit unsafety on mods --- compiler/rustc_ast/src/ast.rs | 10 ++- compiler/rustc_ast/src/mut_visit.rs | 7 +- .../rustc_ast_passes/src/ast_validation.rs | 10 ++- compiler/rustc_ast_pretty/src/pprust.rs | 11 ++- compiler/rustc_expand/src/config.rs | 2 +- compiler/rustc_expand/src/expand.rs | 27 ++++-- compiler/rustc_expand/src/module.rs | 12 ++- compiler/rustc_parse/src/parser/item.rs | 67 ++++++++++---- .../ast-json/ast-json-noexpand-output.stdout | 2 +- src/test/ui/ast-json/ast-json-output.stdout | 2 +- src/test/ui/parser/unsafe-foreign-mod.rs | 9 ++ src/test/ui/parser/unsafe-foreign-mod.stderr | 14 +++ src/test/ui/parser/unsafe-mod.rs | 9 ++ src/test/ui/parser/unsafe-mod.stderr | 23 +++++ .../proc-macro/auxiliary/macro-only-syntax.rs | 89 +++++++++++++++++++ src/test/ui/proc-macro/unsafe-foreign-mod.rs | 14 +++ src/test/ui/proc-macro/unsafe-mod.rs | 13 +++ 17 files changed, 284 insertions(+), 37 deletions(-) create mode 100644 src/test/ui/parser/unsafe-foreign-mod.rs create mode 100644 src/test/ui/parser/unsafe-foreign-mod.stderr create mode 100644 src/test/ui/parser/unsafe-mod.rs create mode 100644 src/test/ui/parser/unsafe-mod.stderr create mode 100644 src/test/ui/proc-macro/auxiliary/macro-only-syntax.rs create mode 100644 src/test/ui/proc-macro/unsafe-foreign-mod.rs create mode 100644 src/test/ui/proc-macro/unsafe-mod.rs diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 49aa1fc17357e..b9f380dc4e835 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2289,12 +2289,15 @@ impl FnRetTy { /// Module declaration. /// /// E.g., `mod foo;` or `mod foo { .. }`. -#[derive(Clone, Encodable, Decodable, Debug, Default)] +#[derive(Clone, Encodable, Decodable, Debug)] pub struct Mod { /// A span from the first token past `{` to the last token until `}`. /// For `mod foo;`, the inner span ranges from the first token /// to the last token in the external file. pub inner: Span, + /// `unsafe` keyword accepted syntactically for macro DSLs, but not + /// semantically by Rust. + pub unsafety: Unsafe, pub items: Vec>, /// `true` for `mod foo { .. }`; `false` for `mod foo;`. pub inline: bool, @@ -2302,9 +2305,12 @@ pub struct Mod { /// Foreign module declaration. /// -/// E.g., `extern { .. }` or `extern C { .. }`. +/// E.g., `extern { .. }` or `extern "C" { .. }`. #[derive(Clone, Encodable, Decodable, Debug)] pub struct ForeignMod { + /// `unsafe` keyword accepted syntactically for macro DSLs, but not + /// semantically by Rust. + pub unsafety: Unsafe, pub abi: Option, pub items: Vec>, } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 3ef83ef3fc973..3119c5e0a12fa 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -490,7 +490,7 @@ pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { } pub fn noop_visit_foreign_mod(foreign_mod: &mut ForeignMod, vis: &mut T) { - let ForeignMod { abi: _, items } = foreign_mod; + let ForeignMod { unsafety: _, abi: _, items } = foreign_mod; items.flat_map_in_place(|item| vis.flat_map_foreign_item(item)); } @@ -970,7 +970,8 @@ pub fn noop_visit_fn_header(header: &mut FnHeader, vis: &mut T) { vis.visit_asyncness(asyncness); } -pub fn noop_visit_mod(Mod { inner, items, inline: _ }: &mut Mod, vis: &mut T) { +pub fn noop_visit_mod(module: &mut Mod, vis: &mut T) { + let Mod { inner, unsafety: _, items, inline: _ } = module; vis.visit_span(inner); items.flat_map_in_place(|item| vis.flat_map_item(item)); } @@ -990,7 +991,7 @@ pub fn noop_visit_crate(krate: &mut Crate, vis: &mut T) { let len = items.len(); if len == 0 { - let module = Mod { inner: span, items: vec![], inline: true }; + let module = Mod { inner: span, unsafety: Unsafe::No, items: vec![], inline: true }; Crate { module, attrs: vec![], span, proc_macros } } else if len == 1 { let Item { attrs, span, kind, .. } = items.into_iter().next().unwrap().into_inner(); diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index a01dd8c939cf6..998acf4fd10cb 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -990,12 +990,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.error_item_without_body(item.span, "function", msg, " { }"); } } - ItemKind::ForeignMod(_) => { + ItemKind::ForeignMod(ForeignMod { unsafety, .. }) => { let old_item = mem::replace(&mut self.extern_mod, Some(item)); self.invalid_visibility( &item.vis, Some("place qualifiers on individual foreign items instead"), ); + if let Unsafe::Yes(span) = unsafety { + self.err_handler().span_err(span, "extern block cannot be declared unsafe"); + } visit::walk_item(self, item); self.extern_mod = old_item; return; // Avoid visiting again. @@ -1029,7 +1032,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { walk_list!(self, visit_attribute, &item.attrs); return; } - ItemKind::Mod(Mod { inline, .. }) => { + ItemKind::Mod(Mod { inline, unsafety, .. }) => { + if let Unsafe::Yes(span) = unsafety { + self.err_handler().span_err(span, "module cannot be declared unsafe"); + } // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584). if !inline && !self.session.contains_name(&item.attrs, sym::path) { self.check_mod_file_item_asciionly(item.ident); diff --git a/compiler/rustc_ast_pretty/src/pprust.rs b/compiler/rustc_ast_pretty/src/pprust.rs index 9743a00042969..955d1677647ec 100644 --- a/compiler/rustc_ast_pretty/src/pprust.rs +++ b/compiler/rustc_ast_pretty/src/pprust.rs @@ -1139,7 +1139,11 @@ impl<'a> State<'a> { self.print_fn_full(sig, item.ident, gen, &item.vis, def, body, &item.attrs); } ast::ItemKind::Mod(ref _mod) => { - self.head(visibility_qualified(&item.vis, "mod")); + self.head(to_string(|s| { + s.print_visibility(&item.vis); + s.print_unsafety(_mod.unsafety); + s.word("mod"); + })); self.print_ident(item.ident); if _mod.inline || self.is_expanded { @@ -1154,7 +1158,10 @@ impl<'a> State<'a> { } } ast::ItemKind::ForeignMod(ref nmod) => { - self.head("extern"); + self.head(to_string(|s| { + s.print_unsafety(nmod.unsafety); + s.word("extern"); + })); if let Some(abi) = nmod.abi { self.print_literal(&abi.as_lit()); self.nbsp(); diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 97608a389035b..dd087ab91509b 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -399,7 +399,7 @@ impl<'a> StripUnconfigured<'a> { } pub fn configure_foreign_mod(&mut self, foreign_mod: &mut ast::ForeignMod) { - let ast::ForeignMod { abi: _, items } = foreign_mod; + let ast::ForeignMod { unsafety: _, abi: _, items } = foreign_mod; items.flat_map_in_place(|item| self.configure(item)); } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index ca6f7324ca40f..241566a042a0e 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -13,7 +13,7 @@ use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, AssocCtxt, Visitor}; use rustc_ast::{self as ast, AttrItem, Block, LitKind, NodeId, PatKind, Path}; -use rustc_ast::{ItemKind, MacArgs, MacCallStmt, MacStmtStyle, StmtKind}; +use rustc_ast::{ItemKind, MacArgs, MacCallStmt, MacStmtStyle, StmtKind, Unsafe}; use rustc_ast_pretty::pprust; use rustc_attr::{self as attr, is_builtin_attr, HasAttrs}; use rustc_data_structures::map_in_place::MapInPlace; @@ -370,11 +370,21 @@ impl<'a, 'b> MacroExpander<'a, 'b> { None => { // Resolution failed so we return an empty expansion krate.attrs = vec![]; - krate.module = ast::Mod { inner: orig_mod_span, items: vec![], inline: true }; + krate.module = ast::Mod { + inner: orig_mod_span, + unsafety: Unsafe::No, + items: vec![], + inline: true, + }; } Some(ast::Item { span, kind, .. }) => { krate.attrs = vec![]; - krate.module = ast::Mod { inner: orig_mod_span, items: vec![], inline: true }; + krate.module = ast::Mod { + inner: orig_mod_span, + unsafety: Unsafe::No, + items: vec![], + inline: true, + }; self.cx.span_err( span, &format!( @@ -1441,8 +1451,15 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { push_directory(&self.cx.sess, ident, &item.attrs, dir) } else { // We have an outline `mod foo;` so we need to parse the file. - let (new_mod, dir) = - parse_external_mod(&self.cx.sess, ident, span, dir, &mut attrs, pushed); + let (new_mod, dir) = parse_external_mod( + &self.cx.sess, + ident, + span, + old_mod.unsafety, + dir, + &mut attrs, + pushed, + ); let krate = ast::Crate { span: new_mod.inner, diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index fefc0bdeb7cc2..171cb3fa8e6e9 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -1,4 +1,4 @@ -use rustc_ast::{token, Attribute, Mod}; +use rustc_ast::{token, Attribute, Mod, Unsafe}; use rustc_errors::{struct_span_err, PResult}; use rustc_parse::new_parser_from_file; use rustc_session::parse::ParseSess; @@ -42,6 +42,7 @@ crate fn parse_external_mod( sess: &Session, id: Ident, span: Span, // The span to blame on errors. + unsafety: Unsafe, Directory { mut ownership, path }: Directory, attrs: &mut Vec, pop_mod_stack: &mut bool, @@ -60,13 +61,16 @@ crate fn parse_external_mod( drop(included_mod_stack); // Actually parse the external file as a module. - let mut module = - new_parser_from_file(&sess.parse_sess, &mp.path, Some(span)).parse_mod(&token::Eof)?; + let mut parser = new_parser_from_file(&sess.parse_sess, &mp.path, Some(span)); + let mut module = parser.parse_mod(&token::Eof, unsafety)?; module.0.inline = false; module }; // (1) ...instead, we return a dummy module. - let (module, mut new_attrs) = result.map_err(|mut err| err.emit()).unwrap_or_default(); + let (module, mut new_attrs) = result.map_err(|mut err| err.emit()).unwrap_or_else(|_| { + let module = Mod { inner: Span::default(), unsafety, items: Vec::new(), inline: false }; + (module, Vec::new()) + }); attrs.append(&mut new_attrs); // Extract the directory path for submodules of `module`. diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 9143af651df2d..1a428f8bb0ab5 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -28,7 +28,7 @@ impl<'a> Parser<'a> { /// Parses a source module as a crate. This is the main entry point for the parser. pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> { let lo = self.token.span; - let (module, attrs) = self.parse_mod(&token::Eof)?; + let (module, attrs) = self.parse_mod(&token::Eof, Unsafe::No)?; let span = lo.to(self.token.span); let proc_macros = Vec::new(); // Filled in by `proc_macro_harness::inject()`. Ok(ast::Crate { attrs, module, span, proc_macros }) @@ -36,27 +36,38 @@ impl<'a> Parser<'a> { /// Parses a `mod { ... }` or `mod ;` item. fn parse_item_mod(&mut self, attrs: &mut Vec) -> PResult<'a, ItemInfo> { + let unsafety = self.parse_unsafety(); + self.expect_keyword(kw::Mod)?; let id = self.parse_ident()?; let (module, mut inner_attrs) = if self.eat(&token::Semi) { - Default::default() + (Mod { inner: Span::default(), unsafety, items: Vec::new(), inline: false }, Vec::new()) } else { self.expect(&token::OpenDelim(token::Brace))?; - self.parse_mod(&token::CloseDelim(token::Brace))? + self.parse_mod(&token::CloseDelim(token::Brace), unsafety)? }; attrs.append(&mut inner_attrs); Ok((id, ItemKind::Mod(module))) } /// Parses the contents of a module (inner attributes followed by module items). - pub fn parse_mod(&mut self, term: &TokenKind) -> PResult<'a, (Mod, Vec)> { + pub fn parse_mod( + &mut self, + term: &TokenKind, + unsafety: Unsafe, + ) -> PResult<'a, (Mod, Vec)> { let lo = self.token.span; let attrs = self.parse_inner_attributes()?; - let module = self.parse_mod_items(term, lo)?; + let module = self.parse_mod_items(term, lo, unsafety)?; Ok((module, attrs)) } /// Given a termination token, parses all of the items in a module. - fn parse_mod_items(&mut self, term: &TokenKind, inner_lo: Span) -> PResult<'a, Mod> { + fn parse_mod_items( + &mut self, + term: &TokenKind, + inner_lo: Span, + unsafety: Unsafe, + ) -> PResult<'a, Mod> { let mut items = vec![]; while let Some(item) = self.parse_item()? { items.push(item); @@ -75,7 +86,7 @@ impl<'a> Parser<'a> { let hi = if self.token.span.is_dummy() { inner_lo } else { self.prev_token.span }; - Ok(Mod { inner: inner_lo.to(hi), items, inline: true }) + Ok(Mod { inner: inner_lo.to(hi), unsafety, items, inline: true }) } } @@ -235,8 +246,13 @@ impl<'a> Parser<'a> { self.parse_item_extern_crate()? } else { // EXTERN BLOCK - self.parse_item_foreign_mod(attrs)? + self.parse_item_foreign_mod(attrs, Unsafe::No)? } + } else if self.is_unsafe_foreign_mod() { + // EXTERN BLOCK + let unsafety = self.parse_unsafety(); + self.expect_keyword(kw::Extern)?; + self.parse_item_foreign_mod(attrs, unsafety)? } else if self.is_static_global() { // STATIC ITEM self.bump(); // `static` @@ -256,7 +272,9 @@ impl<'a> Parser<'a> { { // IMPL ITEM self.parse_item_impl(attrs, def())? - } else if self.eat_keyword(kw::Mod) { + } else if self.check_keyword(kw::Mod) + || self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Mod]) + { // MODULE ITEM self.parse_item_mod(attrs)? } else if self.eat_keyword(kw::Type) { @@ -893,10 +911,14 @@ impl<'a> Parser<'a> { /// extern "C" {} /// extern {} /// ``` - fn parse_item_foreign_mod(&mut self, attrs: &mut Vec) -> PResult<'a, ItemInfo> { + fn parse_item_foreign_mod( + &mut self, + attrs: &mut Vec, + unsafety: Unsafe, + ) -> PResult<'a, ItemInfo> { let abi = self.parse_abi(); // ABI? let items = self.parse_item_list(attrs, |p| p.parse_foreign_item())?; - let module = ast::ForeignMod { abi, items }; + let module = ast::ForeignMod { unsafety, abi, items }; Ok((Ident::invalid(), ItemKind::ForeignMod(module))) } @@ -938,6 +960,15 @@ impl<'a> Parser<'a> { .emit(); } + fn is_unsafe_foreign_mod(&self) -> bool { + self.token.is_keyword(kw::Unsafe) + && self.is_keyword_ahead(1, &[kw::Extern]) + && self.look_ahead( + 2 + self.look_ahead(2, |t| t.can_begin_literal_maybe_minus() as usize), + |t| t.kind == token::OpenDelim(token::Brace), + ) + } + fn is_static_global(&mut self) -> bool { if self.check_keyword(kw::Static) { // Check if this could be a closure. @@ -1552,10 +1583,14 @@ impl<'a> Parser<'a> { // `$qual fn` or `$qual $qual`: || QUALS.iter().any(|&kw| self.check_keyword(kw)) && self.look_ahead(1, |t| { - // ...qualified and then `fn`, e.g. `const fn`. + // `$qual fn`, e.g. `const fn` or `async fn`. t.is_keyword(kw::Fn) - // Two qualifiers. This is enough. Due `async` we need to check that it's reserved. - || t.is_non_raw_ident_where(|i| QUALS.contains(&i.name) && i.is_reserved()) + // Two qualifiers `$qual $qual` is enough, e.g. `async unsafe`. + || t.is_non_raw_ident_where(|i| QUALS.contains(&i.name) + // Rule out 2015 `const async: T = val`. + && i.is_reserved() + // Rule out unsafe extern block. + && !self.is_unsafe_foreign_mod()) }) // `extern ABI fn` || self.check_keyword(kw::Extern) @@ -1567,9 +1602,9 @@ impl<'a> Parser<'a> { /// up to and including the `fn` keyword. The formal grammar is: /// /// ``` - /// Extern = "extern" StringLit ; + /// Extern = "extern" StringLit? ; /// FnQual = "const"? "async"? "unsafe"? Extern? ; - /// FnFrontMatter = FnQual? "fn" ; + /// FnFrontMatter = FnQual "fn" ; /// ``` pub(super) fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> { let constness = self.parse_constness(); diff --git a/src/test/ui/ast-json/ast-json-noexpand-output.stdout b/src/test/ui/ast-json/ast-json-noexpand-output.stdout index 031c0d0cae51c..0e5a3a14ac7b5 100644 --- a/src/test/ui/ast-json/ast-json-noexpand-output.stdout +++ b/src/test/ui/ast-json/ast-json-noexpand-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} +{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout index 9b3b6870cbe7e..8752ed2ae9993 100644 --- a/src/test/ui/ast-json/ast-json-output.stdout +++ b/src/test/ui/ast-json/ast-json-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} +{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} diff --git a/src/test/ui/parser/unsafe-foreign-mod.rs b/src/test/ui/parser/unsafe-foreign-mod.rs new file mode 100644 index 0000000000000..872af95bd225b --- /dev/null +++ b/src/test/ui/parser/unsafe-foreign-mod.rs @@ -0,0 +1,9 @@ +unsafe extern { + //~^ ERROR extern block cannot be declared unsafe +} + +unsafe extern "C" { + //~^ ERROR extern block cannot be declared unsafe +} + +fn main() {} diff --git a/src/test/ui/parser/unsafe-foreign-mod.stderr b/src/test/ui/parser/unsafe-foreign-mod.stderr new file mode 100644 index 0000000000000..5e10988051ea0 --- /dev/null +++ b/src/test/ui/parser/unsafe-foreign-mod.stderr @@ -0,0 +1,14 @@ +error: extern block cannot be declared unsafe + --> $DIR/unsafe-foreign-mod.rs:1:1 + | +LL | unsafe extern { + | ^^^^^^ + +error: extern block cannot be declared unsafe + --> $DIR/unsafe-foreign-mod.rs:5:1 + | +LL | unsafe extern "C" { + | ^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/unsafe-mod.rs b/src/test/ui/parser/unsafe-mod.rs new file mode 100644 index 0000000000000..7916d878ea585 --- /dev/null +++ b/src/test/ui/parser/unsafe-mod.rs @@ -0,0 +1,9 @@ +unsafe mod m { + //~^ ERROR module cannot be declared unsafe +} + +unsafe mod n; +//~^ ERROR module cannot be declared unsafe +//~^^ ERROR file not found for module `n` + +fn main() {} diff --git a/src/test/ui/parser/unsafe-mod.stderr b/src/test/ui/parser/unsafe-mod.stderr new file mode 100644 index 0000000000000..259b2c1d61e08 --- /dev/null +++ b/src/test/ui/parser/unsafe-mod.stderr @@ -0,0 +1,23 @@ +error[E0583]: file not found for module `n` + --> $DIR/unsafe-mod.rs:5:1 + | +LL | unsafe mod n; + | ^^^^^^^^^^^^^ + | + = help: to create the module `n`, create file "$DIR/n.rs" + +error: module cannot be declared unsafe + --> $DIR/unsafe-mod.rs:1:1 + | +LL | unsafe mod m { + | ^^^^^^ + +error: module cannot be declared unsafe + --> $DIR/unsafe-mod.rs:5:1 + | +LL | unsafe mod n; + | ^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0583`. diff --git a/src/test/ui/proc-macro/auxiliary/macro-only-syntax.rs b/src/test/ui/proc-macro/auxiliary/macro-only-syntax.rs new file mode 100644 index 0000000000000..c72306c3d50b3 --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/macro-only-syntax.rs @@ -0,0 +1,89 @@ +// force-host +// no-prefer-dynamic + +// These are tests for syntax that is accepted by the Rust parser but +// unconditionally rejected semantically after macro expansion. Attribute macros +// are permitted to accept such syntax as long as they replace it with something +// that makes sense to Rust. +// +// We also inspect some of the spans to verify the syntax is not triggering the +// lossy string reparse hack (https://github.com/rust-lang/rust/issues/43081). + +#![crate_type = "proc-macro"] +#![feature(proc_macro_span)] + +extern crate proc_macro; +use proc_macro::{token_stream, Delimiter, TokenStream, TokenTree}; +use std::path::Component; + +// unsafe mod m { +// pub unsafe mod inner; +// } +#[proc_macro_attribute] +pub fn expect_unsafe_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream { + let tokens = &mut input.into_iter(); + expect(tokens, "unsafe"); + expect(tokens, "mod"); + expect(tokens, "m"); + let tokens = &mut expect_brace(tokens); + expect(tokens, "pub"); + expect(tokens, "unsafe"); + expect(tokens, "mod"); + let ident = expect(tokens, "inner"); + expect(tokens, ";"); + check_useful_span(ident, "unsafe-mod.rs"); + TokenStream::new() +} + +// unsafe extern { +// type T; +// } +#[proc_macro_attribute] +pub fn expect_unsafe_foreign_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream { + let tokens = &mut input.into_iter(); + expect(tokens, "unsafe"); + expect(tokens, "extern"); + let tokens = &mut expect_brace(tokens); + expect(tokens, "type"); + let ident = expect(tokens, "T"); + expect(tokens, ";"); + check_useful_span(ident, "unsafe-foreign-mod.rs"); + TokenStream::new() +} + +// unsafe extern "C++" {} +#[proc_macro_attribute] +pub fn expect_unsafe_extern_cpp_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream { + let tokens = &mut input.into_iter(); + expect(tokens, "unsafe"); + expect(tokens, "extern"); + let abi = expect(tokens, "\"C++\""); + expect_brace(tokens); + check_useful_span(abi, "unsafe-foreign-mod.rs"); + TokenStream::new() +} + +fn expect(tokens: &mut token_stream::IntoIter, expected: &str) -> TokenTree { + match tokens.next() { + Some(token) if token.to_string() == expected => token, + wrong => panic!("unexpected token: {:?}, expected `{}`", wrong, expected), + } +} + +fn expect_brace(tokens: &mut token_stream::IntoIter) -> token_stream::IntoIter { + match tokens.next() { + Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Brace => { + group.stream().into_iter() + } + wrong => panic!("unexpected token: {:?}, expected `{{`", wrong), + } +} + +fn check_useful_span(token: TokenTree, expected_filename: &str) { + let span = token.span(); + assert!(span.start().column < span.end().column); + + let source_path = span.source_file().path(); + let filename = source_path.components().last().unwrap(); + assert_eq!(filename, Component::Normal(expected_filename.as_ref())); +} diff --git a/src/test/ui/proc-macro/unsafe-foreign-mod.rs b/src/test/ui/proc-macro/unsafe-foreign-mod.rs new file mode 100644 index 0000000000000..7bdfa93c21fc7 --- /dev/null +++ b/src/test/ui/proc-macro/unsafe-foreign-mod.rs @@ -0,0 +1,14 @@ +// run-pass +// aux-build:macro-only-syntax.rs + +extern crate macro_only_syntax; + +#[macro_only_syntax::expect_unsafe_foreign_mod] +unsafe extern { + type T; +} + +#[macro_only_syntax::expect_unsafe_extern_cpp_mod] +unsafe extern "C++" {} + +fn main() {} diff --git a/src/test/ui/proc-macro/unsafe-mod.rs b/src/test/ui/proc-macro/unsafe-mod.rs new file mode 100644 index 0000000000000..8ff6e352c53d0 --- /dev/null +++ b/src/test/ui/proc-macro/unsafe-mod.rs @@ -0,0 +1,13 @@ +// run-pass +// aux-build:macro-only-syntax.rs + +#![feature(proc_macro_hygiene)] + +extern crate macro_only_syntax; + +#[macro_only_syntax::expect_unsafe_mod] +unsafe mod m { + pub unsafe mod inner; +} + +fn main() {} From f7b6ace029d5b5832afa168bfe7d742537e038e4 Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Thu, 10 Sep 2020 11:35:25 +0200 Subject: [PATCH 0265/1052] Use IOV_MAX and UIO_MAXIOV constants in limit vectored I/O Also updates the libc dependency to 0.2.77 (from 0.2.74) as the constants were only recently added. --- library/std/Cargo.toml | 2 +- library/std/src/sys/unix/fd.rs | 42 +++++++++++++++++++++------------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index bfd05db6b1bbe..01babeffd98f0 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -16,7 +16,7 @@ cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core" } -libc = { version = "0.2.74", default-features = false, features = ['rustc-dep-of-std'] } +libc = { version = "0.2.77", default-features = false, features = ['rustc-dep-of-std'] } compiler_builtins = { version = "0.1.35" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index b2f15eda9d7b0..16adbe6d88c4f 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -7,7 +7,6 @@ use crate::cmp; use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read}; use crate::mem; #[cfg(not(any(target_os = "redox", target_env = "newlib")))] -use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sys::cvt; use crate::sys_common::AsInner; @@ -31,24 +30,35 @@ const READ_LIMIT: usize = c_int::MAX as usize - 1; #[cfg(not(target_os = "macos"))] const READ_LIMIT: usize = libc::ssize_t::MAX as usize; -#[cfg(not(any(target_os = "redox", target_env = "newlib")))] -fn max_iov() -> usize { - static LIM: AtomicUsize = AtomicUsize::new(0); - - let mut lim = LIM.load(Ordering::Relaxed); - if lim == 0 { - let ret = unsafe { libc::sysconf(libc::_SC_IOV_MAX) }; - - // 16 is the minimum value required by POSIX. - lim = if ret > 0 { ret as usize } else { 16 }; - LIM.store(lim, Ordering::Relaxed); - } +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", +))] +const fn max_iov() -> usize { + libc::IOV_MAX as usize +} - lim +#[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))] +const fn max_iov() -> usize { + libc::UIO_MAXIOV as usize } -#[cfg(any(target_os = "redox", target_env = "newlib"))] -fn max_iov() -> usize { +#[cfg(not(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", +)))] +const fn max_iov() -> usize { 16 // The minimum value required by POSIX. } From 7c3e1ffd7a945b4044e5e80d7d74ba944ff54d0f Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Thu, 10 Sep 2020 14:37:50 +0200 Subject: [PATCH 0266/1052] Update libc in Cargo.lock --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b687e714d4fa2..cfc1cede0797b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1610,9 +1610,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.74" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10" +checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" dependencies = [ "rustc-std-workspace-core", ] From fd5859a673e69eb9fd98e9a92c32dd0dc7fc1855 Mon Sep 17 00:00:00 2001 From: arijit79 <65700195+arijit79@users.noreply.github.com> Date: Thu, 3 Sep 2020 20:08:15 +0530 Subject: [PATCH 0267/1052] Add docs about crate level documentation support --- src/doc/rustdoc/src/what-is-rustdoc.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/doc/rustdoc/src/what-is-rustdoc.md b/src/doc/rustdoc/src/what-is-rustdoc.md index adcebc832bc0b..7a38c96d7147b 100644 --- a/src/doc/rustdoc/src/what-is-rustdoc.md +++ b/src/doc/rustdoc/src/what-is-rustdoc.md @@ -93,6 +93,29 @@ passes `-L`, a flag that helps rustdoc find the dependencies your code relies on. If our project used dependencies, we'd get documentation for them as well! +## Outer and inner documentation + +The `///` syntax is used to document the item present after it. +That's why it is called an outer documentation. +There is another syntax: `//!`, which is used to document the +item it is present inside. It is called an inner documentation. +It is often used when documenting the entire crate, +because nothing comes before it: it is the root of the crate. +So in order to document an entire crate, you need to use `//!` syntax. +For example: + +``` rust +//! This is my first rust crate +``` + +When used in the crate root, it documents the item it is inside, +which is the crate itself. + +For more information about the `//!` syntax, see [the Book]. + +[the Book]: https://doc.rust-lang.org/book/ch14-02-publishing-to-crates-io.html#commenting-contained-items + + ## Using standalone Markdown files `rustdoc` can also generate HTML from standalone Markdown files. Let's From 36a864854f41dfd25c45fa4881812bd005bd5054 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 10 Sep 2020 17:08:10 +0200 Subject: [PATCH 0268/1052] Fix spelling of "Known problems section" of `interior_mutable_key` --- clippy_lints/src/mut_key.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index fa3a99dad9d23..0826ad0ab55bb 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -12,10 +12,10 @@ declare_clippy_lint! { /// `BtreeSet` rely on either the hash or the order of keys be unchanging, /// so having types with interior mutability is a bad idea. /// - /// **Known problems:** It's correct to use a struct, that contains interior mutability, - /// as a key; when its `Hash` implementation doesn't access any these interior mutable types. - /// However, this lint is unable to recognise it so cause a false positive. - /// `bytes` ctate is a great example of this. + /// **Known problems:** It's correct to use a struct, that contains interior mutability + /// as a key, when its `Hash` implementation doesn't access any of the interior mutable types. + /// However, this lint is unable to recognize this, so it causes a false positive in theses cases. + /// The `bytes` crate is a great example of this. /// /// **Example:** /// ```rust From a12828a80a62fbf2ee3e1ffc3b8169a8dc3c2b80 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 10 Sep 2020 17:47:07 +0200 Subject: [PATCH 0269/1052] Merge commit '5034d47f721ff4c3a3ff2aca9ef2ef3e1d067f9f' into clippyup --- CHANGELOG.md | 110 +++++++++++++++- clippy_lints/src/async_yields_async.rs | 86 +++++++++++++ clippy_lints/src/attrs.rs | 38 +++--- clippy_lints/src/create_dir.rs | 51 ++++++++ clippy_lints/src/default_trait_access.rs | 46 +++---- clippy_lints/src/functions.rs | 7 +- clippy_lints/src/lib.rs | 9 ++ clippy_lints/src/loops.rs | 100 +++++++++------ clippy_lints/src/map_unit_fn.rs | 6 +- clippy_lints/src/methods/mod.rs | 10 +- clippy_lints/src/temporary_assignment.rs | 9 +- clippy_lints/src/transmute.rs | 6 +- clippy_lints/src/types.rs | 124 +++++++++++++------ clippy_lints/src/unnecessary_sort_by.rs | 13 +- clippy_lints/src/utils/ast_utils.rs | 4 +- clippy_lints/src/utils/conf.rs | 2 +- clippy_lints/src/utils/mod.rs | 100 ++++++++------- clippy_lints/src/utils/paths.rs | 1 + clippy_lints/src/utils/sugg.rs | 6 +- src/lintlist/mod.rs | 14 +++ tests/ui-toml/functions_maxlines/test.stderr | 4 +- tests/ui/async_yields_async.fixed | 68 ++++++++++ tests/ui/async_yields_async.rs | 68 ++++++++++ tests/ui/async_yields_async.stderr | 96 ++++++++++++++ tests/ui/collapsible_if.fixed | 3 + tests/ui/collapsible_if.rs | 5 + tests/ui/collapsible_if.stderr | 10 +- tests/ui/create_dir.fixed | 17 +++ tests/ui/create_dir.rs | 17 +++ tests/ui/create_dir.stderr | 16 +++ tests/ui/default_trait_access.fixed | 106 ++++++++++++++++ tests/ui/default_trait_access.rs | 5 +- tests/ui/default_trait_access.stderr | 26 ++-- tests/ui/doc.rs | 13 +- tests/ui/doc.stderr | 50 ++++---- tests/ui/functions_maxlines.stderr | 2 +- tests/ui/option_map_unit_fn_fixable.stderr | 36 +++--- tests/ui/or_fun_call.fixed | 17 ++- tests/ui/or_fun_call.rs | 17 ++- tests/ui/or_fun_call.stderr | 20 +-- tests/ui/result_map_unit_fn_fixable.stderr | 34 ++--- tests/ui/result_map_unit_fn_unfixable.stderr | 12 +- tests/ui/same_item_push.rs | 112 ++++++++++++----- tests/ui/same_item_push.stderr | 42 ++++--- tests/ui/temporary_assignment.rs | 5 - tests/ui/transmute_ptr_to_ptr.rs | 8 ++ tests/ui/unit_arg.rs | 13 +- tests/ui/unit_arg.stderr | 96 +++++++------- tests/ui/unit_arg_empty_blocks.stderr | 14 +-- tests/ui/unnecessary_sort_by.fixed | 42 ++++++- tests/ui/unnecessary_sort_by.rs | 42 ++++++- tests/ui/useless_attribute.fixed | 8 ++ tests/ui/useless_attribute.rs | 8 ++ tests/ui/useless_attribute.stderr | 2 +- 54 files changed, 1360 insertions(+), 416 deletions(-) create mode 100644 clippy_lints/src/async_yields_async.rs create mode 100644 clippy_lints/src/create_dir.rs create mode 100644 tests/ui/async_yields_async.fixed create mode 100644 tests/ui/async_yields_async.rs create mode 100644 tests/ui/async_yields_async.stderr create mode 100644 tests/ui/create_dir.fixed create mode 100644 tests/ui/create_dir.rs create mode 100644 tests/ui/create_dir.stderr create mode 100644 tests/ui/default_trait_access.fixed diff --git a/CHANGELOG.md b/CHANGELOG.md index 137b561028a65..64f9379b303cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,113 @@ document. ## Unreleased / In Rust Nightly -[c2c07fa...master](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...master) +[09bd400...master](https://github.com/rust-lang/rust-clippy/compare/09bd400...master) + +## Rust 1.47 + +Current beta, release 2020-10-08 + +[c2c07fa...09bd400](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...09bd400) + +### New lints + +* [`derive_ord_xor_partial_ord`] [#5848](https://github.com/rust-lang/rust-clippy/pull/5848) +* [`trait_duplication_in_bounds`] [#5852](https://github.com/rust-lang/rust-clippy/pull/5852) +* [`map_identity`] [#5694](https://github.com/rust-lang/rust-clippy/pull/5694) +* [`unit_return_expecting_ord`] [#5737](https://github.com/rust-lang/rust-clippy/pull/5737) +* [`pattern_type_mismatch`] [#4841](https://github.com/rust-lang/rust-clippy/pull/4841) +* [`repeat_once`] [#5773](https://github.com/rust-lang/rust-clippy/pull/5773) +* [`same_item_push`] [#5825](https://github.com/rust-lang/rust-clippy/pull/5825) +* [`needless_arbitrary_self_type`] [#5869](https://github.com/rust-lang/rust-clippy/pull/5869) +* [`match_like_matches_macro`] [#5769](https://github.com/rust-lang/rust-clippy/pull/5769) +* [`stable_sort_primitive`] [#5809](https://github.com/rust-lang/rust-clippy/pull/5809) +* [`blanket_clippy_restriction_lints`] [#5750](https://github.com/rust-lang/rust-clippy/pull/5750) +* [`option_if_let_else`] [#5301](https://github.com/rust-lang/rust-clippy/pull/5301) + +### Moves and Deprecations + +* Deprecate [`regex_macro`] lint + [#5760](https://github.com/rust-lang/rust-clippy/pull/5760) +* Move [`range_minus_one`] to `pedantic` + [#5752](https://github.com/rust-lang/rust-clippy/pull/5752) + +### Enhancements + +* Improve [`needless_collect`] by catching `collect` calls followed by `iter` or `into_iter` calls + [#5837](https://github.com/rust-lang/rust-clippy/pull/5837) +* [`panic`], [`todo`], [`unimplemented`] and [`unreachable`] now detect calls with formatting + [#5811](https://github.com/rust-lang/rust-clippy/pull/5811) +* Detect more cases of [`suboptimal_flops`] and [`imprecise_flops`] + [#5443](https://github.com/rust-lang/rust-clippy/pull/5443) +* Handle asymmetrical implementations of `PartialEq` in [`cmp_owned`] + [#5701](https://github.com/rust-lang/rust-clippy/pull/5701) +* Make it possible to allow [`unsafe_derive_deserialize`] + [#5870](https://github.com/rust-lang/rust-clippy/pull/5870) +* Catch `ord.min(a).max(b)` where a < b in [`min_max`] + [#5871](https://github.com/rust-lang/rust-clippy/pull/5871) +* Make [`clone_on_copy`] suggestion machine applicable + [#5745](https://github.com/rust-lang/rust-clippy/pull/5745) +* Enable [`len_zero`] on ranges now that `is_empty` is stable on them + [#5961](https://github.com/rust-lang/rust-clippy/pull/5961) + +### False Positive Fixes + +* Avoid triggering [`or_fun_call`] with const fns that take no arguments + [#5889](https://github.com/rust-lang/rust-clippy/pull/5889) +* Fix [`redundant_closure_call`] false positive for closures that have multiple calls + [#5800](https://github.com/rust-lang/rust-clippy/pull/5800) +* Don't lint cases involving `ManuallyDrop` in [`redundant_clone`] + [#5824](https://github.com/rust-lang/rust-clippy/pull/5824) +* Treat a single expression the same as a single statement in the 2nd arm of a match in [`single_match_else`] + [#5771](https://github.com/rust-lang/rust-clippy/pull/5771) +* Don't trigger [`unnested_or_patterns`] if the feature `or_patterns` is not enabled + [#5758](https://github.com/rust-lang/rust-clippy/pull/5758) +* Avoid linting if key borrows in [`unnecessary_sort_by`] + [#5756](https://github.com/rust-lang/rust-clippy/pull/5756) +* Consider `Try` impl for `Poll` when generating suggestions in [`try_err`] + [#5857](https://github.com/rust-lang/rust-clippy/pull/5857) +* Take input lifetimes into account in `manual_async_fn` + [#5859](https://github.com/rust-lang/rust-clippy/pull/5859) +* Fix multiple false positives in [`type_repetition_in_bounds`] and add a configuration option + [#5761](https://github.com/rust-lang/rust-clippy/pull/5761) +* Limit the [`suspicious_arithmetic_impl`] lint to one binary operation + [#5820](https://github.com/rust-lang/rust-clippy/pull/5820) + +### Suggestion Fixes/Improvements + +* Improve readability of [`shadow_unrelated`] suggestion by truncating the RHS snippet + [#5788](https://github.com/rust-lang/rust-clippy/pull/5788) +* Suggest `filter_map` instead of `flat_map` when mapping to `Option` in [`map_flatten`] + [#5846](https://github.com/rust-lang/rust-clippy/pull/5846) +* Ensure suggestion is shown correctly for long method call chains in [`iter_nth_zero`] + [#5793](https://github.com/rust-lang/rust-clippy/pull/5793) +* Drop borrow operator in suggestions of [`redundant_pattern_matching`] + [#5815](https://github.com/rust-lang/rust-clippy/pull/5815) +* Add suggestion for [`iter_skip_next`] + [#5843](https://github.com/rust-lang/rust-clippy/pull/5843) +* Improve [`collapsible_if`] fix suggestion + [#5732](https://github.com/rust-lang/rust-clippy/pull/5732) + +### ICE Fixes + +* Fix ICE caused by [`needless_collect`] + [#5877](https://github.com/rust-lang/rust-clippy/pull/5877) +* Fix ICE caused by [`unnested_or_patterns`] + [#5784](https://github.com/rust-lang/rust-clippy/pull/5784) + +### Documentation Improvements + +* Fix grammar of [`await_holding_lock`] documentation + [#5748](https://github.com/rust-lang/rust-clippy/pull/5748) + +### Others + +* Make lints adhere to the rustc dev guide + [#5888](https://github.com/rust-lang/rust-clippy/pull/5888) ## Rust 1.46 -Current beta, release 2020-08-27 +Current stable, released 2020-08-27 [7ea7cd1...c2c07fa](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...c2c07fa) @@ -72,7 +174,7 @@ Current beta, release 2020-08-27 ## Rust 1.45 -Current stable, released 2020-07-16 +Released 2020-07-16 [891e1a8...7ea7cd1](https://github.com/rust-lang/rust-clippy/compare/891e1a8...7ea7cd1) @@ -1410,6 +1512,7 @@ Released 2018-09-13 [`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants [`assign_op_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_op_pattern [`assign_ops`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_ops +[`async_yields_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#async_yields_async [`await_holding_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_lock [`bad_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#bad_bit_mask [`bind_instead_of_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#bind_instead_of_map @@ -1444,6 +1547,7 @@ Released 2018-09-13 [`collapsible_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if [`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain [`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator +[`create_dir`]: https://rust-lang.github.io/rust-clippy/master/index.html#create_dir [`crosspointer_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#crosspointer_transmute [`dbg_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro [`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call diff --git a/clippy_lints/src/async_yields_async.rs b/clippy_lints/src/async_yields_async.rs new file mode 100644 index 0000000000000..88d9d3b5a263d --- /dev/null +++ b/clippy_lints/src/async_yields_async.rs @@ -0,0 +1,86 @@ +use crate::utils::{implements_trait, snippet, span_lint_and_then}; +use rustc_errors::Applicability; +use rustc_hir::{AsyncGeneratorKind, Body, BodyId, ExprKind, GeneratorKind, QPath}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** Checks for async blocks that yield values of types + /// that can themselves be awaited. + /// + /// **Why is this bad?** An await is likely missing. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// async fn foo() {} + /// + /// fn bar() { + /// let x = async { + /// foo() + /// }; + /// } + /// ``` + /// Use instead: + /// ```rust + /// async fn foo() {} + /// + /// fn bar() { + /// let x = async { + /// foo().await + /// }; + /// } + /// ``` + pub ASYNC_YIELDS_ASYNC, + correctness, + "async blocks that return a type that can be awaited" +} + +declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]); + +impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync { + fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) { + use AsyncGeneratorKind::{Block, Closure}; + // For functions, with explicitly defined types, don't warn. + // XXXkhuey maybe we should? + if let Some(GeneratorKind::Async(Block | Closure)) = body.generator_kind { + if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() { + let body_id = BodyId { + hir_id: body.value.hir_id, + }; + let def_id = cx.tcx.hir().body_owner_def_id(body_id); + let typeck_results = cx.tcx.typeck(def_id); + let expr_ty = typeck_results.expr_ty(&body.value); + + if implements_trait(cx, expr_ty, future_trait_def_id, &[]) { + let return_expr_span = match &body.value.kind { + // XXXkhuey there has to be a better way. + ExprKind::Block(block, _) => block.expr.map(|e| e.span), + ExprKind::Path(QPath::Resolved(_, path)) => Some(path.span), + _ => None, + }; + if let Some(return_expr_span) = return_expr_span { + span_lint_and_then( + cx, + ASYNC_YIELDS_ASYNC, + return_expr_span, + "an async construct yields a type which is itself awaitable", + |db| { + db.span_label(body.value.span, "outer async construct"); + db.span_label(return_expr_span, "awaitable value not awaited"); + db.span_suggestion( + return_expr_span, + "consider awaiting this value", + format!("{}.await", snippet(cx, return_expr_span, "..")), + Applicability::MaybeIncorrect, + ); + }, + ); + } + } + } + } + } +} diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index cfcc1b3c5f356..c8f153e7201cb 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -71,8 +71,9 @@ declare_clippy_lint! { /// **What it does:** Checks for `extern crate` and `use` items annotated with /// lint attributes. /// - /// This lint permits `#[allow(unused_imports)]`, `#[allow(deprecated)]` and - /// `#[allow(unreachable_pub)]` on `use` items and `#[allow(unused_imports)]` on + /// This lint permits `#[allow(unused_imports)]`, `#[allow(deprecated)]`, + /// `#[allow(unreachable_pub)]`, `#[allow(clippy::wildcard_imports)]` and + /// `#[allow(clippy::enum_glob_use)]` on `use` items and `#[allow(unused_imports)]` on /// `extern crate` items with a `#[macro_use]` attribute. /// /// **Why is this bad?** Lint attributes have no effect on crate imports. Most @@ -318,7 +319,8 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { if let Some(ident) = attr.ident() { match &*ident.as_str() { "allow" | "warn" | "deny" | "forbid" => { - // permit `unused_imports`, `deprecated` and `unreachable_pub` for `use` items + // permit `unused_imports`, `deprecated`, `unreachable_pub`, + // `clippy::wildcard_imports`, and `clippy::enum_glob_use` for `use` items // and `unused_imports` for `extern crate` items with `macro_use` for lint in lint_list { match item.kind { @@ -327,6 +329,9 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { || is_word(lint, sym!(deprecated)) || is_word(lint, sym!(unreachable_pub)) || is_word(lint, sym!(unused)) + || extract_clippy_lint(lint) + .map_or(false, |s| s == "wildcard_imports") + || extract_clippy_lint(lint).map_or(false, |s| s == "enum_glob_use") { return; } @@ -387,24 +392,25 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { } } -fn check_clippy_lint_names(cx: &LateContext<'_>, ident: &str, items: &[NestedMetaItem]) { - fn extract_name(lint: &NestedMetaItem) -> Option { - if_chain! { - if let Some(meta_item) = lint.meta_item(); - if meta_item.path.segments.len() > 1; - if let tool_name = meta_item.path.segments[0].ident; - if tool_name.as_str() == "clippy"; - let lint_name = meta_item.path.segments.last().unwrap().ident.name; - then { - return Some(lint_name.as_str()); - } +/// Returns the lint name if it is clippy lint. +fn extract_clippy_lint(lint: &NestedMetaItem) -> Option { + if_chain! { + if let Some(meta_item) = lint.meta_item(); + if meta_item.path.segments.len() > 1; + if let tool_name = meta_item.path.segments[0].ident; + if tool_name.as_str() == "clippy"; + let lint_name = meta_item.path.segments.last().unwrap().ident.name; + then { + return Some(lint_name.as_str()); } - None } + None +} +fn check_clippy_lint_names(cx: &LateContext<'_>, ident: &str, items: &[NestedMetaItem]) { let lint_store = cx.lints(); for lint in items { - if let Some(lint_name) = extract_name(lint) { + if let Some(lint_name) = extract_clippy_lint(lint) { if let CheckLintNameResult::Tool(Err((None, _))) = lint_store.check_lint_name(&lint_name, Some(sym!(clippy))) { diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs new file mode 100644 index 0000000000000..4002fb655a5eb --- /dev/null +++ b/clippy_lints/src/create_dir.rs @@ -0,0 +1,51 @@ +use crate::utils::{match_def_path, paths, snippet, span_lint_and_sugg}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** Checks usage of `std::fs::create_dir` and suggest using `std::fs::create_dir_all` instead. + /// + /// **Why is this bad?** Sometimes `std::fs::crate_dir` is mistakenly chosen over `std::fs::create_dir_all`. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// std::fs::create_dir("foo"); + /// ``` + /// Use instead: + /// ```rust + /// std::fs::create_dir_all("foo"); + /// ``` + pub CREATE_DIR, + restriction, + "calling `std::fs::create_dir` instead of `std::fs::create_dir_all`" +} + +declare_lint_pass!(CreateDir => [CREATE_DIR]); + +impl LateLintPass<'_> for CreateDir { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + if_chain! { + if let ExprKind::Call(ref func, ref args) = expr.kind; + if let ExprKind::Path(ref path) = func.kind; + if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id(); + if match_def_path(cx, def_id, &paths::STD_FS_CREATE_DIR); + then { + span_lint_and_sugg( + cx, + CREATE_DIR, + expr.span, + "calling `std::fs::create_dir` where there may be a better way", + "consider calling `std::fs::create_dir_all` instead", + format!("create_dir_all({})", snippet(cx, args[0].span, "..")), + Applicability::MaybeIncorrect, + ) + } + } + } +} diff --git a/clippy_lints/src/default_trait_access.rs b/clippy_lints/src/default_trait_access.rs index 1654df56a9a5b..3048436d9a7b5 100644 --- a/clippy_lints/src/default_trait_access.rs +++ b/clippy_lints/src/default_trait_access.rs @@ -38,37 +38,23 @@ impl<'tcx> LateLintPass<'tcx> for DefaultTraitAccess { if let ExprKind::Path(ref qpath) = path.kind; if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD); + // Detect and ignore ::default() because these calls do explicitly name the type. + if let QPath::Resolved(None, _path) = qpath; then { - match qpath { - QPath::Resolved(..) => { - if_chain! { - // Detect and ignore ::default() because these calls do - // explicitly name the type. - if let ExprKind::Call(ref method, ref _args) = expr.kind; - if let ExprKind::Path(ref p) = method.kind; - if let QPath::Resolved(Some(_ty), _path) = p; - then { - return; - } - } - - // TODO: Work out a way to put "whatever the imported way of referencing - // this type in this file" rather than a fully-qualified type. - let expr_ty = cx.typeck_results().expr_ty(expr); - if let ty::Adt(..) = expr_ty.kind() { - let replacement = format!("{}::default()", expr_ty); - span_lint_and_sugg( - cx, - DEFAULT_TRAIT_ACCESS, - expr.span, - &format!("calling `{}` is more clear than this expression", replacement), - "try", - replacement, - Applicability::Unspecified, // First resolve the TODO above - ); - } - }, - QPath::TypeRelative(..) | QPath::LangItem(..) => {}, + let expr_ty = cx.typeck_results().expr_ty(expr); + if let ty::Adt(def, ..) = expr_ty.kind() { + // TODO: Work out a way to put "whatever the imported way of referencing + // this type in this file" rather than a fully-qualified type. + let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did)); + span_lint_and_sugg( + cx, + DEFAULT_TRAIT_ACCESS, + expr.span, + &format!("calling `{}` is more clear than this expression", replacement), + "try", + replacement, + Applicability::Unspecified, // First resolve the TODO above + ); } } } diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 89fde1d509d30..50b39cf4ea7c0 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -374,7 +374,12 @@ impl<'tcx> Functions { } if line_count > self.max_lines { - span_lint(cx, TOO_MANY_LINES, span, "this function has a large number of lines") + span_lint( + cx, + TOO_MANY_LINES, + span, + &format!("this function has too many lines ({}/{})", line_count, self.max_lines), + ) } } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 577ce6523b491..2020ef78509b0 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -154,6 +154,7 @@ mod arithmetic; mod as_conversions; mod assertions_on_constants; mod assign_ops; +mod async_yields_async; mod atomic_ordering; mod attrs; mod await_holding_lock; @@ -169,6 +170,7 @@ mod collapsible_if; mod comparison_chain; mod copies; mod copy_iterator; +mod create_dir; mod dbg_macro; mod default_trait_access; mod dereference; @@ -483,6 +485,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &assertions_on_constants::ASSERTIONS_ON_CONSTANTS, &assign_ops::ASSIGN_OP_PATTERN, &assign_ops::MISREFACTORED_ASSIGN_OP, + &async_yields_async::ASYNC_YIELDS_ASYNC, &atomic_ordering::INVALID_ATOMIC_ORDERING, &attrs::BLANKET_CLIPPY_RESTRICTION_LINTS, &attrs::DEPRECATED_CFG_ATTR, @@ -511,6 +514,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &copies::MATCH_SAME_ARMS, &copies::SAME_FUNCTIONS_IN_IF_CONDITION, ©_iterator::COPY_ITERATOR, + &create_dir::CREATE_DIR, &dbg_macro::DBG_MACRO, &default_trait_access::DEFAULT_TRAIT_ACCESS, &dereference::EXPLICIT_DEREF_METHODS, @@ -1042,6 +1046,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| box items_after_statements::ItemsAfterStatements); store.register_early_pass(|| box precedence::Precedence); store.register_early_pass(|| box needless_continue::NeedlessContinue); + store.register_late_pass(|| box create_dir::CreateDir); store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType); store.register_early_pass(|| box redundant_static_lifetimes::RedundantStaticLifetimes); store.register_late_pass(|| box cargo_common_metadata::CargoCommonMetadata); @@ -1099,11 +1104,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box unwrap_in_result::UnwrapInResult); store.register_late_pass(|| box self_assignment::SelfAssignment); store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs); + store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), LintId::of(&arithmetic::INTEGER_ARITHMETIC), LintId::of(&as_conversions::AS_CONVERSIONS), + LintId::of(&create_dir::CREATE_DIR), LintId::of(&dbg_macro::DBG_MACRO), LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE), LintId::of(&exit::EXIT), @@ -1232,6 +1239,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&assertions_on_constants::ASSERTIONS_ON_CONSTANTS), LintId::of(&assign_ops::ASSIGN_OP_PATTERN), LintId::of(&assign_ops::MISREFACTORED_ASSIGN_OP), + LintId::of(&async_yields_async::ASYNC_YIELDS_ASYNC), LintId::of(&atomic_ordering::INVALID_ATOMIC_ORDERING), LintId::of(&attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), LintId::of(&attrs::DEPRECATED_CFG_ATTR), @@ -1675,6 +1683,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_group(true, "clippy::correctness", Some("clippy_correctness"), vec![ LintId::of(&approx_const::APPROX_CONSTANT), + LintId::of(&async_yields_async::ASYNC_YIELDS_ASYNC), LintId::of(&atomic_ordering::INVALID_ATOMIC_ORDERING), LintId::of(&attrs::DEPRECATED_SEMVER), LintId::of(&attrs::MISMATCHED_TARGET_OS), diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 604a97e3c0835..6c54c07869ad1 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1131,6 +1131,27 @@ fn detect_same_item_push<'tcx>( body: &'tcx Expr<'_>, _: &'tcx Expr<'_>, ) { + fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>) { + let vec_str = snippet_with_macro_callsite(cx, vec.span, ""); + let item_str = snippet_with_macro_callsite(cx, pushed_item.span, ""); + + span_lint_and_help( + cx, + SAME_ITEM_PUSH, + vec.span, + "it looks like the same item is being pushed into this Vec", + None, + &format!( + "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", + item_str, vec_str, item_str + ), + ) + } + + if !matches!(pat.kind, PatKind::Wild) { + return; + } + // Determine whether it is safe to lint the body let mut same_item_push_visitor = SameItemPushVisitor { should_lint: true, @@ -1140,43 +1161,50 @@ fn detect_same_item_push<'tcx>( walk_expr(&mut same_item_push_visitor, body); if same_item_push_visitor.should_lint { if let Some((vec, pushed_item)) = same_item_push_visitor.vec_push { - // Make sure that the push does not involve possibly mutating values - if let PatKind::Wild = pat.kind { - let vec_str = snippet_with_macro_callsite(cx, vec.span, ""); - let item_str = snippet_with_macro_callsite(cx, pushed_item.span, ""); - if let ExprKind::Path(ref qpath) = pushed_item.kind { - if_chain! { - if let Res::Local(hir_id) = qpath_res(cx, qpath, pushed_item.hir_id); - let node = cx.tcx.hir().get(hir_id); - if let Node::Binding(pat) = node; - if let PatKind::Binding(bind_ann, ..) = pat.kind; - if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable); - then { - span_lint_and_help( - cx, - SAME_ITEM_PUSH, - vec.span, - "it looks like the same item is being pushed into this Vec", - None, - &format!( - "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", - item_str, vec_str, item_str - ), - ) + let vec_ty = cx.typeck_results().expr_ty(vec); + let ty = vec_ty.walk().nth(1).unwrap().expect_ty(); + if cx + .tcx + .lang_items() + .clone_trait() + .map_or(false, |id| implements_trait(cx, ty, id, &[])) + { + // Make sure that the push does not involve possibly mutating values + match pushed_item.kind { + ExprKind::Path(ref qpath) => { + match qpath_res(cx, qpath, pushed_item.hir_id) { + // immutable bindings that are initialized with literal or constant + Res::Local(hir_id) => { + if_chain! { + let node = cx.tcx.hir().get(hir_id); + if let Node::Binding(pat) = node; + if let PatKind::Binding(bind_ann, ..) = pat.kind; + if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable); + let parent_node = cx.tcx.hir().get_parent_node(hir_id); + if let Some(Node::Local(parent_let_expr)) = cx.tcx.hir().find(parent_node); + if let Some(init) = parent_let_expr.init; + then { + match init.kind { + // immutable bindings that are initialized with literal + ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item), + // immutable bindings that are initialized with constant + ExprKind::Path(ref path) => { + if let Res::Def(DefKind::Const, ..) = qpath_res(cx, path, init.hir_id) { + emit_lint(cx, vec, pushed_item); + } + } + _ => {}, + } + } + } + }, + // constant + Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item), + _ => {}, } - } - } else if mutated_variables(pushed_item, cx).map_or(false, |mutvars| mutvars.is_empty()) { - span_lint_and_help( - cx, - SAME_ITEM_PUSH, - vec.span, - "it looks like the same item is being pushed into this Vec", - None, - &format!( - "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", - item_str, vec_str, item_str - ), - ) + }, + ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item), + _ => {}, } } } diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 1f9ae8c931a1e..076ef235b8bd8 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -9,7 +9,7 @@ use rustc_span::source_map::Span; declare_clippy_lint! { /// **What it does:** Checks for usage of `option.map(f)` where f is a function - /// or closure that returns the unit type. + /// or closure that returns the unit type `()`. /// /// **Why is this bad?** Readability, this can be written more clearly with /// an if let statement @@ -51,7 +51,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** Checks for usage of `result.map(f)` where f is a function - /// or closure that returns the unit type. + /// or closure that returns the unit type `()`. /// /// **Why is this bad?** Readability, this can be written more clearly with /// an if let statement @@ -197,7 +197,7 @@ fn let_binding_name(cx: &LateContext<'_>, var_arg: &hir::Expr<'_>) -> String { #[must_use] fn suggestion_msg(function_type: &str, map_type: &str) -> String { format!( - "called `map(f)` on an `{0}` value where `f` is a {1} that returns the unit type", + "called `map(f)` on an `{0}` value where `f` is a {1} that returns the unit type `()`", map_type, function_type ) } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a7a3d67515678..ba69c8266b118 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1324,20 +1324,20 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Warns when using push_str with a single-character string literal, - /// and push with a char would work fine. + /// **What it does:** Warns when using `push_str` with a single-character string literal, + /// and `push` with a `char` would work fine. /// - /// **Why is this bad?** It's less clear that we are pushing a single character + /// **Why is this bad?** It's less clear that we are pushing a single character. /// /// **Known problems:** None /// /// **Example:** - /// ``` + /// ```rust /// let mut string = String::new(); /// string.push_str("R"); /// ``` /// Could be written as - /// ``` + /// ```rust /// let mut string = String::new(); /// string.push('R'); /// ``` diff --git a/clippy_lints/src/temporary_assignment.rs b/clippy_lints/src/temporary_assignment.rs index 2b6ddadd4c112..fb891866364cc 100644 --- a/clippy_lints/src/temporary_assignment.rs +++ b/clippy_lints/src/temporary_assignment.rs @@ -21,11 +21,8 @@ declare_clippy_lint! { "assignments to temporaries" } -fn is_temporary(_cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - match &expr.kind { - ExprKind::Struct(..) | ExprKind::Tup(..) => true, - _ => false, - } +fn is_temporary(expr: &Expr<'_>) -> bool { + matches!(&expr.kind, ExprKind::Struct(..) | ExprKind::Tup(..)) } declare_lint_pass!(TemporaryAssignment => [TEMPORARY_ASSIGNMENT]); @@ -37,7 +34,7 @@ impl<'tcx> LateLintPass<'tcx> for TemporaryAssignment { while let ExprKind::Field(f, _) | ExprKind::Index(f, _) = &base.kind { base = f; } - if is_temporary(cx, base) && !is_adjusted(cx, base) { + if is_temporary(base) && !is_adjusted(cx, base) { span_lint(cx, TEMPORARY_ASSIGNMENT, expr.span, "assignment to temporary"); } } diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index 87c5408c78588..c75adb62f2575 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -331,8 +331,9 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::TRANSMUTE); then { - // Avoid suggesting from/to bits in const contexts. + // Avoid suggesting from/to bits and dereferencing raw pointers in const contexts. // See https://github.com/rust-lang/rust/issues/73736 for progress on making them `const fn`. + // And see https://github.com/rust-lang/rust/issues/51911 for dereferencing raw pointers. let const_context = in_constant(cx, e.hir_id); let from_ty = cx.typeck_results().expr_ty(&args[0]); @@ -486,7 +487,8 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { Applicability::Unspecified, ); } else { - if cx.tcx.erase_regions(&from_ty) != cx.tcx.erase_regions(&to_ty) { + if (cx.tcx.erase_regions(&from_ty) != cx.tcx.erase_regions(&to_ty)) + && !const_context { span_lint_and_then( cx, TRANSMUTE_PTR_TO_PTR, diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index c82deaa43b266..6c6188d61ad52 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -11,8 +11,8 @@ use rustc_hir as hir; use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor}; use rustc_hir::{ BinOpKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericParamKind, HirId, ImplItem, - ImplItemKind, Item, ItemKind, Lifetime, Local, MatchSource, MutTy, Mutability, QPath, Stmt, StmtKind, TraitFn, - TraitItem, TraitItemKind, TyKind, UnOp, + ImplItemKind, Item, ItemKind, Lifetime, Local, MatchSource, MutTy, Mutability, Node, QPath, Stmt, StmtKind, + TraitFn, TraitItem, TraitItemKind, TyKind, UnOp, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; @@ -31,12 +31,13 @@ use crate::utils::paths; use crate::utils::{ clip, comparisons, differing_macro_contexts, higher, in_constant, indent_of, int_bits, is_type_diagnostic_item, last_path_segment, match_def_path, match_path, method_chain_args, multispan_sugg, numeric_literal::NumericLiteral, - qpath_res, sext, snippet, snippet_block_with_applicability, snippet_opt, snippet_with_applicability, - snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, unsext, + qpath_res, reindent_multiline, sext, snippet, snippet_opt, snippet_with_applicability, snippet_with_macro_callsite, + span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, unsext, }; declare_clippy_lint! { /// **What it does:** Checks for use of `Box>` anywhere in the code. + /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. /// /// **Why is this bad?** `Vec` already keeps its contents in a separate area on /// the heap. So if you `Box` it, you just add another level of indirection @@ -65,6 +66,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** Checks for use of `Vec>` where T: Sized anywhere in the code. + /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. /// /// **Why is this bad?** `Vec` already keeps its contents in a separate area on /// the heap. So if you `Box` its contents, you just add another level of indirection. @@ -167,6 +169,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** Checks for use of `&Box` anywhere in the code. + /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. /// /// **Why is this bad?** Any `&Box` can also be a `&T`, which is more /// general. @@ -802,6 +805,45 @@ impl<'tcx> LateLintPass<'tcx> for UnitArg { } } +fn fmt_stmts_and_call( + cx: &LateContext<'_>, + call_expr: &Expr<'_>, + call_snippet: &str, + args_snippets: &[impl AsRef], + non_empty_block_args_snippets: &[impl AsRef], +) -> String { + let call_expr_indent = indent_of(cx, call_expr.span).unwrap_or(0); + let call_snippet_with_replacements = args_snippets + .iter() + .fold(call_snippet.to_owned(), |acc, arg| acc.replacen(arg.as_ref(), "()", 1)); + + let mut stmts_and_call = non_empty_block_args_snippets + .iter() + .map(|it| it.as_ref().to_owned()) + .collect::>(); + stmts_and_call.push(call_snippet_with_replacements); + stmts_and_call = stmts_and_call + .into_iter() + .map(|v| reindent_multiline(v.into(), true, Some(call_expr_indent)).into_owned()) + .collect(); + + let mut stmts_and_call_snippet = stmts_and_call.join(&format!("{}{}", ";\n", " ".repeat(call_expr_indent))); + // expr is not in a block statement or result expression position, wrap in a block + let parent_node = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(call_expr.hir_id)); + if !matches!(parent_node, Some(Node::Block(_))) && !matches!(parent_node, Some(Node::Stmt(_))) { + let block_indent = call_expr_indent + 4; + stmts_and_call_snippet = + reindent_multiline(stmts_and_call_snippet.into(), true, Some(block_indent)).into_owned(); + stmts_and_call_snippet = format!( + "{{\n{}{}\n{}}}", + " ".repeat(block_indent), + &stmts_and_call_snippet, + " ".repeat(call_expr_indent) + ); + } + stmts_and_call_snippet +} + fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Expr<'_>]) { let mut applicability = Applicability::MachineApplicable; let (singular, plural) = if args_to_recover.len() > 1 { @@ -844,43 +886,52 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp Applicability::MaybeIncorrect, ); or = "or "; + applicability = Applicability::MaybeIncorrect; }); - let sugg = args_to_recover + + let arg_snippets: Vec = args_to_recover + .iter() + .filter_map(|arg| snippet_opt(cx, arg.span)) + .collect(); + let arg_snippets_without_empty_blocks: Vec = args_to_recover .iter() .filter(|arg| !is_empty_block(arg)) - .enumerate() - .map(|(i, arg)| { - let indent = if i == 0 { - 0 - } else { - indent_of(cx, expr.span).unwrap_or(0) - }; - format!( - "{}{};", - " ".repeat(indent), - snippet_block_with_applicability(cx, arg.span, "..", Some(expr.span), &mut applicability) - ) - }) - .collect::>(); - let mut and = ""; - if !sugg.is_empty() { - let plural = if sugg.len() > 1 { "s" } else { "" }; - db.span_suggestion( - expr.span.with_hi(expr.span.lo()), - &format!("{}move the expression{} in front of the call...", or, plural), - format!("{}\n", sugg.join("\n")), - applicability, + .filter_map(|arg| snippet_opt(cx, arg.span)) + .collect(); + + if let Some(call_snippet) = snippet_opt(cx, expr.span) { + let sugg = fmt_stmts_and_call( + cx, + expr, + &call_snippet, + &arg_snippets, + &arg_snippets_without_empty_blocks, ); - and = "...and " + + if arg_snippets_without_empty_blocks.is_empty() { + db.multipart_suggestion( + &format!("use {}unit literal{} instead", singular, plural), + args_to_recover + .iter() + .map(|arg| (arg.span, "()".to_string())) + .collect::>(), + applicability, + ); + } else { + let plural = arg_snippets_without_empty_blocks.len() > 1; + let empty_or_s = if plural { "s" } else { "" }; + let it_or_them = if plural { "them" } else { "it" }; + db.span_suggestion( + expr.span, + &format!( + "{}move the expression{} in front of the call and replace {} with the unit literal `()`", + or, empty_or_s, it_or_them + ), + sugg, + applicability, + ); + } } - db.multipart_suggestion( - &format!("{}use {}unit literal{} instead", and, singular, plural), - args_to_recover - .iter() - .map(|arg| (arg.span, "()".to_string())) - .collect::>(), - applicability, - ); }, ); } @@ -2055,6 +2106,7 @@ impl PartialOrd for FullInt { }) } } + impl Ord for FullInt { #[must_use] fn cmp(&self, other: &Self) -> Ordering { diff --git a/clippy_lints/src/unnecessary_sort_by.rs b/clippy_lints/src/unnecessary_sort_by.rs index 8b00d29acb52c..9b6a9075a2954 100644 --- a/clippy_lints/src/unnecessary_sort_by.rs +++ b/clippy_lints/src/unnecessary_sort_by.rs @@ -1,5 +1,4 @@ use crate::utils; -use crate::utils::paths; use crate::utils::sugg::Sugg; use if_chain::if_chain; use rustc_errors::Applicability; @@ -171,12 +170,22 @@ fn mirrored_exprs( } fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { + // NOTE: Vectors of references are not supported. In order to avoid hitting https://github.com/rust-lang/rust/issues/34162, + // (different unnamed lifetimes for closure arg and return type) we need to make sure the suggested + // closure parameter is not a reference in case we suggest `Reverse`. Trying to destructure more + // than one level of references would add some extra complexity as we would have to compensate + // in the closure body. + if_chain! { if let ExprKind::MethodCall(name_ident, _, args, _) = &expr.kind; if let name = name_ident.ident.name.to_ident_string(); if name == "sort_by" || name == "sort_unstable_by"; if let [vec, Expr { kind: ExprKind::Closure(_, _, closure_body_id, _, _), .. }] = args; - if utils::match_type(cx, &cx.typeck_results().expr_ty(vec), &paths::VEC); + let vec_ty = cx.typeck_results().expr_ty(vec); + if utils::is_type_diagnostic_item(cx, vec_ty, sym!(vec_type)); + let ty = vec_ty.walk().nth(1).unwrap().expect_ty(); // T in Vec + if !matches!(&ty.kind(), ty::Ref(..)); + if utils::is_copy(cx, ty); if let closure_body = cx.tcx.hir().body(*closure_body_id); if let &[ Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..}, diff --git a/clippy_lints/src/utils/ast_utils.rs b/clippy_lints/src/utils/ast_utils.rs index 3c3f8b26e3ac1..fa8dd210ebadd 100644 --- a/clippy_lints/src/utils/ast_utils.rs +++ b/clippy_lints/src/utils/ast_utils.rs @@ -191,7 +191,9 @@ pub fn eq_stmt(l: &Stmt, r: &Stmt) -> bool { (Item(l), Item(r)) => eq_item(l, r, eq_item_kind), (Expr(l), Expr(r)) | (Semi(l), Semi(r)) => eq_expr(l, r), (Empty, Empty) => true, - (MacCall(l), MacCall(r)) => l.style == r.style && eq_mac_call(&l.mac, &r.mac) && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)), + (MacCall(l), MacCall(r)) => { + l.style == r.style && eq_mac_call(&l.mac, &r.mac) && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) + }, _ => false, } } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 292dbd7ad6b48..9c5a12ea9c8e1 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -122,7 +122,7 @@ define_Conf! { "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "NaN", "NaNs", - "OAuth", + "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "TensorFlow", diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 45add9ab284d2..3ebbfed645627 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -19,6 +19,7 @@ pub mod paths; pub mod ptr; pub mod sugg; pub mod usage; + pub use self::attrs::*; pub use self::diagnostics::*; pub use self::hir_utils::{both, eq_expr_value, over, SpanlessEq, SpanlessHash}; @@ -108,6 +109,7 @@ pub fn in_macro(span: Span) -> bool { false } } + // If the snippet is empty, it's an attribute that was inserted during macro // expansion and we want to ignore those, because they could come from external // sources that the user has no control over. @@ -571,7 +573,7 @@ pub fn snippet_block<'a, T: LintContext>( ) -> Cow<'a, str> { let snip = snippet(cx, span, default); let indent = indent_relative_to.and_then(|s| indent_of(cx, s)); - trim_multiline(snip, true, indent) + reindent_multiline(snip, true, indent) } /// Same as `snippet_block`, but adapts the applicability level by the rules of @@ -585,7 +587,7 @@ pub fn snippet_block_with_applicability<'a, T: LintContext>( ) -> Cow<'a, str> { let snip = snippet_with_applicability(cx, span, default, applicability); let indent = indent_relative_to.and_then(|s| indent_of(cx, s)); - trim_multiline(snip, true, indent) + reindent_multiline(snip, true, indent) } /// Returns a new Span that extends the original Span to the first non-whitespace char of the first @@ -661,16 +663,16 @@ pub fn expr_block<'a, T: LintContext>( } } -/// Trim indentation from a multiline string with possibility of ignoring the -/// first line. -fn trim_multiline(s: Cow<'_, str>, ignore_first: bool, indent: Option) -> Cow<'_, str> { - let s_space = trim_multiline_inner(s, ignore_first, indent, ' '); - let s_tab = trim_multiline_inner(s_space, ignore_first, indent, '\t'); - trim_multiline_inner(s_tab, ignore_first, indent, ' ') +/// Reindent a multiline string with possibility of ignoring the first line. +#[allow(clippy::needless_pass_by_value)] +pub fn reindent_multiline(s: Cow<'_, str>, ignore_first: bool, indent: Option) -> Cow<'_, str> { + let s_space = reindent_multiline_inner(&s, ignore_first, indent, ' '); + let s_tab = reindent_multiline_inner(&s_space, ignore_first, indent, '\t'); + reindent_multiline_inner(&s_tab, ignore_first, indent, ' ').into() } -fn trim_multiline_inner(s: Cow<'_, str>, ignore_first: bool, indent: Option, ch: char) -> Cow<'_, str> { - let mut x = s +fn reindent_multiline_inner(s: &str, ignore_first: bool, indent: Option, ch: char) -> String { + let x = s .lines() .skip(ignore_first as usize) .filter_map(|l| { @@ -683,26 +685,20 @@ fn trim_multiline_inner(s: Cow<'_, str>, ignore_first: bool, indent: Option 0 { - Cow::Owned( - s.lines() - .enumerate() - .map(|(i, l)| { - if (ignore_first && i == 0) || l.is_empty() { - l - } else { - l.split_at(x).1 - } - }) - .collect::>() - .join("\n"), - ) - } else { - s - } + let indent = indent.unwrap_or(0); + s.lines() + .enumerate() + .map(|(i, l)| { + if (ignore_first && i == 0) || l.is_empty() { + l.to_owned() + } else if x > indent { + l.split_at(x - indent).1.to_owned() + } else { + " ".repeat(indent - x) + l + } + }) + .collect::>() + .join("\n") } /// Gets the parent expression, if any –- this is useful to constrain a lint. @@ -899,7 +895,7 @@ pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_ return match res { def::Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true, // FIXME: check the constness of the arguments, see https://github.com/rust-lang/rust-clippy/pull/5682#issuecomment-638681210 - def::Res::Def(DefKind::Fn, def_id) if has_no_arguments(cx, def_id) => { + def::Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) if has_no_arguments(cx, def_id) => { const_eval::is_const_fn(cx.tcx, def_id) }, def::Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id), @@ -1432,7 +1428,7 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option false, }; @@ -1474,26 +1470,26 @@ macro_rules! unwrap_cargo_metadata { #[cfg(test)] mod test { - use super::{trim_multiline, without_block_comments}; + use super::{reindent_multiline, without_block_comments}; #[test] - fn test_trim_multiline_single_line() { - assert_eq!("", trim_multiline("".into(), false, None)); - assert_eq!("...", trim_multiline("...".into(), false, None)); - assert_eq!("...", trim_multiline(" ...".into(), false, None)); - assert_eq!("...", trim_multiline("\t...".into(), false, None)); - assert_eq!("...", trim_multiline("\t\t...".into(), false, None)); + fn test_reindent_multiline_single_line() { + assert_eq!("", reindent_multiline("".into(), false, None)); + assert_eq!("...", reindent_multiline("...".into(), false, None)); + assert_eq!("...", reindent_multiline(" ...".into(), false, None)); + assert_eq!("...", reindent_multiline("\t...".into(), false, None)); + assert_eq!("...", reindent_multiline("\t\t...".into(), false, None)); } #[test] #[rustfmt::skip] - fn test_trim_multiline_block() { + fn test_reindent_multiline_block() { assert_eq!("\ if x { y } else { z - }", trim_multiline(" if x { + }", reindent_multiline(" if x { y } else { z @@ -1503,7 +1499,7 @@ mod test { \ty } else { \tz - }", trim_multiline(" if x { + }", reindent_multiline(" if x { \ty } else { \tz @@ -1512,14 +1508,14 @@ mod test { #[test] #[rustfmt::skip] - fn test_trim_multiline_empty_line() { + fn test_reindent_multiline_empty_line() { assert_eq!("\ if x { y } else { z - }", trim_multiline(" if x { + }", reindent_multiline(" if x { y } else { @@ -1527,6 +1523,22 @@ mod test { }".into(), false, None)); } + #[test] + #[rustfmt::skip] + fn test_reindent_multiline_lines_deeper() { + assert_eq!("\ + if x { + y + } else { + z + }", reindent_multiline("\ + if x { + y + } else { + z + }".into(), true, Some(8))); + } + #[test] fn test_without_block_comments_lines_without_block_comments() { let result = without_block_comments(vec!["/*", "", "*/"]); diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index d44854aefe97a..65320d6a0e0bd 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -110,6 +110,7 @@ pub const SLICE_ITER: [&str; 3] = ["core", "slice", "Iter"]; pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"]; pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"]; pub const STD_CONVERT_IDENTITY: [&str; 3] = ["std", "convert", "identity"]; +pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"]; pub const STD_MEM_TRANSMUTE: [&str; 3] = ["std", "mem", "transmute"]; pub const STD_PTR_NULL: [&str; 3] = ["std", "ptr", "null"]; pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"]; diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 2955f8d8e5919..811fde388d15a 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -132,7 +132,11 @@ impl<'a> Sugg<'a> { pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self { use rustc_ast::ast::RangeLimits; - let snippet = snippet(cx, expr.span, default); + let snippet = if expr.span.from_expansion() { + snippet_with_macro_callsite(cx, expr.span, default) + } else { + snippet(cx, expr.span, default) + }; match expr.kind { ast::ExprKind::AddrOf(..) diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 687fac7baa848..6697835e950d9 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -52,6 +52,13 @@ pub static ref ALL_LINTS: Vec = vec![ 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: "pedantic", @@ -290,6 +297,13 @@ pub static ref ALL_LINTS: Vec = vec![ 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", diff --git a/tests/ui-toml/functions_maxlines/test.stderr b/tests/ui-toml/functions_maxlines/test.stderr index fb12257021a1e..a27ce945ca584 100644 --- a/tests/ui-toml/functions_maxlines/test.stderr +++ b/tests/ui-toml/functions_maxlines/test.stderr @@ -1,4 +1,4 @@ -error: this function has a large number of lines +error: this function has too many lines (2/1) --> $DIR/test.rs:18:1 | LL | / fn too_many_lines() { @@ -9,7 +9,7 @@ LL | | } | = note: `-D clippy::too-many-lines` implied by `-D warnings` -error: this function has a large number of lines +error: this function has too many lines (2/1) --> $DIR/test.rs:38:1 | LL | / fn comment_before_code() { diff --git a/tests/ui/async_yields_async.fixed b/tests/ui/async_yields_async.fixed new file mode 100644 index 0000000000000..9b1a7ac3ba9de --- /dev/null +++ b/tests/ui/async_yields_async.fixed @@ -0,0 +1,68 @@ +// run-rustfix +// edition:2018 + +#![feature(async_closure)] +#![warn(clippy::async_yields_async)] + +use core::future::Future; +use core::pin::Pin; +use core::task::{Context, Poll}; + +struct CustomFutureType; + +impl Future for CustomFutureType { + type Output = u8; + + fn poll(self: Pin<&mut Self>, _: &mut Context) -> Poll { + Poll::Ready(3) + } +} + +fn custom_future_type_ctor() -> CustomFutureType { + CustomFutureType +} + +async fn f() -> CustomFutureType { + // Don't warn for functions since you have to explicitly declare their + // return types. + CustomFutureType +} + +#[rustfmt::skip] +fn main() { + let _f = { + 3 + }; + let _g = async { + 3 + }; + let _h = async { + async { + 3 + }.await + }; + let _i = async { + CustomFutureType.await + }; + let _i = async || { + 3 + }; + let _j = async || { + async { + 3 + }.await + }; + let _k = async || { + CustomFutureType.await + }; + let _l = async || CustomFutureType.await; + let _m = async || { + println!("I'm bored"); + // Some more stuff + + // Finally something to await + CustomFutureType.await + }; + let _n = async || custom_future_type_ctor(); + let _o = async || f(); +} diff --git a/tests/ui/async_yields_async.rs b/tests/ui/async_yields_async.rs new file mode 100644 index 0000000000000..731c094edb42b --- /dev/null +++ b/tests/ui/async_yields_async.rs @@ -0,0 +1,68 @@ +// run-rustfix +// edition:2018 + +#![feature(async_closure)] +#![warn(clippy::async_yields_async)] + +use core::future::Future; +use core::pin::Pin; +use core::task::{Context, Poll}; + +struct CustomFutureType; + +impl Future for CustomFutureType { + type Output = u8; + + fn poll(self: Pin<&mut Self>, _: &mut Context) -> Poll { + Poll::Ready(3) + } +} + +fn custom_future_type_ctor() -> CustomFutureType { + CustomFutureType +} + +async fn f() -> CustomFutureType { + // Don't warn for functions since you have to explicitly declare their + // return types. + CustomFutureType +} + +#[rustfmt::skip] +fn main() { + let _f = { + 3 + }; + let _g = async { + 3 + }; + let _h = async { + async { + 3 + } + }; + let _i = async { + CustomFutureType + }; + let _i = async || { + 3 + }; + let _j = async || { + async { + 3 + } + }; + let _k = async || { + CustomFutureType + }; + let _l = async || CustomFutureType; + let _m = async || { + println!("I'm bored"); + // Some more stuff + + // Finally something to await + CustomFutureType + }; + let _n = async || custom_future_type_ctor(); + let _o = async || f(); +} diff --git a/tests/ui/async_yields_async.stderr b/tests/ui/async_yields_async.stderr new file mode 100644 index 0000000000000..17d0c3751064f --- /dev/null +++ b/tests/ui/async_yields_async.stderr @@ -0,0 +1,96 @@ +error: an async construct yields a type which is itself awaitable + --> $DIR/async_yields_async.rs:40:9 + | +LL | let _h = async { + | ____________________- +LL | | async { + | |_________^ +LL | || 3 +LL | || } + | ||_________^ awaitable value not awaited +LL | | }; + | |_____- outer async construct + | + = note: `-D clippy::async-yields-async` implied by `-D warnings` +help: consider awaiting this value + | +LL | async { +LL | 3 +LL | }.await + | + +error: an async construct yields a type which is itself awaitable + --> $DIR/async_yields_async.rs:45:9 + | +LL | let _i = async { + | ____________________- +LL | | CustomFutureType + | | ^^^^^^^^^^^^^^^^ + | | | + | | awaitable value not awaited + | | help: consider awaiting this value: `CustomFutureType.await` +LL | | }; + | |_____- outer async construct + +error: an async construct yields a type which is itself awaitable + --> $DIR/async_yields_async.rs:51:9 + | +LL | let _j = async || { + | _______________________- +LL | | async { + | |_________^ +LL | || 3 +LL | || } + | ||_________^ awaitable value not awaited +LL | | }; + | |_____- outer async construct + | +help: consider awaiting this value + | +LL | async { +LL | 3 +LL | }.await + | + +error: an async construct yields a type which is itself awaitable + --> $DIR/async_yields_async.rs:56:9 + | +LL | let _k = async || { + | _______________________- +LL | | CustomFutureType + | | ^^^^^^^^^^^^^^^^ + | | | + | | awaitable value not awaited + | | help: consider awaiting this value: `CustomFutureType.await` +LL | | }; + | |_____- outer async construct + +error: an async construct yields a type which is itself awaitable + --> $DIR/async_yields_async.rs:58:23 + | +LL | let _l = async || CustomFutureType; + | ^^^^^^^^^^^^^^^^ + | | + | outer async construct + | awaitable value not awaited + | help: consider awaiting this value: `CustomFutureType.await` + +error: an async construct yields a type which is itself awaitable + --> $DIR/async_yields_async.rs:64:9 + | +LL | let _m = async || { + | _______________________- +LL | | println!("I'm bored"); +LL | | // Some more stuff +LL | | +LL | | // Finally something to await +LL | | CustomFutureType + | | ^^^^^^^^^^^^^^^^ + | | | + | | awaitable value not awaited + | | help: consider awaiting this value: `CustomFutureType.await` +LL | | }; + | |_____- outer async construct + +error: aborting due to 6 previous errors + diff --git a/tests/ui/collapsible_if.fixed b/tests/ui/collapsible_if.fixed index 561283fc8e73d..efd4187947b20 100644 --- a/tests/ui/collapsible_if.fixed +++ b/tests/ui/collapsible_if.fixed @@ -135,4 +135,7 @@ fn main() { if truth() {} } } + + // Fix #5962 + if matches!(true, true) && matches!(true, true) {} } diff --git a/tests/ui/collapsible_if.rs b/tests/ui/collapsible_if.rs index dc9d9b451c0f9..657f32d38a32b 100644 --- a/tests/ui/collapsible_if.rs +++ b/tests/ui/collapsible_if.rs @@ -149,4 +149,9 @@ fn main() { if truth() {} } } + + // Fix #5962 + if matches!(true, true) { + if matches!(true, true) {} + } } diff --git a/tests/ui/collapsible_if.stderr b/tests/ui/collapsible_if.stderr index f56dd65b9dd26..acd1ec3f2caea 100644 --- a/tests/ui/collapsible_if.stderr +++ b/tests/ui/collapsible_if.stderr @@ -118,5 +118,13 @@ LL | println!("Hello world!"); LL | } | -error: aborting due to 7 previous errors +error: this `if` statement can be collapsed + --> $DIR/collapsible_if.rs:154:5 + | +LL | / if matches!(true, true) { +LL | | if matches!(true, true) {} +LL | | } + | |_____^ help: collapse nested if block: `if matches!(true, true) && matches!(true, true) {}` + +error: aborting due to 8 previous errors diff --git a/tests/ui/create_dir.fixed b/tests/ui/create_dir.fixed new file mode 100644 index 0000000000000..8ed53a56ac043 --- /dev/null +++ b/tests/ui/create_dir.fixed @@ -0,0 +1,17 @@ +// run-rustfix +#![allow(unused_must_use)] +#![warn(clippy::create_dir)] + +use std::fs::create_dir_all; + +fn create_dir() {} + +fn main() { + // Should be warned + create_dir_all("foo"); + create_dir_all("bar").unwrap(); + + // Shouldn't be warned + create_dir(); + std::fs::create_dir_all("foobar"); +} diff --git a/tests/ui/create_dir.rs b/tests/ui/create_dir.rs new file mode 100644 index 0000000000000..19c8fc24ba23f --- /dev/null +++ b/tests/ui/create_dir.rs @@ -0,0 +1,17 @@ +// run-rustfix +#![allow(unused_must_use)] +#![warn(clippy::create_dir)] + +use std::fs::create_dir_all; + +fn create_dir() {} + +fn main() { + // Should be warned + std::fs::create_dir("foo"); + std::fs::create_dir("bar").unwrap(); + + // Shouldn't be warned + create_dir(); + std::fs::create_dir_all("foobar"); +} diff --git a/tests/ui/create_dir.stderr b/tests/ui/create_dir.stderr new file mode 100644 index 0000000000000..67298fc47095c --- /dev/null +++ b/tests/ui/create_dir.stderr @@ -0,0 +1,16 @@ +error: calling `std::fs::create_dir` where there may be a better way + --> $DIR/create_dir.rs:11:5 + | +LL | std::fs::create_dir("foo"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `std::fs::create_dir_all` instead: `create_dir_all("foo")` + | + = note: `-D clippy::create-dir` implied by `-D warnings` + +error: calling `std::fs::create_dir` where there may be a better way + --> $DIR/create_dir.rs:12:5 + | +LL | std::fs::create_dir("bar").unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `std::fs::create_dir_all` instead: `create_dir_all("bar")` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/default_trait_access.fixed b/tests/ui/default_trait_access.fixed new file mode 100644 index 0000000000000..d05567a3f8249 --- /dev/null +++ b/tests/ui/default_trait_access.fixed @@ -0,0 +1,106 @@ +// run-rustfix + +#![allow(unused_imports)] +#![deny(clippy::default_trait_access)] + +use std::default; +use std::default::Default as D2; +use std::string; + +fn main() { + let s1: String = std::string::String::default(); + + let s2 = String::default(); + + let s3: String = std::string::String::default(); + + let s4: String = std::string::String::default(); + + let s5 = string::String::default(); + + let s6: String = std::string::String::default(); + + let s7 = std::string::String::default(); + + let s8: String = DefaultFactory::make_t_badly(); + + let s9: String = DefaultFactory::make_t_nicely(); + + let s10 = DerivedDefault::default(); + + let s11: GenericDerivedDefault = GenericDerivedDefault::default(); + + let s12 = GenericDerivedDefault::::default(); + + let s13 = TupleDerivedDefault::default(); + + let s14: TupleDerivedDefault = TupleDerivedDefault::default(); + + let s15: ArrayDerivedDefault = ArrayDerivedDefault::default(); + + let s16 = ArrayDerivedDefault::default(); + + let s17: TupleStructDerivedDefault = TupleStructDerivedDefault::default(); + + let s18 = TupleStructDerivedDefault::default(); + + let s19 = ::default(); + + println!( + "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}], [{:?}]", + s1, + s2, + s3, + s4, + s5, + s6, + s7, + s8, + s9, + s10, + s11, + s12, + s13, + s14, + s15, + s16, + s17, + s18, + s19, + ); +} + +struct DefaultFactory; + +impl DefaultFactory { + pub fn make_t_badly() -> T { + Default::default() + } + + pub fn make_t_nicely() -> T { + T::default() + } +} + +#[derive(Debug, Default)] +struct DerivedDefault { + pub s: String, +} + +#[derive(Debug, Default)] +struct GenericDerivedDefault { + pub s: T, +} + +#[derive(Debug, Default)] +struct TupleDerivedDefault { + pub s: (String, String), +} + +#[derive(Debug, Default)] +struct ArrayDerivedDefault { + pub s: [String; 10], +} + +#[derive(Debug, Default)] +struct TupleStructDerivedDefault(String); diff --git a/tests/ui/default_trait_access.rs b/tests/ui/default_trait_access.rs index 2f1490a70369e..447e70c0bbbea 100644 --- a/tests/ui/default_trait_access.rs +++ b/tests/ui/default_trait_access.rs @@ -1,4 +1,7 @@ -#![warn(clippy::default_trait_access)] +// run-rustfix + +#![allow(unused_imports)] +#![deny(clippy::default_trait_access)] use std::default; use std::default::Default as D2; diff --git a/tests/ui/default_trait_access.stderr b/tests/ui/default_trait_access.stderr index 26b2057548bd9..df8a5b94ddcf3 100644 --- a/tests/ui/default_trait_access.stderr +++ b/tests/ui/default_trait_access.stderr @@ -1,49 +1,53 @@ error: calling `std::string::String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:8:22 + --> $DIR/default_trait_access.rs:11:22 | LL | let s1: String = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` | - = note: `-D clippy::default-trait-access` implied by `-D warnings` +note: the lint level is defined here + --> $DIR/default_trait_access.rs:4:9 + | +LL | #![deny(clippy::default_trait_access)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: calling `std::string::String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:12:22 + --> $DIR/default_trait_access.rs:15:22 | LL | let s3: String = D2::default(); | ^^^^^^^^^^^^^ help: try: `std::string::String::default()` error: calling `std::string::String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:14:22 + --> $DIR/default_trait_access.rs:17:22 | LL | let s4: String = std::default::Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` error: calling `std::string::String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:18:22 + --> $DIR/default_trait_access.rs:21:22 | LL | let s6: String = default::Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` -error: calling `GenericDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:28:46 +error: calling `GenericDerivedDefault::default()` is more clear than this expression + --> $DIR/default_trait_access.rs:31:46 | LL | let s11: GenericDerivedDefault = Default::default(); - | ^^^^^^^^^^^^^^^^^^ help: try: `GenericDerivedDefault::default()` + | ^^^^^^^^^^^^^^^^^^ help: try: `GenericDerivedDefault::default()` error: calling `TupleDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:34:36 + --> $DIR/default_trait_access.rs:37:36 | LL | let s14: TupleDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `TupleDerivedDefault::default()` error: calling `ArrayDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:36:36 + --> $DIR/default_trait_access.rs:39:36 | LL | let s15: ArrayDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `ArrayDerivedDefault::default()` error: calling `TupleStructDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:40:42 + --> $DIR/default_trait_access.rs:43:42 | LL | let s17: TupleStructDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `TupleStructDerivedDefault::default()` diff --git a/tests/ui/doc.rs b/tests/ui/doc.rs index 77620c857e66e..68c5d32846f19 100644 --- a/tests/ui/doc.rs +++ b/tests/ui/doc.rs @@ -49,6 +49,16 @@ fn test_emphasis() { fn test_units() { } +/// This tests allowed identifiers. +/// DirectX +/// ECMAScript +/// OAuth GraphQL +/// TeX LaTeX BibTeX BibLaTeX +/// CamelCase (see also #2395) +/// be_sure_we_got_to_the_end_of_it +fn test_allowed() { +} + /// This test has [a link_with_underscores][chunked-example] inside it. See #823. /// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues) /// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link]. @@ -168,9 +178,6 @@ fn issue_1920() {} /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels fn issue_1832() {} -/// Ok: CamelCase (It should not be surrounded by backticks) -fn issue_2395() {} - /// An iterator over mycrate::Collection's values. /// It should not lint a `'static` lifetime in ticks. fn issue_2210() {} diff --git a/tests/ui/doc.stderr b/tests/ui/doc.stderr index ae9bb394cb9ac..23fca43590b4f 100644 --- a/tests/ui/doc.stderr +++ b/tests/ui/doc.stderr @@ -54,131 +54,137 @@ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the doc LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation + --> $DIR/doc.rs:58:5 + | +LL | /// be_sure_we_got_to_the_end_of_it + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: you should put `link_with_underscores` between ticks in the documentation - --> $DIR/doc.rs:52:22 + --> $DIR/doc.rs:62:22 | LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823. | ^^^^^^^^^^^^^^^^^^^^^ error: you should put `inline_link2` between ticks in the documentation - --> $DIR/doc.rs:55:21 + --> $DIR/doc.rs:65:21 | LL | /// It can also be [inline_link2]. | ^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:65:5 + --> $DIR/doc.rs:75:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:73:8 + --> $DIR/doc.rs:83:8 | LL | /// ## CamelCaseThing | ^^^^^^^^^^^^^^ error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:76:7 + --> $DIR/doc.rs:86:7 | LL | /// # CamelCaseThing | ^^^^^^^^^^^^^^ error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:78:22 + --> $DIR/doc.rs:88:22 | LL | /// Not a title #897 CamelCaseThing | ^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:79:5 + --> $DIR/doc.rs:89:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:86:5 + --> $DIR/doc.rs:96:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:99:5 + --> $DIR/doc.rs:109:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `FooBar` between ticks in the documentation - --> $DIR/doc.rs:110:43 + --> $DIR/doc.rs:120:43 | LL | /** E.g., serialization of an empty list: FooBar | ^^^^^^ error: you should put `BarQuz` between ticks in the documentation - --> $DIR/doc.rs:115:5 + --> $DIR/doc.rs:125:5 | LL | And BarQuz too. | ^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:116:1 + --> $DIR/doc.rs:126:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `FooBar` between ticks in the documentation - --> $DIR/doc.rs:121:43 + --> $DIR/doc.rs:131:43 | LL | /** E.g., serialization of an empty list: FooBar | ^^^^^^ error: you should put `BarQuz` between ticks in the documentation - --> $DIR/doc.rs:126:5 + --> $DIR/doc.rs:136:5 | LL | And BarQuz too. | ^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:127:1 + --> $DIR/doc.rs:137:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:138:5 + --> $DIR/doc.rs:148:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:165:13 + --> $DIR/doc.rs:175:13 | LL | /// Not ok: http://www.unicode.org | ^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:166:13 + --> $DIR/doc.rs:176:13 | LL | /// Not ok: https://www.unicode.org | ^^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:167:13 + --> $DIR/doc.rs:177:13 | LL | /// Not ok: http://www.unicode.org/ | ^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:168:13 + --> $DIR/doc.rs:178:13 | LL | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `mycrate::Collection` between ticks in the documentation - --> $DIR/doc.rs:174:22 + --> $DIR/doc.rs:181:22 | LL | /// An iterator over mycrate::Collection's values. | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 30 previous errors +error: aborting due to 31 previous errors diff --git a/tests/ui/functions_maxlines.stderr b/tests/ui/functions_maxlines.stderr index c640c82d6d7c9..dc6c8ba2f154d 100644 --- a/tests/ui/functions_maxlines.stderr +++ b/tests/ui/functions_maxlines.stderr @@ -1,4 +1,4 @@ -error: this function has a large number of lines +error: this function has too many lines (102/100) --> $DIR/functions_maxlines.rs:58:1 | LL | / fn bad_lines() { diff --git a/tests/ui/option_map_unit_fn_fixable.stderr b/tests/ui/option_map_unit_fn_fixable.stderr index 1312c70b6d592..d7d45ef9b0b33 100644 --- a/tests/ui/option_map_unit_fn_fixable.stderr +++ b/tests/ui/option_map_unit_fn_fixable.stderr @@ -1,4 +1,4 @@ -error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type +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 | LL | x.field.map(do_nothing); @@ -8,7 +8,7 @@ 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 +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 | LL | x.field.map(do_nothing); @@ -16,7 +16,7 @@ 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 +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 | LL | x.field.map(diverge); @@ -24,7 +24,7 @@ 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 +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 | LL | x.field.map(|value| x.do_option_nothing(value + captured)); @@ -32,7 +32,7 @@ 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 +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 | LL | x.field.map(|value| { x.do_option_plus_one(value + captured); }); @@ -40,7 +40,7 @@ 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 +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 | LL | x.field.map(|value| do_nothing(value + captured)); @@ -48,7 +48,7 @@ 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 +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 | LL | x.field.map(|value| { do_nothing(value + captured) }); @@ -56,7 +56,7 @@ 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 +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 | LL | x.field.map(|value| { do_nothing(value + captured); }); @@ -64,7 +64,7 @@ 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 +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 | LL | x.field.map(|value| { { do_nothing(value + captured); } }); @@ -72,7 +72,7 @@ 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 +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 | LL | x.field.map(|value| diverge(value + captured)); @@ -80,7 +80,7 @@ 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 +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 | LL | x.field.map(|value| { diverge(value + captured) }); @@ -88,7 +88,7 @@ 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 +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 | LL | x.field.map(|value| { diverge(value + captured); }); @@ -96,7 +96,7 @@ 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 +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 | LL | x.field.map(|value| { { diverge(value + captured); } }); @@ -104,7 +104,7 @@ 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 +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 | LL | x.field.map(|value| { let y = plus_one(value + captured); }); @@ -112,7 +112,7 @@ 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 +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 | LL | x.field.map(|value| { plus_one(value + captured); }); @@ -120,7 +120,7 @@ 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 +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 | LL | x.field.map(|value| { { plus_one(value + captured); } }); @@ -128,7 +128,7 @@ 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 +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 | LL | x.field.map(|ref value| { do_nothing(value + captured) }); @@ -136,7 +136,7 @@ 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 +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 | LL | option().map(do_nothing);} diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 67faa8bd4a0aa..5fb568672d356 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -58,12 +58,6 @@ fn or_fun_call() { let without_default = Some(Foo); without_default.unwrap_or_else(Foo::new); - let mut map = HashMap::::new(); - map.entry(42).or_insert_with(String::new); - - let mut btree = BTreeMap::::new(); - btree.entry(42).or_insert_with(String::new); - let stringy = Some(String::from("")); let _ = stringy.unwrap_or_else(|| "".to_owned()); @@ -122,6 +116,17 @@ pub fn skip_const_fn_with_no_args() { Some(42) } let _ = None.or(foo()); + + // See issue #5693. + let mut map = std::collections::HashMap::new(); + map.insert(1, vec![1]); + map.entry(1).or_insert(vec![]); + + let mut map = HashMap::::new(); + map.entry(42).or_insert(String::new()); + + let mut btree = BTreeMap::::new(); + btree.entry(42).or_insert(String::new()); } fn main() {} diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index 9867e2eedcff5..737b0f7e55bc7 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -58,12 +58,6 @@ fn or_fun_call() { let without_default = Some(Foo); without_default.unwrap_or(Foo::new()); - let mut map = HashMap::::new(); - map.entry(42).or_insert(String::new()); - - let mut btree = BTreeMap::::new(); - btree.entry(42).or_insert(String::new()); - let stringy = Some(String::from("")); let _ = stringy.unwrap_or("".to_owned()); @@ -122,6 +116,17 @@ pub fn skip_const_fn_with_no_args() { Some(42) } let _ = None.or(foo()); + + // See issue #5693. + let mut map = std::collections::HashMap::new(); + map.insert(1, vec![1]); + map.entry(1).or_insert(vec![]); + + let mut map = HashMap::::new(); + map.entry(42).or_insert(String::new()); + + let mut btree = BTreeMap::::new(); + btree.entry(42).or_insert(String::new()); } fn main() {} diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index bc5978b538f16..b8a436993f329 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -60,35 +60,23 @@ error: use of `unwrap_or` followed by a function call 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 - | -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 - | -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:62:21 | LL | let _ = stringy.unwrap_or("".to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())` error: use of `or` followed by a function call - --> $DIR/or_fun_call.rs:93:35 + --> $DIR/or_fun_call.rs:87: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:91: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 13 previous errors diff --git a/tests/ui/result_map_unit_fn_fixable.stderr b/tests/ui/result_map_unit_fn_fixable.stderr index 467e00263cd3a..4f3a8c6b79239 100644 --- a/tests/ui/result_map_unit_fn_fixable.stderr +++ b/tests/ui/result_map_unit_fn_fixable.stderr @@ -1,4 +1,4 @@ -error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:35:5 | LL | x.field.map(do_nothing); @@ -8,7 +8,7 @@ LL | x.field.map(do_nothing); | = note: `-D clippy::result-map-unit-fn` implied by `-D warnings` -error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:37:5 | LL | x.field.map(do_nothing); @@ -16,7 +16,7 @@ LL | x.field.map(do_nothing); | | | help: try this: `if let Ok(x_field) = x.field { do_nothing(x_field) }` -error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:39:5 | LL | x.field.map(diverge); @@ -24,7 +24,7 @@ LL | x.field.map(diverge); | | | help: try this: `if let Ok(x_field) = x.field { diverge(x_field) }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:45:5 | LL | x.field.map(|value| x.do_result_nothing(value + captured)); @@ -32,7 +32,7 @@ LL | x.field.map(|value| x.do_result_nothing(value + captured)); | | | help: try this: `if let Ok(value) = x.field { x.do_result_nothing(value + captured) }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:47:5 | LL | x.field.map(|value| { x.do_result_plus_one(value + captured); }); @@ -40,7 +40,7 @@ LL | x.field.map(|value| { x.do_result_plus_one(value + captured); }); | | | help: try this: `if let Ok(value) = x.field { x.do_result_plus_one(value + captured); }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:50:5 | LL | x.field.map(|value| do_nothing(value + captured)); @@ -48,7 +48,7 @@ LL | x.field.map(|value| do_nothing(value + captured)); | | | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured) }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:52:5 | LL | x.field.map(|value| { do_nothing(value + captured) }); @@ -56,7 +56,7 @@ LL | x.field.map(|value| { do_nothing(value + captured) }); | | | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured) }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:54:5 | LL | x.field.map(|value| { do_nothing(value + captured); }); @@ -64,7 +64,7 @@ LL | x.field.map(|value| { do_nothing(value + captured); }); | | | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured); }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:56:5 | LL | x.field.map(|value| { { do_nothing(value + captured); } }); @@ -72,7 +72,7 @@ LL | x.field.map(|value| { { do_nothing(value + captured); } }); | | | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured); }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:59:5 | LL | x.field.map(|value| diverge(value + captured)); @@ -80,7 +80,7 @@ LL | x.field.map(|value| diverge(value + captured)); | | | help: try this: `if let Ok(value) = x.field { diverge(value + captured) }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:61:5 | LL | x.field.map(|value| { diverge(value + captured) }); @@ -88,7 +88,7 @@ LL | x.field.map(|value| { diverge(value + captured) }); | | | help: try this: `if let Ok(value) = x.field { diverge(value + captured) }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:63:5 | LL | x.field.map(|value| { diverge(value + captured); }); @@ -96,7 +96,7 @@ LL | x.field.map(|value| { diverge(value + captured); }); | | | help: try this: `if let Ok(value) = x.field { diverge(value + captured); }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:65:5 | LL | x.field.map(|value| { { diverge(value + captured); } }); @@ -104,7 +104,7 @@ LL | x.field.map(|value| { { diverge(value + captured); } }); | | | help: try this: `if let Ok(value) = x.field { diverge(value + captured); }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:70:5 | LL | x.field.map(|value| { let y = plus_one(value + captured); }); @@ -112,7 +112,7 @@ LL | x.field.map(|value| { let y = plus_one(value + captured); }); | | | help: try this: `if let Ok(value) = x.field { let y = plus_one(value + captured); }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:72:5 | LL | x.field.map(|value| { plus_one(value + captured); }); @@ -120,7 +120,7 @@ LL | x.field.map(|value| { plus_one(value + captured); }); | | | help: try this: `if let Ok(value) = x.field { plus_one(value + captured); }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:74:5 | LL | x.field.map(|value| { { plus_one(value + captured); } }); @@ -128,7 +128,7 @@ LL | x.field.map(|value| { { plus_one(value + captured); } }); | | | help: try this: `if let Ok(value) = x.field { plus_one(value + captured); }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:77:5 | LL | x.field.map(|ref value| { do_nothing(value + captured) }); diff --git a/tests/ui/result_map_unit_fn_unfixable.stderr b/tests/ui/result_map_unit_fn_unfixable.stderr index b23cc608621d0..88e4efdb0f054 100644 --- a/tests/ui/result_map_unit_fn_unfixable.stderr +++ b/tests/ui/result_map_unit_fn_unfixable.stderr @@ -1,4 +1,4 @@ -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_unfixable.rs:23:5 | LL | x.field.map(|value| { do_nothing(value); do_nothing(value) }); @@ -8,7 +8,7 @@ LL | x.field.map(|value| { do_nothing(value); do_nothing(value) }); | = note: `-D clippy::result-map-unit-fn` implied by `-D warnings` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_unfixable.rs:25:5 | LL | x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) }); @@ -16,7 +16,7 @@ LL | x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) | | | help: try this: `if let Ok(value) = x.field { ... }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_unfixable.rs:29:5 | LL | x.field.map(|value| { @@ -30,7 +30,7 @@ LL | || }); | |_______| | -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_unfixable.rs:33:5 | LL | x.field.map(|value| { do_nothing(value); do_nothing(value); }); @@ -38,7 +38,7 @@ LL | x.field.map(|value| { do_nothing(value); do_nothing(value); }); | | | help: try this: `if let Ok(value) = x.field { ... }` -error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` --> $DIR/result_map_unit_fn_unfixable.rs:37:5 | LL | "12".parse::().map(diverge); @@ -46,7 +46,7 @@ LL | "12".parse::().map(diverge); | | | help: try this: `if let Ok(a) = "12".parse::() { diverge(a) }` -error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` --> $DIR/result_map_unit_fn_unfixable.rs:43:5 | LL | y.map(do_nothing); diff --git a/tests/ui/same_item_push.rs b/tests/ui/same_item_push.rs index bfe27e020445c..a37c8782ec330 100644 --- a/tests/ui/same_item_push.rs +++ b/tests/ui/same_item_push.rs @@ -1,5 +1,7 @@ #![warn(clippy::same_item_push)] +const VALUE: u8 = 7; + fn mutate_increment(x: &mut u8) -> u8 { *x += 1; *x @@ -9,65 +11,81 @@ fn increment(x: u8) -> u8 { x + 1 } -fn main() { - // Test for basic case - let mut spaces = Vec::with_capacity(10); - for _ in 0..10 { - spaces.push(vec![b' ']); - } +fn fun() -> usize { + 42 +} - let mut vec2: Vec = Vec::new(); +fn main() { + // ** linted cases ** + let mut vec: Vec = Vec::new(); let item = 2; for _ in 5..=20 { - vec2.push(item); + vec.push(item); } - let mut vec3: Vec = Vec::new(); + let mut vec: Vec = Vec::new(); for _ in 0..15 { let item = 2; - vec3.push(item); + vec.push(item); } - let mut vec4: Vec = Vec::new(); + let mut vec: Vec = Vec::new(); for _ in 0..15 { - vec4.push(13); + vec.push(13); + } + + let mut vec = Vec::new(); + for _ in 0..20 { + vec.push(VALUE); + } + + let mut vec = Vec::new(); + let item = VALUE; + for _ in 0..20 { + vec.push(item); + } + + // ** non-linted cases ** + let mut spaces = Vec::with_capacity(10); + for _ in 0..10 { + spaces.push(vec![b' ']); } // Suggestion should not be given as pushed variable can mutate - let mut vec5: Vec = Vec::new(); + let mut vec: Vec = Vec::new(); let mut item: u8 = 2; for _ in 0..30 { - vec5.push(mutate_increment(&mut item)); + vec.push(mutate_increment(&mut item)); } - let mut vec6: Vec = Vec::new(); + let mut vec: Vec = Vec::new(); let mut item: u8 = 2; let mut item2 = &mut mutate_increment(&mut item); for _ in 0..30 { - vec6.push(mutate_increment(item2)); + vec.push(mutate_increment(item2)); } - let mut vec7: Vec = Vec::new(); + let mut vec: Vec = Vec::new(); for (a, b) in [0, 1, 4, 9, 16].iter().enumerate() { - vec7.push(a); + vec.push(a); } - let mut vec8: Vec = Vec::new(); + let mut vec: Vec = Vec::new(); for i in 0..30 { - vec8.push(increment(i)); + vec.push(increment(i)); } - let mut vec9: Vec = Vec::new(); + let mut vec: Vec = Vec::new(); for i in 0..30 { - vec9.push(i + i * i); + vec.push(i + i * i); } // Suggestion should not be given as there are multiple pushes that are not the same - let mut vec10: Vec = Vec::new(); + let mut vec: Vec = Vec::new(); let item: u8 = 2; for _ in 0..30 { - vec10.push(item); - vec10.push(item * 2); + vec.push(item); + vec.push(item * 2); } // Suggestion should not be given as Vec is not involved @@ -82,16 +100,52 @@ fn main() { for i in 0..30 { vec_a.push(A { kind: i }); } - let mut vec12: Vec = Vec::new(); + let mut vec: Vec = Vec::new(); for a in vec_a { - vec12.push(2u8.pow(a.kind)); + vec.push(2u8.pow(a.kind)); } // Fix #5902 - let mut vec13: Vec = Vec::new(); + let mut vec: Vec = Vec::new(); let mut item = 0; for _ in 0..10 { - vec13.push(item); + vec.push(item); item += 10; } + + // Fix #5979 + let mut vec: Vec = Vec::new(); + for _ in 0..10 { + vec.push(std::fs::File::open("foobar").unwrap()); + } + // Fix #5979 + #[derive(Clone)] + struct S {} + + trait T {} + impl T for S {} + + let mut vec: Vec> = Vec::new(); + for _ in 0..10 { + vec.push(Box::new(S {})); + } + + // Fix #5985 + let mut vec = Vec::new(); + let item = 42; + let item = fun(); + for _ in 0..20 { + vec.push(item); + } + + // Fix #5985 + let mut vec = Vec::new(); + let key = 1; + for _ in 0..20 { + let item = match key { + 1 => 10, + _ => 0, + }; + vec.push(item); + } } diff --git a/tests/ui/same_item_push.stderr b/tests/ui/same_item_push.stderr index ddc5d48cd4135..d9ffa15780ad0 100644 --- a/tests/ui/same_item_push.stderr +++ b/tests/ui/same_item_push.stderr @@ -1,35 +1,43 @@ error: it looks like the same item is being pushed into this Vec - --> $DIR/same_item_push.rs:16:9 + --> $DIR/same_item_push.rs:23:9 | -LL | spaces.push(vec![b' ']); - | ^^^^^^ +LL | vec.push(item); + | ^^^ | = note: `-D clippy::same-item-push` implied by `-D warnings` - = help: try using vec![vec![b' '];SIZE] or spaces.resize(NEW_SIZE, vec![b' ']) + = help: try using vec![item;SIZE] or vec.resize(NEW_SIZE, item) error: it looks like the same item is being pushed into this Vec - --> $DIR/same_item_push.rs:22:9 + --> $DIR/same_item_push.rs:29:9 | -LL | vec2.push(item); - | ^^^^ +LL | vec.push(item); + | ^^^ | - = help: try using vec![item;SIZE] or vec2.resize(NEW_SIZE, item) + = help: try using vec![item;SIZE] or vec.resize(NEW_SIZE, item) error: it looks like the same item is being pushed into this Vec - --> $DIR/same_item_push.rs:28:9 + --> $DIR/same_item_push.rs:34:9 | -LL | vec3.push(item); - | ^^^^ +LL | vec.push(13); + | ^^^ | - = help: try using vec![item;SIZE] or vec3.resize(NEW_SIZE, item) + = help: try using vec![13;SIZE] or vec.resize(NEW_SIZE, 13) error: it looks like the same item is being pushed into this Vec - --> $DIR/same_item_push.rs:33:9 + --> $DIR/same_item_push.rs:39:9 | -LL | vec4.push(13); - | ^^^^ +LL | vec.push(VALUE); + | ^^^ | - = help: try using vec![13;SIZE] or vec4.resize(NEW_SIZE, 13) + = help: try using vec![VALUE;SIZE] or vec.resize(NEW_SIZE, VALUE) -error: aborting due to 4 previous errors +error: it looks like the same item is being pushed into this Vec + --> $DIR/same_item_push.rs:45:9 + | +LL | vec.push(item); + | ^^^ + | + = help: try using vec![item;SIZE] or vec.resize(NEW_SIZE, item) + +error: aborting due to 5 previous errors diff --git a/tests/ui/temporary_assignment.rs b/tests/ui/temporary_assignment.rs index d6f56d40c5d4e..b4a931043b00d 100644 --- a/tests/ui/temporary_assignment.rs +++ b/tests/ui/temporary_assignment.rs @@ -54,11 +54,6 @@ fn main() { ArrayStruct { array: [0] }.array[0] = 1; (0, 0).0 = 1; - A.0 = 2; - B.field = 2; - C.structure.field = 2; - D.array[0] = 2; - // no error s.field = 1; t.0 = 1; diff --git a/tests/ui/transmute_ptr_to_ptr.rs b/tests/ui/transmute_ptr_to_ptr.rs index 0d8a322f2b2b0..26b03bdc74055 100644 --- a/tests/ui/transmute_ptr_to_ptr.rs +++ b/tests/ui/transmute_ptr_to_ptr.rs @@ -51,4 +51,12 @@ fn transmute_ptr_to_ptr() { let _: &GenericParam<&LifetimeParam<'static>> = unsafe { std::mem::transmute(&GenericParam { t: &lp }) }; } +// dereferencing raw pointers in const contexts, should not lint as it's unstable (issue 5959) +const _: &() = { + struct ZST; + let zst = &ZST; + + unsafe { std::mem::transmute::<&'static ZST, &'static ()>(zst) } +}; + fn main() {} diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index 2992abae775b8..fec115ff29d66 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -1,5 +1,11 @@ #![warn(clippy::unit_arg)] -#![allow(clippy::no_effect, unused_must_use, unused_variables)] +#![allow( + clippy::no_effect, + unused_must_use, + unused_variables, + clippy::unused_unit, + clippy::or_fun_call +)] use std::fmt::Debug; @@ -47,6 +53,11 @@ fn bad() { foo(3); }, ); + // here Some(foo(2)) isn't the top level statement expression, wrap the suggestion in a block + None.or(Some(foo(2))); + // in this case, the suggestion can be inlined, no need for a surrounding block + // foo(()); foo(()) instead of { foo(()); foo(()) } + foo(foo(())) } fn ok() { diff --git a/tests/ui/unit_arg.stderr b/tests/ui/unit_arg.stderr index 56f6a855dfa55..90fee3aab23b0 100644 --- a/tests/ui/unit_arg.stderr +++ b/tests/ui/unit_arg.stderr @@ -1,5 +1,5 @@ error: passing a unit value to a function - --> $DIR/unit_arg.rs:23:5 + --> $DIR/unit_arg.rs:29:5 | LL | / foo({ LL | | 1; @@ -11,34 +11,28 @@ help: remove the semicolon from the last statement in the block | LL | 1 | -help: or move the expression in front of the call... +help: or move the expression in front of the call and replace it with the unit literal `()` | LL | { LL | 1; LL | }; - | -help: ...and use a unit literal instead - | LL | foo(()); - | ^^ + | error: passing a unit value to a function - --> $DIR/unit_arg.rs:26:5 + --> $DIR/unit_arg.rs:32:5 | LL | foo(foo(1)); | ^^^^^^^^^^^ | -help: move the expression in front of the call... +help: move the expression in front of the call and replace it with the unit literal `()` | LL | foo(1); - | -help: ...and use a unit literal instead - | LL | foo(()); - | ^^ + | error: passing a unit value to a function - --> $DIR/unit_arg.rs:27:5 + --> $DIR/unit_arg.rs:33:5 | LL | / foo({ LL | | foo(1); @@ -50,20 +44,17 @@ help: remove the semicolon from the last statement in the block | LL | foo(2) | -help: or move the expression in front of the call... +help: or move the expression in front of the call and replace it with the unit literal `()` | LL | { LL | foo(1); LL | foo(2); LL | }; - | -help: ...and use a unit literal instead - | LL | foo(()); - | ^^ + | error: passing a unit value to a function - --> $DIR/unit_arg.rs:32:5 + --> $DIR/unit_arg.rs:38:5 | LL | / b.bar({ LL | | 1; @@ -74,35 +65,29 @@ help: remove the semicolon from the last statement in the block | LL | 1 | -help: or move the expression in front of the call... +help: or move the expression in front of the call and replace it with the unit literal `()` | LL | { LL | 1; LL | }; - | -help: ...and use a unit literal instead - | LL | b.bar(()); - | ^^ + | error: passing unit values to a function - --> $DIR/unit_arg.rs:35:5 + --> $DIR/unit_arg.rs:41:5 | LL | taking_multiple_units(foo(0), foo(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: move the expressions in front of the call... +help: move the expressions in front of the call and replace them with the unit literal `()` | LL | foo(0); LL | foo(1); - | -help: ...and use unit literals instead - | LL | taking_multiple_units((), ()); - | ^^ ^^ + | error: passing unit values to a function - --> $DIR/unit_arg.rs:36:5 + --> $DIR/unit_arg.rs:42:5 | LL | / taking_multiple_units(foo(0), { LL | | foo(1); @@ -114,21 +99,18 @@ help: remove the semicolon from the last statement in the block | LL | foo(2) | -help: or move the expressions in front of the call... +help: or move the expressions in front of the call and replace them with the unit literal `()` | LL | foo(0); LL | { LL | foo(1); LL | foo(2); LL | }; - | -help: ...and use unit literals instead - | LL | taking_multiple_units((), ()); - | ^^ ^^ + | error: passing unit values to a function - --> $DIR/unit_arg.rs:40:5 + --> $DIR/unit_arg.rs:46:5 | LL | / taking_multiple_units( LL | | { @@ -147,7 +129,7 @@ help: remove the semicolon from the last statement in the block | LL | foo(3) | -help: or move the expressions in front of the call... +help: or move the expressions in front of the call and replace them with the unit literal `()` | LL | { LL | foo(0); @@ -156,26 +138,44 @@ LL | }; LL | { LL | foo(2); ... -help: ...and use unit literals instead + +error: passing a unit value to a function + --> $DIR/unit_arg.rs:57:13 + | +LL | None.or(Some(foo(2))); + | ^^^^^^^^^^^^ | -LL | (), -LL | (), +help: move the expression in front of the call and replace it with the unit literal `()` + | +LL | None.or({ +LL | foo(2); +LL | Some(()) +LL | }); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:82:5 + --> $DIR/unit_arg.rs:60:5 | -LL | Some(foo(1)) +LL | foo(foo(())) | ^^^^^^^^^^^^ | -help: move the expression in front of the call... +help: move the expression in front of the call and replace it with the unit literal `()` | -LL | foo(1); +LL | foo(()); +LL | foo(()) | -help: ...and use a unit literal instead + +error: passing a unit value to a function + --> $DIR/unit_arg.rs:93:5 | +LL | Some(foo(1)) + | ^^^^^^^^^^^^ + | +help: move the expression in front of the call and replace it with the unit literal `()` + | +LL | foo(1); LL | Some(()) - | ^^ + | -error: aborting due to 8 previous errors +error: aborting due to 10 previous errors diff --git a/tests/ui/unit_arg_empty_blocks.stderr b/tests/ui/unit_arg_empty_blocks.stderr index bb58483584b3e..456b12a2c6b16 100644 --- a/tests/ui/unit_arg_empty_blocks.stderr +++ b/tests/ui/unit_arg_empty_blocks.stderr @@ -22,14 +22,11 @@ error: passing unit values to a function LL | taking_two_units({}, foo(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: move the expression in front of the call... +help: move the expression in front of the call and replace it with the unit literal `()` | LL | foo(0); - | -help: ...and use unit literals instead - | LL | taking_two_units((), ()); - | ^^ ^^ + | error: passing unit values to a function --> $DIR/unit_arg_empty_blocks.rs:18:5 @@ -37,15 +34,12 @@ error: passing unit values to a function LL | taking_three_units({}, foo(0), foo(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: move the expressions in front of the call... +help: move the expressions in front of the call and replace them with the unit literal `()` | LL | foo(0); LL | foo(1); - | -help: ...and use unit literals instead - | LL | taking_three_units((), (), ()); - | ^^ ^^ ^^ + | error: aborting due to 4 previous errors diff --git a/tests/ui/unnecessary_sort_by.fixed b/tests/ui/unnecessary_sort_by.fixed index 31c2ba0f9c589..ad0d0387db03c 100644 --- a/tests/ui/unnecessary_sort_by.fixed +++ b/tests/ui/unnecessary_sort_by.fixed @@ -25,17 +25,25 @@ fn unnecessary_sort_by() { vec.sort_by(|_, b| b.cmp(&5)); vec.sort_by(|_, b| b.cmp(c)); vec.sort_unstable_by(|a, _| a.cmp(c)); + + // Ignore vectors of references + let mut vec: Vec<&&&isize> = vec![&&&3, &&&6, &&&1, &&&2, &&&5]; + vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs())); + vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs())); + vec.sort_by(|a, b| b.cmp(a)); + vec.sort_unstable_by(|a, b| b.cmp(a)); } -// Should not be linted to avoid hitting https://github.com/rust-lang/rust/issues/34162 +// Do not suggest returning a reference to the closure parameter of `Vec::sort_by_key` mod issue_5754 { - struct Test(String); + #[derive(Clone, Copy)] + struct Test(usize); #[derive(PartialOrd, Ord, PartialEq, Eq)] - struct Wrapper<'a>(&'a str); + struct Wrapper<'a>(&'a usize); impl Test { - fn name(&self) -> &str { + fn name(&self) -> &usize { &self.0 } @@ -60,7 +68,33 @@ mod issue_5754 { } } +// `Vec::sort_by_key` closure parameter is `F: FnMut(&T) -> K` +// The suggestion is destructuring T and we know T is not a reference, so test that non-Copy T are +// not linted. +mod issue_6001 { + struct Test(String); + + impl Test { + // Return an owned type so that we don't hit the fix for 5754 + fn name(&self) -> String { + self.0.clone() + } + } + + pub fn test() { + let mut args: Vec = vec![]; + + // Forward + args.sort_by(|a, b| a.name().cmp(&b.name())); + args.sort_unstable_by(|a, b| a.name().cmp(&b.name())); + // Reverse + args.sort_by(|a, b| b.name().cmp(&a.name())); + args.sort_unstable_by(|a, b| b.name().cmp(&a.name())); + } +} + fn main() { unnecessary_sort_by(); issue_5754::test(); + issue_6001::test(); } diff --git a/tests/ui/unnecessary_sort_by.rs b/tests/ui/unnecessary_sort_by.rs index a3c8ae468ede7..9746f6e6849dd 100644 --- a/tests/ui/unnecessary_sort_by.rs +++ b/tests/ui/unnecessary_sort_by.rs @@ -25,17 +25,25 @@ fn unnecessary_sort_by() { vec.sort_by(|_, b| b.cmp(&5)); vec.sort_by(|_, b| b.cmp(c)); vec.sort_unstable_by(|a, _| a.cmp(c)); + + // Ignore vectors of references + let mut vec: Vec<&&&isize> = vec![&&&3, &&&6, &&&1, &&&2, &&&5]; + vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs())); + vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs())); + vec.sort_by(|a, b| b.cmp(a)); + vec.sort_unstable_by(|a, b| b.cmp(a)); } -// Should not be linted to avoid hitting https://github.com/rust-lang/rust/issues/34162 +// Do not suggest returning a reference to the closure parameter of `Vec::sort_by_key` mod issue_5754 { - struct Test(String); + #[derive(Clone, Copy)] + struct Test(usize); #[derive(PartialOrd, Ord, PartialEq, Eq)] - struct Wrapper<'a>(&'a str); + struct Wrapper<'a>(&'a usize); impl Test { - fn name(&self) -> &str { + fn name(&self) -> &usize { &self.0 } @@ -60,7 +68,33 @@ mod issue_5754 { } } +// `Vec::sort_by_key` closure parameter is `F: FnMut(&T) -> K` +// The suggestion is destructuring T and we know T is not a reference, so test that non-Copy T are +// not linted. +mod issue_6001 { + struct Test(String); + + impl Test { + // Return an owned type so that we don't hit the fix for 5754 + fn name(&self) -> String { + self.0.clone() + } + } + + pub fn test() { + let mut args: Vec = vec![]; + + // Forward + args.sort_by(|a, b| a.name().cmp(&b.name())); + args.sort_unstable_by(|a, b| a.name().cmp(&b.name())); + // Reverse + args.sort_by(|a, b| b.name().cmp(&a.name())); + args.sort_unstable_by(|a, b| b.name().cmp(&a.name())); + } +} + fn main() { unnecessary_sort_by(); issue_5754::test(); + issue_6001::test(); } diff --git a/tests/ui/useless_attribute.fixed b/tests/ui/useless_attribute.fixed index b222e2f7976d5..a5fcde768f183 100644 --- a/tests/ui/useless_attribute.fixed +++ b/tests/ui/useless_attribute.fixed @@ -49,6 +49,14 @@ mod a { pub use self::b::C; } +// don't lint on clippy::wildcard_imports for `use` items +#[allow(clippy::wildcard_imports)] +pub use std::io::prelude::*; + +// don't lint on clippy::enum_glob_use for `use` items +#[allow(clippy::enum_glob_use)] +pub use std::cmp::Ordering::*; + fn test_indented_attr() { #![allow(clippy::almost_swapped)] use std::collections::HashSet; diff --git a/tests/ui/useless_attribute.rs b/tests/ui/useless_attribute.rs index 3422eace4ab97..0396d39e3d54e 100644 --- a/tests/ui/useless_attribute.rs +++ b/tests/ui/useless_attribute.rs @@ -49,6 +49,14 @@ mod a { pub use self::b::C; } +// don't lint on clippy::wildcard_imports for `use` items +#[allow(clippy::wildcard_imports)] +pub use std::io::prelude::*; + +// don't lint on clippy::enum_glob_use for `use` items +#[allow(clippy::enum_glob_use)] +pub use std::cmp::Ordering::*; + fn test_indented_attr() { #[allow(clippy::almost_swapped)] use std::collections::HashSet; diff --git a/tests/ui/useless_attribute.stderr b/tests/ui/useless_attribute.stderr index 57ba976730c17..d0194e4bbbe5b 100644 --- a/tests/ui/useless_attribute.stderr +++ b/tests/ui/useless_attribute.stderr @@ -13,7 +13,7 @@ LL | #[cfg_attr(feature = "cargo-clippy", allow(dead_code))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![cfg_attr(feature = "cargo-clippy", allow(dead_code)` error: useless lint attribute - --> $DIR/useless_attribute.rs:53:5 + --> $DIR/useless_attribute.rs:61:5 | LL | #[allow(clippy::almost_swapped)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![allow(clippy::almost_swapped)]` From 4f2d94180ddffcb23cb1f3682242df735eeac03f Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 10 Sep 2020 11:44:28 -0400 Subject: [PATCH 0270/1052] Only copy LLVM into rust-dev with internal LLVM This avoids needing to figure out where to locate each of the components with an external LLVM. --- src/bootstrap/dist.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 797a1ce20b48b..25d0dad584462 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -2524,6 +2524,14 @@ impl Step for RustDev { fn run(self, builder: &Builder<'_>) -> Option { let target = self.target; + /* run only if llvm-config isn't used */ + if let Some(config) = builder.config.target_config.get(&target) { + if let Some(ref _s) = config.llvm_config { + builder.info(&format!("Skipping RustDev ({}): external LLVM", target)); + return None; + } + } + builder.info(&format!("Dist RustDev ({})", target)); let _time = timeit(builder); let src = builder.src.join("src/llvm-project/llvm"); @@ -2536,6 +2544,7 @@ impl Step for RustDev { // Prepare the image directory let dst_bindir = image.join("bin"); t!(fs::create_dir_all(&dst_bindir)); + let exe = builder.llvm_out(target).join("bin").join(exe("llvm-config", target)); builder.install(&exe, &dst_bindir, 0o755); builder.install(&builder.llvm_filecheck(target), &dst_bindir, 0o755); From c0894e72320a9b8a80f39fae1908d9e83a8b7277 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 9 Sep 2020 15:42:37 +0100 Subject: [PATCH 0271/1052] typeck/expr: inaccessible private fields This commit adjusts the missing field diagnostic logic for struct expressions in typeck to improve the diagnostic when the missing fields are inaccessible. Signed-off-by: David Wood --- compiler/rustc_typeck/src/check/expr.rs | 118 +++++++++++++++++------- src/test/ui/issues/issue-76077.rs | 10 ++ src/test/ui/issues/issue-76077.stderr | 8 ++ 3 files changed, 103 insertions(+), 33 deletions(-) create mode 100644 src/test/ui/issues/issue-76077.rs create mode 100644 src/test/ui/issues/issue-76077.stderr diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index fa8b8dbd9f8d4..dba46f35dca92 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1241,42 +1241,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.sess.span_err(span, "union expressions should have exactly one field"); } } else if check_completeness && !error_happened && !remaining_fields.is_empty() { - let len = remaining_fields.len(); - - let mut displayable_field_names = - remaining_fields.keys().map(|ident| ident.as_str()).collect::>(); - - displayable_field_names.sort(); + let no_accessible_remaining_fields = remaining_fields + .iter() + .filter(|(_, (_, field))| { + field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx) + }) + .next() + .is_none(); - let truncated_fields_error = if len <= 3 { - String::new() + if no_accessible_remaining_fields { + self.report_no_accessible_fields(adt_ty, span); } else { - format!(" and {} other field{}", (len - 3), if len - 3 == 1 { "" } else { "s" }) - }; - - let remaining_fields_names = displayable_field_names - .iter() - .take(3) - .map(|n| format!("`{}`", n)) - .collect::>() - .join(", "); - - struct_span_err!( - tcx.sess, - span, - E0063, - "missing field{} {}{} in initializer of `{}`", - pluralize!(remaining_fields.len()), - remaining_fields_names, - truncated_fields_error, - adt_ty - ) - .span_label( - span, - format!("missing {}{}", remaining_fields_names, truncated_fields_error), - ) - .emit(); + self.report_missing_field(adt_ty, span, remaining_fields); + } } + error_happened } @@ -1293,6 +1272,79 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + /// Report an error for a struct field expression when there are fields which aren't provided. + /// + /// ```ignore (diagnostic) + /// error: missing field `you_can_use_this_field` in initializer of `foo::Foo` + /// --> src/main.rs:8:5 + /// | + /// 8 | foo::Foo {}; + /// | ^^^^^^^^ missing `you_can_use_this_field` + /// + /// error: aborting due to previous error + /// ``` + fn report_missing_field( + &self, + adt_ty: Ty<'tcx>, + span: Span, + remaining_fields: FxHashMap, + ) { + let tcx = self.tcx; + let len = remaining_fields.len(); + + let mut displayable_field_names = + remaining_fields.keys().map(|ident| ident.as_str()).collect::>(); + + displayable_field_names.sort(); + + let truncated_fields_error = if len <= 3 { + String::new() + } else { + format!(" and {} other field{}", (len - 3), if len - 3 == 1 { "" } else { "s" }) + }; + + let remaining_fields_names = displayable_field_names + .iter() + .take(3) + .map(|n| format!("`{}`", n)) + .collect::>() + .join(", "); + + struct_span_err!( + tcx.sess, + span, + E0063, + "missing field{} {}{} in initializer of `{}`", + pluralize!(remaining_fields.len()), + remaining_fields_names, + truncated_fields_error, + adt_ty + ) + .span_label(span, format!("missing {}{}", remaining_fields_names, truncated_fields_error)) + .emit(); + } + + /// Report an error for a struct field expression when there are no visible fields. + /// + /// ```ignore (diagnostic) + /// error: cannot construct `Foo` with struct literal syntax due to inaccessible fields + /// --> src/main.rs:8:5 + /// | + /// 8 | foo::Foo {}; + /// | ^^^^^^^^ + /// + /// error: aborting due to previous error + /// ``` + fn report_no_accessible_fields(&self, adt_ty: Ty<'tcx>, span: Span) { + self.tcx.sess.span_err( + span, + &format!( + "cannot construct `{}` with struct literal syntax due to inaccessible fields", + adt_ty, + ), + ); + } + fn report_unknown_field( &self, ty: Ty<'tcx>, diff --git a/src/test/ui/issues/issue-76077.rs b/src/test/ui/issues/issue-76077.rs new file mode 100644 index 0000000000000..1ecd37de2e14a --- /dev/null +++ b/src/test/ui/issues/issue-76077.rs @@ -0,0 +1,10 @@ +pub mod foo { + pub struct Foo { + you_cant_use_this_field: bool, + } +} + +fn main() { + foo::Foo {}; + //~^ ERROR cannot construct `Foo` with struct literal syntax due to inaccessible fields +} diff --git a/src/test/ui/issues/issue-76077.stderr b/src/test/ui/issues/issue-76077.stderr new file mode 100644 index 0000000000000..d834ec5e0edd2 --- /dev/null +++ b/src/test/ui/issues/issue-76077.stderr @@ -0,0 +1,8 @@ +error: cannot construct `Foo` with struct literal syntax due to inaccessible fields + --> $DIR/issue-76077.rs:8:5 + | +LL | foo::Foo {}; + | ^^^^^^^^ + +error: aborting due to previous error + From 409c14197372495b26fa8ee9f4b812492a7fb75a Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 10 Sep 2020 12:32:45 +0100 Subject: [PATCH 0272/1052] typeck/pat: inaccessible private fields This commit adjusts the missing field diagnostic logic for struct patterns in typeck to improve the diagnostic when the missing fields are inaccessible. Signed-off-by: David Wood --- compiler/rustc_typeck/src/check/pat.rs | 90 ++++++++++++++++++++++--- src/test/ui/issues/issue-76077-1.fixed | 18 +++++ src/test/ui/issues/issue-76077-1.rs | 18 +++++ src/test/ui/issues/issue-76077-1.stderr | 24 +++++++ 4 files changed, 141 insertions(+), 9 deletions(-) create mode 100644 src/test/ui/issues/issue-76077-1.fixed create mode 100644 src/test/ui/issues/issue-76077-1.rs create mode 100644 src/test/ui/issues/issue-76077-1.stderr diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index f06929aa98ff4..1896155e327d8 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -1078,8 +1078,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut unmentioned_fields = variant .fields .iter() - .map(|field| field.ident.normalize_to_macros_2_0()) - .filter(|ident| !used_fields.contains_key(&ident)) + .map(|field| (field, field.ident.normalize_to_macros_2_0())) + .filter(|(_, ident)| !used_fields.contains_key(&ident)) .collect::>(); let inexistent_fields_err = if !(inexistent_fields.is_empty() || variant.is_recovered()) { @@ -1110,7 +1110,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit(); } } else if !etc && !unmentioned_fields.is_empty() { - unmentioned_err = Some(self.error_unmentioned_fields(pat, &unmentioned_fields)); + let no_accessible_unmentioned_fields = unmentioned_fields + .iter() + .filter(|(field, _)| { + field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx) + }) + .next() + .is_none(); + + if no_accessible_unmentioned_fields { + unmentioned_err = Some(self.error_no_accessible_fields(pat, &fields)); + } else { + unmentioned_err = Some(self.error_unmentioned_fields(pat, &unmentioned_fields)); + } } match (inexistent_fields_err, unmentioned_err) { (Some(mut i), Some(mut u)) => { @@ -1173,7 +1185,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, kind_name: &str, inexistent_fields: &[Ident], - unmentioned_fields: &mut Vec, + unmentioned_fields: &mut Vec<(&ty::FieldDef, Ident)>, variant: &ty::VariantDef, ) -> DiagnosticBuilder<'tcx> { let tcx = self.tcx; @@ -1215,7 +1227,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), ); if plural == "" { - let input = unmentioned_fields.iter().map(|field| &field.name); + let input = unmentioned_fields.iter().map(|(_, field)| &field.name); let suggested_name = find_best_match_for_name(input, ident.name, None); if let Some(suggested_name) = suggested_name { err.span_suggestion( @@ -1232,7 +1244,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `smart_resolve_context_dependent_help`. if suggested_name.to_ident_string().parse::().is_err() { // We don't want to throw `E0027` in case we have thrown `E0026` for them. - unmentioned_fields.retain(|&x| x.name != suggested_name); + unmentioned_fields.retain(|&(_, x)| x.name != suggested_name); } } } @@ -1300,17 +1312,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None } + /// Returns a diagnostic reporting a struct pattern which is missing an `..` due to + /// inaccessible fields. + /// + /// ```ignore (diagnostic) + /// error: pattern requires `..` due to inaccessible fields + /// --> src/main.rs:10:9 + /// | + /// LL | let foo::Foo {} = foo::Foo::default(); + /// | ^^^^^^^^^^^ + /// | + /// help: add a `..` + /// | + /// LL | let foo::Foo { .. } = foo::Foo::default(); + /// | ^^^^^^ + /// ``` + fn error_no_accessible_fields( + &self, + pat: &Pat<'_>, + fields: &'tcx [hir::FieldPat<'tcx>], + ) -> DiagnosticBuilder<'tcx> { + let mut err = self + .tcx + .sess + .struct_span_err(pat.span, "pattern requires `..` due to inaccessible fields"); + + if let Some(field) = fields.last() { + err.span_suggestion_verbose( + field.span.shrink_to_hi(), + "ignore the inaccessible and unused fields", + ", ..".to_string(), + Applicability::MachineApplicable, + ); + } else { + let qpath_span = if let PatKind::Struct(qpath, ..) = &pat.kind { + qpath.span() + } else { + bug!("`error_no_accessible_fields` called on non-struct pattern"); + }; + + // Shrink the span to exclude the `foo:Foo` in `foo::Foo { }`. + let span = pat.span.with_lo(qpath_span.shrink_to_hi().hi()); + err.span_suggestion_verbose( + span, + "ignore the inaccessible and unused fields", + " { .. }".to_string(), + Applicability::MachineApplicable, + ); + } + err + } + + /// Returns a diagnostic reporting a struct pattern which does not mention some fields. + /// + /// ```ignore (diagnostic) + /// error[E0027]: pattern does not mention field `you_cant_use_this_field` + /// --> src/main.rs:15:9 + /// | + /// LL | let foo::Foo {} = foo::Foo::new(); + /// | ^^^^^^^^^^^ missing field `you_cant_use_this_field` + /// ``` fn error_unmentioned_fields( &self, pat: &Pat<'_>, - unmentioned_fields: &[Ident], + unmentioned_fields: &[(&ty::FieldDef, Ident)], ) -> DiagnosticBuilder<'tcx> { let field_names = if unmentioned_fields.len() == 1 { - format!("field `{}`", unmentioned_fields[0]) + format!("field `{}`", unmentioned_fields[0].1) } else { let fields = unmentioned_fields .iter() - .map(|name| format!("`{}`", name)) + .map(|(_, name)| format!("`{}`", name)) .collect::>() .join(", "); format!("fields {}", fields) diff --git a/src/test/ui/issues/issue-76077-1.fixed b/src/test/ui/issues/issue-76077-1.fixed new file mode 100644 index 0000000000000..8103a7ca47d4e --- /dev/null +++ b/src/test/ui/issues/issue-76077-1.fixed @@ -0,0 +1,18 @@ +// run-rustfix +#![allow(dead_code, unused_variables)] + +pub mod foo { + #[derive(Default)] + pub struct Foo { invisible: bool, } + + #[derive(Default)] + pub struct Bar { pub visible: bool, invisible: bool, } +} + +fn main() { + let foo::Foo { .. } = foo::Foo::default(); + //~^ ERROR pattern requires `..` due to inaccessible fields + + let foo::Bar { visible, .. } = foo::Bar::default(); + //~^ ERROR pattern requires `..` due to inaccessible fields +} diff --git a/src/test/ui/issues/issue-76077-1.rs b/src/test/ui/issues/issue-76077-1.rs new file mode 100644 index 0000000000000..730332853c124 --- /dev/null +++ b/src/test/ui/issues/issue-76077-1.rs @@ -0,0 +1,18 @@ +// run-rustfix +#![allow(dead_code, unused_variables)] + +pub mod foo { + #[derive(Default)] + pub struct Foo { invisible: bool, } + + #[derive(Default)] + pub struct Bar { pub visible: bool, invisible: bool, } +} + +fn main() { + let foo::Foo {} = foo::Foo::default(); + //~^ ERROR pattern requires `..` due to inaccessible fields + + let foo::Bar { visible } = foo::Bar::default(); + //~^ ERROR pattern requires `..` due to inaccessible fields +} diff --git a/src/test/ui/issues/issue-76077-1.stderr b/src/test/ui/issues/issue-76077-1.stderr new file mode 100644 index 0000000000000..4557595529fa2 --- /dev/null +++ b/src/test/ui/issues/issue-76077-1.stderr @@ -0,0 +1,24 @@ +error: pattern requires `..` due to inaccessible fields + --> $DIR/issue-76077-1.rs:13:9 + | +LL | let foo::Foo {} = foo::Foo::default(); + | ^^^^^^^^^^^ + | +help: ignore the inaccessible and unused fields + | +LL | let foo::Foo { .. } = foo::Foo::default(); + | ^^^^^^ + +error: pattern requires `..` due to inaccessible fields + --> $DIR/issue-76077-1.rs:16:9 + | +LL | let foo::Bar { visible } = foo::Bar::default(); + | ^^^^^^^^^^^^^^^^^^^^ + | +help: ignore the inaccessible and unused fields + | +LL | let foo::Bar { visible, .. } = foo::Bar::default(); + | ^^^^ + +error: aborting due to 2 previous errors + From 283d4c4d148c8c53a8b197c4ff0a9f79a1690eb2 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 10 Sep 2020 16:20:05 -0400 Subject: [PATCH 0273/1052] Ignore `|` and `+` tokens during proc-macro pretty-print check Fixes #76182 This is an alternative to PR #76188 These tokens are not preserved in the AST in certain cases (e.g. a leading `|` in a pattern or a trailing `+` in a trait bound). This PR ignores them entirely during the pretty-print/reparse check to avoid spuriously using the re-parsed tokenstream. --- compiler/rustc_parse/src/lib.rs | 6 ++ .../issue-76182-leading-vert-pat.rs | 16 +++++ .../issue-76182-leading-vert-pat.stdout | 62 +++++++++++++++++++ src/test/ui/proc-macro/trailing-plus.rs | 14 +++++ src/test/ui/proc-macro/trailing-plus.stdout | 57 +++++++++++++++++ 5 files changed, 155 insertions(+) create mode 100644 src/test/ui/proc-macro/issue-76182-leading-vert-pat.rs create mode 100644 src/test/ui/proc-macro/issue-76182-leading-vert-pat.stdout create mode 100644 src/test/ui/proc-macro/trailing-plus.rs create mode 100644 src/test/ui/proc-macro/trailing-plus.stdout diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index e7fd74f551aaa..0f6a111ad7018 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -353,6 +353,12 @@ pub fn tokenstream_probably_equal_for_proc_macro( | token::CloseDelim(DelimToken::NoDelim) // The pretty printer collapses many semicolons into one. | token::Semi + // We don't preserve leading `|` tokens in patterns, so + // we ignore them entirely + | token::BinOp(token::BinOpToken::Or) + // We don't preserve trailing '+' tokens in trait bounds, + // so we ignore them entirely + | token::BinOp(token::BinOpToken::Plus) // The pretty printer can turn `$crate` into `::crate_name` | token::ModSep = token.kind { return false; diff --git a/src/test/ui/proc-macro/issue-76182-leading-vert-pat.rs b/src/test/ui/proc-macro/issue-76182-leading-vert-pat.rs new file mode 100644 index 0000000000000..7d31de1d22df2 --- /dev/null +++ b/src/test/ui/proc-macro/issue-76182-leading-vert-pat.rs @@ -0,0 +1,16 @@ +// check-pass +// aux-build:test-macros.rs +// compile-flags: -Z span-debug +// +// Regression test for issue #76182 +// Tests that we properly handle patterns with a leading vert + +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; + +extern crate test_macros; + +#[test_macros::print_attr] +fn main() { + match () { | () => () } +} diff --git a/src/test/ui/proc-macro/issue-76182-leading-vert-pat.stdout b/src/test/ui/proc-macro/issue-76182-leading-vert-pat.stdout new file mode 100644 index 0000000000000..5493f9c7b606b --- /dev/null +++ b/src/test/ui/proc-macro/issue-76182-leading-vert-pat.stdout @@ -0,0 +1,62 @@ +PRINT-ATTR INPUT (DISPLAY): fn main() { match() { | () => () } } +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Ident { + ident: "fn", + span: $DIR/issue-76182-leading-vert-pat.rs:14:1: 14:3 (#0), + }, + Ident { + ident: "main", + span: $DIR/issue-76182-leading-vert-pat.rs:14:4: 14:8 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-76182-leading-vert-pat.rs:14:8: 14:10 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Ident { + ident: "match", + span: $DIR/issue-76182-leading-vert-pat.rs:15:5: 15:10 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-76182-leading-vert-pat.rs:15:11: 15:13 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '|', + spacing: Alone, + span: $DIR/issue-76182-leading-vert-pat.rs:15:16: 15:17 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-76182-leading-vert-pat.rs:15:18: 15:20 (#0), + }, + Punct { + ch: '=', + spacing: Joint, + span: $DIR/issue-76182-leading-vert-pat.rs:15:21: 15:23 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/issue-76182-leading-vert-pat.rs:15:21: 15:23 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-76182-leading-vert-pat.rs:15:24: 15:26 (#0), + }, + ], + span: $DIR/issue-76182-leading-vert-pat.rs:15:14: 15:28 (#0), + }, + ], + span: $DIR/issue-76182-leading-vert-pat.rs:14:11: 16:2 (#0), + }, +] diff --git a/src/test/ui/proc-macro/trailing-plus.rs b/src/test/ui/proc-macro/trailing-plus.rs new file mode 100644 index 0000000000000..4f61de47d8545 --- /dev/null +++ b/src/test/ui/proc-macro/trailing-plus.rs @@ -0,0 +1,14 @@ +// check-pass +// aux-build:test-macros.rs +// compile-flags: -Z span-debug + +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; + +extern crate test_macros; + +#[test_macros::print_attr] +fn foo() where T: Copy + { +} + +fn main() {} diff --git a/src/test/ui/proc-macro/trailing-plus.stdout b/src/test/ui/proc-macro/trailing-plus.stdout new file mode 100644 index 0000000000000..d60f400af2bb9 --- /dev/null +++ b/src/test/ui/proc-macro/trailing-plus.stdout @@ -0,0 +1,57 @@ +PRINT-ATTR INPUT (DISPLAY): fn foo < T > () where T : Copy + { } +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Ident { + ident: "fn", + span: $DIR/trailing-plus.rs:11:1: 11:3 (#0), + }, + Ident { + ident: "foo", + span: $DIR/trailing-plus.rs:11:4: 11:7 (#0), + }, + Punct { + ch: '<', + spacing: Alone, + span: $DIR/trailing-plus.rs:11:7: 11:8 (#0), + }, + Ident { + ident: "T", + span: $DIR/trailing-plus.rs:11:8: 11:9 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/trailing-plus.rs:11:9: 11:10 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/trailing-plus.rs:11:10: 11:12 (#0), + }, + Ident { + ident: "where", + span: $DIR/trailing-plus.rs:11:13: 11:18 (#0), + }, + Ident { + ident: "T", + span: $DIR/trailing-plus.rs:11:19: 11:20 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/trailing-plus.rs:11:20: 11:21 (#0), + }, + Ident { + ident: "Copy", + span: $DIR/trailing-plus.rs:11:22: 11:26 (#0), + }, + Punct { + ch: '+', + spacing: Alone, + span: $DIR/trailing-plus.rs:11:27: 11:28 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/trailing-plus.rs:11:29: 12:2 (#0), + }, +] From de4bd9f0f8aeb4b89e55ba33b755c9a93e999e1c Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 21 Aug 2020 17:52:52 -0400 Subject: [PATCH 0274/1052] Attach `TokenStream` to `ast::Block` A `Block` does not have outer attributes, so we only capture tokens when parsing a `macro_rules!` matcher --- compiler/rustc_ast/src/ast.rs | 1 + compiler/rustc_ast/src/mut_visit.rs | 2 +- compiler/rustc_builtin_macros/src/deriving/mod.rs | 1 + compiler/rustc_expand/src/build.rs | 8 +++++++- compiler/rustc_interface/src/util.rs | 1 + compiler/rustc_parse/src/lib.rs | 1 + compiler/rustc_parse/src/parser/nonterminal.rs | 9 ++++++++- compiler/rustc_parse/src/parser/stmt.rs | 2 +- 8 files changed, 21 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index b9f380dc4e835..8fbf5ccf5acc9 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -540,6 +540,7 @@ pub struct Block { /// Distinguishes between `unsafe { ... }` and `{ ... }`. pub rules: BlockCheckMode, pub span: Span, + pub tokens: Option, } /// A match pattern. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 3119c5e0a12fa..3e86528fcefe8 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -871,7 +871,7 @@ pub fn noop_visit_mt(MutTy { ty, mutbl: _ }: &mut MutTy, vis: &mu } pub fn noop_visit_block(block: &mut P, vis: &mut T) { - let Block { id, stmts, rules: _, span } = block.deref_mut(); + let Block { id, stmts, rules: _, span, tokens: _ } = block.deref_mut(); vis.visit_id(id); stmts.flat_map_in_place(|stmt| vis.flat_map_stmt(stmt)); vis.visit_span(span); diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index 7e3fd131d4417..9c8e0fc2f016c 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -75,6 +75,7 @@ fn call_intrinsic( id: ast::DUMMY_NODE_ID, rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated), span, + tokens: None, })) } diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 9490b62aa1797..717c4e9406c99 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -207,7 +207,13 @@ impl<'a> ExtCtxt<'a> { ) } pub fn block(&self, span: Span, stmts: Vec) -> P { - P(ast::Block { stmts, id: ast::DUMMY_NODE_ID, rules: BlockCheckMode::Default, span }) + P(ast::Block { + stmts, + id: ast::DUMMY_NODE_ID, + rules: BlockCheckMode::Default, + span, + tokens: None, + }) } pub fn expr(&self, span: Span, kind: ast::ExprKind) -> P { diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index b1b39fd1ad299..01441cafe8a93 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -693,6 +693,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { rules, id: resolver.next_node_id(), span: rustc_span::DUMMY_SP, + tokens: None, } } diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 12afc48356cce..65ded67dcf616 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -268,6 +268,7 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke Nonterminal::NtItem(ref item) => { prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span) } + Nonterminal::NtBlock(ref block) => block.tokens.clone(), Nonterminal::NtPat(ref pat) => pat.tokens.clone(), Nonterminal::NtIdent(ident, is_raw) => { Some(tokenstream::TokenTree::token(token::Ident(ident.name, is_raw), ident.span).into()) diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index f40cd1131d260..47ed98b85994e 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -111,7 +111,14 @@ impl<'a> Parser<'a> { return Err(self.struct_span_err(self.token.span, "expected an item keyword")); } }, - NonterminalKind::Block => token::NtBlock(self.parse_block()?), + NonterminalKind::Block => { + let (mut block, tokens) = self.collect_tokens(|this| this.parse_block())?; + // We have have eaten an NtBlock, which could already have tokens + if block.tokens.is_none() { + block.tokens = Some(tokens); + } + token::NtBlock(block) + } NonterminalKind::Stmt => match self.parse_stmt()? { Some(s) => token::NtStmt(s), None => return Err(self.struct_span_err(self.token.span, "expected a statement")), diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 947ca6b5bd562..6cc42487684bd 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -411,7 +411,7 @@ impl<'a> Parser<'a> { } pub(super) fn mk_block(&self, stmts: Vec, rules: BlockCheckMode, span: Span) -> P { - P(Block { stmts, id: DUMMY_NODE_ID, rules, span }) + P(Block { stmts, id: DUMMY_NODE_ID, rules, span, tokens: None }) } pub(super) fn mk_stmt(&self, span: Span, kind: StmtKind) -> Stmt { From 1823dea7df9e125022dfda8126b6713f142f0e73 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 21 Aug 2020 18:18:04 -0400 Subject: [PATCH 0275/1052] Attach `TokenStream` to `ast::Ty` A `Ty` does not have outer attributes, so we only capture tokens when parsing a `macro_rules!` matcher --- compiler/rustc_ast/src/ast.rs | 8 +++++--- compiler/rustc_ast/src/mut_visit.rs | 2 +- compiler/rustc_ast_lowering/src/lib.rs | 1 + compiler/rustc_builtin_macros/src/concat_idents.rs | 1 + compiler/rustc_expand/src/base.rs | 1 + compiler/rustc_expand/src/build.rs | 2 +- compiler/rustc_expand/src/placeholders.rs | 12 ++++++++---- compiler/rustc_parse/src/lib.rs | 1 + compiler/rustc_parse/src/parser/diagnostics.rs | 9 +++++++-- compiler/rustc_parse/src/parser/item.rs | 9 +++++++-- compiler/rustc_parse/src/parser/nonterminal.rs | 9 ++++++++- compiler/rustc_parse/src/parser/ty.rs | 2 +- 12 files changed, 42 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 8fbf5ccf5acc9..e55a5b6b9a2d3 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -587,7 +587,7 @@ impl Pat { _ => return None, }; - Some(P(Ty { kind, id: self.id, span: self.span })) + Some(P(Ty { kind, id: self.id, span: self.span, tokens: None })) } /// Walk top-down and call `it` in each place where a pattern occurs @@ -1169,7 +1169,7 @@ impl Expr { _ => return None, }; - Some(P(Ty { kind, id: self.id, span: self.span })) + Some(P(Ty { kind, id: self.id, span: self.span, tokens: None })) } pub fn precedence(&self) -> ExprPrecedence { @@ -1867,6 +1867,7 @@ pub struct Ty { pub id: NodeId, pub kind: TyKind, pub span: Span, + pub tokens: Option, } #[derive(Clone, Encodable, Decodable, Debug)] @@ -2145,7 +2146,7 @@ impl Param { /// Builds a `Param` object from `ExplicitSelf`. pub fn from_self(attrs: AttrVec, eself: ExplicitSelf, eself_ident: Ident) -> Param { let span = eself.span.to(eself_ident.span); - let infer_ty = P(Ty { id: DUMMY_NODE_ID, kind: TyKind::ImplicitSelf, span }); + let infer_ty = P(Ty { id: DUMMY_NODE_ID, kind: TyKind::ImplicitSelf, span, tokens: None }); let param = |mutbl, ty| Param { attrs, pat: P(Pat { @@ -2168,6 +2169,7 @@ impl Param { id: DUMMY_NODE_ID, kind: TyKind::Rptr(lt, MutTy { ty: infer_ty, mutbl }), span, + tokens: None, }), ), } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 3e86528fcefe8..ce2bc75fdab85 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -451,7 +451,7 @@ pub fn noop_visit_ty_constraint( } pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { - let Ty { id, kind, span } = ty.deref_mut(); + let Ty { id, kind, span, tokens: _ } = ty.deref_mut(); vis.visit_id(id); match kind { TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err | TyKind::Never | TyKind::CVarArgs => {} diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 586355fe6136e..20f3d55157138 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1106,6 +1106,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { id: node_id, kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()), span: constraint.span, + tokens: None, }, itctx, ); diff --git a/compiler/rustc_builtin_macros/src/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs index 8223cdda07231..c4d1c6eee31c4 100644 --- a/compiler/rustc_builtin_macros/src/concat_idents.rs +++ b/compiler/rustc_builtin_macros/src/concat_idents.rs @@ -61,6 +61,7 @@ pub fn expand_concat_idents<'cx>( id: ast::DUMMY_NODE_ID, kind: ast::TyKind::Path(None, ast::Path::from_ident(self.ident)), span: self.ident.span, + tokens: None, })) } } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 4c01cb8159a30..5bdc4760dcc31 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -607,6 +607,7 @@ impl DummyResult { id: ast::DUMMY_NODE_ID, kind: if is_error { ast::TyKind::Err } else { ast::TyKind::Tup(Vec::new()) }, span: sp, + tokens: None, }) } } diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 717c4e9406c99..c57719d67163c 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -54,7 +54,7 @@ impl<'a> ExtCtxt<'a> { } pub fn ty(&self, span: Span, kind: ast::TyKind) -> P { - P(ast::Ty { id: ast::DUMMY_NODE_ID, span, kind }) + P(ast::Ty { id: ast::DUMMY_NODE_ID, span, kind, tokens: None }) } pub fn ty_path(&self, path: ast::Path) -> P { diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index dbd2e70af6a7a..f642558d5e07a 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -37,7 +37,8 @@ pub fn placeholder( tokens: None, }) }; - let ty = || P(ast::Ty { id, kind: ast::TyKind::MacCall(mac_placeholder()), span }); + let ty = + || P(ast::Ty { id, kind: ast::TyKind::MacCall(mac_placeholder()), span, tokens: None }); let pat = || P(ast::Pat { id, kind: ast::PatKind::MacCall(mac_placeholder()), span, tokens: None }); @@ -88,9 +89,12 @@ pub fn placeholder( kind: ast::PatKind::MacCall(mac_placeholder()), tokens: None, })), - AstFragmentKind::Ty => { - AstFragment::Ty(P(ast::Ty { id, span, kind: ast::TyKind::MacCall(mac_placeholder()) })) - } + AstFragmentKind::Ty => AstFragment::Ty(P(ast::Ty { + id, + span, + kind: ast::TyKind::MacCall(mac_placeholder()), + tokens: None, + })), AstFragmentKind::Stmts => AstFragment::Stmts(smallvec![{ let mac = P(ast::MacCallStmt { mac: mac_placeholder(), diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 65ded67dcf616..19b9c99832025 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -270,6 +270,7 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke } Nonterminal::NtBlock(ref block) => block.tokens.clone(), Nonterminal::NtPat(ref pat) => pat.tokens.clone(), + Nonterminal::NtTy(ref ty) => ty.tokens.clone(), Nonterminal::NtIdent(ident, is_raw) => { Some(tokenstream::TokenTree::token(token::Ident(ident.name, is_raw), ident.span).into()) } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 12efe391fb964..364c859147ac5 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -28,7 +28,7 @@ pub(super) fn dummy_arg(ident: Ident) -> Param { span: ident.span, tokens: None, }); - let ty = Ty { kind: TyKind::Err, span: ident.span, id: ast::DUMMY_NODE_ID }; + let ty = Ty { kind: TyKind::Err, span: ident.span, id: ast::DUMMY_NODE_ID, tokens: None }; Param { attrs: AttrVec::default(), id: ast::DUMMY_NODE_ID, @@ -75,7 +75,12 @@ impl RecoverQPath for Ty { Some(P(self.clone())) } fn recovered(qself: Option, path: ast::Path) -> Self { - Self { span: path.span, kind: TyKind::Path(qself, path), id: ast::DUMMY_NODE_ID } + Self { + span: path.span, + kind: TyKind::Path(qself, path), + id: ast::DUMMY_NODE_ID, + tokens: None, + } } } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 1a428f8bb0ab5..1c4bb4532ebb4 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -510,7 +510,12 @@ impl<'a> Parser<'a> { { let span = self.prev_token.span.between(self.token.span); self.struct_span_err(span, "missing trait in a trait impl").emit(); - P(Ty { kind: TyKind::Path(None, err_path(span)), span, id: DUMMY_NODE_ID }) + P(Ty { + kind: TyKind::Path(None, err_path(span)), + span, + id: DUMMY_NODE_ID, + tokens: None, + }) } else { self.parse_ty()? }; @@ -1046,7 +1051,7 @@ impl<'a> Parser<'a> { // The user intended that the type be inferred, // so treat this as if the user wrote e.g. `const A: _ = expr;`. - P(Ty { kind: TyKind::Infer, span: id.span, id: ast::DUMMY_NODE_ID }) + P(Ty { kind: TyKind::Infer, span: id.span, id: ast::DUMMY_NODE_ID, tokens: None }) } /// Parses an enum declaration. diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 47ed98b85994e..d70fa53285007 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -141,7 +141,14 @@ impl<'a> Parser<'a> { token::NtExpr(expr) } NonterminalKind::Literal => token::NtLiteral(self.parse_literal_maybe_minus()?), - NonterminalKind::Ty => token::NtTy(self.parse_ty()?), + NonterminalKind::Ty => { + let (mut ty, tokens) = self.collect_tokens(|this| this.parse_ty())?; + // We have an eaten an NtTy, which could already have tokens + if ty.tokens.is_none() { + ty.tokens = Some(tokens); + } + token::NtTy(ty) + } // this could be handled like a token, since it is one NonterminalKind::Ident => { if let Some((ident, is_raw)) = get_macro_ident(&self.token) { diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 4356850818ee8..259764a317df8 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -626,6 +626,6 @@ impl<'a> Parser<'a> { } pub(super) fn mk_ty(&self, span: Span, kind: TyKind) -> P { - P(Ty { kind, span, id: ast::DUMMY_NODE_ID }) + P(Ty { kind, span, id: ast::DUMMY_NODE_ID, tokens: None }) } } From d5a04a9927d1685d63f1d59039ea7dd03ee090a5 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 21 Aug 2020 18:28:47 -0400 Subject: [PATCH 0276/1052] Collect tokens when handling `:literal` matcher An `NtLiteral` just wraps an `Expr`, so we don't need to add a new `tokens` field to an AST struct. --- compiler/rustc_parse/src/lib.rs | 2 +- compiler/rustc_parse/src/parser/nonterminal.rs | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 19b9c99832025..df9b87fe7d13e 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -278,7 +278,7 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke Some(tokenstream::TokenTree::token(token::Lifetime(ident.name), ident.span).into()) } Nonterminal::NtTT(ref tt) => Some(tt.clone().into()), - Nonterminal::NtExpr(ref expr) => { + Nonterminal::NtExpr(ref expr) | Nonterminal::NtLiteral(ref expr) => { if expr.tokens.is_none() { debug!("missing tokens for expr {:?}", expr); } diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index d70fa53285007..516c2c7721375 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -140,7 +140,15 @@ impl<'a> Parser<'a> { } token::NtExpr(expr) } - NonterminalKind::Literal => token::NtLiteral(self.parse_literal_maybe_minus()?), + NonterminalKind::Literal => { + let (mut lit, tokens) = + self.collect_tokens(|this| this.parse_literal_maybe_minus())?; + // We have have eaten a nonterminal, which could already have tokens + if lit.tokens.is_none() { + lit.tokens = Some(tokens); + } + token::NtLiteral(lit) + } NonterminalKind::Ty => { let (mut ty, tokens) = self.collect_tokens(|this| this.parse_ty())?; // We have an eaten an NtTy, which could already have tokens From 3815e91ccd8c7c8ed564476425bca6f1dc5e9607 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 21 Aug 2020 18:37:34 -0400 Subject: [PATCH 0277/1052] Attach tokens to `NtMeta` (`ast::AttrItem`) An `AttrItem` does not have outer attributes, so we only capture tokens when parsing a `macro_rules!` matcher --- compiler/rustc_ast/src/ast.rs | 1 + compiler/rustc_ast/src/attr/mod.rs | 2 +- compiler/rustc_ast/src/mut_visit.rs | 4 ++-- compiler/rustc_ast_lowering/src/lib.rs | 1 + compiler/rustc_builtin_macros/src/cmdline_attrs.rs | 2 +- compiler/rustc_expand/src/expand.rs | 1 + compiler/rustc_parse/src/lib.rs | 1 + compiler/rustc_parse/src/parser/attr.rs | 2 +- compiler/rustc_parse/src/parser/nonterminal.rs | 9 ++++++++- 9 files changed, 17 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e55a5b6b9a2d3..6db84f0dbd398 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2419,6 +2419,7 @@ impl rustc_serialize::Decodable for AttrId { pub struct AttrItem { pub path: Path, pub args: MacArgs, + pub tokens: Option, } /// A list of attributes. diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index d819e3cb8152e..33bd93352316a 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -330,7 +330,7 @@ crate fn mk_attr_id() -> AttrId { } pub fn mk_attr(style: AttrStyle, path: Path, args: MacArgs, span: Span) -> Attribute { - mk_attr_from_item(style, AttrItem { path, args }, span) + mk_attr_from_item(style, AttrItem { path, args, tokens: None }, span) } pub fn mk_attr_from_item(style: AttrStyle, item: AttrItem, span: Span) -> Attribute { diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index ce2bc75fdab85..3ba8ff65ee514 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -579,7 +579,7 @@ pub fn noop_visit_local(local: &mut P, vis: &mut T) { pub fn noop_visit_attribute(attr: &mut Attribute, vis: &mut T) { let Attribute { kind, id: _, style: _, span } = attr; match kind { - AttrKind::Normal(AttrItem { path, args }) => { + AttrKind::Normal(AttrItem { path, args, tokens: _ }) => { vis.visit_path(path); visit_mac_args(args, vis); } @@ -709,7 +709,7 @@ pub fn noop_visit_interpolated(nt: &mut token::Nonterminal, vis: token::NtLifetime(ident) => vis.visit_ident(ident), token::NtLiteral(expr) => vis.visit_expr(expr), token::NtMeta(item) => { - let AttrItem { path, args } = item.deref_mut(); + let AttrItem { path, args, tokens: _ } = item.deref_mut(); vis.visit_path(path); visit_mac_args(args, vis); } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 20f3d55157138..a28d022c66139 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -967,6 +967,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { AttrKind::Normal(ref item) => AttrKind::Normal(AttrItem { path: item.path.clone(), args: self.lower_mac_args(&item.args), + tokens: None, }), AttrKind::DocComment(comment_kind, data) => AttrKind::DocComment(comment_kind, data), }; diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs index 34e2accc61541..5ed8b69d92ab7 100644 --- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs +++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs @@ -15,7 +15,7 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) - ); let start_span = parser.token.span; - let AttrItem { path, args } = match parser.parse_attr_item() { + let AttrItem { path, args, tokens: _ } = match parser.parse_attr_item() { Ok(ai) => ai, Err(mut err) => { err.emit(); diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 241566a042a0e..98faa8a0a0f1b 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1777,6 +1777,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { kind: ast::AttrKind::Normal(AttrItem { path: meta.path, args: meta.kind.mac_args(meta.span), + tokens: None, }), span: at.span, id: at.id, diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index df9b87fe7d13e..bf954783d8273 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -277,6 +277,7 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke Nonterminal::NtLifetime(ident) => { Some(tokenstream::TokenTree::token(token::Lifetime(ident.name), ident.span).into()) } + Nonterminal::NtMeta(ref attr) => attr.tokens.clone(), Nonterminal::NtTT(ref tt) => Some(tt.clone().into()), Nonterminal::NtExpr(ref expr) | Nonterminal::NtLiteral(ref expr) => { if expr.tokens.is_none() { diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 4e4429e461f0f..98f94098bfc15 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -162,7 +162,7 @@ impl<'a> Parser<'a> { } else { let path = self.parse_path(PathStyle::Mod)?; let args = self.parse_attr_args()?; - ast::AttrItem { path, args } + ast::AttrItem { path, args, tokens: None } }) } diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 516c2c7721375..8717f4b92451e 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -169,7 +169,14 @@ impl<'a> Parser<'a> { } } NonterminalKind::Path => token::NtPath(self.parse_path(PathStyle::Type)?), - NonterminalKind::Meta => token::NtMeta(P(self.parse_attr_item()?)), + NonterminalKind::Meta => { + let (mut attr, tokens) = self.collect_tokens(|this| this.parse_attr_item())?; + // We may have eaten a nonterminal, which could already have tokens + if attr.tokens.is_none() { + attr.tokens = Some(tokens); + } + token::NtMeta(P(attr)) + } NonterminalKind::TT => token::NtTT(self.parse_token_tree()), NonterminalKind::Vis => token::NtVis(self.parse_visibility(FollowedByType::Yes)?), NonterminalKind::Lifetime => { From 55082ce41334d9685d619182e71b84b495a6aff8 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 21 Aug 2020 18:51:23 -0400 Subject: [PATCH 0278/1052] Attach `TokenStream` to `ast::Path` --- compiler/rustc_ast/src/ast.rs | 5 +++-- compiler/rustc_ast/src/attr/mod.rs | 2 +- compiler/rustc_ast/src/mut_visit.rs | 2 +- compiler/rustc_ast_lowering/src/item.rs | 13 ++++++++----- compiler/rustc_expand/src/build.rs | 2 +- compiler/rustc_expand/src/placeholders.rs | 2 +- compiler/rustc_parse/src/lib.rs | 1 + compiler/rustc_parse/src/parser/diagnostics.rs | 2 +- compiler/rustc_parse/src/parser/item.rs | 2 +- compiler/rustc_parse/src/parser/nonterminal.rs | 10 +++++++++- compiler/rustc_parse/src/parser/path.rs | 9 ++++++--- compiler/rustc_resolve/src/diagnostics.rs | 2 +- compiler/rustc_resolve/src/late.rs | 2 +- compiler/rustc_resolve/src/late/diagnostics.rs | 6 ++++-- compiler/rustc_resolve/src/lib.rs | 2 ++ 15 files changed, 41 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 6db84f0dbd398..80c8cdf703cf3 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -96,6 +96,7 @@ pub struct Path { /// The segments in the path: the things separated by `::`. /// Global paths begin with `kw::PathRoot`. pub segments: Vec, + pub tokens: Option, } impl PartialEq for Path { @@ -117,7 +118,7 @@ impl Path { // Convert a span and an identifier to the corresponding // one-segment path. pub fn from_ident(ident: Ident) -> Path { - Path { segments: vec![PathSegment::from_ident(ident)], span: ident.span } + Path { segments: vec![PathSegment::from_ident(ident)], span: ident.span, tokens: None } } pub fn is_global(&self) -> bool { @@ -1069,7 +1070,7 @@ pub struct Expr { // `Expr` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -rustc_data_structures::static_assert_size!(Expr, 104); +rustc_data_structures::static_assert_size!(Expr, 112); impl Expr { /// Returns `true` if this expression would be valid somewhere that expects a value; diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 33bd93352316a..2782869fb885a 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -415,7 +415,7 @@ impl MetaItem { } } let span = span.with_hi(segments.last().unwrap().ident.span.hi()); - Path { span, segments } + Path { span, segments, tokens: None } } Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. })) => match *nt { token::Nonterminal::NtMeta(ref item) => return item.meta(item.path.span), diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 3ba8ff65ee514..f6ac134bb1671 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -513,7 +513,7 @@ pub fn noop_visit_ident(Ident { name: _, span }: &mut Ident, vis: vis.visit_span(span); } -pub fn noop_visit_path(Path { segments, span }: &mut Path, vis: &mut T) { +pub fn noop_visit_path(Path { segments, span, tokens: _ }: &mut Path, vis: &mut T) { vis.visit_span(span); for PathSegment { ident, id, args } in segments { vis.visit_ident(ident); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index f3309afec7d6b..6a3b9c22597ae 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -251,7 +251,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::ExternCrate(orig_name) => hir::ItemKind::ExternCrate(orig_name), ItemKind::Use(ref use_tree) => { // Start with an empty prefix. - let prefix = Path { segments: vec![], span: use_tree.span }; + let prefix = Path { segments: vec![], span: use_tree.span, tokens: None }; self.lower_use_tree(use_tree, &prefix, id, vis, ident, attrs) } @@ -488,7 +488,7 @@ impl<'hir> LoweringContext<'_, 'hir> { *ident = tree.ident(); // First, apply the prefix to the path. - let mut path = Path { segments, span: path.span }; + let mut path = Path { segments, span: path.span, tokens: None }; // Correctly resolve `self` imports. if path.segments.len() > 1 @@ -540,8 +540,11 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ItemKind::Use(path, hir::UseKind::Single) } UseTreeKind::Glob => { - let path = - self.lower_path(id, &Path { segments, span: path.span }, ParamMode::Explicit); + let path = self.lower_path( + id, + &Path { segments, span: path.span, tokens: None }, + ParamMode::Explicit, + ); hir::ItemKind::Use(path, hir::UseKind::Glob) } UseTreeKind::Nested(ref trees) => { @@ -569,7 +572,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // for that we return the `{}` import (called the // `ListStem`). - let prefix = Path { segments, span: prefix.span.to(path.span) }; + let prefix = Path { segments, span: prefix.span.to(path.span), tokens: None }; // Add all the nested `PathListItem`s to the HIR. for &(ref use_tree, id) in trees { diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index c57719d67163c..0fcffe77d45d3 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -46,7 +46,7 @@ impl<'a> ExtCtxt<'a> { id: ast::DUMMY_NODE_ID, args, }); - ast::Path { span, segments } + ast::Path { span, segments, tokens: None } } pub fn ty_mt(&self, ty: P, mutbl: ast::Mutability) -> ast::MutTy { diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index f642558d5e07a..530e67a134a35 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -18,7 +18,7 @@ pub fn placeholder( ) -> AstFragment { fn mac_placeholder() -> ast::MacCall { ast::MacCall { - path: ast::Path { span: DUMMY_SP, segments: Vec::new() }, + path: ast::Path { span: DUMMY_SP, segments: Vec::new(), tokens: None }, args: P(ast::MacArgs::Empty), prior_type_ascription: None, } diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index bf954783d8273..69f63feac78ee 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -278,6 +278,7 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke Some(tokenstream::TokenTree::token(token::Lifetime(ident.name), ident.span).into()) } Nonterminal::NtMeta(ref attr) => attr.tokens.clone(), + Nonterminal::NtPath(ref path) => path.tokens.clone(), Nonterminal::NtTT(ref tt) => Some(tt.clone().into()), Nonterminal::NtExpr(ref expr) | Nonterminal::NtLiteral(ref expr) => { if expr.tokens.is_none() { diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 364c859147ac5..e2a735188f95c 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -901,7 +901,7 @@ impl<'a> Parser<'a> { ) -> PResult<'a, P> { self.expect(&token::ModSep)?; - let mut path = ast::Path { segments: Vec::new(), span: DUMMY_SP }; + let mut path = ast::Path { segments: Vec::new(), span: DUMMY_SP, tokens: None }; self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?; path.span = ty_span.to(self.prev_token.span); diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 1c4bb4532ebb4..6d90d1128227a 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -787,7 +787,7 @@ impl<'a> Parser<'a> { fn parse_use_tree(&mut self) -> PResult<'a, UseTree> { let lo = self.token.span; - let mut prefix = ast::Path { segments: Vec::new(), span: lo.shrink_to_lo() }; + let mut prefix = ast::Path { segments: Vec::new(), span: lo.shrink_to_lo(), tokens: None }; let kind = if self.check(&token::OpenDelim(token::Brace)) || self.check(&token::BinOp(token::Star)) || self.is_import_coupler() diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 8717f4b92451e..84e887e74a7a4 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -168,7 +168,15 @@ impl<'a> Parser<'a> { return Err(self.struct_span_err(self.token.span, msg)); } } - NonterminalKind::Path => token::NtPath(self.parse_path(PathStyle::Type)?), + NonterminalKind::Path => { + let (mut path, tokens) = + self.collect_tokens(|this| this.parse_path(PathStyle::Type))?; + // We have have eaten an NtPath, which could already have tokens + if path.tokens.is_none() { + path.tokens = Some(tokens); + } + token::NtPath(path) + } NonterminalKind::Meta => { let (mut attr, tokens) = self.collect_tokens(|this| this.parse_attr_item())?; // We may have eaten a nonterminal, which could already have tokens diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 54b4df8613f70..66ce015d02e4c 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -64,7 +64,7 @@ impl<'a> Parser<'a> { path_span = path_lo.to(self.prev_token.span); } else { path_span = self.token.span.to(self.token.span); - path = ast::Path { segments: Vec::new(), span: path_span }; + path = ast::Path { segments: Vec::new(), span: path_span, tokens: None }; } // See doc comment for `unmatched_angle_bracket_count`. @@ -81,7 +81,10 @@ impl<'a> Parser<'a> { let qself = QSelf { ty, path_span, position: path.segments.len() }; self.parse_path_segments(&mut path.segments, style)?; - Ok((qself, Path { segments: path.segments, span: lo.to(self.prev_token.span) })) + Ok(( + qself, + Path { segments: path.segments, span: lo.to(self.prev_token.span), tokens: None }, + )) } /// Recover from an invalid single colon, when the user likely meant a qualified path. @@ -144,7 +147,7 @@ impl<'a> Parser<'a> { } self.parse_path_segments(&mut segments, style)?; - Ok(Path { segments, span: lo.to(self.prev_token.span) }) + Ok(Path { segments, span: lo.to(self.prev_token.span), tokens: None }) } pub(super) fn parse_path_segments( diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 48e1068b8daad..7a0503d68f348 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -794,7 +794,7 @@ impl<'a> Resolver<'a> { } segms.push(ast::PathSegment::from_ident(ident)); - let path = Path { span: name_binding.span, segments: segms }; + let path = Path { span: name_binding.span, segments: segms, tokens: None }; let did = match res { Res::Def(DefKind::Ctor(..), did) => this.parent(did), _ => res.opt_def_id(), diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 2b2123e295d09..dda084214b8f4 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1967,7 +1967,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { if qself.is_none() { let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident); - let path = Path { segments: path.iter().map(path_seg).collect(), span }; + let path = Path { segments: path.iter().map(path_seg).collect(), span, tokens: None }; if let Ok((_, res)) = self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false) { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index a10754f2c0c78..9f631705b2bf8 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -83,6 +83,7 @@ fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, Str let enum_path = ast::Path { span: suggestion.path.span, segments: suggestion.path.segments[0..path_len - 1].to_vec(), + tokens: None, }; let enum_path_string = path_names_to_string(&enum_path); @@ -1065,7 +1066,8 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { path_segments.push(ast::PathSegment::from_ident(ident)); let module_def_id = module.def_id().unwrap(); if module_def_id == def_id { - let path = Path { span: name_binding.span, segments: path_segments }; + let path = + Path { span: name_binding.span, segments: path_segments, tokens: None }; result = Some(( module, ImportSuggestion { @@ -1095,7 +1097,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { if let Res::Def(DefKind::Variant, _) = name_binding.res() { let mut segms = enum_import_suggestion.path.segments.clone(); segms.push(ast::PathSegment::from_ident(ident)); - variants.push(Path { span: name_binding.span, segments: segms }); + variants.push(Path { span: name_binding.span, segments: segms, tokens: None }); } }); variants diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 848f1c116ebcb..c7913e8445531 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -3189,6 +3189,7 @@ impl<'a> Resolver<'a> { .chain(path_str.split("::").skip(1).map(Ident::from_str)) .map(|i| self.new_ast_path_segment(i)) .collect(), + tokens: None, } } else { ast::Path { @@ -3198,6 +3199,7 @@ impl<'a> Resolver<'a> { .map(Ident::from_str) .map(|i| self.new_ast_path_segment(i)) .collect(), + tokens: None, } }; let module = self.get_module(module_id); From c1011165e63480dabf1913e308da8b344dfa8f8a Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 21 Aug 2020 19:11:00 -0400 Subject: [PATCH 0279/1052] Attach `TokenStream` to `ast::Visibility` A `Visibility` does not have outer attributes, so we only capture tokens when parsing a `macro_rules!` matcher --- compiler/rustc_ast/src/ast.rs | 7 +++- compiler/rustc_ast/src/mut_visit.rs | 12 ++++--- compiler/rustc_ast/src/visit.rs | 2 +- compiler/rustc_ast_lowering/src/item.rs | 2 +- .../rustc_ast_passes/src/ast_validation.rs | 4 +-- compiler/rustc_ast_passes/src/feature_gate.rs | 2 +- compiler/rustc_ast_pretty/src/pprust.rs | 2 +- .../src/deriving/generic/mod.rs | 13 +++++-- .../rustc_builtin_macros/src/global_asm.rs | 7 ++-- .../src/proc_macro_harness.rs | 8 ++--- compiler/rustc_builtin_macros/src/test.rs | 9 +++-- .../rustc_builtin_macros/src/test_harness.rs | 3 +- compiler/rustc_expand/src/build.rs | 20 ++++++++--- compiler/rustc_expand/src/expand.rs | 7 ++-- compiler/rustc_expand/src/placeholders.rs | 8 +++-- .../src/rmeta/decoder/cstore_impl.rs | 8 +++-- compiler/rustc_parse/src/lib.rs | 2 +- compiler/rustc_parse/src/parser/item.rs | 6 ++-- compiler/rustc_parse/src/parser/mod.rs | 34 +++++++++++++++---- .../rustc_parse/src/parser/nonterminal.rs | 10 +++++- .../rustc_resolve/src/build_reduced_graph.rs | 2 +- compiler/rustc_resolve/src/check_unused.rs | 2 +- 22 files changed, 120 insertions(+), 50 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 80c8cdf703cf3..e2703989646ff 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2490,7 +2490,12 @@ pub enum CrateSugar { JustCrate, } -pub type Visibility = Spanned; +#[derive(Clone, Encodable, Decodable, Debug)] +pub struct Visibility { + pub kind: VisibilityKind, + pub span: Span, + pub tokens: Option, +} #[derive(Clone, Encodable, Decodable, Debug)] pub enum VisibilityKind { diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index f6ac134bb1671..d37bba646ef6e 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -14,7 +14,7 @@ use crate::tokenstream::*; use rustc_data_structures::map_in_place::MapInPlace; use rustc_data_structures::sync::Lrc; -use rustc_span::source_map::{respan, Spanned}; +use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; use rustc_span::Span; @@ -978,11 +978,13 @@ pub fn noop_visit_mod(module: &mut Mod, vis: &mut T) { pub fn noop_visit_crate(krate: &mut Crate, vis: &mut T) { visit_clobber(krate, |Crate { module, attrs, span, proc_macros }| { + let item_vis = + Visibility { kind: VisibilityKind::Public, span: span.shrink_to_lo(), tokens: None }; let item = P(Item { ident: Ident::invalid(), attrs, id: DUMMY_NODE_ID, - vis: respan(span.shrink_to_lo(), VisibilityKind::Public), + vis: item_vis, span, kind: ItemKind::Mod(module), tokens: None, @@ -1314,13 +1316,13 @@ pub fn noop_flat_map_stmt_kind( } } -pub fn noop_visit_vis(Spanned { node, span }: &mut Visibility, vis: &mut T) { - match node { +pub fn noop_visit_vis(visibility: &mut Visibility, vis: &mut T) { + match &mut visibility.kind { VisibilityKind::Public | VisibilityKind::Crate(_) | VisibilityKind::Inherited => {} VisibilityKind::Restricted { path, id } => { vis.visit_path(path); vis.visit_id(id); } } - vis.visit_span(span); + vis.visit_span(&mut visibility.span); } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 234ce280f97c4..86fd87f6c42c5 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -879,7 +879,7 @@ pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) { } pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) { - if let VisibilityKind::Restricted { ref path, id } = vis.node { + if let VisibilityKind::Restricted { ref path, id } = vis.kind { visitor.visit_path(path, id); } } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 6a3b9c22597ae..6d41b7836b121 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -930,7 +930,7 @@ impl<'hir> LoweringContext<'_, 'hir> { v: &Visibility, explicit_owner: Option, ) -> hir::Visibility<'hir> { - let node = match v.node { + let node = match v.kind { VisibilityKind::Public => hir::VisibilityKind::Public, VisibilityKind::Crate(sugar) => hir::VisibilityKind::Crate(sugar), VisibilityKind::Restricted { ref path, id } => { diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 998acf4fd10cb..31c05325d1d25 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -198,13 +198,13 @@ impl<'a> AstValidator<'a> { } fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) { - if let VisibilityKind::Inherited = vis.node { + if let VisibilityKind::Inherited = vis.kind { return; } let mut err = struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier"); - if vis.node.is_pub() { + if vis.kind.is_pub() { err.span_label(vis.span, "`pub` not permitted here because it's implied"); } if let Some(note) = note { diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 97e6b363eff60..40643da2881a0 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -594,7 +594,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } fn visit_vis(&mut self, vis: &'a ast::Visibility) { - if let ast::VisibilityKind::Crate(ast::CrateSugar::JustCrate) = vis.node { + if let ast::VisibilityKind::Crate(ast::CrateSugar::JustCrate) = vis.kind { gate_feature_post!( &self, crate_visibility_modifier, diff --git a/compiler/rustc_ast_pretty/src/pprust.rs b/compiler/rustc_ast_pretty/src/pprust.rs index 955d1677647ec..d16b541c6999e 100644 --- a/compiler/rustc_ast_pretty/src/pprust.rs +++ b/compiler/rustc_ast_pretty/src/pprust.rs @@ -1359,7 +1359,7 @@ impl<'a> State<'a> { } crate fn print_visibility(&mut self, vis: &ast::Visibility) { - match vis.node { + match vis.kind { ast::VisibilityKind::Public => self.word_nbsp("pub"), ast::VisibilityKind::Crate(sugar) => match sugar { ast::CrateSugar::PubCrate => self.word_nbsp("pub(crate)"), diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 849e8b136e12d..d235caec1031f 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -187,7 +187,6 @@ use rustc_ast::{GenericArg, GenericParamKind, VariantData}; use rustc_attr as attr; use rustc_data_structures::map_in_place::MapInPlace; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::source_map::respan; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; @@ -532,7 +531,11 @@ impl<'a> TraitDef<'a> { id: ast::DUMMY_NODE_ID, span: self.span, ident, - vis: respan(self.span.shrink_to_lo(), ast::VisibilityKind::Inherited), + vis: ast::Visibility { + span: self.span.shrink_to_lo(), + kind: ast::VisibilityKind::Inherited, + tokens: None, + }, attrs: Vec::new(), kind: ast::AssocItemKind::TyAlias( ast::Defaultness::Final, @@ -933,7 +936,11 @@ impl<'a> MethodDef<'a> { id: ast::DUMMY_NODE_ID, attrs: self.attributes.clone(), span: trait_.span, - vis: respan(trait_lo_sp, ast::VisibilityKind::Inherited), + vis: ast::Visibility { + span: trait_lo_sp, + kind: ast::VisibilityKind::Inherited, + tokens: None, + }, ident: method_ident, kind: ast::AssocItemKind::Fn(def, sig, fn_generics, Some(body_block)), tokens: None, diff --git a/compiler/rustc_builtin_macros/src/global_asm.rs b/compiler/rustc_builtin_macros/src/global_asm.rs index 2465f33622e84..3689e33be6f0f 100644 --- a/compiler/rustc_builtin_macros/src/global_asm.rs +++ b/compiler/rustc_builtin_macros/src/global_asm.rs @@ -14,7 +14,6 @@ use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_errors::DiagnosticBuilder; use rustc_expand::base::{self, *}; -use rustc_span::source_map::respan; use rustc_span::symbol::Ident; use rustc_span::Span; use smallvec::smallvec; @@ -30,7 +29,11 @@ pub fn expand_global_asm<'cx>( attrs: Vec::new(), id: ast::DUMMY_NODE_ID, kind: ast::ItemKind::GlobalAsm(P(global_asm)), - vis: respan(sp.shrink_to_lo(), ast::VisibilityKind::Inherited), + vis: ast::Visibility { + span: sp.shrink_to_lo(), + kind: ast::VisibilityKind::Inherited, + tokens: None, + }, span: cx.with_def_site_ctxt(sp), tokens: None, })]), diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 0c6769906f339..c6ab3faf56897 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -98,7 +98,7 @@ pub fn inject( impl<'a> CollectProcMacros<'a> { fn check_not_pub_in_root(&self, vis: &ast::Visibility, sp: Span) { - if self.is_proc_macro_crate && self.in_root && vis.node.is_pub() { + if self.is_proc_macro_crate && self.in_root && vis.kind.is_pub() { self.handler.span_err( sp, "`proc-macro` crate types currently cannot export any items other \ @@ -184,7 +184,7 @@ impl<'a> CollectProcMacros<'a> { Vec::new() }; - if self.in_root && item.vis.node.is_pub() { + if self.in_root && item.vis.kind.is_pub() { self.macros.push(ProcMacro::Derive(ProcMacroDerive { id: item.id, span: item.span, @@ -204,7 +204,7 @@ impl<'a> CollectProcMacros<'a> { } fn collect_attr_proc_macro(&mut self, item: &'a ast::Item) { - if self.in_root && item.vis.node.is_pub() { + if self.in_root && item.vis.kind.is_pub() { self.macros.push(ProcMacro::Def(ProcMacroDef { id: item.id, span: item.span, @@ -223,7 +223,7 @@ impl<'a> CollectProcMacros<'a> { } fn collect_bang_proc_macro(&mut self, item: &'a ast::Item) { - if self.in_root && item.vis.node.is_pub() { + if self.in_root && item.vis.kind.is_pub() { self.macros.push(ProcMacro::Def(ProcMacroDef { id: item.id, span: item.span, diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 8e56e80bba204..1de0b32f5196b 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -7,7 +7,6 @@ use rustc_ast::attr; use rustc_ast_pretty::pprust; use rustc_expand::base::*; use rustc_session::Session; -use rustc_span::source_map::respan; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; @@ -35,7 +34,11 @@ pub fn expand_test_case( let sp = ecx.with_def_site_ctxt(attr_sp); let mut item = anno_item.expect_item(); item = item.map(|mut item| { - item.vis = respan(item.vis.span, ast::VisibilityKind::Public); + item.vis = ast::Visibility { + span: item.vis.span, + kind: ast::VisibilityKind::Public, + tokens: None, + }; item.ident.span = item.ident.span.with_ctxt(sp.ctxt()); item.attrs.push(ecx.attribute(ecx.meta_word(sp, sym::rustc_test_marker))); item @@ -292,7 +295,7 @@ pub fn expand_test_or_bench( ), ); test_const = test_const.map(|mut tc| { - tc.vis.node = ast::VisibilityKind::Public; + tc.vis.kind = ast::VisibilityKind::Public; tc }); diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 0ea60665d6755..0a60ca8faaa12 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -10,7 +10,6 @@ use rustc_expand::expand::{AstFragment, ExpansionConfig}; use rustc_feature::Features; use rustc_session::Session; use rustc_span::hygiene::{AstPass, SyntaxContext, Transparency}; -use rustc_span::source_map::respan; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::PanicStrategy; @@ -333,7 +332,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { attrs: vec![main_attr], id: ast::DUMMY_NODE_ID, kind: main, - vis: respan(sp, ast::VisibilityKind::Public), + vis: ast::Visibility { span: sp, kind: ast::VisibilityKind::Public, tokens: None }, span: sp, tokens: None, }); diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 0fcffe77d45d3..70603622bedda 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -3,7 +3,7 @@ use crate::base::ExtCtxt; use rustc_ast::attr; use rustc_ast::ptr::P; use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Expr, PatKind, UnOp}; -use rustc_span::source_map::{respan, Spanned}; +use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; @@ -584,7 +584,11 @@ impl<'a> ExtCtxt<'a> { attrs, id: ast::DUMMY_NODE_ID, kind, - vis: respan(span.shrink_to_lo(), ast::VisibilityKind::Inherited), + vis: ast::Visibility { + span: span.shrink_to_lo(), + kind: ast::VisibilityKind::Inherited, + tokens: None, + }, span, tokens: None, }) @@ -598,7 +602,11 @@ impl<'a> ExtCtxt<'a> { span: ty.span, ty, ident: None, - vis: respan(vis_span, ast::VisibilityKind::Inherited), + vis: ast::Visibility { + span: vis_span, + kind: ast::VisibilityKind::Inherited, + tokens: None, + }, attrs: Vec::new(), id: ast::DUMMY_NODE_ID, is_placeholder: false, @@ -617,7 +625,11 @@ impl<'a> ExtCtxt<'a> { disr_expr: None, id: ast::DUMMY_NODE_ID, ident, - vis: respan(vis_span, ast::VisibilityKind::Inherited), + vis: ast::Visibility { + span: vis_span, + kind: ast::VisibilityKind::Inherited, + tokens: None, + }, span, is_placeholder: false, } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 98faa8a0a0f1b..47c070f16516a 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -26,7 +26,6 @@ use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::{feature_err, ParseSess}; use rustc_session::Limit; -use rustc_span::source_map::respan; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{ExpnId, FileName, Span, DUMMY_SP}; @@ -358,7 +357,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { kind: ast::ItemKind::Mod(krate.module), ident: Ident::invalid(), id: ast::DUMMY_NODE_ID, - vis: respan(krate.span.shrink_to_lo(), ast::VisibilityKind::Public), + vis: ast::Visibility { + span: krate.span.shrink_to_lo(), + kind: ast::VisibilityKind::Public, + tokens: None, + }, tokens: None, })]); diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 530e67a134a35..036c00bb7537f 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -4,7 +4,7 @@ use crate::expand::{AstFragment, AstFragmentKind}; use rustc_ast as ast; use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; -use rustc_span::source_map::{dummy_spanned, DUMMY_SP}; +use rustc_span::source_map::DUMMY_SP; use rustc_span::symbol::Ident; use smallvec::{smallvec, SmallVec}; @@ -26,7 +26,11 @@ pub fn placeholder( let ident = Ident::invalid(); let attrs = Vec::new(); - let vis = vis.unwrap_or_else(|| dummy_spanned(ast::VisibilityKind::Inherited)); + let vis = vis.unwrap_or(ast::Visibility { + span: DUMMY_SP, + kind: ast::VisibilityKind::Inherited, + tokens: None, + }); let span = DUMMY_SP; let expr_placeholder = || { P(ast::Expr { diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 36ff65fc5eb00..94abfac19c665 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::utils::NativeLibKind; use rustc_session::{CrateDisambiguator, Session}; -use rustc_span::source_map::{self, Span, Spanned}; +use rustc_span::source_map::{Span, Spanned}; use rustc_span::symbol::Symbol; use rustc_data_structures::sync::Lrc; @@ -421,7 +421,11 @@ impl CStore { span, attrs: attrs.to_vec(), kind: ast::ItemKind::MacroDef(data.get_macro(id.index, sess)), - vis: source_map::respan(span.shrink_to_lo(), ast::VisibilityKind::Inherited), + vis: ast::Visibility { + span: span.shrink_to_lo(), + kind: ast::VisibilityKind::Inherited, + tokens: None, + }, tokens: None, }, data.root.edition, diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 69f63feac78ee..3807daa701598 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -279,6 +279,7 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke } Nonterminal::NtMeta(ref attr) => attr.tokens.clone(), Nonterminal::NtPath(ref path) => path.tokens.clone(), + Nonterminal::NtVis(ref vis) => vis.tokens.clone(), Nonterminal::NtTT(ref tt) => Some(tt.clone().into()), Nonterminal::NtExpr(ref expr) | Nonterminal::NtLiteral(ref expr) => { if expr.tokens.is_none() { @@ -286,7 +287,6 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke } prepend_attrs(sess, &expr.attrs, expr.tokens.as_ref(), span) } - _ => None, }; // FIXME(#43081): Avoid this pretty-print + reparse hack diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 6d90d1128227a..26ca99801277b 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -187,7 +187,7 @@ impl<'a> Parser<'a> { /// Error in-case a non-inherited visibility was parsed but no item followed. fn error_on_unmatched_vis(&self, vis: &Visibility) { - if let VisibilityKind::Inherited = vis.node { + if let VisibilityKind::Inherited = vis.kind { return; } let vs = pprust::vis_to_string(&vis); @@ -296,7 +296,7 @@ impl<'a> Parser<'a> { } else if self.is_macro_rules_item() { // MACRO_RULES ITEM self.parse_item_macro_rules(vis)? - } else if vis.node.is_pub() && self.isnt_macro_invocation() { + } else if vis.kind.is_pub() && self.isnt_macro_invocation() { self.recover_missing_kw_before_item()?; return Ok(None); } else if macros_allowed && self.check_path() { @@ -1418,7 +1418,7 @@ impl<'a> Parser<'a> { /// Item macro invocations or `macro_rules!` definitions need inherited visibility. /// If that's not the case, emit an error. fn complain_if_pub_macro(&self, vis: &Visibility, macro_rules: bool) { - if let VisibilityKind::Inherited = vis.node { + if let VisibilityKind::Inherited = vis.kind { return; } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index d22d08cd14438..5eefae3af60e9 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -22,7 +22,7 @@ use rustc_ast::{Async, MacArgs, MacDelimiter, Mutability, StrLit, Visibility, Vi use rustc_ast_pretty::pprust; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError, PResult}; use rustc_session::parse::ParseSess; -use rustc_span::source_map::{respan, Span, DUMMY_SP}; +use rustc_span::source_map::{Span, DUMMY_SP}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use tracing::debug; @@ -1022,14 +1022,22 @@ impl<'a> Parser<'a> { if self.is_crate_vis() { self.bump(); // `crate` self.sess.gated_spans.gate(sym::crate_visibility_modifier, self.prev_token.span); - return Ok(respan(self.prev_token.span, VisibilityKind::Crate(CrateSugar::JustCrate))); + return Ok(Visibility { + span: self.prev_token.span, + kind: VisibilityKind::Crate(CrateSugar::JustCrate), + tokens: None, + }); } if !self.eat_keyword(kw::Pub) { // We need a span for our `Spanned`, but there's inherently no // keyword to grab a span from for inherited visibility; an empty span at the // beginning of the current token would seem to be the "Schelling span". - return Ok(respan(self.token.span.shrink_to_lo(), VisibilityKind::Inherited)); + return Ok(Visibility { + span: self.token.span.shrink_to_lo(), + kind: VisibilityKind::Inherited, + tokens: None, + }); } let lo = self.prev_token.span; @@ -1046,7 +1054,11 @@ impl<'a> Parser<'a> { self.bump(); // `crate` self.expect(&token::CloseDelim(token::Paren))?; // `)` let vis = VisibilityKind::Crate(CrateSugar::PubCrate); - return Ok(respan(lo.to(self.prev_token.span), vis)); + return Ok(Visibility { + span: lo.to(self.prev_token.span), + kind: vis, + tokens: None, + }); } else if self.is_keyword_ahead(1, &[kw::In]) { // Parse `pub(in path)`. self.bump(); // `(` @@ -1054,7 +1066,11 @@ impl<'a> Parser<'a> { let path = self.parse_path(PathStyle::Mod)?; // `path` self.expect(&token::CloseDelim(token::Paren))?; // `)` let vis = VisibilityKind::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }; - return Ok(respan(lo.to(self.prev_token.span), vis)); + return Ok(Visibility { + span: lo.to(self.prev_token.span), + kind: vis, + tokens: None, + }); } else if self.look_ahead(2, |t| t == &token::CloseDelim(token::Paren)) && self.is_keyword_ahead(1, &[kw::Super, kw::SelfLower]) { @@ -1063,7 +1079,11 @@ impl<'a> Parser<'a> { let path = self.parse_path(PathStyle::Mod)?; // `super`/`self` self.expect(&token::CloseDelim(token::Paren))?; // `)` let vis = VisibilityKind::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }; - return Ok(respan(lo.to(self.prev_token.span), vis)); + return Ok(Visibility { + span: lo.to(self.prev_token.span), + kind: vis, + tokens: None, + }); } else if let FollowedByType::No = fbt { // Provide this diagnostic if a type cannot follow; // in particular, if this is not a tuple struct. @@ -1072,7 +1092,7 @@ impl<'a> Parser<'a> { } } - Ok(respan(lo, VisibilityKind::Public)) + Ok(Visibility { span: lo, kind: VisibilityKind::Public, tokens: None }) } /// Recovery for e.g. `pub(something) fn ...` or `struct X { pub(something) y: Z }` diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 84e887e74a7a4..f98f2a89dc629 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -186,7 +186,15 @@ impl<'a> Parser<'a> { token::NtMeta(P(attr)) } NonterminalKind::TT => token::NtTT(self.parse_token_tree()), - NonterminalKind::Vis => token::NtVis(self.parse_visibility(FollowedByType::Yes)?), + NonterminalKind::Vis => { + let (mut vis, tokens) = + self.collect_tokens(|this| this.parse_visibility(FollowedByType::Yes))?; + // We may have etan an `NtVis`, which could already have tokens + if vis.tokens.is_none() { + vis.tokens = Some(tokens); + } + token::NtVis(vis) + } NonterminalKind::Lifetime => { if self.check_lifetime() { token::NtLifetime(self.expect_lifetime().ident) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 761724be57daf..03c2915f8486b 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -218,7 +218,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { speculative: bool, ) -> Result> { let parent_scope = &self.parent_scope; - match vis.node { + match vis.kind { ast::VisibilityKind::Public => Ok(ty::Visibility::Public), ast::VisibilityKind::Crate(..) => { Ok(ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))) diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 5624a6b6accc6..89ce89b2e9a94 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -105,7 +105,7 @@ impl<'a, 'b> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b> { // because this means that they were generated in some fashion by the // compiler and we don't need to consider them. if let ast::ItemKind::Use(..) = item.kind { - if item.vis.node.is_pub() || item.span.is_dummy() { + if item.vis.kind.is_pub() || item.span.is_dummy() { return; } } From 156ef2bee8f3941d4d7e3414652b803348ccd165 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 10 Sep 2020 16:59:30 -0400 Subject: [PATCH 0280/1052] Attach tokens to `ast::Stmt` We currently only attach tokens when parsing a `:stmt` matcher for a `macro_rules!` macro. Proc-macro attributes on statements are still unstable, and need additional work. --- compiler/rustc_ast/src/ast.rs | 1 + compiler/rustc_ast/src/mut_visit.rs | 7 ++++-- .../src/deriving/debug.rs | 2 +- compiler/rustc_expand/src/base.rs | 2 ++ compiler/rustc_expand/src/build.rs | 24 +++++++++++++++---- compiler/rustc_expand/src/expand.rs | 4 ++-- compiler/rustc_expand/src/placeholders.rs | 2 +- compiler/rustc_interface/src/util.rs | 2 ++ compiler/rustc_parse/src/lib.rs | 7 ++++++ .../rustc_parse/src/parser/nonterminal.rs | 18 ++++++++++---- compiler/rustc_parse/src/parser/stmt.rs | 2 +- 11 files changed, 56 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e2703989646ff..dee3a16f9b133 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -918,6 +918,7 @@ pub struct Stmt { pub id: NodeId, pub kind: StmtKind, pub span: Span, + pub tokens: Option, } impl Stmt { diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index d37bba646ef6e..425ef83b57af5 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1286,12 +1286,15 @@ pub fn noop_filter_map_expr(mut e: P, vis: &mut T) -> Optio } pub fn noop_flat_map_stmt( - Stmt { kind, mut span, mut id }: Stmt, + Stmt { kind, mut span, mut id, tokens }: Stmt, vis: &mut T, ) -> SmallVec<[Stmt; 1]> { vis.visit_id(&mut id); vis.visit_span(&mut span); - noop_flat_map_stmt_kind(kind, vis).into_iter().map(|kind| Stmt { id, kind, span }).collect() + noop_flat_map_stmt_kind(kind, vis) + .into_iter() + .map(|kind| Stmt { id, kind, span, tokens: tokens.clone() }) + .collect() } pub fn noop_flat_map_stmt_kind( diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index 120e859f2b1a4..d84b3956475d8 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -133,5 +133,5 @@ fn stmt_let_underscore(cx: &mut ExtCtxt<'_>, sp: Span, expr: P) -> as span: sp, attrs: ast::AttrVec::new(), }); - ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp } + ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp, tokens: None } } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 5bdc4760dcc31..926e3dbfc5266 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -400,6 +400,7 @@ macro_rules! make_stmts_default { id: ast::DUMMY_NODE_ID, span: e.span, kind: ast::StmtKind::Expr(e), + tokens: None }] }) }; @@ -642,6 +643,7 @@ impl MacResult for DummyResult { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Expr(DummyResult::raw_expr(self.span, self.is_error)), span: self.span, + tokens: None }]) } diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 70603622bedda..a5a7ee6c9a349 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -158,7 +158,12 @@ impl<'a> ExtCtxt<'a> { } pub fn stmt_expr(&self, expr: P) -> ast::Stmt { - ast::Stmt { id: ast::DUMMY_NODE_ID, span: expr.span, kind: ast::StmtKind::Expr(expr) } + ast::Stmt { + id: ast::DUMMY_NODE_ID, + span: expr.span, + kind: ast::StmtKind::Expr(expr), + tokens: None, + } } pub fn stmt_let(&self, sp: Span, mutbl: bool, ident: Ident, ex: P) -> ast::Stmt { @@ -176,7 +181,12 @@ impl<'a> ExtCtxt<'a> { span: sp, attrs: AttrVec::new(), }); - ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp } + ast::Stmt { + id: ast::DUMMY_NODE_ID, + kind: ast::StmtKind::Local(local), + span: sp, + tokens: None, + } } // Generates `let _: Type;`, which is usually used for type assertions. @@ -189,11 +199,16 @@ impl<'a> ExtCtxt<'a> { span, attrs: AttrVec::new(), }); - ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span } + ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span, tokens: None } } pub fn stmt_item(&self, sp: Span, item: P) -> ast::Stmt { - ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Item(item), span: sp } + ast::Stmt { + id: ast::DUMMY_NODE_ID, + kind: ast::StmtKind::Item(item), + span: sp, + tokens: None, + } } pub fn block_expr(&self, expr: P) -> P { @@ -203,6 +218,7 @@ impl<'a> ExtCtxt<'a> { id: ast::DUMMY_NODE_ID, span: expr.span, kind: ast::StmtKind::Expr(expr), + tokens: None, }], ) } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 47c070f16516a..e5cfb866938e5 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1396,10 +1396,10 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } // The placeholder expander gives ids to statements, so we avoid folding the id here. - let ast::Stmt { id, kind, span } = stmt; + let ast::Stmt { id, kind, span, tokens } = stmt; noop_flat_map_stmt_kind(kind, self) .into_iter() - .map(|kind| ast::Stmt { id, kind, span }) + .map(|kind| ast::Stmt { id, kind, span, tokens: tokens.clone() }) .collect() } diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 036c00bb7537f..4c9271a58df58 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -105,7 +105,7 @@ pub fn placeholder( style: ast::MacStmtStyle::Braces, attrs: ast::AttrVec::new(), }); - ast::Stmt { id, span, kind: ast::StmtKind::MacCall(mac) } + ast::Stmt { id, span, kind: ast::StmtKind::MacCall(mac), tokens: None } }]), AstFragmentKind::Arms => AstFragment::Arms(smallvec![ast::Arm { attrs: Default::default(), diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 01441cafe8a93..f15eb413833ae 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -710,6 +710,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { id: resolver.next_node_id(), kind: ast::StmtKind::Expr(expr), span: rustc_span::DUMMY_SP, + tokens: None, } } @@ -726,6 +727,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { 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 { diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 3807daa701598..dedb9850b5a19 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -269,6 +269,13 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span) } Nonterminal::NtBlock(ref block) => block.tokens.clone(), + 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 + stmt.tokens.clone() + } Nonterminal::NtPat(ref pat) => pat.tokens.clone(), Nonterminal::NtTy(ref ty) => ty.tokens.clone(), Nonterminal::NtIdent(ident, is_raw) => { diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index f98f2a89dc629..15660fd574c13 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -119,10 +119,20 @@ impl<'a> Parser<'a> { } token::NtBlock(block) } - NonterminalKind::Stmt => match self.parse_stmt()? { - Some(s) => token::NtStmt(s), - None => return Err(self.struct_span_err(self.token.span, "expected a statement")), - }, + NonterminalKind::Stmt => { + let (stmt, tokens) = self.collect_tokens(|this| this.parse_stmt())?; + match stmt { + Some(mut s) => { + if s.tokens.is_none() { + s.tokens = Some(tokens); + } + token::NtStmt(s) + } + None => { + return Err(self.struct_span_err(self.token.span, "expected a statement")); + } + } + } NonterminalKind::Pat => { let (mut pat, tokens) = self.collect_tokens(|this| this.parse_pat(None))?; // We have have eaten an NtPat, which could already have tokens diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 6cc42487684bd..64b959e83251d 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -415,7 +415,7 @@ impl<'a> Parser<'a> { } pub(super) fn mk_stmt(&self, span: Span, kind: StmtKind) -> Stmt { - Stmt { id: DUMMY_NODE_ID, kind, span } + Stmt { id: DUMMY_NODE_ID, kind, span, tokens: None } } fn mk_stmt_err(&self, span: Span) -> Stmt { From 09f7a377a663043c6f63ded70436ac0969e4abc7 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Thu, 10 Sep 2020 14:50:10 -0700 Subject: [PATCH 0281/1052] Add comments to the invalid_atomic_ordering example --- clippy_lints/src/atomic_ordering.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/atomic_ordering.rs b/clippy_lints/src/atomic_ordering.rs index 614e33a06da34..703d8a6f62bb1 100644 --- a/clippy_lints/src/atomic_ordering.rs +++ b/clippy_lints/src/atomic_ordering.rs @@ -22,18 +22,27 @@ declare_clippy_lint! { /// /// let x = AtomicU8::new(0); /// + /// // Bad: `Release` and `AcqRel` cannot be used for `load`. /// let _ = x.load(Ordering::Release); /// let _ = x.load(Ordering::AcqRel); /// + /// // Bad: `Acquire` and `AcqRel` cannot be used for `store`. /// x.store(1, Ordering::Acquire); /// x.store(2, Ordering::AcqRel); /// + /// // Bad: `Relaxed` cannot be used as a fence's ordering. /// atomic::fence(Ordering::Relaxed); /// atomic::compiler_fence(Ordering::Relaxed); /// - /// let _ = x.compare_exchange(1, 2, Ordering::Relaxed, Ordering::SeqCst); - /// let _ = x.compare_exchange_weak(2, 3, Ordering::SeqCst, Ordering::Release); - /// let _ = x.fetch_update(Ordering::AcqRel, Ordering::AcqRel, |val| Some(val + val)); + /// // Bad: `Release` and `AcqRel` are both always invalid + /// // for the failure ordering (the last arg). + /// let _ = x.compare_exchange(1, 2, Ordering::SeqCst, Ordering::Release); + /// let _ = x.compare_exchange_weak(2, 3, Ordering::AcqRel, Ordering::AcqRel); + /// + /// // Bad: The failure ordering is not allowed to be + /// // stronger than the success order, and `SeqCst` is + /// // stronger than `Relaxed`. + /// let _ = x.fetch_update(Ordering::Relaxed, Ordering::SeqCst, |val| Some(val + val)); /// ``` pub INVALID_ATOMIC_ORDERING, correctness, From fec047907572ef84bf128da9c4026e5ae5bcaa34 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 21 Aug 2020 22:11:41 -0400 Subject: [PATCH 0282/1052] Fully integrate token collection for additional AST structs This commit contains miscellaneous changes that don't fit into any of the other commits in this PR --- compiler/rustc_ast/src/token.rs | 2 +- compiler/rustc_ast_pretty/src/pprust/tests.rs | 7 +- src/test/ui-fulldeps/pprust-expr-roundtrip.rs | 3 +- .../ast-json/ast-json-noexpand-output.stdout | 2 +- src/test/ui/ast-json/ast-json-output.stdout | 2 +- .../proc-macro/capture-macro-rules-invoke.rs | 29 +- .../capture-macro-rules-invoke.stdout | 303 +++++++++++++++++- .../clippy/clippy_lints/src/enum_variants.rs | 4 +- .../clippy_lints/src/manual_non_exhaustive.rs | 4 +- .../src/single_component_path_imports.rs | 2 +- .../clippy_lints/src/utils/ast_utils.rs | 2 +- 11 files changed, 338 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 09c0983bb9d1a..d5b3e87adc36a 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -700,7 +700,7 @@ pub enum Nonterminal { // `Nonterminal` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -rustc_data_structures::static_assert_size!(Nonterminal, 40); +rustc_data_structures::static_assert_size!(Nonterminal, 48); #[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable)] pub enum NonterminalKind { diff --git a/compiler/rustc_ast_pretty/src/pprust/tests.rs b/compiler/rustc_ast_pretty/src/pprust/tests.rs index fdbf3feb900ef..b1a73a0bf0277 100644 --- a/compiler/rustc_ast_pretty/src/pprust/tests.rs +++ b/compiler/rustc_ast_pretty/src/pprust/tests.rs @@ -1,7 +1,6 @@ use super::*; use rustc_ast as ast; -use rustc_span::source_map::respan; use rustc_span::symbol::Ident; use rustc_span::with_default_session_globals; @@ -45,7 +44,11 @@ fn test_variant_to_string() { let var = ast::Variant { ident, - vis: respan(rustc_span::DUMMY_SP, ast::VisibilityKind::Inherited), + vis: ast::Visibility { + span: rustc_span::DUMMY_SP, + kind: ast::VisibilityKind::Inherited, + tokens: None, + }, attrs: Vec::new(), id: ast::DUMMY_NODE_ID, data: ast::VariantData::Unit(ast::DUMMY_NODE_ID), diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs index 633d153e391dd..caf55bec53ddd 100644 --- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs @@ -62,7 +62,7 @@ fn expr(kind: ExprKind) -> P { fn make_x() -> P { let seg = PathSegment::from_ident(Ident::from_str("x")); - let path = Path { segments: vec![seg], span: DUMMY_SP }; + let path = Path { segments: vec![seg], span: DUMMY_SP, tokens: None }; expr(ExprKind::Path(None, path)) } @@ -113,6 +113,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P)) { id: DUMMY_NODE_ID, rules: BlockCheckMode::Default, span: DUMMY_SP, + tokens: None, }); iter_exprs(depth - 1, &mut |e| g(ExprKind::If(e, block.clone(), None))); }, diff --git a/src/test/ui/ast-json/ast-json-noexpand-output.stdout b/src/test/ui/ast-json/ast-json-noexpand-output.stdout index 0e5a3a14ac7b5..3d7d476cf6c05 100644 --- a/src/test/ui/ast-json/ast-json-noexpand-output.stdout +++ b/src/test/ui/ast-json/ast-json-noexpand-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} +{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"tokens":null}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout index 8752ed2ae9993..a4ce6061b4c9d 100644 --- a/src/test/ui/ast-json/ast-json-output.stdout +++ b/src/test/ui/ast-json/ast-json-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} +{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"tokens":null}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} diff --git a/src/test/ui/proc-macro/capture-macro-rules-invoke.rs b/src/test/ui/proc-macro/capture-macro-rules-invoke.rs index 2ff6ad6d68f35..de008a3708ae8 100644 --- a/src/test/ui/proc-macro/capture-macro-rules-invoke.rs +++ b/src/test/ui/proc-macro/capture-macro-rules-invoke.rs @@ -1,10 +1,20 @@ // aux-build:test-macros.rs // check-pass // compile-flags: -Z span-debug -// normalize-stdout-test "#\d+" -> "#CTXT" + +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; extern crate test_macros; -use test_macros::print_bang; +use test_macros::{print_bang, print_bang_consume}; + +macro_rules! test_matchers { + ($expr:expr, $block:block, $stmt:stmt, $ty:ty, $ident:ident, $lifetime:lifetime, + $meta:meta, $path:path, $vis:vis, $tt:tt, $lit:literal) => { + print_bang_consume!($expr, $block, $stmt, $ty, $ident, + $lifetime, $meta, $path, $vis, $tt, $lit) + } +} macro_rules! use_expr { ($expr:expr) => { @@ -24,10 +34,23 @@ impl Foo { #[allow(dead_code)] fn use_self(self) { drop(use_expr!(self)); + test_matchers!( + 1 + 1, + { "a" }, + let a = 1, + String, + my_name, + 'a, + my_val = 30, + std::option::Option, + pub(in some::path), + [ a b c ], + -30 + ); } fn with_pat(use_pat!((a, b)): (u32, u32)) { - println!("Args: {} {}", a, b); + let _ = (a, b); } } diff --git a/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout b/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout index 28812e2054803..652bf6b6b22f5 100644 --- a/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout +++ b/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout @@ -5,10 +5,299 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "self", - span: $DIR/capture-macro-rules-invoke.rs:26:24: 26:28 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:36:24: 36:28 (#0), }, ], - span: $DIR/capture-macro-rules-invoke.rs:11:21: 11:26 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:21:21: 21:26 (#3), + }, +] +PRINT-BANG INPUT (DISPLAY): 1 + 1, { "a" }, let a = 1;, String, my_name, 'a, my_val = 30, +std::option::Option, pub(in some::path) , [a b c], -30 +PRINT-BANG RE-COLLECTED (DISPLAY): 1 + 1, { "a" }, let a = 1, String, my_name, 'a, my_val = 30, +std :: option :: Option, pub(in some :: path), [a b c], - 30 +PRINT-BANG INPUT (DEBUG): TokenStream [ + Group { + delimiter: None, + stream: TokenStream [ + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/capture-macro-rules-invoke.rs:38:13: 38:14 (#0), + }, + Punct { + ch: '+', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:38:15: 38:16 (#0), + }, + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/capture-macro-rules-invoke.rs:38:17: 38:18 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:14:29: 14:34 (#7), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:14:34: 14:35 (#7), + }, + Group { + delimiter: None, + stream: TokenStream [ + Group { + delimiter: Brace, + stream: TokenStream [ + Literal { + kind: Str, + symbol: "a", + suffix: None, + span: $DIR/capture-macro-rules-invoke.rs:39:15: 39:18 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:39:13: 39:20 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:14:36: 14:42 (#7), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:14:42: 14:43 (#7), + }, + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "let", + span: $DIR/capture-macro-rules-invoke.rs:40:13: 40:16 (#0), + }, + Ident { + ident: "a", + span: $DIR/capture-macro-rules-invoke.rs:40:17: 40:18 (#0), + }, + Punct { + ch: '=', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:40:19: 40:20 (#0), + }, + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/capture-macro-rules-invoke.rs:40:21: 40:22 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:14:44: 14:49 (#7), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:14:49: 14:50 (#7), + }, + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "String", + span: $DIR/capture-macro-rules-invoke.rs:41:13: 41:19 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:14:51: 14:54 (#7), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:14:54: 14:55 (#7), + }, + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "my_name", + span: $DIR/capture-macro-rules-invoke.rs:42:13: 42:20 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:14:56: 14:62 (#7), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:14:62: 14:63 (#7), + }, + Group { + delimiter: None, + stream: TokenStream [ + Punct { + ch: '\'', + spacing: Joint, + span: $DIR/capture-macro-rules-invoke.rs:43:13: 43:15 (#0), + }, + Ident { + ident: "a", + span: $DIR/capture-macro-rules-invoke.rs:43:13: 43:15 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:15:29: 15:38 (#7), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:15:38: 15:39 (#7), + }, + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "my_val", + span: $DIR/capture-macro-rules-invoke.rs:44:13: 44:19 (#0), + }, + Punct { + ch: '=', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:44:20: 44:21 (#0), + }, + Literal { + kind: Integer, + symbol: "30", + suffix: None, + span: $DIR/capture-macro-rules-invoke.rs:44:22: 44:24 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:15:40: 15:45 (#7), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:15:45: 15:46 (#7), + }, + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "std", + span: $DIR/capture-macro-rules-invoke.rs:45:13: 45:16 (#0), + }, + Punct { + ch: ':', + spacing: Joint, + span: $DIR/capture-macro-rules-invoke.rs:45:16: 45:18 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:45:16: 45:18 (#0), + }, + Ident { + ident: "option", + span: $DIR/capture-macro-rules-invoke.rs:45:18: 45:24 (#0), + }, + Punct { + ch: ':', + spacing: Joint, + span: $DIR/capture-macro-rules-invoke.rs:45:24: 45:26 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:45:24: 45:26 (#0), + }, + Ident { + ident: "Option", + span: $DIR/capture-macro-rules-invoke.rs:45:26: 45:32 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:15:47: 15:52 (#7), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:15:52: 15:53 (#7), + }, + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "pub", + span: $DIR/capture-macro-rules-invoke.rs:46:13: 46:16 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "in", + span: $DIR/capture-macro-rules-invoke.rs:46:17: 46:19 (#0), + }, + Ident { + ident: "some", + span: $DIR/capture-macro-rules-invoke.rs:46:20: 46:24 (#0), + }, + Punct { + ch: ':', + spacing: Joint, + span: $DIR/capture-macro-rules-invoke.rs:46:24: 46:26 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:46:24: 46:26 (#0), + }, + Ident { + ident: "path", + span: $DIR/capture-macro-rules-invoke.rs:46:26: 46:30 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:46:16: 46:31 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:15:54: 15:58 (#7), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:15:58: 15:59 (#7), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "a", + span: $DIR/capture-macro-rules-invoke.rs:47:15: 47:16 (#0), + }, + Ident { + ident: "b", + span: $DIR/capture-macro-rules-invoke.rs:47:17: 47:18 (#0), + }, + Ident { + ident: "c", + span: $DIR/capture-macro-rules-invoke.rs:47:19: 47:20 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:47:13: 47:22 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:15:63: 15:64 (#7), + }, + Group { + delimiter: None, + stream: TokenStream [ + Punct { + ch: '-', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:48:13: 48:14 (#0), + }, + Literal { + kind: Integer, + symbol: "30", + suffix: None, + span: $DIR/capture-macro-rules-invoke.rs:48:14: 48:16 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:15:65: 15:69 (#7), }, ] PRINT-BANG INPUT (DISPLAY): (a, b) @@ -21,21 +310,21 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "a", - span: $DIR/capture-macro-rules-invoke.rs:29:27: 29:28 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:52:27: 52:28 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/capture-macro-rules-invoke.rs:29:28: 29:29 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:52:28: 52:29 (#0), }, Ident { ident: "b", - span: $DIR/capture-macro-rules-invoke.rs:29:30: 29:31 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:52:30: 52:31 (#0), }, ], - span: $DIR/capture-macro-rules-invoke.rs:29:26: 29:32 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:52:26: 52:32 (#0), }, ], - span: $DIR/capture-macro-rules-invoke.rs:17:21: 17:25 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:27:21: 27:25 (#11), }, ] diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/enum_variants.rs index a9294a87f15d0..67a463538568e 100644 --- a/src/tools/clippy/clippy_lints/src/enum_variants.rs +++ b/src/tools/clippy/clippy_lints/src/enum_variants.rs @@ -285,7 +285,7 @@ impl EarlyLintPass for EnumVariantNames { ); } } - if item.vis.node.is_pub() { + if item.vis.kind.is_pub() { let matching = partial_match(mod_camel, &item_camel); let rmatching = partial_rmatch(mod_camel, &item_camel); let nchars = mod_camel.chars().count(); @@ -316,7 +316,7 @@ impl EarlyLintPass for EnumVariantNames { } } if let ItemKind::Enum(ref def, _) = item.kind { - let lint = match item.vis.node { + let lint = match item.vis.kind { VisibilityKind::Public => PUB_ENUM_VARIANT_NAMES, _ => ENUM_VARIANT_NAMES, }; diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs index 4e49bdbdd21bd..9c623821fdddc 100644 --- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs +++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs @@ -122,7 +122,7 @@ fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants fn check_manual_non_exhaustive_struct(cx: &EarlyContext<'_>, item: &Item, data: &VariantData) { fn is_private(field: &StructField) -> bool { - matches!(field.vis.node, VisibilityKind::Inherited) + matches!(field.vis.kind, VisibilityKind::Inherited) } fn is_non_exhaustive_marker(field: &StructField) -> bool { @@ -141,7 +141,7 @@ fn check_manual_non_exhaustive_struct(cx: &EarlyContext<'_>, item: &Item, data: let fields = data.fields(); let private_fields = fields.iter().filter(|f| is_private(f)).count(); - let public_fields = fields.iter().filter(|f| f.vis.node.is_pub()).count(); + let public_fields = fields.iter().filter(|f| f.vis.kind.is_pub()).count(); if_chain! { if private_fields == 1 && public_fields >= 1 && public_fields == fields.len() - 1; diff --git a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs index 58bfd0bc553f4..35b38eca14d1b 100644 --- a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs +++ b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs @@ -41,7 +41,7 @@ impl EarlyLintPass for SingleComponentPathImports { if_chain! { if !in_macro(item.span); if cx.sess.opts.edition == Edition::Edition2018; - if !item.vis.node.is_pub(); + if !item.vis.kind.is_pub(); if let ItemKind::Use(use_tree) = &item.kind; if let segments = &use_tree.prefix.segments; if segments.len() == 1; diff --git a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs index 3c3f8b26e3ac1..4f0474c62cb6f 100644 --- a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs +++ b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs @@ -392,7 +392,7 @@ pub fn eq_defaultness(l: Defaultness, r: Defaultness) -> bool { pub fn eq_vis(l: &Visibility, r: &Visibility) -> bool { use VisibilityKind::*; - match (&l.node, &r.node) { + match (&l.kind, &r.kind) { (Public, Public) | (Inherited, Inherited) | (Crate(_), Crate(_)) => true, (Restricted { path: l, .. }, Restricted { path: r, .. }) => eq_path(l, r), _ => false, From 8808dc6abf8eeada2934b09f4f4245e57c1d6584 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 21 Aug 2020 22:11:41 -0400 Subject: [PATCH 0283/1052] Fully integrate token collection for additional AST structs This commit contains miscellaneous changes that don't fit into any of the other commits in this PR --- clippy_lints/src/enum_variants.rs | 4 ++-- clippy_lints/src/manual_non_exhaustive.rs | 4 ++-- clippy_lints/src/single_component_path_imports.rs | 2 +- clippy_lints/src/utils/ast_utils.rs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index a9294a87f15d0..67a463538568e 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -285,7 +285,7 @@ impl EarlyLintPass for EnumVariantNames { ); } } - if item.vis.node.is_pub() { + if item.vis.kind.is_pub() { let matching = partial_match(mod_camel, &item_camel); let rmatching = partial_rmatch(mod_camel, &item_camel); let nchars = mod_camel.chars().count(); @@ -316,7 +316,7 @@ impl EarlyLintPass for EnumVariantNames { } } if let ItemKind::Enum(ref def, _) = item.kind { - let lint = match item.vis.node { + let lint = match item.vis.kind { VisibilityKind::Public => PUB_ENUM_VARIANT_NAMES, _ => ENUM_VARIANT_NAMES, }; diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 4e49bdbdd21bd..9c623821fdddc 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -122,7 +122,7 @@ fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants fn check_manual_non_exhaustive_struct(cx: &EarlyContext<'_>, item: &Item, data: &VariantData) { fn is_private(field: &StructField) -> bool { - matches!(field.vis.node, VisibilityKind::Inherited) + matches!(field.vis.kind, VisibilityKind::Inherited) } fn is_non_exhaustive_marker(field: &StructField) -> bool { @@ -141,7 +141,7 @@ fn check_manual_non_exhaustive_struct(cx: &EarlyContext<'_>, item: &Item, data: let fields = data.fields(); let private_fields = fields.iter().filter(|f| is_private(f)).count(); - let public_fields = fields.iter().filter(|f| f.vis.node.is_pub()).count(); + let public_fields = fields.iter().filter(|f| f.vis.kind.is_pub()).count(); if_chain! { if private_fields == 1 && public_fields >= 1 && public_fields == fields.len() - 1; diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs index 58bfd0bc553f4..35b38eca14d1b 100644 --- a/clippy_lints/src/single_component_path_imports.rs +++ b/clippy_lints/src/single_component_path_imports.rs @@ -41,7 +41,7 @@ impl EarlyLintPass for SingleComponentPathImports { if_chain! { if !in_macro(item.span); if cx.sess.opts.edition == Edition::Edition2018; - if !item.vis.node.is_pub(); + if !item.vis.kind.is_pub(); if let ItemKind::Use(use_tree) = &item.kind; if let segments = &use_tree.prefix.segments; if segments.len() == 1; diff --git a/clippy_lints/src/utils/ast_utils.rs b/clippy_lints/src/utils/ast_utils.rs index 3c3f8b26e3ac1..4f0474c62cb6f 100644 --- a/clippy_lints/src/utils/ast_utils.rs +++ b/clippy_lints/src/utils/ast_utils.rs @@ -392,7 +392,7 @@ pub fn eq_defaultness(l: Defaultness, r: Defaultness) -> bool { pub fn eq_vis(l: &Visibility, r: &Visibility) -> bool { use VisibilityKind::*; - match (&l.node, &r.node) { + match (&l.kind, &r.kind) { (Public, Public) | (Inherited, Inherited) | (Crate(_), Crate(_)) => true, (Restricted { path: l, .. }, Restricted { path: r, .. }) => eq_path(l, r), _ => false, From 15aa6f31b974d41ecc0312faf8d50cde19a74cca Mon Sep 17 00:00:00 2001 From: Gus Wynn Date: Thu, 10 Sep 2020 14:58:45 -0700 Subject: [PATCH 0284/1052] add debug-logging to config.toml --- compiler/rustc/Cargo.toml | 1 + compiler/rustc_driver/Cargo.toml | 3 ++- config.toml.example | 6 ++++++ src/bootstrap/config.rs | 6 ++++++ src/bootstrap/lib.rs | 10 ++++++++++ 5 files changed, 25 insertions(+), 1 deletion(-) diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml index cf011e63e02fd..b740793a3e554 100644 --- a/compiler/rustc/Cargo.toml +++ b/compiler/rustc/Cargo.toml @@ -19,3 +19,4 @@ features = ['unprefixed_malloc_on_supported_platforms'] [features] jemalloc = ['jemalloc-sys'] llvm = ['rustc_driver/llvm'] +release_max_level_info = ['rustc_driver/release_max_level_info'] diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml index 0d9dcb262b269..6f0d7bc4d58e8 100644 --- a/compiler/rustc_driver/Cargo.toml +++ b/compiler/rustc_driver/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["dylib"] [dependencies] libc = "0.2" -tracing = { version = "0.1.18", features = ["release_max_level_info"] } +tracing = { version = "0.1.18" } tracing-subscriber = { version = "0.2.10", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] } rustc_middle = { path = "../rustc_middle" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } @@ -38,3 +38,4 @@ winapi = { version = "0.3", features = ["consoleapi", "debugapi", "processenv"] [features] llvm = ['rustc_interface/llvm'] +release_max_level_info = ['tracing/release_max_level_info'] diff --git a/config.toml.example b/config.toml.example index 9abb8add785a9..a162c543a50c3 100644 --- a/config.toml.example +++ b/config.toml.example @@ -329,6 +329,12 @@ # Defaults to rust.debug-assertions value #debug-assertions-std = false +# Whether or not to leave debug! and trace! calls in the rust binary. +# Overrides the `debug-assertions` option, if defined. +# +# Defaults to rust.debug-assertions value +#debug-logging = true + # Debuginfo level for most of Rust code, corresponds to the `-C debuginfo=N` option of `rustc`. # `0` - no debug info # `1` - line tables only - sufficient to generate backtraces that include line diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index ad2f48778674f..49a0855b97884 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -100,6 +100,7 @@ pub struct Config { pub rust_codegen_units_std: Option, pub rust_debug_assertions: bool, pub rust_debug_assertions_std: bool, + pub rust_debug_logging: bool, pub rust_debuginfo_level_rustc: u32, pub rust_debuginfo_level_std: u32, pub rust_debuginfo_level_tools: u32, @@ -381,6 +382,7 @@ struct Rust { codegen_units_std: Option, debug_assertions: Option, debug_assertions_std: Option, + debug_logging: Option, debuginfo_level: Option, debuginfo_level_rustc: Option, debuginfo_level_std: Option, @@ -591,6 +593,7 @@ impl Config { let mut debug = None; let mut debug_assertions = None; let mut debug_assertions_std = None; + let mut debug_logging = None; let mut debuginfo_level = None; let mut debuginfo_level_rustc = None; let mut debuginfo_level_std = None; @@ -634,6 +637,7 @@ impl Config { debug = rust.debug; debug_assertions = rust.debug_assertions; debug_assertions_std = rust.debug_assertions_std; + debug_logging = rust.debug_logging; debuginfo_level = rust.debuginfo_level; debuginfo_level_rustc = rust.debuginfo_level_rustc; debuginfo_level_std = rust.debuginfo_level_std; @@ -737,6 +741,8 @@ impl Config { config.rust_debug_assertions_std = debug_assertions_std.unwrap_or(config.rust_debug_assertions); + config.rust_debug_logging = debug_logging.unwrap_or(config.rust_debug_assertions); + let with_defaults = |debuginfo_level_specific: Option| { debuginfo_level_specific.or(debuginfo_level).unwrap_or(if debug == Some(true) { 1 diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index c1dec8ed18131..3c2663f6d9f57 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -541,6 +541,16 @@ impl Build { if self.config.llvm_enabled() { features.push_str(" llvm"); } + + // If debug logging is on, then we want the default for tracing: + // https://github.com/tokio-rs/tracing/blob/3dd5c03d907afdf2c39444a29931833335171554/tracing/src/level_filters.rs#L26 + // which is everything (including debug/trace/etc.) + // if its unset, if debug_assertions is on, then debug_logging will also be on + // as well as tracing *ignoring* this feature when debug_assertions is on + if !self.config.rust_debug_logging { + features.push_str(" release_max_level_info"); + } + features } From d18b4bb7a735add53cad717fd96ec5f4b89d752d Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 25 Jul 2020 07:04:13 -0400 Subject: [PATCH 0285/1052] Note when a a move/borrow error is caused by a deref coercion Fixes #73268 When a deref coercion occurs, we may end up with a move error if the base value has been partially moved out of. However, we do not indicate anywhere that a deref coercion is occuring, resulting in an error message with a confusing span. This PR adds an explicit note to move errors when a deref coercion is involved. We mention the name of the type that the deref-coercion resolved to, as well as the `Deref::Target` associated type being used. --- compiler/rustc_middle/src/ty/adjustment.rs | 4 + .../rustc_middle/src/ty/structural_impls.rs | 7 +- .../diagnostics/conflict_errors.rs | 27 ++++++- .../diagnostics/explain_borrow.rs | 2 +- .../src/borrow_check/diagnostics/mod.rs | 73 +++++++++++++++---- .../borrow_check/diagnostics/move_errors.rs | 6 +- compiler/rustc_mir/src/borrow_check/mod.rs | 5 +- .../transform/check_const_item_mutation.rs | 2 +- compiler/rustc_mir/src/util/find_self_call.rs | 13 ++-- compiler/rustc_mir_build/src/thir/cx/expr.rs | 29 ++++++-- compiler/rustc_span/src/symbol.rs | 2 + .../rustc_trait_selection/src/autoderef.rs | 7 ++ .../src/traits/error_reporting/suggestions.rs | 2 +- compiler/rustc_typeck/src/check/autoderef.rs | 19 ++++- .../rustc_typeck/src/check/method/confirm.rs | 3 +- .../rustc_typeck/src/check/method/probe.rs | 7 +- compiler/rustc_typeck/src/check/place_op.rs | 2 +- library/core/src/ops/deref.rs | 2 + .../lint/lint-unconditional-recursion.stderr | 2 +- src/test/ui/moves/move-deref-coercion.rs | 33 +++++++++ src/test/ui/moves/move-deref-coercion.stderr | 35 +++++++++ src/test/ui/no-capture-arc.stderr | 11 ++- src/test/ui/no-reuse-move-arc.stderr | 11 ++- 23 files changed, 250 insertions(+), 54 deletions(-) create mode 100644 src/test/ui/moves/move-deref-coercion.rs create mode 100644 src/test/ui/moves/move-deref-coercion.stderr diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index 6a9bb8d6c284f..46ef5ff7dd8c5 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -4,6 +4,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_macros::HashStable; +use rustc_span::Span; #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] pub enum PointerCast { @@ -113,6 +114,9 @@ pub enum Adjust<'tcx> { pub struct OverloadedDeref<'tcx> { pub region: ty::Region<'tcx>, pub mutbl: hir::Mutability, + /// The `Span` associated with the field access or method call + /// that triggered this overloaded deref. + pub span: Span, } impl<'tcx> OverloadedDeref<'tcx> { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index f8627e2f1b646..daa8b64959629 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -606,8 +606,11 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjust<'a> { impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::OverloadedDeref<'a> { type Lifted = ty::adjustment::OverloadedDeref<'tcx>; fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { - tcx.lift(&self.region) - .map(|region| ty::adjustment::OverloadedDeref { region, mutbl: self.mutbl }) + tcx.lift(&self.region).map(|region| ty::adjustment::OverloadedDeref { + region, + mutbl: self.mutbl, + span: self.span, + }) } } diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index 676065007b7ef..11122b195c0c4 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -66,7 +66,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let span = use_spans.args_or_use(); let move_site_vec = self.get_moved_indexes(location, mpi); - debug!("report_use_of_moved_or_uninitialized: move_site_vec={:?}", move_site_vec); + debug!( + "report_use_of_moved_or_uninitialized: move_site_vec={:?} use_spans={:?}", + move_site_vec, use_spans + ); let move_out_indices: Vec<_> = move_site_vec.iter().map(|move_site| move_site.moi).collect(); @@ -229,6 +232,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } } + // Deref::deref takes &self, which cannot cause a move + FnSelfUseKind::DerefCoercion { .. } => unreachable!(), } } else { err.span_label( @@ -355,6 +360,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.note_type_does_not_implement_copy(&mut err, ¬e_msg, ty, span, partial_str); } + if let UseSpans::FnSelfUse { + kind: FnSelfUseKind::DerefCoercion { deref_target, deref_target_ty }, + .. + } = use_spans + { + err.note(&format!( + "{} occurs due to deref coercion to `{}`", + desired_action.as_noun(), + deref_target_ty + )); + + err.span_note(deref_target, "deref defined here"); + } + if let Some((_, mut old_err)) = self.move_error_reported.insert(move_out_indices, (used_place, err)) { @@ -945,7 +964,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { name: &str, borrow: &BorrowData<'tcx>, drop_span: Span, - borrow_spans: UseSpans, + borrow_spans: UseSpans<'tcx>, explanation: BorrowExplanation, ) -> DiagnosticBuilder<'cx> { debug!( @@ -1146,7 +1165,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { location: Location, borrow: &BorrowData<'tcx>, drop_span: Span, - borrow_spans: UseSpans, + borrow_spans: UseSpans<'tcx>, proper_span: Span, explanation: BorrowExplanation, ) -> DiagnosticBuilder<'cx> { @@ -1274,7 +1293,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn report_escaping_closure_capture( &mut self, - use_span: UseSpans, + use_span: UseSpans<'tcx>, var_span: Span, fr_name: &RegionName, category: ConstraintCategory, diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs index eaaf202f3bd13..eccb6168229c2 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs @@ -501,7 +501,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn later_use_kind( &self, borrow: &BorrowData<'tcx>, - use_spans: UseSpans, + use_spans: UseSpans<'tcx>, location: Location, ) -> (LaterUseKind, Span) { match use_spans { diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs index 3cee32834beb7..4256f6e39d5e8 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs @@ -11,7 +11,7 @@ use rustc_middle::mir::{ PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }; use rustc_middle::ty::print::Print; -use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt}; +use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt}; use rustc_span::{ hygiene::{DesugaringKind, ForLoopLoc}, symbol::sym, @@ -538,7 +538,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// The span(s) associated to a use of a place. #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub(super) enum UseSpans { +pub(super) enum UseSpans<'tcx> { /// The access is caused by capturing a variable for a closure. ClosureUse { /// This is true if the captured variable was from a generator. @@ -558,7 +558,7 @@ pub(super) enum UseSpans { fn_call_span: Span, /// The definition span of the method being called fn_span: Span, - kind: FnSelfUseKind, + kind: FnSelfUseKind<'tcx>, }, /// This access is caused by a `match` or `if let` pattern. PatUse(Span), @@ -567,22 +567,32 @@ pub(super) enum UseSpans { } #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub(super) enum FnSelfUseKind { +pub(super) enum FnSelfUseKind<'tcx> { /// A normal method call of the form `receiver.foo(a, b, c)` Normal { self_arg: Ident, implicit_into_iter: bool }, /// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)` FnOnceCall, /// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`) Operator { self_arg: Ident }, + DerefCoercion { + /// The `Span` of the `Target` associated type + /// in the `Deref` impl we are using. + deref_target: Span, + /// The type `T::Deref` we are dereferencing to + deref_target_ty: Ty<'tcx>, + }, } -impl UseSpans { +impl UseSpans<'_> { pub(super) fn args_or_use(self) -> Span { match self { UseSpans::ClosureUse { args_span: span, .. } | UseSpans::PatUse(span) - | UseSpans::FnSelfUse { var_span: span, .. } | UseSpans::OtherUse(span) => span, + UseSpans::FnSelfUse { + fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, .. + } => fn_call_span, + UseSpans::FnSelfUse { var_span, .. } => var_span, } } @@ -590,8 +600,11 @@ impl UseSpans { match self { UseSpans::ClosureUse { var_span: span, .. } | UseSpans::PatUse(span) - | UseSpans::FnSelfUse { var_span: span, .. } | UseSpans::OtherUse(span) => span, + UseSpans::FnSelfUse { + fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, .. + } => fn_call_span, + UseSpans::FnSelfUse { var_span, .. } => var_span, } } @@ -754,7 +767,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &self, moved_place: PlaceRef<'tcx>, // Could also be an upvar. location: Location, - ) -> UseSpans { + ) -> UseSpans<'tcx> { use self::UseSpans::*; let stmt = match self.body[location.block].statements.get(location.statement_index) { @@ -809,36 +822,64 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { kind: TerminatorKind::Call { fn_span, from_hir_call, .. }, .. }) = &self.body[location.block].terminator { - let method_did = if let Some(method_did) = + let (method_did, method_substs) = if let Some(info) = crate::util::find_self_call(self.infcx.tcx, &self.body, target_temp, location.block) { - method_did + info } else { return normal_ret; }; let tcx = self.infcx.tcx; - let parent = tcx.parent(method_did); let is_fn_once = parent == tcx.lang_items().fn_once_trait(); let is_operator = !from_hir_call && parent.map_or(false, |p| tcx.lang_items().group(LangItemGroup::Op).contains(&p)); + let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did); let fn_call_span = *fn_span; let self_arg = tcx.fn_arg_names(method_did)[0]; + debug!( + "terminator = {:?} from_hir_call={:?}", + self.body[location.block].terminator, from_hir_call + ); + + // Check for a 'special' use of 'self' - + // an FnOnce call, an operator (e.g. `<<`), or a + // deref coercion. let kind = if is_fn_once { - FnSelfUseKind::FnOnceCall + Some(FnSelfUseKind::FnOnceCall) } else if is_operator { - FnSelfUseKind::Operator { self_arg } + Some(FnSelfUseKind::Operator { self_arg }) + } else if is_deref { + let deref_target = + tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| { + Instance::resolve(tcx, self.param_env, deref_target, method_substs) + .transpose() + }); + if let Some(Ok(instance)) = deref_target { + let deref_target_ty = instance.ty(tcx, self.param_env); + Some(FnSelfUseKind::DerefCoercion { + deref_target: tcx.def_span(instance.def_id()), + deref_target_ty, + }) + } else { + None + } } else { + None + }; + + let kind = kind.unwrap_or_else(|| { + // This isn't a 'special' use of `self` debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span); let implicit_into_iter = matches!( fn_call_span.desugaring_kind(), Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter)) ); FnSelfUseKind::Normal { self_arg, implicit_into_iter } - }; + }); return FnSelfUse { var_span: stmt.source_info.span, @@ -859,7 +900,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// and its usage of the local assigned at `location`. /// This is done by searching in statements succeeding `location` /// and originating from `maybe_closure_span`. - pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans { + pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans<'tcx> { use self::UseSpans::*; debug!("borrow_spans: use_span={:?} location={:?}", use_span, location); @@ -963,7 +1004,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// Helper to retrieve span(s) of given borrow from the current MIR /// representation - pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans { + pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans<'tcx> { let span = self.body.source_info(borrow.reserve_location).span; self.borrow_spans(span, borrow.reserve_location) } diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs index 6cf1cf20b5afd..e256fb55b124b 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs @@ -47,7 +47,7 @@ enum GroupedMoveError<'tcx> { // Everything that isn't from pattern matching. OtherIllegalMove { original_path: Place<'tcx>, - use_spans: UseSpans, + use_spans: UseSpans<'tcx>, kind: IllegalMoveOriginKind<'tcx>, }, } @@ -222,7 +222,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let (mut err, err_span) = { let (span, use_spans, original_path, kind): ( Span, - Option, + Option>, Place<'tcx>, &IllegalMoveOriginKind<'_>, ) = match error { @@ -291,7 +291,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { move_place: Place<'tcx>, deref_target_place: Place<'tcx>, span: Span, - use_spans: Option, + use_spans: Option>, ) -> DiagnosticBuilder<'a> { // Inspect the type of the content behind the // borrow to provide feedback about why this diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs index acd9e3dcf3fcd..64ad0627720aa 100644 --- a/compiler/rustc_mir/src/borrow_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/mod.rs @@ -17,7 +17,7 @@ use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind}; use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind}; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, InstanceDef, RegionVid, TyCtxt}; +use rustc_middle::ty::{self, InstanceDef, ParamEnv, RegionVid, TyCtxt}; use rustc_session::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT, UNUSED_MUT}; use rustc_span::{Span, Symbol, DUMMY_SP}; @@ -287,6 +287,7 @@ fn do_mir_borrowck<'a, 'tcx>( if let Err((move_data, move_errors)) = move_data_results { let mut promoted_mbcx = MirBorrowckCtxt { infcx, + param_env, body: promoted_body, mir_def_id: def.did, move_data: &move_data, @@ -320,6 +321,7 @@ fn do_mir_borrowck<'a, 'tcx>( let mut mbcx = MirBorrowckCtxt { infcx, + param_env, body, mir_def_id: def.did, move_data: &mdpe.move_data, @@ -473,6 +475,7 @@ fn do_mir_borrowck<'a, 'tcx>( crate struct MirBorrowckCtxt<'cx, 'tcx> { crate infcx: &'cx InferCtxt<'cx, 'tcx>, + param_env: ParamEnv<'tcx>, body: &'cx Body<'tcx>, mir_def_id: LocalDefId, move_data: &'cx MoveData<'tcx>, diff --git a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs index 589268e39bda9..70c1aed0957f8 100644 --- a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs +++ b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs @@ -101,7 +101,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ConstMutationChecker<'a, 'tcx> { .note("each usage of a `const` item creates a new temporary") .note("the mutable reference will refer to this temporary, not the original `const` item"); - if let Some(method_did) = method_did { + if let Some((method_did, _substs)) = method_did { lint.span_note(self.tcx.def_span(method_did), "mutable reference created due to call to this method"); } diff --git a/compiler/rustc_mir/src/util/find_self_call.rs b/compiler/rustc_mir/src/util/find_self_call.rs index 049b5f01214cf..5b146eeb87c04 100644 --- a/compiler/rustc_mir/src/util/find_self_call.rs +++ b/compiler/rustc_mir/src/util/find_self_call.rs @@ -1,30 +1,31 @@ use rustc_middle::mir::*; +use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::def_id::DefId; /// Checks if the specified `local` is used as the `self` prameter of a method call /// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is /// returned. -pub fn find_self_call( - tcx: TyCtxt<'_>, - body: &Body<'_>, +pub fn find_self_call<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, local: Local, block: BasicBlock, -) -> Option { +) -> Option<(DefId, SubstsRef<'tcx>)> { debug!("find_self_call(local={:?}): terminator={:?}", local, &body[block].terminator); if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) = &body[block].terminator { debug!("find_self_call: func={:?}", func); if let Operand::Constant(box Constant { literal: ty::Const { ty, .. }, .. }) = func { - if let ty::FnDef(def_id, _) = *ty.kind() { + if let ty::FnDef(def_id, substs) = *ty.kind() { if let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) = tcx.opt_associated_item(def_id) { debug!("find_self_call: args={:?}", args); if let [Operand::Move(self_place) | Operand::Copy(self_place), ..] = **args { if self_place.as_local() == Some(local) { - return Some(def_id); + return Some((def_id, substs)); } } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 70c7abc265492..13e69474cfb96 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -117,7 +117,14 @@ fn apply_adjustment<'a, 'tcx>( }, }; - overloaded_place(cx, hir_expr, adjustment.target, Some(call), vec![expr.to_ref()]) + overloaded_place( + cx, + hir_expr, + adjustment.target, + Some(call), + vec![expr.to_ref()], + deref.span, + ) } Adjust::Borrow(AutoBorrow::Ref(_, m)) => { ExprKind::Borrow { borrow_kind: m.to_borrow_kind(), arg: expr.to_ref() } @@ -277,7 +284,14 @@ fn make_mirror_unadjusted<'a, 'tcx>( hir::ExprKind::Index(ref lhs, ref index) => { if cx.typeck_results().is_method_call(expr) { - overloaded_place(cx, expr, expr_ty, None, vec![lhs.to_ref(), index.to_ref()]) + overloaded_place( + cx, + expr, + expr_ty, + None, + vec![lhs.to_ref(), index.to_ref()], + expr.span, + ) } else { ExprKind::Index { lhs: lhs.to_ref(), index: index.to_ref() } } @@ -285,7 +299,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( hir::ExprKind::Unary(hir::UnOp::UnDeref, ref arg) => { if cx.typeck_results().is_method_call(expr) { - overloaded_place(cx, expr, expr_ty, None, vec![arg.to_ref()]) + overloaded_place(cx, expr, expr_ty, None, vec![arg.to_ref()], expr.span) } else { ExprKind::Deref { arg: arg.to_ref() } } @@ -1025,6 +1039,7 @@ fn overloaded_place<'a, 'tcx>( place_ty: Ty<'tcx>, overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>, args: Vec>, + span: Span, ) -> ExprKind<'tcx> { // For an overloaded *x or x[y] expression of type T, the method // call returns an &T and we must add the deref so that the types @@ -1040,24 +1055,24 @@ fn overloaded_place<'a, 'tcx>( // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`. let (region, mutbl) = match *recv_ty.kind() { ty::Ref(region, _, mutbl) => (region, mutbl), - _ => span_bug!(expr.span, "overloaded_place: receiver is not a reference"), + _ => span_bug!(span, "overloaded_place: receiver is not a reference"), }; let ref_ty = cx.tcx.mk_ref(region, ty::TypeAndMut { ty: place_ty, mutbl }); // construct the complete expression `foo()` for the overloaded call, // which will yield the &T type let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id); - let fun = method_callee(cx, expr, expr.span, overloaded_callee); + let fun = method_callee(cx, expr, span, overloaded_callee); let ref_expr = Expr { temp_lifetime, ty: ref_ty, - span: expr.span, + span, kind: ExprKind::Call { ty: fun.ty, fun: fun.to_ref(), args, from_hir_call: false, - fn_span: expr.span, + fn_span: span, }, }; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 407663e57577a..94f795b11ea4d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -416,7 +416,9 @@ symbols! { deny, deprecated, deref, + deref_method, deref_mut, + deref_target, derive, diagnostic, direct, diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs index 02eefe5622384..b9c5123e49a0e 100644 --- a/compiler/rustc_trait_selection/src/autoderef.rs +++ b/compiler/rustc_trait_selection/src/autoderef.rs @@ -27,6 +27,7 @@ pub struct Autoderef<'a, 'tcx> { // Meta infos: infcx: &'a InferCtxt<'a, 'tcx>, span: Span, + overloaded_span: Span, body_id: hir::HirId, param_env: ty::ParamEnv<'tcx>, @@ -98,10 +99,12 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { body_id: hir::HirId, span: Span, base_ty: Ty<'tcx>, + overloaded_span: Span, ) -> Autoderef<'a, 'tcx> { Autoderef { infcx, span, + overloaded_span, body_id, param_env, state: AutoderefSnapshot { @@ -190,6 +193,10 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { self.span } + pub fn overloaded_span(&self) -> Span { + self.overloaded_span + } + pub fn reached_recursion_limit(&self) -> bool { self.state.reached_recursion_limit } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 82e809d014dd0..90a8d9634ae1e 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -483,7 +483,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }; if let ty::Ref(region, base_ty, mutbl) = *real_ty.kind() { - let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty); + let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty, span); if let Some(steps) = autoderef.find_map(|(ty, steps)| { // Re-add the `&` let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl }); diff --git a/compiler/rustc_typeck/src/check/autoderef.rs b/compiler/rustc_typeck/src/check/autoderef.rs index 17364897bde13..59c366ad7d776 100644 --- a/compiler/rustc_typeck/src/check/autoderef.rs +++ b/compiler/rustc_typeck/src/check/autoderef.rs @@ -12,7 +12,18 @@ use std::iter; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> { - Autoderef::new(self, self.param_env, self.body_id, span, base_ty) + Autoderef::new(self, self.param_env, self.body_id, span, base_ty, span) + } + + /// Like `autoderef`, but provides a custom `Span` to use for calls to + /// an overloaded `Deref` operator + pub fn autoderef_overloaded_span( + &'a self, + span: Span, + base_ty: Ty<'tcx>, + overloaded_span: Span, + ) -> Autoderef<'a, 'tcx> { + Autoderef::new(self, self.param_env, self.body_id, span, base_ty, overloaded_span) } pub fn try_overloaded_deref( @@ -44,7 +55,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |InferOk { value: method, obligations: o }| { obligations.extend(o); if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() { - Some(OverloadedDeref { region, mutbl }) + Some(OverloadedDeref { + region, + mutbl, + span: autoderef.overloaded_span(), + }) } else { None } diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs index ae338cccf7977..fd2700b85e279 100644 --- a/compiler/rustc_typeck/src/check/method/confirm.rs +++ b/compiler/rustc_typeck/src/check/method/confirm.rs @@ -137,7 +137,8 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { ) -> Ty<'tcx> { // Commit the autoderefs by calling `autoderef` again, but this // time writing the results into the various typeck results. - let mut autoderef = self.autoderef(self.span, unadjusted_self_ty); + let mut autoderef = + self.autoderef_overloaded_span(self.span, unadjusted_self_ty, self.call_expr.span); let (_, n) = match autoderef.nth(pick.autoderefs) { Some(n) => n, None => { diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index 14d80fded7122..37e8e82e60a8b 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -446,9 +446,10 @@ fn method_autoderef_steps<'tcx>( tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &goal, |ref infcx, goal, inference_vars| { let ParamEnvAnd { param_env, value: self_ty } = goal; - let mut autoderef = Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty) - .include_raw_pointers() - .silence_errors(); + let mut autoderef = + Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty, DUMMY_SP) + .include_raw_pointers() + .silence_errors(); let mut reached_raw_pointer = false; let mut steps: Vec<_> = autoderef .by_ref() diff --git a/compiler/rustc_typeck/src/check/place_op.rs b/compiler/rustc_typeck/src/check/place_op.rs index aed2af20e5271..502cb562385e0 100644 --- a/compiler/rustc_typeck/src/check/place_op.rs +++ b/compiler/rustc_typeck/src/check/place_op.rs @@ -242,7 +242,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { let method = self.register_infer_ok_obligations(ok); if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() { - *deref = OverloadedDeref { region, mutbl }; + *deref = OverloadedDeref { region, mutbl, span: deref.span }; } // If this is a union field, also throw an error for `DerefMut` of `ManuallyDrop` (see RFC 2514). // This helps avoid accidental drops. diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index d6c097eee17bf..245152e5490d8 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -63,11 +63,13 @@ pub trait Deref { /// The resulting type after dereferencing. #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_diagnostic_item = "deref_target"] type Target: ?Sized; /// Dereferences the value. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_diagnostic_item = "deref_method"] fn deref(&self) -> &Self::Target; } diff --git a/src/test/ui/lint/lint-unconditional-recursion.stderr b/src/test/ui/lint/lint-unconditional-recursion.stderr index 1770d71e2e2fe..fb884e3129999 100644 --- a/src/test/ui/lint/lint-unconditional-recursion.stderr +++ b/src/test/ui/lint/lint-unconditional-recursion.stderr @@ -149,7 +149,7 @@ error: function cannot return without recursing LL | fn deref(&self) -> &Baz { | ^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing LL | self.as_ref() - | ---- recursive call site + | ------------- recursive call site | = help: a `loop` may express intention better if this is on purpose diff --git a/src/test/ui/moves/move-deref-coercion.rs b/src/test/ui/moves/move-deref-coercion.rs new file mode 100644 index 0000000000000..41154388f56a8 --- /dev/null +++ b/src/test/ui/moves/move-deref-coercion.rs @@ -0,0 +1,33 @@ +use std::ops::Deref; + +struct NotCopy { + inner: bool +} + +impl NotCopy { + fn inner_method(&self) {} +} + +struct Foo { + first: NotCopy, + second: NotCopy +} + +impl Deref for Foo { + type Target = NotCopy; + fn deref(&self) -> &NotCopy { + &self.second + } +} + +fn use_field(val: Foo) { + let _val = val.first; + val.inner; //~ ERROR borrow of +} + +fn use_method(val: Foo) { + let _val = val.first; + val.inner_method(); //~ ERROR borrow of +} + +fn main() {} diff --git a/src/test/ui/moves/move-deref-coercion.stderr b/src/test/ui/moves/move-deref-coercion.stderr new file mode 100644 index 0000000000000..e3bdf6d783207 --- /dev/null +++ b/src/test/ui/moves/move-deref-coercion.stderr @@ -0,0 +1,35 @@ +error[E0382]: borrow of partially moved value: `val` + --> $DIR/move-deref-coercion.rs:25:5 + | +LL | let _val = val.first; + | --------- value partially moved here +LL | val.inner; + | ^^^^^^^^^ value borrowed here after partial move + | + = note: partial move occurs because `val.first` has type `NotCopy`, which does not implement the `Copy` trait + = note: borrow occurs due to deref coercion to `NotCopy` +note: deref defined here + --> $DIR/move-deref-coercion.rs:17:5 + | +LL | type Target = NotCopy; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0382]: borrow of partially moved value: `val` + --> $DIR/move-deref-coercion.rs:30:5 + | +LL | let _val = val.first; + | --------- value partially moved here +LL | val.inner_method(); + | ^^^^^^^^^^^^^^^^^^ value borrowed here after partial move + | + = note: partial move occurs because `val.first` has type `NotCopy`, which does not implement the `Copy` trait + = note: borrow occurs due to deref coercion to `NotCopy` +note: deref defined here + --> $DIR/move-deref-coercion.rs:17:5 + | +LL | type Target = NotCopy; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/no-capture-arc.stderr b/src/test/ui/no-capture-arc.stderr index 0081841fec090..37032e73f1900 100644 --- a/src/test/ui/no-capture-arc.stderr +++ b/src/test/ui/no-capture-arc.stderr @@ -1,5 +1,5 @@ error[E0382]: borrow of moved value: `arc_v` - --> $DIR/no-capture-arc.rs:14:18 + --> $DIR/no-capture-arc.rs:14:16 | LL | let arc_v = Arc::new(v); | ----- move occurs because `arc_v` has type `Arc>`, which does not implement the `Copy` trait @@ -10,7 +10,14 @@ LL | assert_eq!((*arc_v)[3], 4); | ----- variable moved due to use in closure ... LL | assert_eq!((*arc_v)[2], 3); - | ^^^^^ value borrowed here after move + | ^^^^^^^^ value borrowed here after move + | + = note: borrow occurs due to deref coercion to `Vec` +note: deref defined here + --> $SRC_DIR/alloc/src/sync.rs:LL:COL + | +LL | type Target = T; + | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/no-reuse-move-arc.stderr b/src/test/ui/no-reuse-move-arc.stderr index bb4e0871224a2..6f37d4c9d8691 100644 --- a/src/test/ui/no-reuse-move-arc.stderr +++ b/src/test/ui/no-reuse-move-arc.stderr @@ -1,5 +1,5 @@ error[E0382]: borrow of moved value: `arc_v` - --> $DIR/no-reuse-move-arc.rs:12:18 + --> $DIR/no-reuse-move-arc.rs:12:16 | LL | let arc_v = Arc::new(v); | ----- move occurs because `arc_v` has type `Arc>`, which does not implement the `Copy` trait @@ -10,7 +10,14 @@ LL | assert_eq!((*arc_v)[3], 4); | ----- variable moved due to use in closure ... LL | assert_eq!((*arc_v)[2], 3); - | ^^^^^ value borrowed here after move + | ^^^^^^^^ value borrowed here after move + | + = note: borrow occurs due to deref coercion to `Vec` +note: deref defined here + --> $SRC_DIR/alloc/src/sync.rs:LL:COL + | +LL | type Target = T; + | ^^^^^^^^^^^^^^^^ error: aborting due to previous error From 954361a3d4f8b87a9311b5c976b7e301f6bae1bb Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Fri, 11 Sep 2020 04:05:19 +0200 Subject: [PATCH 0286/1052] Update `std::os` module documentation. Adds missing descriptions for the modules std::os::linux::fs and std::os::windows::io. Also adds punctuation for consistency with other descriptions. --- library/std/src/os/linux/fs.rs | 2 ++ library/std/src/os/linux/mod.rs | 2 +- library/std/src/os/linux/raw.rs | 2 +- library/std/src/sys/unix/ext/ffi.rs | 2 +- library/std/src/sys/unix/ext/io.rs | 2 +- library/std/src/sys/unix/ext/net.rs | 4 ++-- library/std/src/sys/unix/ext/raw.rs | 2 +- library/std/src/sys/windows/ext/io.rs | 2 ++ library/std/src/sys/windows/ext/raw.rs | 2 +- 9 files changed, 12 insertions(+), 8 deletions(-) diff --git a/library/std/src/os/linux/fs.rs b/library/std/src/os/linux/fs.rs index 14719a9be5e8a..ff23c3d67e3b4 100644 --- a/library/std/src/os/linux/fs.rs +++ b/library/std/src/os/linux/fs.rs @@ -1,3 +1,5 @@ +//! Linux-specific extensions to primitives in the `std::fs` module. + #![stable(feature = "metadata_ext", since = "1.1.0")] use crate::fs::Metadata; diff --git a/library/std/src/os/linux/mod.rs b/library/std/src/os/linux/mod.rs index d35307162cc7e..f179a524336fc 100644 --- a/library/std/src/os/linux/mod.rs +++ b/library/std/src/os/linux/mod.rs @@ -1,4 +1,4 @@ -//! Linux-specific definitions +//! Linux-specific definitions. #![stable(feature = "raw_ext", since = "1.1.0")] diff --git a/library/std/src/os/linux/raw.rs b/library/std/src/os/linux/raw.rs index 1950ffcb21b67..a007fd2b6be04 100644 --- a/library/std/src/os/linux/raw.rs +++ b/library/std/src/os/linux/raw.rs @@ -1,4 +1,4 @@ -//! Linux-specific raw type definitions +//! Linux-specific raw type definitions. #![stable(feature = "raw_ext", since = "1.1.0")] #![rustc_deprecated( diff --git a/library/std/src/sys/unix/ext/ffi.rs b/library/std/src/sys/unix/ext/ffi.rs index 76b34a6b5d84a..123f85deaf9e3 100644 --- a/library/std/src/sys/unix/ext/ffi.rs +++ b/library/std/src/sys/unix/ext/ffi.rs @@ -1,4 +1,4 @@ -//! Unix-specific extension to the primitives in the `std::ffi` module +//! Unix-specific extension to the primitives in the `std::ffi` module. //! //! # Examples //! diff --git a/library/std/src/sys/unix/ext/io.rs b/library/std/src/sys/unix/ext/io.rs index 5077e2e28d18b..ec7a32b675c02 100644 --- a/library/std/src/sys/unix/ext/io.rs +++ b/library/std/src/sys/unix/ext/io.rs @@ -1,4 +1,4 @@ -//! Unix-specific extensions to general I/O primitives +//! Unix-specific extensions to general I/O primitives. #![stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/sys/unix/ext/net.rs b/library/std/src/sys/unix/ext/net.rs index 0e07106f5ce5c..0efd5b9f11043 100644 --- a/library/std/src/sys/unix/ext/net.rs +++ b/library/std/src/sys/unix/ext/net.rs @@ -1,6 +1,6 @@ -#![stable(feature = "unix_socket", since = "1.10.0")] +//! Unix-specific networking functionality. -//! Unix-specific networking functionality +#![stable(feature = "unix_socket", since = "1.10.0")] #[cfg(all(test, not(target_os = "emscripten")))] mod tests; diff --git a/library/std/src/sys/unix/ext/raw.rs b/library/std/src/sys/unix/ext/raw.rs index 40fa53d484f84..3199a0bff0bcc 100644 --- a/library/std/src/sys/unix/ext/raw.rs +++ b/library/std/src/sys/unix/ext/raw.rs @@ -1,4 +1,4 @@ -//! Unix-specific primitives available on all unix platforms +//! Unix-specific primitives available on all unix platforms. #![stable(feature = "raw_ext", since = "1.1.0")] #![rustc_deprecated( diff --git a/library/std/src/sys/windows/ext/io.rs b/library/std/src/sys/windows/ext/io.rs index 4573ee589321d..e75f9a4bfd5e3 100644 --- a/library/std/src/sys/windows/ext/io.rs +++ b/library/std/src/sys/windows/ext/io.rs @@ -1,3 +1,5 @@ +//! Windows-specific extensions to general I/O primitives. + #![stable(feature = "rust1", since = "1.0.0")] use crate::fs; diff --git a/library/std/src/sys/windows/ext/raw.rs b/library/std/src/sys/windows/ext/raw.rs index 7f2a2877828cf..5014e008eb599 100644 --- a/library/std/src/sys/windows/ext/raw.rs +++ b/library/std/src/sys/windows/ext/raw.rs @@ -1,4 +1,4 @@ -//! Windows-specific primitives +//! Windows-specific primitives. #![stable(feature = "raw_ext", since = "1.1.0")] From 439b7661616ec26092176baf905a0ceeb4a3c620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Deharbe?= Date: Fri, 11 Sep 2020 11:11:11 +0200 Subject: [PATCH 0287/1052] replacing sub's that can wrap by saturating_sub's --- compiler/rustc_errors/src/emitter.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 5a654e83aed8e..4555168af0ab5 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -959,15 +959,15 @@ impl EmitterWriter { '_', line_offset + pos, width_offset + depth, - code_offset + annotation.start_col - left, + (code_offset + annotation.start_col).saturating_sub(left), style, ); } _ if self.teach => { buffer.set_style_range( line_offset, - code_offset + annotation.start_col - left, - code_offset + annotation.end_col - left, + (code_offset + annotation.start_col).saturating_sub(left), + (code_offset + annotation.end_col).saturating_sub(left), style, annotation.is_primary, ); From ec7f9b927f1896c7f29c602d6b0f961c891d0941 Mon Sep 17 00:00:00 2001 From: Federico Ponzi Date: Fri, 11 Sep 2020 11:11:34 +0200 Subject: [PATCH 0288/1052] Deduplicates io::Write implementations --- library/std/src/io/stdio.rs | 28 ++++++++++++++-------------- library/std/src/process.rs | 8 ++++---- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index f320cf907c365..cccc0aadf9989 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -584,26 +584,26 @@ impl fmt::Debug for Stdout { #[stable(feature = "rust1", since = "1.0.0")] impl Write for Stdout { fn write(&mut self, buf: &[u8]) -> io::Result { - self.lock().write(buf) + (&*self).write(buf) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.lock().write_vectored(bufs) + (&*self).write_vectored(bufs) } #[inline] fn is_write_vectored(&self) -> bool { - self.lock().is_write_vectored() + io::Write::is_write_vectored(&&*self) } fn flush(&mut self) -> io::Result<()> { - self.lock().flush() + (&*self).flush() } fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.lock().write_all(buf) + (&*self).write_all(buf) } fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - self.lock().write_all_vectored(bufs) + (&*self).write_all_vectored(bufs) } fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { - self.lock().write_fmt(args) + (&*self).write_fmt(args) } } @@ -787,26 +787,26 @@ impl fmt::Debug for Stderr { #[stable(feature = "rust1", since = "1.0.0")] impl Write for Stderr { fn write(&mut self, buf: &[u8]) -> io::Result { - self.lock().write(buf) + (&*self).write(buf) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.lock().write_vectored(bufs) + (&*self).write_vectored(bufs) } #[inline] fn is_write_vectored(&self) -> bool { - self.lock().is_write_vectored() + io::Write::is_write_vectored(&&*self) } fn flush(&mut self) -> io::Result<()> { - self.lock().flush() + (&*self).flush() } fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.lock().write_all(buf) + (&*self).write_all(buf) } fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - self.lock().write_all_vectored(bufs) + (&*self).write_all_vectored(bufs) } fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { - self.lock().write_fmt(args) + (&*self).write_fmt(args) } } diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 36521fdaec00f..d620a720be3ab 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -246,19 +246,19 @@ pub struct ChildStdin { #[stable(feature = "process", since = "1.0.0")] impl Write for ChildStdin { fn write(&mut self, buf: &[u8]) -> io::Result { - self.inner.write(buf) + (&*self).write(buf) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.inner.write_vectored(bufs) + (&*self).write_vectored(bufs) } fn is_write_vectored(&self) -> bool { - self.inner.is_write_vectored() + io::Write::is_write_vectored(&&*self) } fn flush(&mut self) -> io::Result<()> { - Ok(()) + (&*self).flush() } } From 9abc6bd28df390279b9f477538a778edf38ffd80 Mon Sep 17 00:00:00 2001 From: Hameer Abbasi Date: Fri, 11 Sep 2020 11:42:32 +0200 Subject: [PATCH 0289/1052] Add revisions to const generic const_evaluatable_checked tests. --- ...feature-gate-const_evaluatable_checked.full.stderr} | 2 +- .../feature-gate-const_evaluatable_checked.min.stderr | 10 ++++++++++ .../feature-gate-const_evaluatable_checked.rs | 9 ++++++--- .../const_evaluatable_checked/simple.min.stderr | 10 ++++++++++ .../const-generics/const_evaluatable_checked/simple.rs | 8 ++++++-- .../{simple_fail.stderr => simple_fail.full.stderr} | 2 +- .../const_evaluatable_checked/simple_fail.min.stderr | 10 ++++++++++ .../const_evaluatable_checked/simple_fail.rs | 8 ++++++-- 8 files changed, 50 insertions(+), 9 deletions(-) rename src/test/ui/const-generics/const_evaluatable_checked/{feature-gate-const_evaluatable_checked.stderr => feature-gate-const_evaluatable_checked.full.stderr} (82%) create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr rename src/test/ui/const-generics/const_evaluatable_checked/{simple_fail.stderr => simple_fail.full.stderr} (90%) create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.stderr b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.full.stderr similarity index 82% rename from src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.stderr rename to src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.full.stderr index 6e4a22a38b17c..b2816367ea107 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.full.stderr @@ -1,5 +1,5 @@ error: constant expression depends on a generic parameter - --> $DIR/feature-gate-const_evaluatable_checked.rs:6:30 + --> $DIR/feature-gate-const_evaluatable_checked.rs:9:30 | LL | fn test() -> Arr where Arr: Default { | ^^^^^^ diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr new file mode 100644 index 0000000000000..269710db164b1 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/feature-gate-const_evaluatable_checked.rs:6:33 + | +LL | type Arr = [u8; N - 1]; + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs index 941bd5e9e5d0a..af3090115f24a 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs +++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs @@ -1,10 +1,13 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] type Arr = [u8; N - 1]; +//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values fn test() -> Arr where Arr: Default { - //~^ ERROR constant expression depends + //[full]~^ ERROR constant expression depends Default::default() } diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr new file mode 100644 index 0000000000000..da8ccdaee4146 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/simple.rs:8:33 + | +LL | type Arr = [u8; N - 1]; + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple.rs index a7ead78b97bae..27dc6b103200d 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/simple.rs +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple.rs @@ -1,8 +1,12 @@ -// run-pass -#![feature(const_generics, const_evaluatable_checked)] +// [full] run-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(min, feature(min_const_generics))] +#![feature(const_evaluatable_checked)] #![allow(incomplete_features)] type Arr = [u8; N - 1]; +//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values fn test() -> Arr where Arr: Default { Default::default() diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr similarity index 90% rename from src/test/ui/const-generics/const_evaluatable_checked/simple_fail.stderr rename to src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr index 1ac5e1d95537a..104cab8667c70 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr @@ -1,5 +1,5 @@ error[E0080]: evaluation of constant value failed - --> $DIR/simple_fail.rs:4:33 + --> $DIR/simple_fail.rs:7:33 | LL | type Arr = [u8; N - 1]; | ^^^^^ attempt to compute `0_usize - 1_usize` which would overflow diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr new file mode 100644 index 0000000000000..042710f13273e --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/simple_fail.rs:7:33 + | +LL | type Arr = [u8; N - 1]; + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs index 1edf1885dd281..b15e0ff183954 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs @@ -1,7 +1,11 @@ -#![feature(const_generics, const_evaluatable_checked)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(min, feature(min_const_generics))] +#![feature(const_evaluatable_checked)] #![allow(incomplete_features)] -type Arr = [u8; N - 1]; //~ ERROR evaluation of constant +type Arr = [u8; N - 1]; //[full]~ ERROR evaluation of constant +//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values fn test() -> Arr where Arr: Sized { todo!() From 5e188f5803bdbfdf3ff000e8b7e266405531c8d7 Mon Sep 17 00:00:00 2001 From: Hameer Abbasi Date: Fri, 11 Sep 2020 11:48:44 +0200 Subject: [PATCH 0290/1052] Add revisions to const generic type-dependent UI tests. --- .../type-dependent/auxiliary/type_dependent_lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs b/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs index c8db91b62b58c..aa85376bf0d75 100644 --- a/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs +++ b/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs @@ -1,5 +1,6 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub struct Struct(()); From 1854f8b3d8bb5f35554f3bdf61f63853ae720742 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 9 Sep 2020 22:16:13 +0200 Subject: [PATCH 0291/1052] Warn for #[unstable] on trait impls when it has no effect. --- compiler/rustc_passes/src/stability.rs | 66 +++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 91edc7d9db775..d3141c34d0e11 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -9,7 +9,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_hir::{Generics, HirId, Item, StructField, Variant}; +use rustc_hir::{Generics, HirId, Item, StructField, TraitRef, Ty, TyKind, Variant}; use rustc_middle::hir::map::Map; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::middle::stability::{DeprecationEntry, Index}; @@ -538,7 +538,31 @@ impl Visitor<'tcx> for Checker<'tcx> { // For implementations of traits, check the stability of each item // individually as it's possible to have a stable trait with unstable // items. - hir::ItemKind::Impl { of_trait: Some(ref t), items, .. } => { + hir::ItemKind::Impl { of_trait: Some(ref t), self_ty, items, .. } => { + // If this impl block has an #[unstable] attribute, give an + // error if all involved types and traits are stable, because + // it will have no effect. + // See: https://github.com/rust-lang/rust/issues/55436 + if let (Some(Stability { level: attr::Unstable { .. }, .. }), _) = + attr::find_stability(&self.tcx.sess, &item.attrs, item.span) + { + let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true }; + c.visit_ty(self_ty); + c.visit_trait_ref(t); + if c.fully_stable { + let span = item + .attrs + .iter() + .find(|a| a.has_name(sym::unstable)) + .map_or(item.span, |a| a.span); + self.tcx.sess.span_warn( + span, + "An `#[unstable]` annotation here has no effect. \ + See issue #55436 for more information.", + ); + } + } + if let Res::Def(DefKind::Trait, trait_did) = t.path.res { for impl_item_ref in items { let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); @@ -598,6 +622,44 @@ impl Visitor<'tcx> for Checker<'tcx> { } } +struct CheckTraitImplStable<'tcx> { + tcx: TyCtxt<'tcx>, + fully_stable: bool, +} + +impl Visitor<'tcx> for CheckTraitImplStable<'tcx> { + type Map = Map<'tcx>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } + + fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _id: hir::HirId) { + if let Some(def_id) = path.res.opt_def_id() { + if let Some(stab) = self.tcx.lookup_stability(def_id) { + self.fully_stable &= stab.level.is_stable(); + } + } + intravisit::walk_path(self, path) + } + + fn visit_trait_ref(&mut self, t: &'tcx TraitRef<'tcx>) { + if let Res::Def(DefKind::Trait, trait_did) = t.path.res { + if let Some(stab) = self.tcx.lookup_stability(trait_did) { + self.fully_stable &= stab.level.is_stable(); + } + } + intravisit::walk_trait_ref(self, t) + } + + fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) { + if let TyKind::Never = t.kind { + self.fully_stable = false; + } + intravisit::walk_ty(self, t) + } +} + /// Given the list of enabled features that were not language features (i.e., that /// were expected to be library features), and the list of features used from /// libraries, identify activated features that don't exist and error about them. From e5c645f40e98bfcda81a10929aaaf18dd0a00414 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 10 Sep 2020 09:36:17 +0200 Subject: [PATCH 0292/1052] Turn useless #[unstable] attributes into errors. --- compiler/rustc_passes/src/stability.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index d3141c34d0e11..dc82c80d205b6 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -555,7 +555,7 @@ impl Visitor<'tcx> for Checker<'tcx> { .iter() .find(|a| a.has_name(sym::unstable)) .map_or(item.span, |a| a.span); - self.tcx.sess.span_warn( + self.tcx.sess.span_err( span, "An `#[unstable]` annotation here has no effect. \ See issue #55436 for more information.", From f6fbf669ab0c47034afe53103da7706a593480b9 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 10 Sep 2020 09:40:40 +0200 Subject: [PATCH 0293/1052] Mark RefUnwindSafe impls for stable atomic types as stable. These impls were effectively stable. #[unstable] had no effect here, since both RefUnwindSafe and these types were already stable. These effectively became stable as soon as the types became stable, which was in 1.34.0. --- library/std/src/panic.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index 87493945db6dc..18d9c2f11b544 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -232,16 +232,16 @@ impl RefUnwindSafe for RwLock {} #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] impl RefUnwindSafe for atomic::AtomicIsize {} #[cfg(target_has_atomic_load_store = "8")] -#[unstable(feature = "integer_atomics", issue = "32976")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for atomic::AtomicI8 {} #[cfg(target_has_atomic_load_store = "16")] -#[unstable(feature = "integer_atomics", issue = "32976")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for atomic::AtomicI16 {} #[cfg(target_has_atomic_load_store = "32")] -#[unstable(feature = "integer_atomics", issue = "32976")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for atomic::AtomicI32 {} #[cfg(target_has_atomic_load_store = "64")] -#[unstable(feature = "integer_atomics", issue = "32976")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for atomic::AtomicI64 {} #[cfg(target_has_atomic_load_store = "128")] #[unstable(feature = "integer_atomics", issue = "32976")] @@ -251,16 +251,16 @@ impl RefUnwindSafe for atomic::AtomicI128 {} #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] impl RefUnwindSafe for atomic::AtomicUsize {} #[cfg(target_has_atomic_load_store = "8")] -#[unstable(feature = "integer_atomics", issue = "32976")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for atomic::AtomicU8 {} #[cfg(target_has_atomic_load_store = "16")] -#[unstable(feature = "integer_atomics", issue = "32976")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for atomic::AtomicU16 {} #[cfg(target_has_atomic_load_store = "32")] -#[unstable(feature = "integer_atomics", issue = "32976")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for atomic::AtomicU32 {} #[cfg(target_has_atomic_load_store = "64")] -#[unstable(feature = "integer_atomics", issue = "32976")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for atomic::AtomicU64 {} #[cfg(target_has_atomic_load_store = "128")] #[unstable(feature = "integer_atomics", issue = "32976")] From cf8e5d1bc969987aba074bd7f4b01565badca434 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 10 Sep 2020 09:40:40 +0200 Subject: [PATCH 0294/1052] Mark Error impl for LayoutErr as stable. This impl was effectively stable. #[unstable] had no effect here, since both Error and LayoutErr were already stable. This effectively became stable as soon as LayoutErr became stable, which was in 1.28.0. --- library/std/src/error.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 8da033439768e..ee25311d3b7ee 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -389,11 +389,7 @@ impl Error for ! {} )] impl Error for AllocErr {} -#[unstable( - feature = "allocator_api", - reason = "the precise API and guarantees it provides may be tweaked.", - issue = "32838" -)] +#[stable(feature = "alloc_layout", since = "1.28.0")] impl Error for LayoutErr {} #[stable(feature = "rust1", since = "1.0.0")] From 89fb34fea79fd803c9ea8a333a18ccb32e0c991d Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 10 Sep 2020 20:43:13 +0200 Subject: [PATCH 0295/1052] Turn unstable trait impl error into a lint, so it can be disabled. --- compiler/rustc_passes/src/stability.rs | 49 ++++++++++++---------- compiler/rustc_session/src/lint/builtin.rs | 9 +++- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index dc82c80d205b6..4eb983365ffb5 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -16,6 +16,7 @@ use rustc_middle::middle::stability::{DeprecationEntry, Index}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::lint; +use rustc_session::lint::builtin::INEFFECTIVE_UNSTABLE_TRAIT_IMPL; use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; @@ -539,27 +540,33 @@ impl Visitor<'tcx> for Checker<'tcx> { // individually as it's possible to have a stable trait with unstable // items. hir::ItemKind::Impl { of_trait: Some(ref t), self_ty, items, .. } => { - // If this impl block has an #[unstable] attribute, give an - // error if all involved types and traits are stable, because - // it will have no effect. - // See: https://github.com/rust-lang/rust/issues/55436 - if let (Some(Stability { level: attr::Unstable { .. }, .. }), _) = - attr::find_stability(&self.tcx.sess, &item.attrs, item.span) - { - let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true }; - c.visit_ty(self_ty); - c.visit_trait_ref(t); - if c.fully_stable { - let span = item - .attrs - .iter() - .find(|a| a.has_name(sym::unstable)) - .map_or(item.span, |a| a.span); - self.tcx.sess.span_err( - span, - "An `#[unstable]` annotation here has no effect. \ - See issue #55436 for more information.", - ); + if self.tcx.features().staged_api { + // If this impl block has an #[unstable] attribute, give an + // error if all involved types and traits are stable, because + // it will have no effect. + // See: https://github.com/rust-lang/rust/issues/55436 + if let (Some(Stability { level: attr::Unstable { .. }, .. }), _) = + attr::find_stability(&self.tcx.sess, &item.attrs, item.span) + { + let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true }; + c.visit_ty(self_ty); + c.visit_trait_ref(t); + if c.fully_stable { + let span = item + .attrs + .iter() + .find(|a| a.has_name(sym::unstable)) + .map_or(item.span, |a| a.span); + self.tcx.struct_span_lint_hir( + INEFFECTIVE_UNSTABLE_TRAIT_IMPL, + item.hir_id, + span, + |lint| lint.build( + "An `#[unstable]` annotation here has no effect. \ + See issue #55436 for more information.", + ).emit() + ); + } } } diff --git a/compiler/rustc_session/src/lint/builtin.rs b/compiler/rustc_session/src/lint/builtin.rs index a9deaaae0daeb..0fd6cc1038284 100644 --- a/compiler/rustc_session/src/lint/builtin.rs +++ b/compiler/rustc_session/src/lint/builtin.rs @@ -5,7 +5,7 @@ //! lints are all available in `rustc_lint::builtin`. use crate::lint::FutureIncompatibleInfo; -use crate::{declare_lint, declare_lint_pass}; +use crate::{declare_lint, declare_lint_pass, declare_tool_lint}; use rustc_span::edition::Edition; use rustc_span::symbol::sym; @@ -555,6 +555,12 @@ declare_lint! { }; } +declare_tool_lint! { + pub rustc::INEFFECTIVE_UNSTABLE_TRAIT_IMPL, + Deny, + "detects `#[unstable]` on stable trait implementations for stable types" +} + declare_lint_pass! { /// Does nothing as a lint pass, but registers some `Lint`s /// that are used by other parts of the compiler. @@ -630,6 +636,7 @@ declare_lint_pass! { INCOMPLETE_INCLUDE, CENUM_IMPL_DROP_CAST, CONST_EVALUATABLE_UNCHECKED, + INEFFECTIVE_UNSTABLE_TRAIT_IMPL, ] } From 471fb622aaa234c0a69d59ee24b76092244a1c6c Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 10 Sep 2020 20:44:42 +0200 Subject: [PATCH 0296/1052] Allow unstable From impl for [Raw]Waker. --- library/alloc/src/task.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs index 5edc579605669..fcab3fd0badce 100644 --- a/library/alloc/src/task.rs +++ b/library/alloc/src/task.rs @@ -33,6 +33,7 @@ pub trait Wake { } } +#[allow(rustc::ineffective_unstable_trait_impl)] #[unstable(feature = "wake_trait", issue = "69912")] impl From> for Waker { fn from(waker: Arc) -> Waker { @@ -42,6 +43,7 @@ impl From> for Waker { } } +#[allow(rustc::ineffective_unstable_trait_impl)] #[unstable(feature = "wake_trait", issue = "69912")] impl From> for RawWaker { fn from(waker: Arc) -> RawWaker { From 1c1bfba84a92e0fe8bf1eb85e8c3e3d10caf07cb Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 10 Sep 2020 20:55:04 +0200 Subject: [PATCH 0297/1052] Add test for unstable trait impl lint. --- .../stability-attribute-trait-impl.rs | 28 +++++++++++++++++++ .../stability-attribute-trait-impl.stderr | 10 +++++++ 2 files changed, 38 insertions(+) create mode 100644 src/test/ui/stability-attribute/stability-attribute-trait-impl.rs create mode 100644 src/test/ui/stability-attribute/stability-attribute-trait-impl.stderr diff --git a/src/test/ui/stability-attribute/stability-attribute-trait-impl.rs b/src/test/ui/stability-attribute/stability-attribute-trait-impl.rs new file mode 100644 index 0000000000000..9be772a7be323 --- /dev/null +++ b/src/test/ui/stability-attribute/stability-attribute-trait-impl.rs @@ -0,0 +1,28 @@ +#![feature(staged_api)] + +#[stable(feature = "x", since = "1")] +struct StableType; + +#[unstable(feature = "x", issue = "none")] +struct UnstableType; + +#[stable(feature = "x", since = "1")] +trait StableTrait {} + +#[unstable(feature = "x", issue = "none")] +trait UnstableTrait {} + +#[unstable(feature = "x", issue = "none")] +impl UnstableTrait for UnstableType {} + +#[unstable(feature = "x", issue = "none")] +impl StableTrait for UnstableType {} + +#[unstable(feature = "x", issue = "none")] +impl UnstableTrait for StableType {} + +#[unstable(feature = "x", issue = "none")] +//~^ ERROR An `#[unstable]` annotation here has no effect. +impl StableTrait for StableType {} + +fn main() {} diff --git a/src/test/ui/stability-attribute/stability-attribute-trait-impl.stderr b/src/test/ui/stability-attribute/stability-attribute-trait-impl.stderr new file mode 100644 index 0000000000000..808636238fcc2 --- /dev/null +++ b/src/test/ui/stability-attribute/stability-attribute-trait-impl.stderr @@ -0,0 +1,10 @@ +error: An `#[unstable]` annotation here has no effect. See issue #55436 for more information. + --> $DIR/stability-attribute-trait-impl.rs:24:1 + | +LL | #[unstable(feature = "x", issue = "none")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(rustc::ineffective_unstable_trait_impl)]` on by default + +error: aborting due to previous error + From f9059a41b48813845e1ffa2d1bdcbc455ffcd10c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Deharbe?= Date: Fri, 11 Sep 2020 13:58:03 +0200 Subject: [PATCH 0298/1052] add non-regression test for issue #76597 --- src/test/ui/issue-76597.rs | 7 +++++++ src/test/ui/issue-76597.stderr | 14 ++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 src/test/ui/issue-76597.rs create mode 100644 src/test/ui/issue-76597.stderr diff --git a/src/test/ui/issue-76597.rs b/src/test/ui/issue-76597.rs new file mode 100644 index 0000000000000..879e6b49e9b77 --- /dev/null +++ b/src/test/ui/issue-76597.rs @@ -0,0 +1,7 @@ +fn f( + x: u8 + y: u8, +) {} +//~^^ ERROR: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `y` + +fn main() {} diff --git a/src/test/ui/issue-76597.stderr b/src/test/ui/issue-76597.stderr new file mode 100644 index 0000000000000..163ce61cb18e3 --- /dev/null +++ b/src/test/ui/issue-76597.stderr @@ -0,0 +1,14 @@ +error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `y` + --> $DIR/issue-76597.rs:3:38 + | +LL | ... x: u8 + | - expected one of 7 possible tokens + | ____________________________| + | | +LL | | ... y: u8, +| | | ^ unexpected token +| | | + | help: missing `,` + +error: aborting due to previous error + From b729368d4e6a7e6a85dd4189ca16d49622a1582a Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Fri, 11 Sep 2020 07:25:28 -0500 Subject: [PATCH 0299/1052] Address review comments --- library/alloc/src/rc.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 4821c8f567626..f998e49dcfcde 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -295,6 +295,13 @@ impl, U: ?Sized> CoerceUnsized> for Rc {} impl, U: ?Sized> DispatchFromDyn> for Rc {} impl Rc { + #[inline(always)] + fn inner(&self) -> &RcBox { + // This unsafety is ok because while this Rc is alive we're guaranteed + // that the inner pointer is valid. + unsafe { self.ptr.as_ref() } + } + fn from_inner(ptr: NonNull>) -> Self { Self { ptr, phantom: PhantomData } } @@ -845,17 +852,10 @@ impl Rc { #[unstable(feature = "get_mut_unchecked", issue = "63292")] pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T { // We are careful to *not* create a reference covering the "count" fields, as - // this would alias with concurrent access to the reference counts (e.g. by `Weak`). + // this would conflict with accesses to the reference counts (e.g. by `Weak`). unsafe { &mut (*this.ptr.as_ptr()).value } } - #[inline] - fn inner(&self) -> &RcBox { - // This unsafety is ok because while this Rc is alive we're guaranteed - // that the inner pointer is valid. - unsafe { self.ptr.as_ref() } - } - #[inline] #[stable(feature = "ptr_eq", since = "1.17.0")] /// Returns `true` if the two `Rc`s point to the same allocation @@ -2145,18 +2145,24 @@ trait RcInnerPtr { } impl RcInnerPtr for RcBox { + #[inline(always)] fn weak_ref(&self) -> &Cell { &self.weak } + + #[inline(always)] fn strong_ref(&self) -> &Cell { &self.strong } } impl<'a> RcInnerPtr for WeakInner<'a> { + #[inline(always)] fn weak_ref(&self) -> &Cell { self.weak } + + #[inline(always)] fn strong_ref(&self) -> &Cell { self.strong } From 3193d52a21576b8c93f00132c784cce1159f733e Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sun, 6 Sep 2020 12:24:22 -0400 Subject: [PATCH 0300/1052] Remove host parameter from step configurations rustc is a natively cross-compiling compiler, and generally none of our steps should care whether they are using a compiler built of triple A or B, just the --target directive being passed to the running compiler. e.g., when building for some target C, you don't generally want to build two stds: one with a host A compiler and the other with a host B compiler. Just one std is sufficient. --- src/bootstrap/builder.rs | 21 ++++++++----------- src/bootstrap/builder/tests.rs | 10 --------- src/bootstrap/compile.rs | 6 +++--- src/bootstrap/dist.rs | 4 +++- src/bootstrap/test.rs | 38 ++++++++++++++++------------------ src/bootstrap/tool.rs | 5 +++-- 6 files changed, 36 insertions(+), 48 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 844a29fadae1e..31d4f1f28a86d 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -87,11 +87,16 @@ pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash { pub struct RunConfig<'a> { pub builder: &'a Builder<'a>, - pub host: TargetSelection, pub target: TargetSelection, pub path: PathBuf, } +impl RunConfig<'_> { + pub fn build_triple(&self) -> TargetSelection { + self.builder.build.build + } +} + struct StepDescription { default: bool, only_hosts: bool, @@ -165,7 +170,6 @@ impl StepDescription { pathset, self.name, builder.config.exclude ); } - let hosts = &builder.hosts; // Determine the targets participating in this rule. let targets = if self.only_hosts { @@ -178,16 +182,9 @@ impl StepDescription { &builder.targets }; - for host in hosts { - for target in targets { - let run = RunConfig { - builder, - path: pathset.path(builder), - host: *host, - target: *target, - }; - (self.make_run)(run); - } + for target in targets { + let run = RunConfig { builder, path: pathset.path(builder), target: *target }; + (self.make_run)(run); } } diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index aeb0d713ef051..144c4dc4c9514 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -384,12 +384,9 @@ mod dist { compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a }, - compile::Std { compiler: Compiler { host: b, stage: 2 }, target: a }, compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b }, - compile::Std { compiler: Compiler { host: b, stage: 2 }, target: b }, compile::Std { compiler: Compiler { host: a, stage: 2 }, target: c }, - compile::Std { compiler: Compiler { host: b, stage: 2 }, target: c }, ] ); assert!(!builder.cache.all::().is_empty()); @@ -399,10 +396,8 @@ mod dist { compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a }, compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: a }, compile::Rustc { compiler: Compiler { host: a, stage: 2 }, target: a }, - compile::Rustc { compiler: Compiler { host: b, stage: 2 }, target: a }, compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b }, compile::Rustc { compiler: Compiler { host: a, stage: 2 }, target: b }, - compile::Rustc { compiler: Compiler { host: b, stage: 2 }, target: b }, ] ); } @@ -425,12 +420,9 @@ mod dist { compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a }, - compile::Std { compiler: Compiler { host: b, stage: 2 }, target: a }, compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b }, - compile::Std { compiler: Compiler { host: b, stage: 2 }, target: b }, compile::Std { compiler: Compiler { host: a, stage: 2 }, target: c }, - compile::Std { compiler: Compiler { host: b, stage: 2 }, target: c }, ] ); assert_eq!( @@ -439,7 +431,6 @@ mod dist { compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } }, compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } }, compile::Assemble { target_compiler: Compiler { host: a, stage: 2 } }, - compile::Assemble { target_compiler: Compiler { host: b, stage: 2 } }, ] ); assert_eq!( @@ -447,7 +438,6 @@ mod dist { &[ compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a }, compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: a }, - compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b }, ] ); } diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 9d314e8452b9c..e0dddda83b98f 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -45,7 +45,7 @@ impl Step for Std { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Std { - compiler: run.builder.compiler(run.builder.top_stage, run.host), + compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), target: run.target, }); } @@ -385,7 +385,7 @@ impl Step for StartupObjects { fn make_run(run: RunConfig<'_>) { run.builder.ensure(StartupObjects { - compiler: run.builder.compiler(run.builder.top_stage, run.host), + compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), target: run.target, }); } @@ -454,7 +454,7 @@ impl Step for Rustc { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Rustc { - compiler: run.builder.compiler(run.builder.top_stage, run.host), + compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), target: run.target, }); } diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 797a1ce20b48b..28a0b411b1d29 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -605,7 +605,9 @@ impl Step for DebuggerScripts { fn make_run(run: RunConfig<'_>) { run.builder.ensure(DebuggerScripts { - sysroot: run.builder.sysroot(run.builder.compiler(run.builder.top_stage, run.host)), + sysroot: run + .builder + .sysroot(run.builder.compiler(run.builder.top_stage, run.build_triple())), host: run.target, }); } diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 732028fb6ed47..045dda2d4cb4c 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -584,7 +584,7 @@ impl Step for RustdocTheme { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.host); + let compiler = run.builder.compiler(run.builder.top_stage, run.target); run.builder.ensure(RustdocTheme { compiler }); } @@ -651,7 +651,6 @@ impl Step for RustdocJSStd { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct RustdocJSNotStd { - pub host: TargetSelection, pub target: TargetSelection, pub compiler: Compiler, } @@ -666,8 +665,8 @@ impl Step for RustdocJSNotStd { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.host); - run.builder.ensure(RustdocJSNotStd { host: run.host, target: run.target, compiler }); + let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); + run.builder.ensure(RustdocJSNotStd { target: run.target, compiler }); } fn run(self, builder: &Builder<'_>) { @@ -688,7 +687,6 @@ impl Step for RustdocJSNotStd { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct RustdocUi { - pub host: TargetSelection, pub target: TargetSelection, pub compiler: Compiler, } @@ -703,8 +701,8 @@ impl Step for RustdocUi { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.host); - run.builder.ensure(RustdocUi { host: run.host, target: run.target, compiler }); + let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); + run.builder.ensure(RustdocUi { target: run.target, compiler }); } fn run(self, builder: &Builder<'_>) { @@ -873,7 +871,7 @@ macro_rules! test_definitions { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.host); + let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); run.builder.ensure($name { compiler, target: run.target }); } @@ -1422,7 +1420,7 @@ macro_rules! test_book { fn make_run(run: RunConfig<'_>) { run.builder.ensure($name { - compiler: run.builder.compiler(run.builder.top_stage, run.host), + compiler: run.builder.compiler(run.builder.top_stage, run.target), }); } @@ -1469,7 +1467,7 @@ impl Step for ErrorIndex { // error_index_generator depends on librustdoc. Use the compiler that // is normally used to build rustdoc for other tests (like compiletest // tests in src/test/rustdoc) so that it shares the same artifacts. - let compiler = run.builder.compiler_for(run.builder.top_stage, run.host, run.host); + let compiler = run.builder.compiler_for(run.builder.top_stage, run.target, run.target); run.builder.ensure(ErrorIndex { compiler }); } @@ -1573,7 +1571,7 @@ impl Step for CrateLibrustc { fn make_run(run: RunConfig<'_>) { let builder = run.builder; - let compiler = builder.compiler(builder.top_stage, run.host); + let compiler = builder.compiler(builder.top_stage, run.build_triple()); for krate in builder.in_tree_crates("rustc-main") { if krate.path.ends_with(&run.path) { @@ -1620,7 +1618,7 @@ impl Step for CrateNotDefault { fn make_run(run: RunConfig<'_>) { let builder = run.builder; - let compiler = builder.compiler(builder.top_stage, run.host); + let compiler = builder.compiler(builder.top_stage, run.build_triple()); let test_kind = builder.kind.into(); @@ -1668,7 +1666,7 @@ impl Step for Crate { fn make_run(run: RunConfig<'_>) { let builder = run.builder; - let compiler = builder.compiler(builder.top_stage, run.host); + let compiler = builder.compiler(builder.top_stage, run.build_triple()); let make = |mode: Mode, krate: &CargoCrate| { let test_kind = builder.kind.into(); @@ -1808,7 +1806,7 @@ impl Step for CrateRustdoc { let test_kind = builder.kind.into(); - builder.ensure(CrateRustdoc { host: run.host, test_kind }); + builder.ensure(CrateRustdoc { host: run.target, test_kind }); } fn run(self, builder: &Builder<'_>) { @@ -2054,7 +2052,6 @@ impl Step for Bootstrap { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct TierCheck { pub compiler: Compiler, - target: TargetSelection, } impl Step for TierCheck { @@ -2067,18 +2064,19 @@ impl Step for TierCheck { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler_for(run.builder.top_stage, run.host, run.host); - run.builder.ensure(TierCheck { compiler, target: run.host }); + let compiler = + run.builder.compiler_for(run.builder.top_stage, run.builder.build.build, run.target); + run.builder.ensure(TierCheck { compiler }); } /// Tests the Platform Support page in the rustc book. fn run(self, builder: &Builder<'_>) { - builder.ensure(compile::Std { compiler: self.compiler, target: self.target }); + builder.ensure(compile::Std { compiler: self.compiler, target: self.compiler.host }); let mut cargo = tool::prepare_tool_cargo( builder, self.compiler, - Mode::ToolRustc, - self.target, + Mode::ToolStd, + self.compiler.host, "run", "src/tools/tier-check", SourceType::InTree, diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index e8d7de7a5dcaa..a607f0fe258d4 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -469,8 +469,9 @@ impl Step for Rustdoc { } fn make_run(run: RunConfig<'_>) { - run.builder - .ensure(Rustdoc { compiler: run.builder.compiler(run.builder.top_stage, run.host) }); + run.builder.ensure(Rustdoc { + compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), + }); } fn run(self, builder: &Builder<'_>) -> PathBuf { From b4eb0992614acc242169154d434db658ef6790e0 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sun, 6 Sep 2020 12:41:28 -0400 Subject: [PATCH 0301/1052] Verify we compile std without involving a b host compiler --- src/bootstrap/builder/tests.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index 144c4dc4c9514..c6eac95c34507 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -217,6 +217,16 @@ mod dist { dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, ] ); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, + compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, + compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a }, + compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, + compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b }, + ], + ); assert_eq!(first(builder.cache.all::()), &[dist::Src]); } From 78125ec6b393441e628f9b04b84d6d125225fe30 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sun, 6 Sep 2020 12:57:13 -0400 Subject: [PATCH 0302/1052] Stop implicitly appending triples to config.toml hosts and targets Previously, the CLI --target/--host definitions and configured options differed in their effect: when setting these on the CLI, only the passed triples would be compiled for, while in config.toml we would also compile for the build triple and any host triples. This is needlessly confusing; users expect --target and --host to be identical to editing the configuration file. The new behavior is to respect --host and --target when passed as the *only* configured triples (no triples are implicitly added). The default for --host is the build triple, and the default for --target is the host triple(s), either configured or the default build triple. --- config.toml.example | 15 ++++++------ src/bootstrap/config.rs | 52 +++++++++++++++++++---------------------- src/bootstrap/flags.rs | 32 +++++++++++++++++-------- 3 files changed, 53 insertions(+), 46 deletions(-) diff --git a/config.toml.example b/config.toml.example index c311c933e7edc..2d5b3136450b9 100644 --- a/config.toml.example +++ b/config.toml.example @@ -120,19 +120,18 @@ # Defaults to host platform #build = "x86_64-unknown-linux-gnu" -# In addition to the build triple, other triples to produce full compiler -# toolchains for. Each of these triples will be bootstrapped from the build -# triple and then will continue to bootstrap themselves. This platform must -# currently be able to run all of the triples provided here. +# Which triples to produce a compiler toolchain for. Each of these triples will +# be bootstrapped from the build triple themselves. # # Defaults to just the build triple #host = ["x86_64-unknown-linux-gnu"] -# In addition to all host triples, other triples to produce the standard library -# for. Each host triple will be used to produce a copy of the standard library -# for each target triple. +# Which triples to build libraries (core/alloc/std/test/proc_macro) for. Each of +# these triples will be bootstrapped from the build triple themselves. # -# Defaults to just the build triple +# Defaults to `host`. If you set this explicitly, you likely want to add all +# host triples to this list as well in order for those host toolchains to be +# able to compile programs for their native target. #target = ["x86_64-unknown-linux-gnu"] # Use this directory to store build artifacts. diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index ad2f48778674f..5a79d3db5c905 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -273,10 +273,8 @@ struct TomlConfig { #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct Build { build: Option, - #[serde(default)] - host: Vec, - #[serde(default)] - target: Vec, + host: Option>, + target: Option>, // This is ignored, the rust code always gets the build directory from the `BUILD_DIR` env variable build_dir: Option, cargo: Option, @@ -505,11 +503,6 @@ impl Config { config.out = dir; } - // If --target was specified but --host wasn't specified, don't run any host-only tests. - let has_hosts = !flags.host.is_empty(); - let has_targets = !flags.target.is_empty(); - config.skip_only_host_steps = !has_hosts && has_targets; - let toml = file .map(|file| { let contents = t!(fs::read_to_string(&file)); @@ -528,25 +521,28 @@ impl Config { .unwrap_or_else(TomlConfig::default); let build = toml.build.clone().unwrap_or_default(); - // set by bootstrap.py - config.hosts.push(config.build); - for host in build.host.iter().map(|h| TargetSelection::from_user(h)) { - if !config.hosts.contains(&host) { - config.hosts.push(host); - } - } - for target in config - .hosts - .iter() - .copied() - .chain(build.target.iter().map(|h| TargetSelection::from_user(h))) - { - if !config.targets.contains(&target) { - config.targets.push(target); - } - } - config.hosts = if !flags.host.is_empty() { flags.host } else { config.hosts }; - config.targets = if !flags.target.is_empty() { flags.target } else { config.targets }; + + // If --target was specified but --host wasn't specified, don't run any host-only tests. + let has_hosts = build.host.is_some() || flags.host.is_some(); + let has_targets = build.target.is_some() || flags.target.is_some(); + config.skip_only_host_steps = !has_hosts && has_targets; + + config.hosts = if let Some(arg_host) = flags.host.clone() { + arg_host + } else if let Some(file_host) = build.host { + file_host.iter().map(|h| TargetSelection::from_user(h)).collect() + } else { + vec![config.build] + }; + config.targets = if let Some(arg_target) = flags.target.clone() { + arg_target + } else if let Some(file_target) = build.target { + file_target.iter().map(|h| TargetSelection::from_user(h)).collect() + } else { + // If target is *not* configured, then default to the host + // toolchains. + config.hosts.clone() + }; config.nodejs = build.nodejs.map(PathBuf::from); config.gdb = build.gdb.map(PathBuf::from); diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 2db4bb07a9ff1..ff8468574469e 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -20,8 +20,8 @@ pub struct Flags { pub stage: Option, pub keep_stage: Vec, - pub host: Vec, - pub target: Vec, + pub host: Option>, + pub target: Option>, pub config: Option, pub jobs: Option, pub cmd: Subcommand, @@ -526,14 +526,26 @@ Arguments: .into_iter() .map(|j| j.parse().expect("`keep-stage` should be a number")) .collect(), - host: split(&matches.opt_strs("host")) - .into_iter() - .map(|x| TargetSelection::from_user(&x)) - .collect::>(), - target: split(&matches.opt_strs("target")) - .into_iter() - .map(|x| TargetSelection::from_user(&x)) - .collect::>(), + host: if matches.opt_present("host") { + Some( + split(&matches.opt_strs("host")) + .into_iter() + .map(|x| TargetSelection::from_user(&x)) + .collect::>(), + ) + } else { + None + }, + target: if matches.opt_present("target") { + Some( + split(&matches.opt_strs("target")) + .into_iter() + .map(|x| TargetSelection::from_user(&x)) + .collect::>(), + ) + } else { + None + }, config: cfg_file, jobs: matches.opt_str("jobs").map(|j| j.parse().expect("`jobs` should be a number")), cmd, From 64b8fd7920e177023364c7d9dada0d3f8fad3911 Mon Sep 17 00:00:00 2001 From: rijenkii <5338332+rijenkii@users.noreply.github.com> Date: Fri, 21 Aug 2020 19:50:53 +0700 Subject: [PATCH 0303/1052] Add `peek` and `peek_from` to `UnixStream` and `UnixDatagram` --- library/std/src/sys/unix/ext/net.rs | 132 ++++++++++++++++++---- library/std/src/sys/unix/ext/net/tests.rs | 80 +++++++++++++ 2 files changed, 192 insertions(+), 20 deletions(-) diff --git a/library/std/src/sys/unix/ext/net.rs b/library/std/src/sys/unix/ext/net.rs index 0e07106f5ce5c..3fbd0cb58b120 100644 --- a/library/std/src/sys/unix/ext/net.rs +++ b/library/std/src/sys/unix/ext/net.rs @@ -594,6 +594,32 @@ impl UnixStream { pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { self.0.shutdown(how) } + + /// Receives data on the socket from the remote address to which it is + /// connected, without removing that data from the queue. On success, + /// returns the number of bytes peeked. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recv` system call. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_peek)] + /// + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let mut buf = [0; 10]; + /// let len = socket.peek(&mut buf).expect("peek failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_peek", issue = "none")] + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.0.peek(buf) + } } #[stable(feature = "unix_socket", since = "1.10.0")] @@ -1291,6 +1317,33 @@ impl UnixDatagram { SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) } + fn recv_from_flags( + &self, + buf: &mut [u8], + flags: libc::c_int, + ) -> io::Result<(usize, SocketAddr)> { + let mut count = 0; + let addr = SocketAddr::new(|addr, len| unsafe { + count = libc::recvfrom( + *self.0.as_inner(), + buf.as_mut_ptr() as *mut _, + buf.len(), + flags, + addr, + len, + ); + if count > 0 { + 1 + } else if count == 0 { + 0 + } else { + -1 + } + })?; + + Ok((count as usize, addr)) + } + /// Receives data from the socket. /// /// On success, returns the number of bytes read and the address from @@ -1311,26 +1364,7 @@ impl UnixDatagram { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - let mut count = 0; - let addr = SocketAddr::new(|addr, len| unsafe { - count = libc::recvfrom( - *self.0.as_inner(), - buf.as_mut_ptr() as *mut _, - buf.len(), - 0, - addr, - len, - ); - if count > 0 { - 1 - } else if count == 0 { - 0 - } else { - -1 - } - })?; - - Ok((count as usize, addr)) + self.recv_from_flags(buf, 0) } /// Receives data from the socket. @@ -1601,6 +1635,64 @@ impl UnixDatagram { pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { self.0.shutdown(how) } + + /// Receives data on the socket from the remote address to which it is + /// connected, without removing that data from the queue. On success, + /// returns the number of bytes peeked. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recv` system call. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_peek)] + /// + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::bind("/tmp/sock")?; + /// let mut buf = [0; 10]; + /// let len = socket.peek(&mut buf).expect("peek failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_peek", issue = "none")] + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.0.peek(buf) + } + + /// Receives a single datagram message on the socket, without removing it from the + /// queue. On success, returns the number of bytes read and the origin. + /// + /// The function must be called with valid byte array `buf` of sufficient size to + /// hold the message bytes. If a message is too long to fit in the supplied buffer, + /// excess bytes may be discarded. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call. + /// + /// Do not use this function to implement busy waiting, instead use `libc::poll` to + /// synchronize IO events on one or more sockets. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_peek)] + /// + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::bind("/tmp/sock")?; + /// let mut buf = [0; 10]; + /// let (len, addr) = socket.peek_from(&mut buf).expect("peek failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_peek", issue = "none")] + pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_from_flags(buf, libc::MSG_PEEK) + } } #[stable(feature = "unix_socket", since = "1.10.0")] diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs index be98766f0f3aa..ee73a6ed538ff 100644 --- a/library/std/src/sys/unix/ext/net/tests.rs +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -372,3 +372,83 @@ fn test_unix_datagram_timeout_zero_duration() { fn abstract_namespace_not_allowed() { assert!(UnixStream::connect("\0asdf").is_err()); } + +#[test] +fn test_unix_stream_peek() { + let (txdone, rxdone) = crate::sync::mpsc::channel(); + + let dir = tmpdir(); + let path = dir.path().join("sock"); + + let listener = or_panic!(UnixListener::bind(&path)); + let thread = thread::spawn(move || { + let mut stream = or_panic!(listener.accept()).0; + or_panic!(stream.write_all(&[1, 3, 3, 7])); + or_panic!(rxdone.recv()); + }); + + let mut stream = or_panic!(UnixStream::connect(&path)); + let mut buf = [0; 10]; + for _ in 0..2 { + assert_eq!(or_panic!(stream.peek(&mut buf)), 4); + } + assert_eq!(or_panic!(stream.read(&mut buf)), 4); + + or_panic!(stream.set_nonblocking(true)); + match stream.peek(&mut buf) { + Ok(_) => panic!("expected error"), + Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} + Err(e) => panic!("unexpected error: {}", e), + } + + or_panic!(txdone.send(())); + thread.join().unwrap(); +} + +#[test] +fn test_unix_datagram_peek() { + let dir = tmpdir(); + let path1 = dir.path().join("sock"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let sock2 = or_panic!(UnixDatagram::unbound()); + or_panic!(sock2.connect(&path1)); + + let msg = b"hello world"; + or_panic!(sock2.send(msg)); + for _ in 0..2 { + let mut buf = [0; 11]; + let size = or_panic!(sock1.peek(&mut buf)); + assert_eq!(size, 11); + assert_eq!(msg, &buf[..]); + } + + let mut buf = [0; 11]; + let size = or_panic!(sock1.recv(&mut buf)); + assert_eq!(size, 11); + assert_eq!(msg, &buf[..]); +} + +#[test] +fn test_unix_datagram_peek_from() { + let dir = tmpdir(); + let path1 = dir.path().join("sock"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let sock2 = or_panic!(UnixDatagram::unbound()); + or_panic!(sock2.connect(&path1)); + + let msg = b"hello world"; + or_panic!(sock2.send(msg)); + for _ in 0..2 { + let mut buf = [0; 11]; + let (size, _) = or_panic!(sock1.peek_from(&mut buf)); + assert_eq!(size, 11); + assert_eq!(msg, &buf[..]); + } + + let mut buf = [0; 11]; + let size = or_panic!(sock1.recv(&mut buf)); + assert_eq!(size, 11); + assert_eq!(msg, &buf[..]); +} From 2487f8f461134f93459415642f730ac6c4a2d659 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Fri, 11 Sep 2020 16:52:25 +0200 Subject: [PATCH 0304/1052] into_iter_on_ref: rephrase lint message: will not move the x -> will not consume the x imo that's a bit clearer. --- clippy_lints/src/methods/mod.rs | 2 +- tests/ui/into_iter_on_ref.stderr | 54 ++++++++++++++++---------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index ba69c8266b118..98e027b6d2290 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3374,7 +3374,7 @@ fn lint_into_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, self_ref_ty: Ty<'_ INTO_ITER_ON_REF, method_span, &format!( - "this `.into_iter()` call is equivalent to `.{}()` and will not move the `{}`", + "this `.into_iter()` call is equivalent to `.{}()` and will not consume the `{}`", method_name, kind, ), "call directly", diff --git a/tests/ui/into_iter_on_ref.stderr b/tests/ui/into_iter_on_ref.stderr index 1cd6400b0195b..28003b365bbd5 100644 --- a/tests/ui/into_iter_on_ref.stderr +++ b/tests/ui/into_iter_on_ref.stderr @@ -1,4 +1,4 @@ -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `Vec` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Vec` --> $DIR/into_iter_on_ref.rs:14:30 | LL | let _ = (&vec![1, 2, 3]).into_iter(); //~ WARN equivalent to .iter() @@ -6,157 +6,157 @@ LL | let _ = (&vec![1, 2, 3]).into_iter(); //~ WARN equivalent to .iter() | = note: `-D clippy::into-iter-on-ref` implied by `-D warnings` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `slice` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice` --> $DIR/into_iter_on_ref.rs:15:46 | LL | let _ = vec![1, 2, 3].into_boxed_slice().into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `slice` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice` --> $DIR/into_iter_on_ref.rs:16:41 | LL | let _ = std::rc::Rc::from(&[X][..]).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `slice` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice` --> $DIR/into_iter_on_ref.rs:17:44 | LL | let _ = std::sync::Arc::from(&[X][..]).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `array` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array` --> $DIR/into_iter_on_ref.rs:19:32 | LL | let _ = (&&&&&&&[1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `array` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array` --> $DIR/into_iter_on_ref.rs:20:36 | LL | let _ = (&&&&mut &&&[1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `array` +error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `array` --> $DIR/into_iter_on_ref.rs:21:40 | LL | let _ = (&mut &mut &mut [1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter_mut() | ^^^^^^^^^ help: call directly: `iter_mut` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `Option` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Option` --> $DIR/into_iter_on_ref.rs:23:24 | LL | let _ = (&Some(4)).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `Option` +error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Option` --> $DIR/into_iter_on_ref.rs:24:28 | LL | let _ = (&mut Some(5)).into_iter(); //~ WARN equivalent to .iter_mut() | ^^^^^^^^^ help: call directly: `iter_mut` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `Result` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Result` --> $DIR/into_iter_on_ref.rs:25:32 | LL | let _ = (&Ok::<_, i32>(6)).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `Result` +error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Result` --> $DIR/into_iter_on_ref.rs:26:37 | LL | let _ = (&mut Err::(7)).into_iter(); //~ WARN equivalent to .iter_mut() | ^^^^^^^^^ help: call directly: `iter_mut` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `Vec` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Vec` --> $DIR/into_iter_on_ref.rs:27:34 | LL | let _ = (&Vec::::new()).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `Vec` +error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Vec` --> $DIR/into_iter_on_ref.rs:28:38 | LL | let _ = (&mut Vec::::new()).into_iter(); //~ WARN equivalent to .iter_mut() | ^^^^^^^^^ help: call directly: `iter_mut` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `BTreeMap` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BTreeMap` --> $DIR/into_iter_on_ref.rs:29:44 | LL | let _ = (&BTreeMap::::new()).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `BTreeMap` +error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `BTreeMap` --> $DIR/into_iter_on_ref.rs:30:48 | LL | let _ = (&mut BTreeMap::::new()).into_iter(); //~ WARN equivalent to .iter_mut() | ^^^^^^^^^ help: call directly: `iter_mut` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `VecDeque` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `VecDeque` --> $DIR/into_iter_on_ref.rs:31:39 | LL | let _ = (&VecDeque::::new()).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `VecDeque` +error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `VecDeque` --> $DIR/into_iter_on_ref.rs:32:43 | LL | let _ = (&mut VecDeque::::new()).into_iter(); //~ WARN equivalent to .iter_mut() | ^^^^^^^^^ help: call directly: `iter_mut` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `LinkedList` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `LinkedList` --> $DIR/into_iter_on_ref.rs:33:41 | LL | let _ = (&LinkedList::::new()).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `LinkedList` +error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `LinkedList` --> $DIR/into_iter_on_ref.rs:34:45 | LL | let _ = (&mut LinkedList::::new()).into_iter(); //~ WARN equivalent to .iter_mut() | ^^^^^^^^^ help: call directly: `iter_mut` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `HashMap` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `HashMap` --> $DIR/into_iter_on_ref.rs:35:43 | LL | let _ = (&HashMap::::new()).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `HashMap` +error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `HashMap` --> $DIR/into_iter_on_ref.rs:36:47 | LL | let _ = (&mut HashMap::::new()).into_iter(); //~ WARN equivalent to .iter_mut() | ^^^^^^^^^ help: call directly: `iter_mut` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `BTreeSet` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BTreeSet` --> $DIR/into_iter_on_ref.rs:38:39 | LL | let _ = (&BTreeSet::::new()).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `BinaryHeap` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BinaryHeap` --> $DIR/into_iter_on_ref.rs:39:41 | LL | let _ = (&BinaryHeap::::new()).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `HashSet` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `HashSet` --> $DIR/into_iter_on_ref.rs:40:38 | LL | let _ = (&HashSet::::new()).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `Path` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Path` --> $DIR/into_iter_on_ref.rs:41:43 | LL | let _ = std::path::Path::new("12/34").into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `PathBuf` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `PathBuf` --> $DIR/into_iter_on_ref.rs:42:47 | LL | let _ = std::path::PathBuf::from("12/34").into_iter(); //~ ERROR equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `array` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array` --> $DIR/into_iter_on_ref.rs:44:26 | LL | let _ = (&[1, 2, 3]).into_iter().next(); //~ WARN equivalent to .iter() From 62068a59eea44ff78c4293d5fcc676279b1deab0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Deharbe?= Date: Fri, 11 Sep 2020 17:31:52 +0200 Subject: [PATCH 0305/1052] repairing broken error message and rustfix application for the new test case --- compiler/rustc_parse/src/parser/mod.rs | 6 +++++- src/test/ui/issue-76597.fixed | 11 +++++++++++ src/test/ui/issue-76597.rs | 4 ++++ src/test/ui/issue-76597.stderr | 17 ++++++++--------- 4 files changed, 28 insertions(+), 10 deletions(-) create mode 100644 src/test/ui/issue-76597.fixed diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 5eefae3af60e9..7340c5744808c 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -694,9 +694,13 @@ impl<'a> Parser<'a> { Ok(t) => { // Parsed successfully, therefore most probably the code only // misses a separator. + let mut exp_span = self.sess.source_map().next_point(sp); + if self.sess.source_map().is_multiline(exp_span) { + exp_span = sp; + } expect_err .span_suggestion_short( - self.sess.source_map().next_point(sp), + exp_span, &format!("missing `{}`", token_str), token_str, Applicability::MaybeIncorrect, diff --git a/src/test/ui/issue-76597.fixed b/src/test/ui/issue-76597.fixed new file mode 100644 index 0000000000000..2d7a30b8361ad --- /dev/null +++ b/src/test/ui/issue-76597.fixed @@ -0,0 +1,11 @@ +// run-rustfix + +#![allow(dead_code)] +#![allow(unused_variables)] +fn f( + x: u8, + y: u8, +) {} +//~^^ ERROR: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `y` + +fn main() {} diff --git a/src/test/ui/issue-76597.rs b/src/test/ui/issue-76597.rs index 879e6b49e9b77..521b9c64b1c57 100644 --- a/src/test/ui/issue-76597.rs +++ b/src/test/ui/issue-76597.rs @@ -1,3 +1,7 @@ +// run-rustfix + +#![allow(dead_code)] +#![allow(unused_variables)] fn f( x: u8 y: u8, diff --git a/src/test/ui/issue-76597.stderr b/src/test/ui/issue-76597.stderr index 163ce61cb18e3..50b23329f0ceb 100644 --- a/src/test/ui/issue-76597.stderr +++ b/src/test/ui/issue-76597.stderr @@ -1,14 +1,13 @@ error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `y` - --> $DIR/issue-76597.rs:3:38 + --> $DIR/issue-76597.rs:7:38 | -LL | ... x: u8 - | - expected one of 7 possible tokens - | ____________________________| - | | -LL | | ... y: u8, -| | | ^ unexpected token -| | | - | help: missing `,` +LL | ... x: u8 + | - + | | + | expected one of 7 possible tokens + | help: missing `,` +LL | ... y: u8, + | ^ unexpected token error: aborting due to previous error From 56f5c7f95f3f7772cb3263d48cd2d8a136706767 Mon Sep 17 00:00:00 2001 From: Gus Wynn Date: Fri, 11 Sep 2020 09:01:31 -0700 Subject: [PATCH 0306/1052] comments + add max_level_info so false works with debug_assertions on --- compiler/rustc_driver/Cargo.toml | 2 +- config.toml.example | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml index 6f0d7bc4d58e8..1e371f8254ddd 100644 --- a/compiler/rustc_driver/Cargo.toml +++ b/compiler/rustc_driver/Cargo.toml @@ -38,4 +38,4 @@ winapi = { version = "0.3", features = ["consoleapi", "debugapi", "processenv"] [features] llvm = ['rustc_interface/llvm'] -release_max_level_info = ['tracing/release_max_level_info'] +release_max_level_info = ['tracing/release_max_level_info', 'tracing/max_level_info'] diff --git a/config.toml.example b/config.toml.example index a162c543a50c3..3bb6d3cad55e7 100644 --- a/config.toml.example +++ b/config.toml.example @@ -321,19 +321,19 @@ # binary, otherwise they are omitted. # # Defaults to rust.debug value -#debug-assertions = false +#debug-assertions = debug # Whether or not debug assertions are enabled for the standard library. # Overrides the `debug-assertions` option, if defined. # # Defaults to rust.debug-assertions value -#debug-assertions-std = false +#debug-assertions-std = debug-assertions # Whether or not to leave debug! and trace! calls in the rust binary. # Overrides the `debug-assertions` option, if defined. # # Defaults to rust.debug-assertions value -#debug-logging = true +#debug-logging = debug-assertions # Debuginfo level for most of Rust code, corresponds to the `-C debuginfo=N` option of `rustc`. # `0` - no debug info From 0be66d7f30ba31638e14c00bd2303dd0327964f4 Mon Sep 17 00:00:00 2001 From: Gus Wynn Date: Fri, 11 Sep 2020 09:37:51 -0700 Subject: [PATCH 0307/1052] just max_level_info --- compiler/rustc/Cargo.toml | 2 +- compiler/rustc_driver/Cargo.toml | 2 +- src/bootstrap/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml index b740793a3e554..6e6c0c71a1f3b 100644 --- a/compiler/rustc/Cargo.toml +++ b/compiler/rustc/Cargo.toml @@ -19,4 +19,4 @@ features = ['unprefixed_malloc_on_supported_platforms'] [features] jemalloc = ['jemalloc-sys'] llvm = ['rustc_driver/llvm'] -release_max_level_info = ['rustc_driver/release_max_level_info'] +max_level_info = ['rustc_driver/max_level_info'] diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml index 1e371f8254ddd..adfce1008e1ed 100644 --- a/compiler/rustc_driver/Cargo.toml +++ b/compiler/rustc_driver/Cargo.toml @@ -38,4 +38,4 @@ winapi = { version = "0.3", features = ["consoleapi", "debugapi", "processenv"] [features] llvm = ['rustc_interface/llvm'] -release_max_level_info = ['tracing/release_max_level_info', 'tracing/max_level_info'] +max_level_info = ['tracing/max_level_info'] diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 3c2663f6d9f57..87a893cd83664 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -548,7 +548,7 @@ impl Build { // if its unset, if debug_assertions is on, then debug_logging will also be on // as well as tracing *ignoring* this feature when debug_assertions is on if !self.config.rust_debug_logging { - features.push_str(" release_max_level_info"); + features.push_str(" max_level_info"); } features From c394624471c66c42bd9641ab30d2a2ccea894dbc Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Fri, 11 Sep 2020 19:12:06 +0200 Subject: [PATCH 0308/1052] Ignore unnecessary unsafe warnings This is a work-around for a libc issue: https://github.com/rust-lang/libc/issues/1888. --- library/std/src/sys/unix/fd.rs | 1 - .../std/src/sys/unix/process/process_unix.rs | 22 ++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index 16adbe6d88c4f..2224a055d6d87 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -6,7 +6,6 @@ mod tests; use crate::cmp; use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read}; use crate::mem; -#[cfg(not(any(target_os = "redox", target_env = "newlib")))] use crate::sys::cvt; use crate::sys_common::AsInner; diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 0f349dfa30216..08efe154e4c3b 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -459,7 +459,15 @@ impl ExitStatus { } fn exited(&self) -> bool { - unsafe { libc::WIFEXITED(self.0) } + // On Linux-like OSes this function is safe, on others it is not. See + // libc issue: https://github.com/rust-lang/libc/issues/1888. + #[cfg_attr( + any(target_os = "linux", target_os = "android", target_os = "emscripten"), + allow(unused_unsafe) + )] + unsafe { + libc::WIFEXITED(self.0) + } } pub fn success(&self) -> bool { @@ -467,10 +475,22 @@ impl ExitStatus { } pub fn code(&self) -> Option { + // On Linux-like OSes this function is safe, on others it is not. See + // libc issue: https://github.com/rust-lang/libc/issues/1888. + #[cfg_attr( + any(target_os = "linux", target_os = "android", target_os = "emscripten"), + allow(unused_unsafe) + )] if self.exited() { Some(unsafe { libc::WEXITSTATUS(self.0) }) } else { None } } pub fn signal(&self) -> Option { + // On Linux-like OSes this function is safe, on others it is not. See + // libc issue: https://github.com/rust-lang/libc/issues/1888. + #[cfg_attr( + any(target_os = "linux", target_os = "android", target_os = "emscripten"), + allow(unused_unsafe) + )] if !self.exited() { Some(unsafe { libc::WTERMSIG(self.0) }) } else { None } } } From c213c68500f5fff51f26997d27a346c896232df7 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 11 Sep 2020 13:29:55 -0400 Subject: [PATCH 0309/1052] box ResolutionFailures on the heap This decreases the size of the `Result`s being returned, improving performance in the common case. --- .../passes/collect_intra_doc_links.rs | 69 +++++++++---------- 1 file changed, 32 insertions(+), 37 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index d8abf411de7c2..7fea70253b301 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -48,10 +48,16 @@ pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_>) -> Crate { } enum ErrorKind<'a> { - Resolve(ResolutionFailure<'a>), + Resolve(Box>), AnchorFailure(AnchorFailure), } +impl<'a> From> for ErrorKind<'a> { + fn from(err: ResolutionFailure<'a>) -> Self { + ErrorKind::Resolve(box err) + } +} + #[derive(Debug)] enum ResolutionFailure<'a> { /// This resolved, but with the wrong namespace. @@ -142,10 +148,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .expect("fold_item should ensure link is non-empty"); let variant_name = // we're not sure this is a variant at all, so use the full string - split.next().map(|f| Symbol::intern(f)).ok_or(ErrorKind::Resolve(ResolutionFailure::NotInScope{ + split.next().map(|f| Symbol::intern(f)).ok_or_else(|| ResolutionFailure::NotInScope { module_id, name: path_str.into(), - }))?; + })?; let path = split .next() .map(|f| { @@ -156,10 +162,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } f.to_owned() }) - .ok_or(ErrorKind::Resolve(ResolutionFailure::NotInScope { + .ok_or_else(|| ResolutionFailure::NotInScope { module_id, name: variant_name.to_string().into(), - }))?; + })?; let ty_res = cx .enter_resolver(|resolver| { resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) @@ -167,10 +173,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .map(|(_, res)| res) .unwrap_or(Res::Err); if let Res::Err = ty_res { - return Err(ErrorKind::Resolve(ResolutionFailure::NotInScope { - module_id, - name: path.into(), - })); + return Err(ResolutionFailure::NotInScope { module_id, name: path.into() }.into()); } let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); match ty_res { @@ -184,7 +187,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { { // This is just to let `fold_item` know that this shouldn't be considered; // it's a bug for the error to make it to the user - return Err(ErrorKind::Resolve(ResolutionFailure::Dummy)); + return Err(ResolutionFailure::Dummy.into()); } match cx.tcx.type_of(did).kind() { ty::Adt(def, _) if def.is_enum() => { @@ -197,10 +200,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { )), )) } else { - Err(ErrorKind::Resolve(ResolutionFailure::NotAVariant( - ty_res, - variant_field_name, - ))) + Err(ResolutionFailure::NotAVariant(ty_res, variant_field_name).into()) } } _ => unreachable!(), @@ -226,7 +226,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // Even with the shorter path, it didn't resolve, so say that. ResolutionFailure::NoAssocItem(ty_res, variant_name) }; - Err(ErrorKind::Resolve(kind)) + Err(kind.into()) } } } @@ -344,7 +344,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }; if value != (ns == ValueNS) { - return Err(ErrorKind::Resolve(ResolutionFailure::WrongNamespace(res, ns))); + return Err(ResolutionFailure::WrongNamespace(res, ns).into()); } } else if let Some((path, prim)) = is_primitive(path_str, ns) { if extra_fragment.is_some() { @@ -373,16 +373,12 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved. .ok_or_else(|| { debug!("found no `::`, assumming {} was correctly not in scope", item_name); - ErrorKind::Resolve(ResolutionFailure::NotInScope { - module_id, - name: item_name.to_string().into(), - }) + ResolutionFailure::NotInScope { module_id, name: item_name.to_string().into() } })?; if let Some((path, prim)) = is_primitive(&path_root, TypeNS) { - let impls = primitive_impl(cx, &path).ok_or_else(|| { - ErrorKind::Resolve(ResolutionFailure::NoPrimitiveImpl(prim, path_root.into())) - })?; + let impls = primitive_impl(cx, &path) + .ok_or_else(|| ResolutionFailure::NoPrimitiveImpl(prim, path_root.into()))?; for &impl_ in impls { let link = cx .tcx @@ -409,11 +405,12 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { item_name, ns.descr() ); - return Err(ErrorKind::Resolve(ResolutionFailure::NoPrimitiveAssocItem { + return Err(ResolutionFailure::NoPrimitiveAssocItem { res: prim, prim_name: path, assoc_item: item_name, - })); + } + .into()); } let ty_res = cx @@ -445,7 +442,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } ResolutionFailure::NotInScope { module_id, name: path_root.into() } }); - Err(ErrorKind::Resolve(kind)) + Err(kind.into()) }; } Ok(res) => res, @@ -548,9 +545,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } } else { // We already know this isn't in ValueNS, so no need to check variant_field - return Err(ErrorKind::Resolve(ResolutionFailure::NoAssocItem( - ty_res, item_name, - ))); + return Err(ResolutionFailure::NoAssocItem(ty_res, item_name).into()); } } Res::Def(DefKind::Trait, did) => cx @@ -585,12 +580,12 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { if ns == Namespace::ValueNS { self.variant_field(path_str, current_item, module_id, extra_fragment) } else { - Err(ErrorKind::Resolve(ResolutionFailure::NoAssocItem(ty_res, item_name))) + Err(ResolutionFailure::NoAssocItem(ty_res, item_name).into()) } }) } else { debug!("attempting to resolve item without parent module: {}", path_str); - Err(ErrorKind::Resolve(ResolutionFailure::NoParentItem)) + Err(ResolutionFailure::NoParentItem.into()) } } @@ -611,7 +606,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { let check_full_res_inner = |this: &Self, result: Result>| { let res = match result { Ok(res) => Some(res), - Err(ErrorKind::Resolve(kind)) => kind.full_res(), + Err(ErrorKind::Resolve(box kind)) => kind.full_res(), Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res))) => { Some(res) } @@ -626,7 +621,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }; let check_full_res_macro = |this: &Self| { let result = this.macro_resolve(path_str, base_node); - check_full_res_inner(this, result.map_err(ErrorKind::Resolve)) + check_full_res_inner(this, result.map_err(ErrorKind::from)) }; match ns { Namespace::MacroNS => check_full_res_macro(self), @@ -970,7 +965,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { match self.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment) { Ok(res) => res, - Err(ErrorKind::Resolve(mut kind)) => { + Err(ErrorKind::Resolve(box mut kind)) => { // We only looked in one namespace. Try to give a better error if possible. if kind.full_res().is_none() { let other_ns = if ns == ValueNS { TypeNS } else { ValueNS }; @@ -1028,7 +1023,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); continue; } - Err(ErrorKind::Resolve(kind)) => Err(kind), + Err(ErrorKind::Resolve(box kind)) => Err(kind), }, value_ns: match self.resolve( path_str, @@ -1042,7 +1037,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); continue; } - Err(ErrorKind::Resolve(kind)) => Err(kind), + Err(ErrorKind::Resolve(box kind)) => Err(kind), } .and_then(|(res, fragment)| { // Constructors are picked up in the type namespace. @@ -1816,7 +1811,7 @@ fn handle_variant( let parent = if let Some(parent) = cx.tcx.parent(res.def_id()) { parent } else { - return Err(ErrorKind::Resolve(ResolutionFailure::NoParentItem)); + return Err(ResolutionFailure::NoParentItem.into()); }; let parent_def = Res::Def(DefKind::Enum, parent); let variant = cx.tcx.expect_variant_res(res); From 57250eff55db7c034b9d3468b45b0df2d6ee4bb3 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 11 Sep 2020 13:42:56 -0400 Subject: [PATCH 0310/1052] Use `span_label` instead of `note` This puts the error message closer to the link, making it easier to see what went wrong. --- .../passes/collect_intra_doc_links.rs | 84 +++++++++++-------- .../intra-links-warning-crlf.stderr | 12 +-- .../rustdoc-ui/intra-links-warning.stderr | 47 ++++------- 3 files changed, 65 insertions(+), 78 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 7fea70253b301..0319096635211 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1516,16 +1516,15 @@ fn resolution_failure( collector.cx.tcx.item_name(res.def_id()).to_string() ) }; - let assoc_item_not_allowed = |res: Res, diag: &mut DiagnosticBuilder<'_>| { + let assoc_item_not_allowed = |res: Res| { let def_id = res.def_id(); let name = collector.cx.tcx.item_name(def_id); - let note = format!( + format!( "`{}` is {} {}, not a module or type, and cannot have associated items", name, res.article(), res.descr() - ); - diag.note(¬e); + ) }; // ignore duplicates let mut variants_seen = SmallVec::<[_; 3]>::new(); @@ -1559,12 +1558,18 @@ fn resolution_failure( continue; } variants_seen.push(variant); - match failure { + let note = match failure { ResolutionFailure::NotInScope { name, .. } => { if in_scope { continue; } - diag.note(&format!("no item named `{}` is in scope", name)); + // NOTE: uses an explicit `continue` so the `note:` will come before the `help:` + let note = format!("no item named `{}` is in scope", name); + if let Some(span) = sp { + diag.span_label(span, ¬e); + } else { + diag.note(¬e); + } // If the link has `::` in the path, assume it's meant to be an intra-doc link if !path_str.contains("::") { // Otherwise, the `[]` might be unrelated. @@ -1572,16 +1577,10 @@ fn resolution_failure( // don't show this for autolinks (`<>`), `()` style links, or reference links diag.help(r#"to escape `[` and `]` characters, add '\' before them like `\[` or `\]`"#); } + continue; } ResolutionFailure::Dummy => continue, ResolutionFailure::WrongNamespace(res, expected_ns) => { - let note = format!( - "this link resolves to {}, which is not in the {} namespace", - item(res), - expected_ns.descr() - ); - diag.note(¬e); - if let Res::Def(kind, _) = res { let disambiguator = Disambiguator::Kind(kind); suggest_disambiguator( @@ -1593,24 +1592,26 @@ fn resolution_failure( &link_range, ) } + + format!( + "this link resolves to {}, which is not in the {} namespace", + item(res), + expected_ns.descr() + ) } ResolutionFailure::NoParentItem => { diag.level = rustc_errors::Level::Bug; - diag.note("all intra doc links should have a parent item"); - } - ResolutionFailure::NoPrimitiveImpl(res, _) => { - let note = format!( - "this link partially resolves to {}, which does not have any associated items", - item(res), - ); - diag.note(¬e); + "all intra doc links should have a parent item".to_owned() } + ResolutionFailure::NoPrimitiveImpl(res, _) => format!( + "this link partially resolves to {}, which does not have any associated items", + item(res), + ), ResolutionFailure::NoPrimitiveAssocItem { prim_name, assoc_item, .. } => { - let note = format!( + format!( "the builtin type `{}` does not have an associated item named `{}`", prim_name, assoc_item - ); - diag.note(¬e); + ) } ResolutionFailure::NoAssocItem(res, assoc_item) => { use DefKind::*; @@ -1645,32 +1646,41 @@ fn resolution_failure( | Use | LifetimeParam | Ctor(_, _) - | AnonConst => return assoc_item_not_allowed(res, diag), + | AnonConst => { + let note = assoc_item_not_allowed(res); + if let Some(span) = sp { + diag.span_label(span, ¬e); + } else { + diag.note(¬e); + } + return; + } Trait | TyAlias | ForeignTy | OpaqueTy | TraitAlias | TyParam | Static => "associated item", Impl | GlobalAsm => unreachable!("not a path"), } }; - let note = format!( + format!( "the {} `{}` has no {} named `{}`", res.descr(), name, path_description, assoc_item - ); - diag.note(¬e); + ) } ResolutionFailure::CannotHaveAssociatedItems(res, _) => { - assoc_item_not_allowed(res, diag) - } - ResolutionFailure::NotAVariant(res, variant) => { - let note = format!( - "this link partially resolves to {}, but there is no variant named {}", - item(res), - variant - ); - diag.note(¬e); + assoc_item_not_allowed(res) } + ResolutionFailure::NotAVariant(res, variant) => format!( + "this link partially resolves to {}, but there is no variant named {}", + item(res), + variant + ), + }; + if let Some(span) = sp { + diag.span_label(span, ¬e); + } else { + diag.note(¬e); } } }, diff --git a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr b/src/test/rustdoc-ui/intra-links-warning-crlf.stderr index 1da27b786180f..d64c7e14ba61d 100644 --- a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr +++ b/src/test/rustdoc-ui/intra-links-warning-crlf.stderr @@ -2,37 +2,33 @@ warning: unresolved link to `error` --> $DIR/intra-links-warning-crlf.rs:7:6 | LL | /// [error] - | ^^^^^ + | ^^^^^ no item named `error` is in scope | = note: `#[warn(broken_intra_doc_links)]` on by default - = note: no item named `error` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error1` --> $DIR/intra-links-warning-crlf.rs:12:11 | LL | /// docs [error1] - | ^^^^^^ + | ^^^^^^ no item named `error1` is in scope | - = note: no item named `error1` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error2` --> $DIR/intra-links-warning-crlf.rs:15:11 | LL | /// docs [error2] - | ^^^^^^ + | ^^^^^^ no item named `error2` is in scope | - = note: no item named `error2` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` --> $DIR/intra-links-warning-crlf.rs:23:20 | LL | * It also has an [error]. - | ^^^^^ + | ^^^^^ no item named `error` is in scope | - = note: no item named `error` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: 4 warnings emitted diff --git a/src/test/rustdoc-ui/intra-links-warning.stderr b/src/test/rustdoc-ui/intra-links-warning.stderr index 25c6975d3a509..0eaad25501a32 100644 --- a/src/test/rustdoc-ui/intra-links-warning.stderr +++ b/src/test/rustdoc-ui/intra-links-warning.stderr @@ -2,76 +2,62 @@ warning: unresolved link to `Foo::baz` --> $DIR/intra-links-warning.rs:3:23 | LL | //! Test with [Foo::baz], [Bar::foo], ... - | ^^^^^^^^ + | ^^^^^^^^ the struct `Foo` has no field or associated item named `baz` | = note: `#[warn(broken_intra_doc_links)]` on by default - = note: the struct `Foo` has no field or associated item named `baz` warning: unresolved link to `Bar::foo` --> $DIR/intra-links-warning.rs:3:35 | LL | //! Test with [Foo::baz], [Bar::foo], ... - | ^^^^^^^^ - | - = note: no item named `Bar` is in scope + | ^^^^^^^^ no item named `Bar` is in scope warning: unresolved link to `Uniooon::X` --> $DIR/intra-links-warning.rs:6:13 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^^^^^ - | - = note: no item named `Uniooon` is in scope + | ^^^^^^^^^^ no item named `Uniooon` is in scope warning: unresolved link to `Qux::Z` --> $DIR/intra-links-warning.rs:6:30 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^ - | - = note: no item named `Qux` is in scope + | ^^^^^^ no item named `Qux` is in scope warning: unresolved link to `Uniooon::X` --> $DIR/intra-links-warning.rs:10:14 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^^^^^ - | - = note: no item named `Uniooon` is in scope + | ^^^^^^^^^^ no item named `Uniooon` is in scope warning: unresolved link to `Qux::Z` --> $DIR/intra-links-warning.rs:10:31 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^ - | - = note: no item named `Qux` is in scope + | ^^^^^^ no item named `Qux` is in scope warning: unresolved link to `Qux:Y` --> $DIR/intra-links-warning.rs:14:13 | LL | /// [Qux:Y] - | ^^^^^ + | ^^^^^ no item named `Qux:Y` is in scope | - = note: no item named `Qux:Y` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` --> $DIR/intra-links-warning.rs:58:30 | LL | * time to introduce a link [error]*/ - | ^^^^^ + | ^^^^^ no item named `error` is in scope | - = note: no item named `error` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` --> $DIR/intra-links-warning.rs:64:30 | LL | * time to introduce a link [error] - | ^^^^^ + | ^^^^^ no item named `error` is in scope | - = note: no item named `error` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` @@ -119,45 +105,40 @@ warning: unresolved link to `error1` --> $DIR/intra-links-warning.rs:80:11 | LL | /// docs [error1] - | ^^^^^^ + | ^^^^^^ no item named `error1` is in scope | - = note: no item named `error1` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error2` --> $DIR/intra-links-warning.rs:82:11 | LL | /// docs [error2] - | ^^^^^^ + | ^^^^^^ no item named `error2` is in scope | - = note: no item named `error2` is in scope = 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` is in scope | - = note: no item named `BarA` is 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` is in scope | - = note: no item named `BarB` is 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` is in scope | - = note: no item named `BarC` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `BarD` From 1c1bb1309f5b2e15438711b701f6ab59f04fd633 Mon Sep 17 00:00:00 2001 From: aticu <15schnic@gmail.com> Date: Thu, 27 Aug 2020 23:55:22 +0200 Subject: [PATCH 0311/1052] Improve E0118 description --- .../src/error_codes/E0118.md | 27 ++++++++++++++++--- .../src/coherence/inherent_impls.rs | 25 ++++++++++------- src/test/ui/error-codes/E0118-2.rs | 8 ++++++ src/test/ui/error-codes/E0118-2.stderr | 12 +++++++++ src/test/ui/error-codes/E0118.stderr | 4 +-- .../privacy/private-in-public-ill-formed.rs | 6 +++-- .../private-in-public-ill-formed.stderr | 10 +++---- 7 files changed, 71 insertions(+), 21 deletions(-) create mode 100644 src/test/ui/error-codes/E0118-2.rs create mode 100644 src/test/ui/error-codes/E0118-2.stderr diff --git a/compiler/rustc_error_codes/src/error_codes/E0118.md b/compiler/rustc_error_codes/src/error_codes/E0118.md index 5cb5f506e0a4b..ddd4f498f0c34 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0118.md +++ b/compiler/rustc_error_codes/src/error_codes/E0118.md @@ -1,10 +1,10 @@ -An inherent implementation was defined for something which isn't a struct nor -an enum. +An inherent implementation was defined for something which isn't a struct, an +enum, a union or a trait object. Erroneous code example: ```compile_fail,E0118 -impl (u8, u8) { // error: no base type found for inherent implementation +impl (u8, u8) { // error: no nominal type found for inherent implementation fn get_state(&self) -> String { // ... } @@ -41,3 +41,24 @@ impl TypeWrapper { } } ``` + +Instead of defining an inherent implementation on a reference, you could also +move the reference inside the implementation: + +```compile_fail,E0118 +struct Foo; + +impl &Foo { // error: no nominal type found for inherent implementation + fn bar(self, other: Self) {} +} +``` + +becomes + +``` +struct Foo; + +impl Foo { + fn bar(&self, other: &Self) {} +} +``` diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_typeck/src/coherence/inherent_impls.rs index 042ecdbadc61b..373acb95c9e37 100644 --- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs +++ b/compiler/rustc_typeck/src/coherence/inherent_impls.rs @@ -308,18 +308,25 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { } ty::Error(_) => {} _ => { - struct_span_err!( + let mut err = struct_span_err!( self.tcx.sess, ty.span, E0118, - "no base type found for inherent implementation" - ) - .span_label(ty.span, "impl requires a base type") - .note( - "either implement a trait on it or create a newtype \ - to wrap it instead", - ) - .emit(); + "no nominal type found for inherent implementation" + ); + + err.span_label(ty.span, "impl requires a nominal type") + .note("either implement a trait on it or create a newtype to wrap it instead"); + + if let ty::Ref(_, subty, _) = self_ty.kind() { + err.note(&format!( + "you could also try moving the reference to \ + uses of `{}` (such as `self`) within the implementation", + subty + )); + } + + err.emit(); } } } diff --git a/src/test/ui/error-codes/E0118-2.rs b/src/test/ui/error-codes/E0118-2.rs new file mode 100644 index 0000000000000..fe04190162af4 --- /dev/null +++ b/src/test/ui/error-codes/E0118-2.rs @@ -0,0 +1,8 @@ +struct Foo; + +impl &mut Foo { + //~^ ERROR E0118 + fn bar(self) {} +} + +fn main() {} diff --git a/src/test/ui/error-codes/E0118-2.stderr b/src/test/ui/error-codes/E0118-2.stderr new file mode 100644 index 0000000000000..2a1fe23111687 --- /dev/null +++ b/src/test/ui/error-codes/E0118-2.stderr @@ -0,0 +1,12 @@ +error[E0118]: no nominal type found for inherent implementation + --> $DIR/E0118-2.rs:3:6 + | +LL | impl &mut Foo { + | ^^^^^^^^ impl requires a nominal type + | + = note: either implement a trait on it or create a newtype to wrap it instead + = note: you could also try moving the reference to uses of `Foo` (such as `self`) within the implementation + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0118`. diff --git a/src/test/ui/error-codes/E0118.stderr b/src/test/ui/error-codes/E0118.stderr index b0afaeb5c1fa9..2693a93213a3b 100644 --- a/src/test/ui/error-codes/E0118.stderr +++ b/src/test/ui/error-codes/E0118.stderr @@ -1,8 +1,8 @@ -error[E0118]: no base type found for inherent implementation +error[E0118]: no nominal type found for inherent implementation --> $DIR/E0118.rs:1:6 | LL | impl (u8, u8) { - | ^^^^^^^^ impl requires a base type + | ^^^^^^^^ impl requires a nominal type | = note: either implement a trait on it or create a newtype to wrap it instead diff --git a/src/test/ui/privacy/private-in-public-ill-formed.rs b/src/test/ui/privacy/private-in-public-ill-formed.rs index 0ef5d89002e49..031e2874a2ba8 100644 --- a/src/test/ui/privacy/private-in-public-ill-formed.rs +++ b/src/test/ui/privacy/private-in-public-ill-formed.rs @@ -11,7 +11,8 @@ mod aliases_pub { type AssocAlias = m::Pub3; } - impl ::AssocAlias { //~ ERROR no base type found for inherent implementation + impl ::AssocAlias { + //~^ ERROR no nominal type found for inherent implementation pub fn f(arg: Priv) {} // private type `aliases_pub::Priv` in public interface } } @@ -27,7 +28,8 @@ mod aliases_priv { type AssocAlias = Priv3; } - impl ::AssocAlias { //~ ERROR no base type found for inherent implementation + impl ::AssocAlias { + //~^ ERROR no nominal type found for inherent implementation pub fn f(arg: Priv) {} // OK } } diff --git a/src/test/ui/privacy/private-in-public-ill-formed.stderr b/src/test/ui/privacy/private-in-public-ill-formed.stderr index a1a326f2873e1..e7c94bc301bdf 100644 --- a/src/test/ui/privacy/private-in-public-ill-formed.stderr +++ b/src/test/ui/privacy/private-in-public-ill-formed.stderr @@ -1,16 +1,16 @@ -error[E0118]: no base type found for inherent implementation +error[E0118]: no nominal type found for inherent implementation --> $DIR/private-in-public-ill-formed.rs:14:10 | LL | impl ::AssocAlias { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl requires a base type + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl requires a nominal type | = note: either implement a trait on it or create a newtype to wrap it instead -error[E0118]: no base type found for inherent implementation - --> $DIR/private-in-public-ill-formed.rs:30:10 +error[E0118]: no nominal type found for inherent implementation + --> $DIR/private-in-public-ill-formed.rs:31:10 | LL | impl ::AssocAlias { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl requires a base type + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl requires a nominal type | = note: either implement a trait on it or create a newtype to wrap it instead From b2a5a7a8c21c9cc271f3ce44b4cffdaefaa7f6d1 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 11 Sep 2020 13:49:45 -0400 Subject: [PATCH 0312/1052] Remove unnecessary clone --- src/librustdoc/passes/collect_intra_doc_links.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 0319096635211..3e3eebcb51827 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1056,12 +1056,9 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { }), }; - let mut candidates_iter = - candidates.iter().filter_map(|res| res.as_ref().ok()); - let len = candidates_iter.clone().count(); + let len = candidates.iter().filter(|res| res.is_ok()).count(); if len == 0 { - drop(candidates_iter); resolution_failure( self, &item, @@ -1076,12 +1073,10 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } if len == 1 { - candidates_iter.next().unwrap().clone() + candidates.into_iter().filter_map(|res| res.ok()).next().unwrap() } else if len == 2 && is_derive_trait_collision(&candidates) { - drop(candidates_iter); candidates.type_ns.unwrap() } else { - drop(candidates_iter); if is_derive_trait_collision(&candidates) { candidates.macro_ns = Err(ResolutionFailure::Dummy); } From c63f634a4b0550a398d5bf08f8b036edaf67c48d Mon Sep 17 00:00:00 2001 From: Gus Wynn Date: Tue, 8 Sep 2020 15:14:09 -0700 Subject: [PATCH 0313/1052] Give better diagnostic when using a private tuple struct constructor --- .../rustc_resolve/src/build_reduced_graph.rs | 17 +++--- compiler/rustc_resolve/src/late.rs | 30 ++++++---- .../rustc_resolve/src/late/diagnostics.rs | 55 +++++++++++++++---- compiler/rustc_resolve/src/lib.rs | 7 ++- src/test/ui/issues/auxiliary/issue-75907.rs | 5 ++ src/test/ui/issues/issue-75907.rs | 18 ++++++ src/test/ui/issues/issue-75907.stderr | 29 ++++++++++ src/test/ui/issues/issue-75907_b.rs | 11 ++++ src/test/ui/issues/issue-75907_b.stderr | 9 +++ 9 files changed, 152 insertions(+), 29 deletions(-) create mode 100644 src/test/ui/issues/auxiliary/issue-75907.rs create mode 100644 src/test/ui/issues/issue-75907.rs create mode 100644 src/test/ui/issues/issue-75907.stderr create mode 100644 src/test/ui/issues/issue-75907_b.rs create mode 100644 src/test/ui/issues/issue-75907_b.stderr diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 761724be57daf..128e3b3e7466d 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -796,23 +796,26 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { vis }; + let mut ret_fields = Vec::with_capacity(vdata.fields().len()); + for field in vdata.fields() { // NOTE: The field may be an expansion placeholder, but expansion sets // correct visibilities for unnamed field placeholders specifically, so the // constructor visibility should still be determined correctly. - if let Ok(field_vis) = self.resolve_visibility_speculative(&field.vis, true) - { - if ctor_vis.is_at_least(field_vis, &*self.r) { - ctor_vis = field_vis; - } + let field_vis = self + .resolve_visibility_speculative(&field.vis, true) + .unwrap_or(ty::Visibility::Public); + if ctor_vis.is_at_least(field_vis, &*self.r) { + ctor_vis = field_vis; } + ret_fields.push(field_vis); } let ctor_res = Res::Def( DefKind::Ctor(CtorOf::Struct, CtorKind::from_ast(vdata)), self.r.local_def_id(ctor_node_id).to_def_id(), ); self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion)); - self.r.struct_constructors.insert(def_id, (ctor_res, ctor_vis)); + self.r.struct_constructors.insert(def_id, (ctor_res, ctor_vis, ret_fields)); } } @@ -964,7 +967,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { Res::Def(DefKind::Ctor(CtorOf::Struct, ..), def_id) => { let parent = cstore.def_key(def_id).parent; if let Some(struct_def_id) = parent.map(|index| DefId { index, ..def_id }) { - self.r.struct_constructors.insert(struct_def_id, (res, vis)); + self.r.struct_constructors.insert(struct_def_id, (res, vis, vec![])); } } _ => {} diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 2b2123e295d09..cb0aa577a1c21 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -188,7 +188,7 @@ crate enum PathSource<'a> { // Paths in struct expressions and patterns `Path { .. }`. Struct, // Paths in tuple struct patterns `Path(..)`. - TupleStruct(Span), + TupleStruct(Span, &'a [Span]), // `m::A::B` in `::B::C`. TraitItem(Namespace), } @@ -197,7 +197,7 @@ impl<'a> PathSource<'a> { fn namespace(self) -> Namespace { match self { PathSource::Type | PathSource::Trait(_) | PathSource::Struct => TypeNS, - PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct(_) => ValueNS, + PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct(..) => ValueNS, PathSource::TraitItem(ns) => ns, } } @@ -208,7 +208,7 @@ impl<'a> PathSource<'a> { | PathSource::Expr(..) | PathSource::Pat | PathSource::Struct - | PathSource::TupleStruct(_) => true, + | PathSource::TupleStruct(..) => true, PathSource::Trait(_) | PathSource::TraitItem(..) => false, } } @@ -219,7 +219,7 @@ impl<'a> PathSource<'a> { PathSource::Trait(_) => "trait", PathSource::Pat => "unit struct, unit variant or constant", PathSource::Struct => "struct, variant or union type", - PathSource::TupleStruct(_) => "tuple struct or tuple variant", + PathSource::TupleStruct(..) => "tuple struct or tuple variant", PathSource::TraitItem(ns) => match ns { TypeNS => "associated type", ValueNS => "method or associated constant", @@ -305,7 +305,7 @@ impl<'a> PathSource<'a> { | Res::SelfCtor(..) => true, _ => false, }, - PathSource::TupleStruct(_) => match res { + PathSource::TupleStruct(..) => match res { Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(..) => true, _ => false, }, @@ -340,8 +340,8 @@ impl<'a> PathSource<'a> { (PathSource::Struct, false) => error_code!(E0422), (PathSource::Expr(..), true) => error_code!(E0423), (PathSource::Expr(..), false) => error_code!(E0425), - (PathSource::Pat | PathSource::TupleStruct(_), true) => error_code!(E0532), - (PathSource::Pat | PathSource::TupleStruct(_), false) => error_code!(E0531), + (PathSource::Pat | PathSource::TupleStruct(..), true) => error_code!(E0532), + (PathSource::Pat | PathSource::TupleStruct(..), false) => error_code!(E0531), (PathSource::TraitItem(..), true) => error_code!(E0575), (PathSource::TraitItem(..), false) => error_code!(E0576), } @@ -411,7 +411,7 @@ struct LateResolutionVisitor<'a, 'b, 'ast> { } /// Walks the whole crate in DFS order, visiting each item, resolving names as it goes. -impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { +impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { fn visit_item(&mut self, item: &'ast Item) { let prev = replace(&mut self.diagnostic_metadata.current_item, Some(item)); // Always report errors in items we just entered. @@ -659,7 +659,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } } -impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { +impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { fn new(resolver: &'b mut Resolver<'a>) -> LateResolutionVisitor<'a, 'b, 'ast> { // During late resolution we only track the module component of the parent scope, // although it may be useful to track other components as well for diagnostics. @@ -1539,8 +1539,16 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { .unwrap_or_else(|| self.fresh_binding(ident, pat.id, pat_src, bindings)); self.r.record_partial_res(pat.id, PartialRes::new(res)); } - PatKind::TupleStruct(ref path, ..) => { - self.smart_resolve_path(pat.id, None, path, PathSource::TupleStruct(pat.span)); + PatKind::TupleStruct(ref path, ref sub_patterns) => { + self.smart_resolve_path( + pat.id, + None, + path, + PathSource::TupleStruct( + pat.span, + self.r.arenas.alloc_pattern_spans(sub_patterns.iter().map(|p| p.span)), + ), + ); } PatKind::Path(ref qself, ref path) => { self.smart_resolve_path(pat.id, qself.as_ref(), path, PathSource::Pat); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 8cb6b6553ffe0..b307b3d52b4f6 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -89,7 +89,7 @@ fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, Str (variant_path_string, enum_path_string) } -impl<'a> LateResolutionVisitor<'a, '_, '_> { +impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { fn def_span(&self, def_id: DefId) -> Option { match def_id.krate { LOCAL_CRATE => self.r.opt_span(def_id), @@ -622,12 +622,12 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { ); } } - PathSource::Expr(_) | PathSource::TupleStruct(_) | PathSource::Pat => { + PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => { let span = match &source { PathSource::Expr(Some(Expr { span, kind: ExprKind::Call(_, _), .. })) - | PathSource::TupleStruct(span) => { + | PathSource::TupleStruct(span, _) => { // We want the main underline to cover the suggested code as well for // cleaner output. err.set_span(*span); @@ -639,7 +639,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { err.span_label(span, &format!("`{}` defined here", path_str)); } let (tail, descr, applicability) = match source { - PathSource::Pat | PathSource::TupleStruct(_) => { + PathSource::Pat | PathSource::TupleStruct(..) => { ("", "pattern", Applicability::MachineApplicable) } _ => (": val", "literal", Applicability::HasPlaceholders), @@ -704,7 +704,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { } ( Res::Def(DefKind::Enum, def_id), - PathSource::TupleStruct(_) | PathSource::Expr(..), + PathSource::TupleStruct(..) | PathSource::Expr(..), ) => { if self .diagnostic_metadata @@ -744,15 +744,50 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { } } (Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => { - if let Some((ctor_def, ctor_vis)) = self.r.struct_constructors.get(&def_id).cloned() + if let Some((ctor_def, ctor_vis, fields)) = + self.r.struct_constructors.get(&def_id).cloned() { let accessible_ctor = self.r.is_accessible_from(ctor_vis, self.parent_scope.module); if is_expected(ctor_def) && !accessible_ctor { - err.span_label( - span, - "constructor is not visible here due to private fields".to_string(), - ); + let mut better_diag = false; + if let PathSource::TupleStruct(_, pattern_spans) = source { + if pattern_spans.len() > 0 && fields.len() == pattern_spans.len() { + let non_visible_spans: Vec = fields + .iter() + .zip(pattern_spans.iter()) + .filter_map(|(vis, span)| { + match self + .r + .is_accessible_from(*vis, self.parent_scope.module) + { + true => None, + false => Some(*span), + } + }) + .collect(); + // Extra check to be sure + if non_visible_spans.len() > 0 { + let mut m: rustc_span::MultiSpan = + non_visible_spans.clone().into(); + non_visible_spans.into_iter().for_each(|s| { + m.push_span_label(s, "private field".to_string()) + }); + err.span_note( + m, + "constructor is not visible here due to private fields", + ); + better_diag = true; + } + } + } + + if !better_diag { + err.span_label( + span, + "constructor is not visible here due to private fields".to_string(), + ); + } } } else { bad_struct_syntax_suggestion(def_id); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 5892edf7652b7..b77e3d34eb35b 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -999,7 +999,8 @@ pub struct Resolver<'a> { /// Table for mapping struct IDs into struct constructor IDs, /// it's not used during normal resolution, only for better error reporting. - struct_constructors: DefIdMap<(Res, ty::Visibility)>, + /// Also includes of list of each fields visibility + struct_constructors: DefIdMap<(Res, ty::Visibility, Vec)>, /// Features enabled for this crate. active_features: FxHashSet, @@ -1036,6 +1037,7 @@ pub struct ResolverArenas<'a> { name_resolutions: TypedArena>>, macro_rules_bindings: TypedArena>, ast_paths: TypedArena, + pattern_spans: TypedArena, } impl<'a> ResolverArenas<'a> { @@ -1067,6 +1069,9 @@ impl<'a> ResolverArenas<'a> { fn alloc_ast_paths(&'a self, paths: &[ast::Path]) -> &'a [ast::Path] { self.ast_paths.alloc_from_iter(paths.iter().cloned()) } + fn alloc_pattern_spans(&'a self, spans: impl Iterator) -> &'a [Span] { + self.pattern_spans.alloc_from_iter(spans) + } } impl<'a> AsMut> for Resolver<'a> { diff --git a/src/test/ui/issues/auxiliary/issue-75907.rs b/src/test/ui/issues/auxiliary/issue-75907.rs new file mode 100644 index 0000000000000..0b70452a24d71 --- /dev/null +++ b/src/test/ui/issues/auxiliary/issue-75907.rs @@ -0,0 +1,5 @@ +pub struct Bar(pub u8, u8, u8); + +pub fn make_bar() -> Bar { + Bar(1, 12, 10) +} diff --git a/src/test/ui/issues/issue-75907.rs b/src/test/ui/issues/issue-75907.rs new file mode 100644 index 0000000000000..8c155d9be3565 --- /dev/null +++ b/src/test/ui/issues/issue-75907.rs @@ -0,0 +1,18 @@ +// Test for for diagnostic improvement issue #75907 + +mod foo { + pub(crate) struct Foo(u8); + pub(crate) struct Bar(pub u8, u8, Foo); + + pub(crate) fn make_bar() -> Bar { + Bar(1, 12, Foo(10)) + } +} + +use foo::{make_bar, Bar, Foo}; + +fn main() { + let Bar(x, y, Foo(z)) = make_bar(); + //~^ ERROR expected tuple struct + //~| ERROR expected tuple struct +} diff --git a/src/test/ui/issues/issue-75907.stderr b/src/test/ui/issues/issue-75907.stderr new file mode 100644 index 0000000000000..65b9a51e01dee --- /dev/null +++ b/src/test/ui/issues/issue-75907.stderr @@ -0,0 +1,29 @@ +error[E0532]: expected tuple struct or tuple variant, found struct `Bar` + --> $DIR/issue-75907.rs:15:9 + | +LL | let Bar(x, y, Foo(z)) = make_bar(); + | ^^^ + | +note: constructor is not visible here due to private fields + --> $DIR/issue-75907.rs:15:16 + | +LL | let Bar(x, y, Foo(z)) = make_bar(); + | ^ ^^^^^^ private field + | | + | private field + +error[E0532]: expected tuple struct or tuple variant, found struct `Foo` + --> $DIR/issue-75907.rs:15:19 + | +LL | let Bar(x, y, Foo(z)) = make_bar(); + | ^^^ + | +note: constructor is not visible here due to private fields + --> $DIR/issue-75907.rs:15:23 + | +LL | let Bar(x, y, Foo(z)) = make_bar(); + | ^ private field + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0532`. diff --git a/src/test/ui/issues/issue-75907_b.rs b/src/test/ui/issues/issue-75907_b.rs new file mode 100644 index 0000000000000..fdd3bc6d7244e --- /dev/null +++ b/src/test/ui/issues/issue-75907_b.rs @@ -0,0 +1,11 @@ +// Test for for diagnostic improvement issue #75907, extern crate +// aux-build:issue-75907.rs + +extern crate issue_75907 as a; + +use a::{make_bar, Bar}; + +fn main() { + let Bar(x, y, z) = make_bar(); + //~^ ERROR expected tuple struct +} diff --git a/src/test/ui/issues/issue-75907_b.stderr b/src/test/ui/issues/issue-75907_b.stderr new file mode 100644 index 0000000000000..cdd21de6c33e4 --- /dev/null +++ b/src/test/ui/issues/issue-75907_b.stderr @@ -0,0 +1,9 @@ +error[E0532]: expected tuple struct or tuple variant, found struct `Bar` + --> $DIR/issue-75907_b.rs:9:9 + | +LL | let Bar(x, y, z) = make_bar(); + | ^^^ constructor is not visible here due to private fields + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0532`. From 5ea3eaf237793c978cad9d48f7850619c7f49d69 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 11 Sep 2020 14:00:40 -0400 Subject: [PATCH 0314/1052] Name the current module 'not in scope' -> 'not in `module`' --- .../passes/collect_intra_doc_links.rs | 5 +- .../rustdoc-ui/assoc-item-not-in-scope.stderr | 3 +- .../deny-intra-link-resolution-failure.stderr | 3 +- .../rustdoc-ui/intra-doc-alias-ice.stderr | 3 +- src/test/rustdoc-ui/intra-link-errors.rs | 6 +- src/test/rustdoc-ui/intra-link-errors.stderr | 75 +++++++------------ .../intra-link-span-ice-55723.stderr | 3 +- .../intra-links-warning-crlf.stderr | 8 +- .../rustdoc-ui/intra-links-warning.stderr | 36 ++++----- src/test/rustdoc-ui/lint-group.stderr | 3 +- 10 files changed, 61 insertions(+), 84 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 3e3eebcb51827..5780610c86210 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1554,12 +1554,13 @@ fn resolution_failure( } variants_seen.push(variant); let note = match failure { - ResolutionFailure::NotInScope { name, .. } => { + ResolutionFailure::NotInScope { module_id, name, .. } => { if in_scope { continue; } // NOTE: uses an explicit `continue` so the `note:` will come before the `help:` - let note = format!("no item named `{}` is in scope", name); + let module_name = collector.cx.tcx.item_name(module_id); + let note = format!("no item named `{}` in `{}`", name, module_name); if let Some(span) = sp { diag.span_label(span, ¬e); } else { diff --git a/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr b/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr index 8acfcca2139e3..92d27179e8c3f 100644 --- a/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr +++ b/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr @@ -2,14 +2,13 @@ error: unresolved link to `S::fmt` --> $DIR/assoc-item-not-in-scope.rs:4:14 | LL | /// Link to [`S::fmt`] - | ^^^^^^^^ + | ^^^^^^^^ the struct `S` has no field or associated item named `fmt` | note: the lint level is defined here --> $DIR/assoc-item-not-in-scope.rs:1:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ - = note: the struct `S` has no field or associated item named `fmt` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr index 4ae53e83613e0..5020b97b2f201 100644 --- a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr +++ b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr @@ -2,14 +2,13 @@ error: unresolved link to `v2` --> $DIR/deny-intra-link-resolution-failure.rs:3:6 | LL | /// [v2] - | ^^ + | ^^ no item named `v2` in `deny_intra_link_resolution_failure` | note: the lint level is defined here --> $DIR/deny-intra-link-resolution-failure.rs:1:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ - = note: no item named `v2` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr index 5379a91883753..771fc2204f5f8 100644 --- a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr +++ b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr @@ -2,14 +2,13 @@ error: unresolved link to `TypeAlias::hoge` --> $DIR/intra-doc-alias-ice.rs:5:30 | LL | /// [broken cross-reference](TypeAlias::hoge) - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ the type alias `TypeAlias` has no associated item named `hoge` | note: the lint level is defined here --> $DIR/intra-doc-alias-ice.rs:1:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ - = note: the type alias `TypeAlias` has no associated item named `hoge` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-link-errors.rs b/src/test/rustdoc-ui/intra-link-errors.rs index 477ad6464f887..26b629b1313da 100644 --- a/src/test/rustdoc-ui/intra-link-errors.rs +++ b/src/test/rustdoc-ui/intra-link-errors.rs @@ -6,15 +6,15 @@ /// [path::to::nonexistent::module] //~^ ERROR unresolved link -//~| NOTE no item named `path` is in scope +//~| NOTE no item named `path` in `intra_link_errors` /// [path::to::nonexistent::macro!] //~^ ERROR unresolved link -//~| NOTE no item named `path` is in scope +//~| NOTE no item named `path` in `intra_link_errors` /// [type@path::to::nonexistent::type] //~^ ERROR unresolved link -//~| NOTE no item named `path` is in scope +//~| NOTE no item named `path` in `intra_link_errors` /// [std::io::not::here] //~^ ERROR unresolved link diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr index 3b1a09f913e9f..fbf3dcbbec29a 100644 --- a/src/test/rustdoc-ui/intra-link-errors.stderr +++ b/src/test/rustdoc-ui/intra-link-errors.stderr @@ -2,134 +2,115 @@ error: unresolved link to `path::to::nonexistent::module` --> $DIR/intra-link-errors.rs:7:6 | LL | /// [path::to::nonexistent::module] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in `intra_link_errors` | note: the lint level is defined here --> $DIR/intra-link-errors.rs:1:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ - = note: no item named `path` is in scope error: unresolved link to `path::to::nonexistent::macro` --> $DIR/intra-link-errors.rs:11:6 | LL | /// [path::to::nonexistent::macro!] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: no item named `path` is in scope + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in `intra_link_errors` error: unresolved link to `path::to::nonexistent::type` --> $DIR/intra-link-errors.rs:15:6 | LL | /// [type@path::to::nonexistent::type] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: no item named `path` is in scope + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in `intra_link_errors` error: unresolved link to `std::io::not::here` --> $DIR/intra-link-errors.rs:19:6 | LL | /// [std::io::not::here] - | ^^^^^^^^^^^^^^^^^^ - | - = note: the module `io` has no inner item named `not` + | ^^^^^^^^^^^^^^^^^^ the module `io` has no inner item named `not` error: unresolved link to `std::io::Error::x` --> $DIR/intra-link-errors.rs:23:6 | LL | /// [std::io::Error::x] - | ^^^^^^^^^^^^^^^^^ - | - = note: the struct `Error` has no field or associated item named `x` + | ^^^^^^^^^^^^^^^^^ the struct `Error` has no field or associated item named `x` error: unresolved link to `std::io::ErrorKind::x` --> $DIR/intra-link-errors.rs:27:6 | LL | /// [std::io::ErrorKind::x] - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: the enum `ErrorKind` has no variant or associated item named `x` + | ^^^^^^^^^^^^^^^^^^^^^ the enum `ErrorKind` has no variant or associated item named `x` error: unresolved link to `f::A` --> $DIR/intra-link-errors.rs:31:6 | LL | /// [f::A] - | ^^^^ - | - = note: `f` is a function, not a module or type, and cannot have associated items + | ^^^^ `f` is a function, not a module or type, and cannot have associated items error: unresolved link to `S::A` --> $DIR/intra-link-errors.rs:35:6 | LL | /// [S::A] - | ^^^^ - | - = note: the struct `S` has no field or associated item named `A` + | ^^^^ the struct `S` has no field or associated item named `A` error: unresolved link to `S::fmt` --> $DIR/intra-link-errors.rs:39:6 | LL | /// [S::fmt] - | ^^^^^^ - | - = note: the struct `S` has no field or associated item named `fmt` + | ^^^^^^ the struct `S` has no field or associated item named `fmt` error: unresolved link to `E::D` --> $DIR/intra-link-errors.rs:43:6 | LL | /// [E::D] - | ^^^^ - | - = note: the enum `E` has no variant or associated item named `D` + | ^^^^ the enum `E` has no variant or associated item named `D` error: unresolved link to `u8::not_found` --> $DIR/intra-link-errors.rs:47:6 | LL | /// [u8::not_found] - | ^^^^^^^^^^^^^ - | - = note: the builtin type `u8` does not have an associated item named `not_found` + | ^^^^^^^^^^^^^ the builtin type `u8` does not have an associated item named `not_found` error: unresolved link to `S` --> $DIR/intra-link-errors.rs:51:6 | LL | /// [S!] - | ^^ help: to link to the struct, prefix with `struct@`: `struct@S` - | - = note: this link resolves to the struct `S`, which is not in the macro namespace + | ^^ + | | + | 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 `T::g` --> $DIR/intra-link-errors.rs:69:6 | LL | /// [type@T::g] - | ^^^^^^^^^ help: to link to the associated function, add parentheses: `T::g()` - | - = note: this link resolves to the associated function `g`, which is not in the type namespace + | ^^^^^^^^^ + | | + | this link resolves to the associated function `g`, which is not in the type namespace + | help: to link to the associated function, add parentheses: `T::g()` error: unresolved link to `T::h` --> $DIR/intra-link-errors.rs:74:6 | LL | /// [T::h!] - | ^^^^^ - | - = note: the trait `T` has no macro named `h` + | ^^^^^ the trait `T` has no macro named `h` error: unresolved link to `S::h` --> $DIR/intra-link-errors.rs:61:6 | LL | /// [type@S::h] - | ^^^^^^^^^ help: to link to the associated function, add parentheses: `S::h()` - | - = note: this link resolves to the associated function `h`, which is not in the type namespace + | ^^^^^^^^^ + | | + | 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:81:6 | LL | /// [m()] - | ^^^ help: to link to the macro, add an exclamation mark: `m!` - | - = note: this link resolves to the macro `m`, which is not in the value namespace + | ^^^ + | | + | this link resolves to the macro `m`, which is not in the value namespace + | help: to link to the macro, add an exclamation mark: `m!` error: aborting due to 16 previous errors diff --git a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr index 47b6a08baf37d..3c13df20588d8 100644 --- a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr +++ b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr @@ -2,14 +2,13 @@ error: unresolved link to `i` --> $DIR/intra-link-span-ice-55723.rs:9:10 | LL | /// (arr[i]) - | ^ + | ^ no item named `i` in `intra_link_span_ice_55723` | note: the lint level is defined here --> $DIR/intra-link-span-ice-55723.rs:1:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ - = note: no item named `i` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr b/src/test/rustdoc-ui/intra-links-warning-crlf.stderr index d64c7e14ba61d..351f8fafa64d8 100644 --- a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr +++ b/src/test/rustdoc-ui/intra-links-warning-crlf.stderr @@ -2,7 +2,7 @@ warning: unresolved link to `error` --> $DIR/intra-links-warning-crlf.rs:7:6 | LL | /// [error] - | ^^^^^ no item named `error` is in scope + | ^^^^^ no item named `error` in `intra_links_warning_crlf` | = note: `#[warn(broken_intra_doc_links)]` on by default = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -11,7 +11,7 @@ warning: unresolved link to `error1` --> $DIR/intra-links-warning-crlf.rs:12:11 | LL | /// docs [error1] - | ^^^^^^ no item named `error1` is in scope + | ^^^^^^ no item named `error1` in `intra_links_warning_crlf` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -19,7 +19,7 @@ warning: unresolved link to `error2` --> $DIR/intra-links-warning-crlf.rs:15:11 | LL | /// docs [error2] - | ^^^^^^ no item named `error2` is in scope + | ^^^^^^ no item named `error2` in `intra_links_warning_crlf` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -27,7 +27,7 @@ warning: unresolved link to `error` --> $DIR/intra-links-warning-crlf.rs:23:20 | LL | * It also has an [error]. - | ^^^^^ no item named `error` is in scope + | ^^^^^ no item named `error` in `intra_links_warning_crlf` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` diff --git a/src/test/rustdoc-ui/intra-links-warning.stderr b/src/test/rustdoc-ui/intra-links-warning.stderr index 0eaad25501a32..0832e00d35a00 100644 --- a/src/test/rustdoc-ui/intra-links-warning.stderr +++ b/src/test/rustdoc-ui/intra-links-warning.stderr @@ -10,37 +10,37 @@ warning: unresolved link to `Bar::foo` --> $DIR/intra-links-warning.rs:3:35 | LL | //! Test with [Foo::baz], [Bar::foo], ... - | ^^^^^^^^ no item named `Bar` is in scope + | ^^^^^^^^ no item named `Bar` in `intra_links_warning` warning: unresolved link to `Uniooon::X` --> $DIR/intra-links-warning.rs:6:13 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^^^^^ no item named `Uniooon` is in scope + | ^^^^^^^^^^ no item named `Uniooon` in `intra_links_warning` warning: unresolved link to `Qux::Z` --> $DIR/intra-links-warning.rs:6:30 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^ no item named `Qux` is in scope + | ^^^^^^ no item named `Qux` in `intra_links_warning` warning: unresolved link to `Uniooon::X` --> $DIR/intra-links-warning.rs:10:14 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^^^^^ no item named `Uniooon` is in scope + | ^^^^^^^^^^ no item named `Uniooon` in `intra_links_warning` warning: unresolved link to `Qux::Z` --> $DIR/intra-links-warning.rs:10:31 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^ no item named `Qux` is in scope + | ^^^^^^ no item named `Qux` in `intra_links_warning` warning: unresolved link to `Qux:Y` --> $DIR/intra-links-warning.rs:14:13 | LL | /// [Qux:Y] - | ^^^^^ no item named `Qux:Y` is in scope + | ^^^^^ no item named `Qux:Y` in `intra_links_warning` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -48,7 +48,7 @@ warning: unresolved link to `error` --> $DIR/intra-links-warning.rs:58:30 | LL | * time to introduce a link [error]*/ - | ^^^^^ no item named `error` is in scope + | ^^^^^ no item named `error` in `intra_links_warning` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -56,7 +56,7 @@ warning: unresolved link to `error` --> $DIR/intra-links-warning.rs:64:30 | LL | * time to introduce a link [error] - | ^^^^^ no item named `error` is in scope + | ^^^^^ no item named `error` in `intra_links_warning` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -70,7 +70,7 @@ LL | #[doc = "single line [error]"] single line [error] ^^^^^ - = note: no item named `error` is in scope + = note: no item named `error` in `intra_links_warning` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` @@ -83,7 +83,7 @@ LL | #[doc = "single line with \"escaping\" [error]"] single line with "escaping" [error] ^^^^^ - = note: no item named `error` is in scope + = note: no item named `error` in `intra_links_warning` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` @@ -98,14 +98,14 @@ LL | | /// [error] [error] ^^^^^ - = note: no item named `error` is in scope + = note: no item named `error` in `intra_links_warning` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error1` --> $DIR/intra-links-warning.rs:80:11 | LL | /// docs [error1] - | ^^^^^^ no item named `error1` is in scope + | ^^^^^^ no item named `error1` in `intra_links_warning` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -113,7 +113,7 @@ warning: unresolved link to `error2` --> $DIR/intra-links-warning.rs:82:11 | LL | /// docs [error2] - | ^^^^^^ no item named `error2` is in scope + | ^^^^^^ no item named `error2` in `intra_links_warning` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -121,7 +121,7 @@ warning: unresolved link to `BarA` --> $DIR/intra-links-warning.rs:21:10 | LL | /// bar [BarA] bar - | ^^^^ no item named `BarA` is in scope + | ^^^^ no item named `BarA` in `intra_links_warning` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -129,7 +129,7 @@ warning: unresolved link to `BarB` --> $DIR/intra-links-warning.rs:27:9 | LL | * bar [BarB] bar - | ^^^^ no item named `BarB` is in scope + | ^^^^ no item named `BarB` in `intra_links_warning` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -137,7 +137,7 @@ warning: unresolved link to `BarC` --> $DIR/intra-links-warning.rs:34:6 | LL | bar [BarC] bar - | ^^^^ no item named `BarC` is in scope + | ^^^^ no item named `BarC` in `intra_links_warning` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -151,7 +151,7 @@ LL | #[doc = "Foo\nbar [BarD] bar\nbaz"] bar [BarD] bar ^^^^ - = note: no item named `BarD` is in scope + = note: no item named `BarD` in `intra_links_warning` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `BarF` @@ -167,7 +167,7 @@ LL | f!("Foo\nbar [BarF] bar\nbaz"); bar [BarF] bar ^^^^ - = note: no item named `BarF` is in scope + = note: no item named `BarF` in `intra_links_warning` = 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) diff --git a/src/test/rustdoc-ui/lint-group.stderr b/src/test/rustdoc-ui/lint-group.stderr index 10fcebb27fe0c..550b79f6e8928 100644 --- a/src/test/rustdoc-ui/lint-group.stderr +++ b/src/test/rustdoc-ui/lint-group.stderr @@ -32,7 +32,7 @@ error: unresolved link to `error` --> $DIR/lint-group.rs:9:29 | LL | /// what up, let's make an [error] - | ^^^^^ + | ^^^^^ no item named `error` in `lint_group` | note: the lint level is defined here --> $DIR/lint-group.rs:7:9 @@ -40,7 +40,6 @@ note: the lint level is defined here LL | #![deny(rustdoc)] | ^^^^^^^ = note: `#[deny(broken_intra_doc_links)]` implied by `#[deny(rustdoc)]` - = note: no item named `error` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: aborting due to 3 previous errors From 14cc17759de0863e85eea46c0f5bfcc362d1bfe8 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 11 Sep 2020 21:42:28 +0200 Subject: [PATCH 0315/1052] Improve `ineffective_unstable_trait_impl` error message. --- compiler/rustc_passes/src/stability.rs | 8 ++++---- .../stability-attribute/stability-attribute-trait-impl.rs | 2 +- .../stability-attribute-trait-impl.stderr | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 4eb983365ffb5..4ca52f405fb94 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -561,10 +561,10 @@ impl Visitor<'tcx> for Checker<'tcx> { INEFFECTIVE_UNSTABLE_TRAIT_IMPL, item.hir_id, span, - |lint| lint.build( - "An `#[unstable]` annotation here has no effect. \ - See issue #55436 for more information.", - ).emit() + |lint| lint + .build("an `#[unstable]` annotation here has no effect") + .note("see issue #55436 for more information") + .emit() ); } } diff --git a/src/test/ui/stability-attribute/stability-attribute-trait-impl.rs b/src/test/ui/stability-attribute/stability-attribute-trait-impl.rs index 9be772a7be323..cc57071b87cea 100644 --- a/src/test/ui/stability-attribute/stability-attribute-trait-impl.rs +++ b/src/test/ui/stability-attribute/stability-attribute-trait-impl.rs @@ -22,7 +22,7 @@ impl StableTrait for UnstableType {} impl UnstableTrait for StableType {} #[unstable(feature = "x", issue = "none")] -//~^ ERROR An `#[unstable]` annotation here has no effect. +//~^ ERROR an `#[unstable]` annotation here has no effect [rustc::ineffective_unstable_trait_impl] impl StableTrait for StableType {} fn main() {} diff --git a/src/test/ui/stability-attribute/stability-attribute-trait-impl.stderr b/src/test/ui/stability-attribute/stability-attribute-trait-impl.stderr index 808636238fcc2..1915d03fb0aaf 100644 --- a/src/test/ui/stability-attribute/stability-attribute-trait-impl.stderr +++ b/src/test/ui/stability-attribute/stability-attribute-trait-impl.stderr @@ -1,10 +1,11 @@ -error: An `#[unstable]` annotation here has no effect. See issue #55436 for more information. +error: an `#[unstable]` annotation here has no effect --> $DIR/stability-attribute-trait-impl.rs:24:1 | LL | #[unstable(feature = "x", issue = "none")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `#[deny(rustc::ineffective_unstable_trait_impl)]` on by default + = note: see issue #55436 for more information error: aborting due to previous error From 21f8326cec03848368e02936a032103aa24cf6d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 11 Sep 2020 13:47:33 -0700 Subject: [PATCH 0316/1052] Provide suggestion for missing fields in patterns --- compiler/rustc_typeck/src/check/pat.rs | 58 ++++++++++++++++--- src/test/ui/error-codes/E0027-teach.rs | 15 ----- src/test/ui/error-codes/E0027-teach.stderr | 11 ---- src/test/ui/error-codes/E0027.rs | 6 +- src/test/ui/error-codes/E0027.stderr | 26 ++++++++- src/test/ui/structs/struct-field-cfg.stderr | 9 +++ .../structs/struct-pat-derived-error.stderr | 9 +++ 7 files changed, 96 insertions(+), 38 deletions(-) delete mode 100644 src/test/ui/error-codes/E0027-teach.rs delete mode 100644 src/test/ui/error-codes/E0027-teach.stderr diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 1896155e327d8..bae0a7e611af6 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -1121,7 +1121,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if no_accessible_unmentioned_fields { unmentioned_err = Some(self.error_no_accessible_fields(pat, &fields)); } else { - unmentioned_err = Some(self.error_unmentioned_fields(pat, &unmentioned_fields)); + unmentioned_err = + Some(self.error_unmentioned_fields(pat, &unmentioned_fields, &fields)); } } match (inexistent_fields_err, unmentioned_err) { @@ -1376,6 +1377,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, pat: &Pat<'_>, unmentioned_fields: &[(&ty::FieldDef, Ident)], + fields: &'tcx [hir::FieldPat<'tcx>], ) -> DiagnosticBuilder<'tcx> { let field_names = if unmentioned_fields.len() == 1 { format!("field `{}`", unmentioned_fields[0].1) @@ -1395,14 +1397,52 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { field_names ); err.span_label(pat.span, format!("missing {}", field_names)); - if self.tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "This error indicates that a pattern for a struct fails to specify a \ - sub-pattern for every one of the struct's fields. Ensure that each field \ - from the struct's definition is mentioned in the pattern, or use `..` to \ - ignore unwanted fields.", - ); - } + let len = unmentioned_fields.len(); + let (prefix, postfix, sp) = match fields { + [] => match &pat.kind { + PatKind::Struct(path, [], false) => { + (" { ", " }", path.span().shrink_to_hi().until(pat.span.shrink_to_hi())) + } + _ => return err, + }, + [.., field] => ( + match pat.kind { + PatKind::Struct(_, [_, ..], _) => ", ", + _ => "", + }, + "", + field.span.shrink_to_hi(), + ), + }; + err.span_suggestion( + sp, + &format!( + "include the missing field{} in the pattern", + if len == 1 { "" } else { "s" }, + ), + format!( + "{}{}{}", + prefix, + unmentioned_fields + .iter() + .map(|(_, name)| name.to_string()) + .collect::>() + .join(", "), + postfix, + ), + Applicability::MachineApplicable, + ); + err.span_suggestion( + sp, + &format!( + "if you don't care about {} missing field{}, you can explicitely ignore {}", + if len == 1 { "this" } else { "these" }, + if len == 1 { "" } else { "s" }, + if len == 1 { "it" } else { "them" }, + ), + format!("{}..{}", prefix, postfix), + Applicability::MachineApplicable, + ); err } diff --git a/src/test/ui/error-codes/E0027-teach.rs b/src/test/ui/error-codes/E0027-teach.rs deleted file mode 100644 index 11402f014842d..0000000000000 --- a/src/test/ui/error-codes/E0027-teach.rs +++ /dev/null @@ -1,15 +0,0 @@ -// compile-flags: -Z teach - -struct Dog { - name: String, - age: u32, -} - -fn main() { - let d = Dog { name: "Rusty".to_string(), age: 8 }; - - match d { - Dog { age: x } => {} - //~^ ERROR pattern does not mention field `name` - } -} diff --git a/src/test/ui/error-codes/E0027-teach.stderr b/src/test/ui/error-codes/E0027-teach.stderr deleted file mode 100644 index aa4cb9d4d18d9..0000000000000 --- a/src/test/ui/error-codes/E0027-teach.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0027]: pattern does not mention field `name` - --> $DIR/E0027-teach.rs:12:9 - | -LL | Dog { age: x } => {} - | ^^^^^^^^^^^^^^ missing field `name` - | - = note: This error indicates that a pattern for a struct fails to specify a sub-pattern for every one of the struct's fields. Ensure that each field from the struct's definition is mentioned in the pattern, or use `..` to ignore unwanted fields. - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0027`. diff --git a/src/test/ui/error-codes/E0027.rs b/src/test/ui/error-codes/E0027.rs index b8c6a2b7fcd70..8d08e17893480 100644 --- a/src/test/ui/error-codes/E0027.rs +++ b/src/test/ui/error-codes/E0027.rs @@ -7,7 +7,9 @@ fn main() { let d = Dog { name: "Rusty".to_string(), age: 8 }; match d { - Dog { age: x } => {} - //~^ ERROR pattern does not mention field `name` + Dog { age: x } => {} //~ ERROR pattern does not mention field `name` + } + match d { + Dog {} => {} //~ ERROR pattern does not mention fields `name`, `age` } } diff --git a/src/test/ui/error-codes/E0027.stderr b/src/test/ui/error-codes/E0027.stderr index 4f17bba6477a9..c09f1ff1f2a8c 100644 --- a/src/test/ui/error-codes/E0027.stderr +++ b/src/test/ui/error-codes/E0027.stderr @@ -3,7 +3,31 @@ error[E0027]: pattern does not mention field `name` | LL | Dog { age: x } => {} | ^^^^^^^^^^^^^^ missing field `name` + | +help: include the missing field in the pattern + | +LL | Dog { age: x, name } => {} + | ^^^^^^ +help: if you don't care about this missing field, you can explicitely ignore it + | +LL | Dog { age: x, .. } => {} + | ^^^^ + +error[E0027]: pattern does not mention fields `name`, `age` + --> $DIR/E0027.rs:13:9 + | +LL | Dog {} => {} + | ^^^^^^ missing fields `name`, `age` + | +help: include the missing fields in the pattern + | +LL | Dog { name, age } => {} + | ^^^^^^^^^^^^^ +help: if you don't care about these missing fields, you can explicitely ignore them + | +LL | Dog { .. } => {} + | ^^^^^^ -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0027`. diff --git a/src/test/ui/structs/struct-field-cfg.stderr b/src/test/ui/structs/struct-field-cfg.stderr index 29bad31ef969f..b913b929079c6 100644 --- a/src/test/ui/structs/struct-field-cfg.stderr +++ b/src/test/ui/structs/struct-field-cfg.stderr @@ -17,6 +17,15 @@ error[E0027]: pattern does not mention field `present` | LL | let Foo { #[cfg(any())] present: () } = foo; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `present` + | +help: include the missing field in the pattern + | +LL | let Foo { present } = foo; + | ^^^^^^^^^^^ +help: if you don't care about this missing field, you can explicitely ignore it + | +LL | let Foo { .. } = foo; + | ^^^^^^ error[E0026]: struct `Foo` does not have a field named `absent` --> $DIR/struct-field-cfg.rs:16:42 diff --git a/src/test/ui/structs/struct-pat-derived-error.stderr b/src/test/ui/structs/struct-pat-derived-error.stderr index 6526ef58a4479..f3e9ce76f1e2a 100644 --- a/src/test/ui/structs/struct-pat-derived-error.stderr +++ b/src/test/ui/structs/struct-pat-derived-error.stderr @@ -15,6 +15,15 @@ error[E0027]: pattern does not mention fields `b`, `c` | LL | let A { x, y } = self.d; | ^^^^^^^^^^ missing fields `b`, `c` + | +help: include the missing fields in the pattern + | +LL | let A { x, y, b, c } = self.d; + | ^^^^^^ +help: if you don't care about these missing fields, you can explicitely ignore them + | +LL | let A { x, y, .. } = self.d; + | ^^^^ error: aborting due to 3 previous errors From bb9ce7cb01fba4b34bbebf8a44056016cabfa40e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 11 Sep 2020 23:43:37 +0200 Subject: [PATCH 0317/1052] Add missing examples on binary core traits --- library/core/src/ops/bit.rs | 134 ++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) diff --git a/library/core/src/ops/bit.rs b/library/core/src/ops/bit.rs index bcfff4a223bec..3d71e0b0002c2 100644 --- a/library/core/src/ops/bit.rs +++ b/library/core/src/ops/bit.rs @@ -36,6 +36,15 @@ pub trait Not { type Output; /// Performs the unary `!` operation. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(!true, false); + /// assert_eq!(!false, true); + /// assert_eq!(!1u8, 254); + /// assert_eq!(!0u8, 255); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn not(self) -> Self::Output; @@ -122,6 +131,15 @@ pub trait BitAnd { type Output; /// Performs the `&` operation. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(true & false, false); + /// assert_eq!(true & true, true); + /// assert_eq!(5u8 & 1u8, 1); + /// assert_eq!(5u8 & 2u8, 0); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn bitand(self, rhs: Rhs) -> Self::Output; @@ -208,6 +226,15 @@ pub trait BitOr { type Output; /// Performs the `|` operation. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(true | false, true); + /// assert_eq!(false | false, false); + /// assert_eq!(5u8 | 1u8, 5); + /// assert_eq!(5u8 | 2u8, 7); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn bitor(self, rhs: Rhs) -> Self::Output; @@ -297,6 +324,15 @@ pub trait BitXor { type Output; /// Performs the `^` operation. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(true ^ false, true); + /// assert_eq!(true ^ true, false); + /// assert_eq!(5u8 ^ 1u8, 4); + /// assert_eq!(5u8 ^ 2u8, 7); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn bitxor(self, rhs: Rhs) -> Self::Output; @@ -387,6 +423,13 @@ pub trait Shl { type Output; /// Performs the `<<` operation. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(5u8 << 1, 10); + /// assert_eq!(1u8 << 1, 2); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn shl(self, rhs: Rhs) -> Self::Output; @@ -498,6 +541,13 @@ pub trait Shr { type Output; /// Performs the `>>` operation. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(5u8 >> 1, 2); + /// assert_eq!(2u8 >> 1, 1); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn shr(self, rhs: Rhs) -> Self::Output; @@ -612,6 +662,26 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } )] pub trait BitAndAssign { /// Performs the `&=` operation. + /// + /// # Examples + /// + /// ``` + /// let mut x = true; + /// x &= false; + /// assert_eq!(x, false); + /// + /// let mut x = true; + /// x &= true; + /// assert_eq!(x, true); + /// + /// let mut x: u8 = 5; + /// x &= 1; + /// assert_eq!(x, 1); + /// + /// let mut x: u8 = 5; + /// x &= 2; + /// assert_eq!(x, 0); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn bitand_assign(&mut self, rhs: Rhs); } @@ -663,6 +733,26 @@ bitand_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } )] pub trait BitOrAssign { /// Performs the `|=` operation. + /// + /// # Examples + /// + /// ``` + /// let mut x = true; + /// x |= false; + /// assert_eq!(x, true); + /// + /// let mut x = false; + /// x |= false; + /// assert_eq!(x, false); + /// + /// let mut x: u8 = 5; + /// x |= 1; + /// assert_eq!(x, 5); + /// + /// let mut x: u8 = 5; + /// x |= 2; + /// assert_eq!(x, 7); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn bitor_assign(&mut self, rhs: Rhs); } @@ -714,6 +804,26 @@ bitor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } )] pub trait BitXorAssign { /// Performs the `^=` operation. + /// + /// # Examples + /// + /// ``` + /// let mut x = true; + /// x ^= false; + /// assert_eq!(x, true); + /// + /// let mut x = true; + /// x ^= true; + /// assert_eq!(x, false); + /// + /// let mut x: u8 = 5; + /// x ^= 1; + /// assert_eq!(x, 4); + /// + /// let mut x: u8 = 5; + /// x ^= 2; + /// assert_eq!(x, 7); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn bitxor_assign(&mut self, rhs: Rhs); } @@ -763,6 +873,18 @@ bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } )] pub trait ShlAssign { /// Performs the `<<=` operation. + /// + /// # Examples + /// + /// ``` + /// let mut x: u8 = 5; + /// x <<= 1; + /// assert_eq!(x, 10); + /// + /// let mut x: u8 = 1; + /// x <<= 1; + /// assert_eq!(x, 2); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn shl_assign(&mut self, rhs: Rhs); } @@ -833,6 +955,18 @@ shl_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } )] pub trait ShrAssign { /// Performs the `>>=` operation. + /// + /// # Examples + /// + /// ``` + /// let mut x: u8 = 5; + /// x >>= 1; + /// assert_eq!(x, 2); + /// + /// let mut x: u8 = 2; + /// x >>= 1; + /// assert_eq!(x, 1); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn shr_assign(&mut self, rhs: Rhs); } From 5e126c944b83d8402e0414914ef7d6c05004d483 Mon Sep 17 00:00:00 2001 From: Gus Wynn Date: Tue, 1 Sep 2020 15:53:04 -0700 Subject: [PATCH 0318/1052] better diag when const ranges are used in patterns --- compiler/rustc_typeck/src/check/pat.rs | 39 ++++++++++++++++++++++---- src/test/ui/issues/issue-76191.rs | 14 +++++++++ src/test/ui/issues/issue-76191.stderr | 21 ++++++++++++++ 3 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/issues/issue-76191.rs create mode 100644 src/test/ui/issues/issue-76191.stderr diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 1896155e327d8..171d5ee4ff206 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -10,7 +10,7 @@ use rustc_hir::{HirId, Pat, PatKind}; use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::ty::subst::GenericArg; -use rustc_middle::ty::{self, BindingMode, Ty, TypeFoldable}; +use rustc_middle::ty::{self, Adt, BindingMode, Ty, TypeFoldable}; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::{Span, Spanned}; use rustc_span::symbol::Ident; @@ -735,7 +735,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(err) = self.demand_suptype_with_origin(&self.pattern_cause(ti, pat.span), expected, pat_ty) { - self.emit_bad_pat_path(err, pat.span, res, pat_res, segments, ti.parent_pat); + self.emit_bad_pat_path(err, pat.span, res, pat_res, pat_ty, segments, ti.parent_pat); } pat_ty } @@ -746,6 +746,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat_span: Span, res: Res, pat_res: Res, + pat_ty: Ty<'tcx>, segments: &'b [hir::PathSegment<'b>], parent_pat: Option<&Pat<'_>>, ) { @@ -771,9 +772,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } _ => { - let msg = "introduce a new binding instead"; - let sugg = format!("other_{}", ident.as_str().to_lowercase()); - e.span_suggestion(ident.span, msg, sugg, Applicability::HasPlaceholders); + let const_def_id = match pat_ty.kind() { + Adt(def, _) => match res { + Res::Def(DefKind::Const, _) => Some(def.did), + _ => None, + }, + _ => None, + }; + + let ranges = &[ + self.tcx.lang_items().range_struct(), + self.tcx.lang_items().range_from_struct(), + self.tcx.lang_items().range_to_struct(), + self.tcx.lang_items().range_full_struct(), + self.tcx.lang_items().range_inclusive_struct(), + self.tcx.lang_items().range_to_inclusive_struct(), + ]; + if const_def_id != None && ranges.contains(&const_def_id) { + let msg = "constants only support matching by type, \ + if you meant to match against a range of values, \ + consider using a range pattern like `min ..= max` in the match block"; + e.note(msg); + } else { + let msg = "introduce a new binding instead"; + let sugg = format!("other_{}", ident.as_str().to_lowercase()); + e.span_suggestion( + ident.span, + msg, + sugg, + Applicability::HasPlaceholders, + ); + } } }; } diff --git a/src/test/ui/issues/issue-76191.rs b/src/test/ui/issues/issue-76191.rs new file mode 100644 index 0000000000000..bc327123c6fe9 --- /dev/null +++ b/src/test/ui/issues/issue-76191.rs @@ -0,0 +1,14 @@ +// Regression test for diagnostic issue #76191 +#![allow(non_snake_case)] + +use std::ops::RangeInclusive; +const RANGE: RangeInclusive = 0..=255; + +fn main() { + let n: i32 = 1; + match n { + RANGE => {} + //~^ ERROR mismatched types + _ => {} + } +} diff --git a/src/test/ui/issues/issue-76191.stderr b/src/test/ui/issues/issue-76191.stderr new file mode 100644 index 0000000000000..a5544d9e9da40 --- /dev/null +++ b/src/test/ui/issues/issue-76191.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/issue-76191.rs:10:9 + | +LL | const RANGE: RangeInclusive = 0..=255; + | ------------------------------------------- constant defined here +... +LL | match n { + | - this expression has type `i32` +LL | RANGE => {} + | ^^^^^ + | | + | expected `i32`, found struct `RangeInclusive` + | `RANGE` is interpreted as a constant, not a new binding + | + = note: expected type `i32` + found struct `RangeInclusive` + = note: constants only support matching by type, if you meant to match against a range of values, consider using a range pattern like `min ..= max` in the match block + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. From c8ee33714becbda0f1deddf1befe0383b4aad135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 17 Aug 2020 19:04:27 -0700 Subject: [PATCH 0319/1052] Use structured suggestion for `impl T` to `Box` --- compiler/rustc_typeck/src/check/coercion.rs | 12 ++--- ...trait-in-return-position-impl-trait.stderr | 5 ++- ...-to-type-err-cause-on-impl-trait-return.rs | 23 ++++------ ...type-err-cause-on-impl-trait-return.stderr | 44 +++++++++++++------ 4 files changed, 50 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index e19130112970d..c19bc767563bf 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -37,7 +37,7 @@ use crate::astconv::AstConv; use crate::check::FnCtxt; -use rustc_errors::{struct_span_err, DiagnosticBuilder}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{Coercion, InferOk, InferResult}; @@ -1523,10 +1523,12 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { }; if has_impl { if is_object_safe { - err.help(&format!( - "you can instead return a boxed trait object using `Box`", - &snippet[5..] - )); + err.span_suggestion_verbose( + return_sp, + "you could change the return type to be a boxed trait object", + format!("Box", &snippet[5..]), + Applicability::MachineApplicable, + ); } else { err.help(&format!( "if the trait `{}` were object safe, you could return a boxed trait object", diff --git a/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr b/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr index dd4260fbe4f91..a3bf21832551b 100644 --- a/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr +++ b/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr @@ -30,9 +30,12 @@ LL | B | = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see - = help: you can instead return a boxed trait object using `Box` = note: for information on trait objects, see = help: alternatively, create a new `enum` with a variant for each returned type +help: you could change the return type to be a boxed trait object + | +LL | fn cat() -> Box { + | ^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs index a80e5df1a26a2..6114e8c72a3df 100644 --- a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs +++ b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs @@ -2,16 +2,14 @@ fn foo() -> impl std::fmt::Display { if false { return 0i32; } - 1u32 - //~^ ERROR mismatched types + 1u32 //~ ERROR mismatched types } fn bar() -> impl std::fmt::Display { if false { return 0i32; } else { - return 1u32; - //~^ ERROR mismatched types + return 1u32; //~ ERROR mismatched types } } @@ -19,8 +17,7 @@ fn baz() -> impl std::fmt::Display { if false { return 0i32; } else { - 1u32 - //~^ ERROR mismatched types + 1u32 //~ ERROR mismatched types } } @@ -28,22 +25,19 @@ fn qux() -> impl std::fmt::Display { if false { 0i32 } else { - 1u32 - //~^ ERROR `if` and `else` have incompatible types + 1u32 //~ ERROR `if` and `else` have incompatible types } } fn bat() -> impl std::fmt::Display { match 13 { 0 => return 0i32, - _ => 1u32, - //~^ ERROR mismatched types + _ => 1u32, //~ ERROR mismatched types } } fn can() -> impl std::fmt::Display { - match 13 { - //~^ ERROR mismatched types + match 13 { //~ ERROR mismatched types 0 => return 0i32, 1 => 1u32, _ => 2u32, @@ -56,8 +50,9 @@ fn cat() -> impl std::fmt::Display { return 0i32; } _ => { - 1u32 - //~^ ERROR mismatched types + 1u32 //~ ERROR mismatched types + } + } } } } diff --git a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr index b663cccbeef0f..4e4d57f35d243 100644 --- a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr +++ b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr @@ -12,12 +12,15 @@ LL | 1u32 | = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see - = help: you can instead return a boxed trait object using `Box` = note: for information on trait objects, see = help: alternatively, create a new `enum` with a variant for each returned type +help: you could change the return type to be a boxed trait object + | +LL | fn foo() -> Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:13:16 + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:12:16 | LL | fn bar() -> impl std::fmt::Display { | ---------------------- expected because this return type... @@ -30,12 +33,15 @@ LL | return 1u32; | = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see - = help: you can instead return a boxed trait object using `Box` = note: for information on trait objects, see = help: alternatively, create a new `enum` with a variant for each returned type +help: you could change the return type to be a boxed trait object + | +LL | fn bar() -> Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:22:9 + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:20:9 | LL | fn baz() -> impl std::fmt::Display { | ---------------------- expected because this return type... @@ -48,12 +54,15 @@ LL | 1u32 | = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see - = help: you can instead return a boxed trait object using `Box` = note: for information on trait objects, see = help: alternatively, create a new `enum` with a variant for each returned type +help: you could change the return type to be a boxed trait object + | +LL | fn baz() -> Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: `if` and `else` have incompatible types - --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:31:9 + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:28:9 | LL | / if false { LL | | 0i32 @@ -61,12 +70,11 @@ LL | | 0i32 LL | | } else { LL | | 1u32 | | ^^^^ expected `i32`, found `u32` -LL | | LL | | } | |_____- `if` and `else` have incompatible types error[E0308]: mismatched types - --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:39:14 + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:35:14 | LL | fn bat() -> impl std::fmt::Display { | ---------------------- expected because this return type... @@ -78,17 +86,19 @@ LL | _ => 1u32, | = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see - = help: you can instead return a boxed trait object using `Box` = note: for information on trait objects, see = help: alternatively, create a new `enum` with a variant for each returned type +help: you could change the return type to be a boxed trait object + | +LL | fn bat() -> Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:45:5 + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:40:5 | LL | fn can() -> impl std::fmt::Display { | ---------------------- expected because this return type... LL | / match 13 { -LL | | LL | | 0 => return 0i32, | | ---- ...is found to be `i32` here LL | | 1 => 1u32, @@ -98,12 +108,15 @@ LL | | } | = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see - = help: you can instead return a boxed trait object using `Box` = note: for information on trait objects, see = help: alternatively, create a new `enum` with a variant for each returned type +help: you could change the return type to be a boxed trait object + | +LL | fn can() -> Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:59:13 + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:53:13 | LL | fn cat() -> impl std::fmt::Display { | ---------------------- expected because this return type... @@ -116,9 +129,12 @@ LL | 1u32 | = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see - = help: you can instead return a boxed trait object using `Box` = note: for information on trait objects, see = help: alternatively, create a new `enum` with a variant for each returned type +help: you could change the return type to be a boxed trait object + | +LL | fn cat() -> Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 7 previous errors From fd9133b9c336e55d12bd5da1c610949473844dcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 17 Aug 2020 22:39:46 -0700 Subject: [PATCH 0320/1052] Suggest boxed trait objects in tail `match` and `if` expressions When encountering a `match` or `if` as a tail expression where the different arms do not have the same type *and* the return type of that `fn` is an `impl Trait`, check whether those arms can implement `Trait` and if so, suggest using boxed trait objects. --- .../src/infer/error_reporting/mod.rs | 66 +++++++++++++- compiler/rustc_middle/src/traits/mod.rs | 3 + compiler/rustc_typeck/src/check/_match.rs | 85 +++++++++++++++++-- compiler/rustc_typeck/src/check/mod.rs | 18 ++++ ...-to-type-err-cause-on-impl-trait-return.rs | 8 +- ...type-err-cause-on-impl-trait-return.stderr | 35 +++++++- 6 files changed, 203 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 1225776db4590..e772aacfbf9ec 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -617,11 +617,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ref prior_arms, last_ty, scrut_hir_id, + suggest_box, + arm_span, .. }) => match source { hir::MatchSource::IfLetDesugar { .. } => { let msg = "`if let` arms have incompatible types"; err.span_label(cause.span, msg); + if let Some(ret_sp) = suggest_box { + self.suggest_boxing_for_return_impl_trait( + err, + ret_sp, + prior_arms.iter().chain(std::iter::once(&arm_span)).map(|s| *s), + ); + } } hir::MatchSource::TryDesugar => { if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found { @@ -675,9 +684,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Applicability::MachineApplicable, ); } + if let Some(ret_sp) = suggest_box { + // Get return type span and point to it. + self.suggest_boxing_for_return_impl_trait( + err, + ret_sp, + prior_arms.iter().chain(std::iter::once(&arm_span)).map(|s| *s), + ); + } } }, - ObligationCauseCode::IfExpression(box IfExpressionCause { then, outer, semicolon }) => { + ObligationCauseCode::IfExpression(box IfExpressionCause { + then, + else_sp, + outer, + semicolon, + suggest_box, + }) => { err.span_label(then, "expected because of this"); if let Some(sp) = outer { err.span_label(sp, "`if` and `else` have incompatible types"); @@ -690,11 +713,52 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Applicability::MachineApplicable, ); } + if let Some(ret_sp) = suggest_box { + self.suggest_boxing_for_return_impl_trait( + err, + ret_sp, + vec![then, else_sp].into_iter(), + ); + } } _ => (), } } + fn suggest_boxing_for_return_impl_trait( + &self, + err: &mut DiagnosticBuilder<'tcx>, + return_sp: Span, + arm_spans: impl Iterator, + ) { + let snippet = self + .tcx + .sess + .source_map() + .span_to_snippet(return_sp) + .unwrap_or_else(|_| "dyn Trait".to_string()); + err.span_suggestion_verbose( + return_sp, + "you could change the return type to be a boxed trait object", + format!("Box", &snippet[5..]), + Applicability::MaybeIncorrect, + ); + let sugg = arm_spans + .flat_map(|sp| { + vec![ + (sp.shrink_to_lo(), "Box::new(".to_string()), + (sp.shrink_to_hi(), ")".to_string()), + ] + .into_iter() + }) + .collect::>(); + err.multipart_suggestion( + "if you change the return type to expect trait objects box the returned expressions", + sugg, + Applicability::MaybeIncorrect, + ); + } + /// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value` /// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and /// populate `other_value` with `other_ty`. diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index f86403fa502bb..71582b7ed735d 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -350,13 +350,16 @@ pub struct MatchExpressionArmCause<'tcx> { pub prior_arms: Vec, pub last_ty: Ty<'tcx>, pub scrut_hir_id: hir::HirId, + pub suggest_box: Option, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct IfExpressionCause { pub then: Span, + pub else_sp: Span, pub outer: Option, pub semicolon: Option, + pub suggest_box: Option, } #[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)] diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs index afd4413069ee1..98e53a258794c 100644 --- a/compiler/rustc_typeck/src/check/_match.rs +++ b/compiler/rustc_typeck/src/check/_match.rs @@ -1,12 +1,15 @@ use crate::check::coercion::CoerceMany; use crate::check::{Diverges, Expectation, FnCtxt, Needs}; -use rustc_hir as hir; -use rustc_hir::ExprKind; +use rustc_hir::{self as hir, ExprKind}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_middle::ty::Ty; +use rustc_infer::traits::Obligation; +use rustc_middle::ty::{self, ToPredicate, Ty}; use rustc_span::Span; -use rustc_trait_selection::traits::ObligationCauseCode; -use rustc_trait_selection::traits::{IfExpressionCause, MatchExpressionArmCause, ObligationCause}; +use rustc_trait_selection::opaque_types::InferCtxtExt as _; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; +use rustc_trait_selection::traits::{ + IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, +}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn check_match( @@ -14,7 +17,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr<'tcx>, scrut: &'tcx hir::Expr<'tcx>, arms: &'tcx [hir::Arm<'tcx>], - expected: Expectation<'tcx>, + orig_expected: Expectation<'tcx>, match_src: hir::MatchSource, ) -> Ty<'tcx> { let tcx = self.tcx; @@ -22,7 +25,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { use hir::MatchSource::*; let (source_if, if_no_else, force_scrutinee_bool) = match match_src { IfDesugar { contains_else_clause } => (true, !contains_else_clause, true), - IfLetDesugar { contains_else_clause } => (true, !contains_else_clause, false), + IfLetDesugar { contains_else_clause, .. } => (true, !contains_else_clause, false), WhileDesugar => (false, false, true), _ => (false, false, false), }; @@ -69,7 +72,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // type in that case) let mut all_arms_diverge = Diverges::WarnedAlways; - let expected = expected.adjust_for_branches(self); + let expected = orig_expected.adjust_for_branches(self); let mut coercion = { let coerce_first = match expected { @@ -112,6 +115,59 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_expr_with_expectation(&arm.body, expected) }; all_arms_diverge &= self.diverges.get(); + + // When we have a `match` as a tail expression in a `fn` with a returned `impl Trait` + // we check if the different arms would work with boxed trait objects instead and + // provide a structured suggestion in that case. + let suggest_box = match ( + orig_expected, + self.body_id + .owner + .to_def_id() + .as_local() + .and_then(|id| self.ret_coercion_impl_trait.map(|ty| (id, ty))), + ) { + (Expectation::ExpectHasType(expected), Some((id, ty))) + if self.in_tail_expr && self.can_coerce(arm_ty, expected) => + { + let impl_trait_ret_ty = self.infcx.instantiate_opaque_types( + id, + self.body_id, + self.param_env, + &ty, + arm.body.span, + ); + let mut suggest_box = !impl_trait_ret_ty.obligations.is_empty(); + for o in impl_trait_ret_ty.obligations { + match o.predicate.skip_binders_unchecked() { + ty::PredicateAtom::Trait(t, constness) => { + let pred = ty::PredicateAtom::Trait( + ty::TraitPredicate { + trait_ref: ty::TraitRef { + def_id: t.def_id(), + substs: self.infcx.tcx.mk_substs_trait(arm_ty, &[]), + }, + }, + constness, + ); + let obl = Obligation::new( + o.cause.clone(), + self.param_env, + pred.to_predicate(self.infcx.tcx), + ); + suggest_box &= self.infcx.predicate_must_hold_modulo_regions(&obl); + if !suggest_box { + break; + } + } + _ => {} + } + } + if suggest_box { self.ret_type_span.clone() } else { None } + } + _ => None, + }; + if source_if { let then_expr = &arms[0].body; match (i, if_no_else) { @@ -119,7 +175,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (_, true) => {} // Handled above to avoid duplicated type errors (#60254). (_, _) => { let then_ty = prior_arm_ty.unwrap(); - let cause = self.if_cause(expr.span, then_expr, &arm.body, then_ty, arm_ty); + let cause = self.if_cause( + expr.span, + then_expr, + &arm.body, + then_ty, + arm_ty, + suggest_box, + ); coercion.coerce(self, &cause, &arm.body, arm_ty); } } @@ -142,6 +205,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { prior_arms: other_arms.clone(), last_ty: prior_arm_ty.unwrap(), scrut_hir_id: scrut.hir_id, + suggest_box, }), ), }; @@ -266,6 +330,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { else_expr: &'tcx hir::Expr<'tcx>, then_ty: Ty<'tcx>, else_ty: Ty<'tcx>, + suggest_box: Option, ) -> ObligationCause<'tcx> { let mut outer_sp = if self.tcx.sess.source_map().is_multiline(span) { // The `if`/`else` isn't in one line in the output, include some context to make it @@ -353,8 +418,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { error_sp, ObligationCauseCode::IfExpression(box IfExpressionCause { then: then_sp, + else_sp: error_sp, outer: outer_sp, semicolon: remove_semicolon, + suggest_box, }), ) } diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index cb5f5731aa611..d6abf5f225da8 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -570,6 +570,14 @@ pub struct FnCtxt<'a, 'tcx> { /// any). ret_coercion: Option>>, + ret_coercion_impl_trait: Option>, + + ret_type_span: Option, + + /// Used exclusively to reduce cost of advanced evaluation used for + /// more helpful diagnostics. + in_tail_expr: bool, + /// First span of a return site that we find. Used in error messages. ret_coercion_span: RefCell>, @@ -1302,10 +1310,15 @@ fn check_fn<'a, 'tcx>( let hir = tcx.hir(); let declared_ret_ty = fn_sig.output(); + let revealed_ret_ty = fcx.instantiate_opaque_types_from_value(fn_id, &declared_ret_ty, decl.output.span()); debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty); fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty))); + fcx.ret_type_span = Some(decl.output.span()); + if let ty::Opaque(..) = declared_ret_ty.kind() { + fcx.ret_coercion_impl_trait = Some(declared_ret_ty); + } fn_sig = tcx.mk_fn_sig( fn_sig.inputs().iter().cloned(), revealed_ret_ty, @@ -1366,6 +1379,7 @@ fn check_fn<'a, 'tcx>( inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig); + fcx.in_tail_expr = true; if let ty::Dynamic(..) = declared_ret_ty.kind() { // FIXME: We need to verify that the return type is `Sized` after the return expression has // been evaluated so that we have types available for all the nodes being returned, but that @@ -1385,6 +1399,7 @@ fn check_fn<'a, 'tcx>( fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); fcx.check_return_expr(&body.value); } + fcx.in_tail_expr = false; // We insert the deferred_generator_interiors entry after visiting the body. // This ensures that all nested generators appear before the entry of this generator. @@ -3084,6 +3099,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { param_env, err_count_on_creation: inh.tcx.sess.err_count(), ret_coercion: None, + ret_coercion_impl_trait: None, + ret_type_span: None, + in_tail_expr: false, ret_coercion_span: RefCell::new(None), resume_yield_tys: None, ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)), diff --git a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs index 6114e8c72a3df..1a477e5db99ac 100644 --- a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs +++ b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs @@ -53,7 +53,13 @@ fn cat() -> impl std::fmt::Display { 1u32 //~ ERROR mismatched types } } - } +} + +fn dog() -> impl std::fmt::Display { + match 13 { + 0 => 0i32, + 1 => 1u32, //~ ERROR `match` arms have incompatible types + _ => 2u32, } } diff --git a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr index 4e4d57f35d243..a198203e24529 100644 --- a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr +++ b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr @@ -72,6 +72,17 @@ LL | | 1u32 | | ^^^^ expected `i32`, found `u32` LL | | } | |_____- `if` and `else` have incompatible types + | +help: you could change the return type to be a boxed trait object + | +LL | fn qux() -> Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: if you change the return type to expect trait objects box the returned expressions + | +LL | Box::new(0i32) +LL | } else { +LL | Box::new(1u32) + | error[E0308]: mismatched types --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:35:14 @@ -136,6 +147,28 @@ help: you could change the return type to be a boxed trait object LL | fn cat() -> Box { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 7 previous errors +error[E0308]: `match` arms have incompatible types + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:61:14 + | +LL | / match 13 { +LL | | 0 => 0i32, + | | ---- this is found to be of type `i32` +LL | | 1 => 1u32, + | | ^^^^ expected `i32`, found `u32` +LL | | _ => 2u32, +LL | | } + | |_____- `match` arms have incompatible types + | +help: you could change the return type to be a boxed trait object + | +LL | fn dog() -> Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: if you change the return type to expect trait objects box the returned expressions + | +LL | 0 => Box::new(0i32), +LL | 1 => Box::new(1u32), + | + +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0308`. From ff297fafbfb9af47bc75bc7eac9ff76d83fdd49c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 18 Aug 2020 16:15:55 -0700 Subject: [PATCH 0321/1052] Make suggestion have a more targetted underline --- .../rustc_infer/src/infer/error_reporting/mod.rs | 16 ++++++---------- compiler/rustc_typeck/src/check/coercion.rs | 10 ++++++---- ...fe-trait-in-return-position-impl-trait.stderr | 2 +- ...to-type-err-cause-on-impl-trait-return.stderr | 16 ++++++++-------- 4 files changed, 21 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index e772aacfbf9ec..fe53ccdbad50c 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -70,7 +70,7 @@ use rustc_middle::ty::{ subst::{Subst, SubstsRef}, Region, Ty, TyCtxt, TypeFoldable, }; -use rustc_span::{DesugaringKind, Pos, Span}; +use rustc_span::{BytePos, DesugaringKind, Pos, Span}; use rustc_target::spec::abi; use std::{cmp, fmt}; @@ -731,16 +731,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { return_sp: Span, arm_spans: impl Iterator, ) { - let snippet = self - .tcx - .sess - .source_map() - .span_to_snippet(return_sp) - .unwrap_or_else(|_| "dyn Trait".to_string()); - err.span_suggestion_verbose( - return_sp, + err.multipart_suggestion( "you could change the return type to be a boxed trait object", - format!("Box", &snippet[5..]), + vec![ + (return_sp.with_hi(return_sp.lo() + BytePos(4)), "Box".to_string()), + ], Applicability::MaybeIncorrect, ); let sugg = arm_spans diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index c19bc767563bf..b669476483b10 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -51,7 +51,7 @@ use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, Ty, TypeAndMut}; use rustc_session::parse::feature_err; use rustc_span::symbol::sym; -use rustc_span::{self, Span}; +use rustc_span::{self, BytePos, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; @@ -1523,10 +1523,12 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { }; if has_impl { if is_object_safe { - err.span_suggestion_verbose( - return_sp, + err.multipart_suggestion( "you could change the return type to be a boxed trait object", - format!("Box", &snippet[5..]), + vec![ + (return_sp.with_hi(return_sp.lo() + BytePos(4)), "Box".to_string()), + ], Applicability::MachineApplicable, ); } else { diff --git a/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr b/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr index a3bf21832551b..9abebeff95a87 100644 --- a/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr +++ b/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr @@ -35,7 +35,7 @@ LL | B help: you could change the return type to be a boxed trait object | LL | fn cat() -> Box { - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ ^ error: aborting due to 2 previous errors diff --git a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr index a198203e24529..66d9ff307d98f 100644 --- a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr +++ b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr @@ -17,7 +17,7 @@ LL | 1u32 help: you could change the return type to be a boxed trait object | LL | fn foo() -> Box { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ ^ error[E0308]: mismatched types --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:12:16 @@ -38,7 +38,7 @@ LL | return 1u32; help: you could change the return type to be a boxed trait object | LL | fn bar() -> Box { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ ^ error[E0308]: mismatched types --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:20:9 @@ -59,7 +59,7 @@ LL | 1u32 help: you could change the return type to be a boxed trait object | LL | fn baz() -> Box { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ ^ error[E0308]: `if` and `else` have incompatible types --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:28:9 @@ -76,7 +76,7 @@ LL | | } help: you could change the return type to be a boxed trait object | LL | fn qux() -> Box { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ ^ help: if you change the return type to expect trait objects box the returned expressions | LL | Box::new(0i32) @@ -102,7 +102,7 @@ LL | _ => 1u32, help: you could change the return type to be a boxed trait object | LL | fn bat() -> Box { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ ^ error[E0308]: mismatched types --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:40:5 @@ -124,7 +124,7 @@ LL | | } help: you could change the return type to be a boxed trait object | LL | fn can() -> Box { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ ^ error[E0308]: mismatched types --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:53:13 @@ -145,7 +145,7 @@ LL | 1u32 help: you could change the return type to be a boxed trait object | LL | fn cat() -> Box { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ ^ error[E0308]: `match` arms have incompatible types --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:61:14 @@ -162,7 +162,7 @@ LL | | } help: you could change the return type to be a boxed trait object | LL | fn dog() -> Box { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ ^ help: if you change the return type to expect trait objects box the returned expressions | LL | 0 => Box::new(0i32), From 5d2a935e6cf25e0bc86354962929ee02513549b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 18 Aug 2020 16:44:45 -0700 Subject: [PATCH 0322/1052] Make suggestion more complete --- .../src/infer/error_reporting/mod.rs | 2 +- compiler/rustc_typeck/src/check/coercion.rs | 21 +++++++- src/test/ui/impl-trait/equality.stderr | 2 +- ...trait-in-return-position-impl-trait.stderr | 10 +++- ...type-err-cause-on-impl-trait-return.stderr | 54 ++++++++++++++++--- 5 files changed, 75 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index fe53ccdbad50c..ca6f4243c2880 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -749,7 +749,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }) .collect::>(); err.multipart_suggestion( - "if you change the return type to expect trait objects box the returned expressions", + "if you change the return type to expect trait objects, box the returned expressions", sugg, Applicability::MaybeIncorrect, ); diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index b669476483b10..4addee1a4c976 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -1459,7 +1459,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { } } if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.borrow().as_ref(), fn_output) { - self.add_impl_trait_explanation(&mut err, fcx, expected, *sp, fn_output); + self.add_impl_trait_explanation(&mut err, cause, fcx, expected, *sp, fn_output); } err } @@ -1467,6 +1467,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { fn add_impl_trait_explanation<'a>( &self, err: &mut DiagnosticBuilder<'a>, + cause: &ObligationCause<'tcx>, fcx: &FnCtxt<'a, 'tcx>, expected: Ty<'tcx>, sp: Span, @@ -1531,6 +1532,22 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { ], Applicability::MachineApplicable, ); + let sugg = vec![sp, cause.span] + .into_iter() + .flat_map(|sp| { + vec![ + (sp.shrink_to_lo(), "Box::new(".to_string()), + (sp.shrink_to_hi(), ")".to_string()), + ] + .into_iter() + }) + .collect::>(); + err.multipart_suggestion( + "if you change the return type to expect trait objects, box the returned \ + expressions", + sugg, + Applicability::MaybeIncorrect, + ); } else { err.help(&format!( "if the trait `{}` were object safe, you could return a boxed trait object", @@ -1539,7 +1556,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { } err.note(trait_obj_msg); } - err.help("alternatively, create a new `enum` with a variant for each returned type"); + err.help("you could instead create a new `enum` with a variant for each returned type"); } fn is_return_ty_unsized(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool { diff --git a/src/test/ui/impl-trait/equality.stderr b/src/test/ui/impl-trait/equality.stderr index 9667a9785dc63..cdaa61ac323dd 100644 --- a/src/test/ui/impl-trait/equality.stderr +++ b/src/test/ui/impl-trait/equality.stderr @@ -23,7 +23,7 @@ LL | 0_u32 = note: for information on `impl Trait`, see = help: if the trait `Foo` were object safe, you could return a boxed trait object = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type error[E0277]: cannot add `impl Foo` to `u32` --> $DIR/equality.rs:24:11 diff --git a/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr b/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr index 9abebeff95a87..66043267f91cd 100644 --- a/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr +++ b/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr @@ -14,7 +14,7 @@ LL | B = note: for information on `impl Trait`, see = help: if the trait `NotObjectSafe` were object safe, you could return a boxed trait object = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type error[E0308]: mismatched types --> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:43:5 @@ -31,11 +31,17 @@ LL | B = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type help: you could change the return type to be a boxed trait object | LL | fn cat() -> Box { | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | return Box::new(A); +LL | } +LL | Box::new(B) + | error: aborting due to 2 previous errors diff --git a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr index 66d9ff307d98f..4265381eb401c 100644 --- a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr +++ b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr @@ -13,11 +13,17 @@ LL | 1u32 = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type help: you could change the return type to be a boxed trait object | LL | fn foo() -> Box { | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | return Box::new(0i32); +LL | } +LL | Box::new(1u32) + | error[E0308]: mismatched types --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:12:16 @@ -34,11 +40,17 @@ LL | return 1u32; = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type help: you could change the return type to be a boxed trait object | LL | fn bar() -> Box { | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | return Box::new(0i32); +LL | } else { +LL | return Box::new(1u32); + | error[E0308]: mismatched types --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:20:9 @@ -55,11 +67,17 @@ LL | 1u32 = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type help: you could change the return type to be a boxed trait object | LL | fn baz() -> Box { | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | return Box::new(0i32); +LL | } else { +LL | Box::new(1u32) + | error[E0308]: `if` and `else` have incompatible types --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:28:9 @@ -77,7 +95,7 @@ help: you could change the return type to be a boxed trait object | LL | fn qux() -> Box { | ^^^^^^^ ^ -help: if you change the return type to expect trait objects box the returned expressions +help: if you change the return type to expect trait objects, box the returned expressions | LL | Box::new(0i32) LL | } else { @@ -98,11 +116,16 @@ LL | _ => 1u32, = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type help: you could change the return type to be a boxed trait object | LL | fn bat() -> Box { | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | 0 => return Box::new(0i32), +LL | _ => Box::new(1u32), + | error[E0308]: mismatched types --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:40:5 @@ -120,11 +143,19 @@ LL | | } = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type help: you could change the return type to be a boxed trait object | LL | fn can() -> Box { | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | Box::new(match 13 { +LL | 0 => return Box::new(0i32), +LL | 1 => 1u32, +LL | _ => 2u32, +LL | }) + | error[E0308]: mismatched types --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:53:13 @@ -141,11 +172,18 @@ LL | 1u32 = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type help: you could change the return type to be a boxed trait object | LL | fn cat() -> Box { | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | return Box::new(0i32); +LL | } +LL | _ => { +LL | Box::new(1u32) + | error[E0308]: `match` arms have incompatible types --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:61:14 @@ -163,7 +201,7 @@ help: you could change the return type to be a boxed trait object | LL | fn dog() -> Box { | ^^^^^^^ ^ -help: if you change the return type to expect trait objects box the returned expressions +help: if you change the return type to expect trait objects, box the returned expressions | LL | 0 => Box::new(0i32), LL | 1 => Box::new(1u32), From dc53cfea7eb75b941e05e45fc7d8c412fd2a1bcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 22 Aug 2020 17:24:26 -0700 Subject: [PATCH 0323/1052] Add test cases and address review comments --- .../src/infer/error_reporting/mod.rs | 10 +- compiler/rustc_middle/src/traits/mod.rs | 4 +- compiler/rustc_typeck/src/check/_match.rs | 16 +-- ...-to-type-err-cause-on-impl-trait-return.rs | 35 ++++++ ...type-err-cause-on-impl-trait-return.stderr | 110 +++++++++++++++++- 5 files changed, 156 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index ca6f4243c2880..bcfcee23d13fe 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -617,14 +617,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ref prior_arms, last_ty, scrut_hir_id, - suggest_box, + opt_suggest_box_span, arm_span, .. }) => match source { hir::MatchSource::IfLetDesugar { .. } => { let msg = "`if let` arms have incompatible types"; err.span_label(cause.span, msg); - if let Some(ret_sp) = suggest_box { + if let Some(ret_sp) = opt_suggest_box_span { self.suggest_boxing_for_return_impl_trait( err, ret_sp, @@ -684,7 +684,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Applicability::MachineApplicable, ); } - if let Some(ret_sp) = suggest_box { + if let Some(ret_sp) = opt_suggest_box_span { // Get return type span and point to it. self.suggest_boxing_for_return_impl_trait( err, @@ -699,7 +699,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { else_sp, outer, semicolon, - suggest_box, + opt_suggest_box_span, }) => { err.span_label(then, "expected because of this"); if let Some(sp) = outer { @@ -713,7 +713,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Applicability::MachineApplicable, ); } - if let Some(ret_sp) = suggest_box { + if let Some(ret_sp) = opt_suggest_box_span { self.suggest_boxing_for_return_impl_trait( err, ret_sp, diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 71582b7ed735d..9db3b57a5c21e 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -350,7 +350,7 @@ pub struct MatchExpressionArmCause<'tcx> { pub prior_arms: Vec, pub last_ty: Ty<'tcx>, pub scrut_hir_id: hir::HirId, - pub suggest_box: Option, + pub opt_suggest_box_span: Option, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] @@ -359,7 +359,7 @@ pub struct IfExpressionCause { pub else_sp: Span, pub outer: Option, pub semicolon: Option, - pub suggest_box: Option, + pub opt_suggest_box_span: Option, } #[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)] diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs index 98e53a258794c..08cf178c81390 100644 --- a/compiler/rustc_typeck/src/check/_match.rs +++ b/compiler/rustc_typeck/src/check/_match.rs @@ -119,13 +119,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // When we have a `match` as a tail expression in a `fn` with a returned `impl Trait` // we check if the different arms would work with boxed trait objects instead and // provide a structured suggestion in that case. - let suggest_box = match ( + let opt_suggest_box_span = match ( orig_expected, - self.body_id - .owner - .to_def_id() - .as_local() - .and_then(|id| self.ret_coercion_impl_trait.map(|ty| (id, ty))), + self.ret_coercion_impl_trait.map(|ty| (self.body_id.owner, ty)), ) { (Expectation::ExpectHasType(expected), Some((id, ty))) if self.in_tail_expr && self.can_coerce(arm_ty, expected) => @@ -181,7 +177,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &arm.body, then_ty, arm_ty, - suggest_box, + opt_suggest_box_span, ); coercion.coerce(self, &cause, &arm.body, arm_ty); } @@ -205,7 +201,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { prior_arms: other_arms.clone(), last_ty: prior_arm_ty.unwrap(), scrut_hir_id: scrut.hir_id, - suggest_box, + opt_suggest_box_span, }), ), }; @@ -330,7 +326,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { else_expr: &'tcx hir::Expr<'tcx>, then_ty: Ty<'tcx>, else_ty: Ty<'tcx>, - suggest_box: Option, + opt_suggest_box_span: Option, ) -> ObligationCause<'tcx> { let mut outer_sp = if self.tcx.sess.source_map().is_multiline(span) { // The `if`/`else` isn't in one line in the output, include some context to make it @@ -421,7 +417,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { else_sp: error_sp, outer: outer_sp, semicolon: remove_semicolon, - suggest_box, + opt_suggest_box_span, }), ) } diff --git a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs index 1a477e5db99ac..fa7664a83eee0 100644 --- a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs +++ b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs @@ -63,4 +63,39 @@ fn dog() -> impl std::fmt::Display { } } +fn hat() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed trait object + match 13 { + 0 => { + return 0i32; + } + _ => { + 1u32 + } + } +} + +fn pug() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed trait object + match 13 { + 0 => 0i32, + 1 => 1u32, //~ ERROR `match` arms have incompatible types + _ => 2u32, + } +} + +fn man() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed trait object + if false { + 0i32 + } else { + 1u32 //~ ERROR `if` and `else` have incompatible types + } +} + +fn apt() -> impl std::fmt::Display { + if let Some(42) = Some(42) { + 0i32 + } else { + 1u32 //~ ERROR `if` and `else` have incompatible types + } +} + fn main() {} diff --git a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr index 4265381eb401c..eb4dc45c8a932 100644 --- a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr +++ b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr @@ -207,6 +207,112 @@ LL | 0 => Box::new(0i32), LL | 1 => Box::new(1u32), | -error: aborting due to 8 previous errors +error[E0308]: `if` and `else` have incompatible types + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:97:9 + | +LL | / if let Some(42) = Some(42) { +LL | | 0i32 + | | ---- expected because of this +LL | | } else { +LL | | 1u32 + | | ^^^^ expected `i32`, found `u32` +LL | | } + | |_____- `if` and `else` have incompatible types + | +help: you could change the return type to be a boxed trait object + | +LL | fn apt() -> Box { + | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | Box::new(0i32) +LL | } else { +LL | Box::new(1u32) + | + +error[E0746]: return type cannot have an unboxed trait object + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:66:13 + | +LL | fn hat() -> dyn std::fmt::Display { + | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = note: for information on trait objects, see + = note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type + = note: for information on `impl Trait`, see + = note: you can create a new `enum` with a variant for each returned type +help: return a boxed trait object instead + | +LL | fn hat() -> Box { +LL | match 13 { +LL | 0 => { +LL | return Box::new(0i32); +LL | } +LL | _ => { + ... + +error[E0308]: `match` arms have incompatible types + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:80:14 + | +LL | / match 13 { +LL | | 0 => 0i32, + | | ---- this is found to be of type `i32` +LL | | 1 => 1u32, + | | ^^^^ expected `i32`, found `u32` +LL | | _ => 2u32, +LL | | } + | |_____- `match` arms have incompatible types + +error[E0746]: return type cannot have an unboxed trait object + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:77:13 + | +LL | fn pug() -> dyn std::fmt::Display { + | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = note: for information on trait objects, see + = note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type + = note: for information on `impl Trait`, see + = note: you can create a new `enum` with a variant for each returned type +help: return a boxed trait object instead + | +LL | fn pug() -> Box { +LL | match 13 { +LL | 0 => Box::new(0i32), +LL | 1 => Box::new(1u32), +LL | _ => Box::new(2u32), + | + +error[E0308]: `if` and `else` have incompatible types + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:89:9 + | +LL | / if false { +LL | | 0i32 + | | ---- expected because of this +LL | | } else { +LL | | 1u32 + | | ^^^^ expected `i32`, found `u32` +LL | | } + | |_____- `if` and `else` have incompatible types + +error[E0746]: return type cannot have an unboxed trait object + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:85:13 + | +LL | fn man() -> dyn std::fmt::Display { + | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = note: for information on trait objects, see + = note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type + = note: for information on `impl Trait`, see + = note: you can create a new `enum` with a variant for each returned type +help: return a boxed trait object instead + | +LL | fn man() -> Box { +LL | if false { +LL | Box::new(0i32) +LL | } else { +LL | Box::new(1u32) + | + +error: aborting due to 14 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0308, E0746. +For more information about an error, try `rustc --explain E0308`. From 85ab152be78ffaf7dd97f60ececceda28f4e4802 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 11 Sep 2020 20:53:52 -0400 Subject: [PATCH 0324/1052] Update bootstrap readme - Reflect changes in x.py defaults - Remove recommendation to use nightly for incremental; it works fine on beta - Remove note that incremental chooses stage 1 by default; stage 1 is already the default - Update Discord -> Zulip --- src/bootstrap/README.md | 38 ++++++++++---------------------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index 975b8be02c898..a69bd1cc3bc53 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -26,10 +26,10 @@ The script accepts commands, flags, and arguments to determine what to do: ``` # build the whole compiler - ./x.py build + ./x.py build --stage 2 # build the stage1 compiler - ./x.py build --stage 1 + ./x.py build # build stage0 libstd ./x.py build --stage 0 library/std @@ -43,8 +43,8 @@ The script accepts commands, flags, and arguments to determine what to do: that belong to stage n or earlier: ``` - # keep old build products for stage 0 and build stage 1 - ./x.py build --keep-stage 0 --stage 1 + # build stage 1, keeping old build products for stage 0 + ./x.py build --keep-stage 0 ``` * `test` - a command for executing unit tests. Like the `build` command this @@ -123,24 +123,8 @@ that (b) leverage Rust as much as possible! ## Incremental builds -You can configure rustbuild to use incremental compilation. Because -incremental is new and evolving rapidly, if you want to use it, it is -recommended that you replace the snapshot with a locally installed -nightly build of rustc. You will want to keep this up to date. - -To follow this course of action, first thing you will want to do is to -install a nightly, presumably using `rustup`. You will then want to -configure your directory to use this build, like so: - -```sh -# configure to use local rust instead of downloading a beta. -# `--local-rust-root` is optional here. If elided, we will -# use whatever rustc we find on your PATH. -$ ./configure --local-rust-root=~/.cargo/ --enable-local-rebuild -``` - -After that, you can use the `--incremental` flag to actually do -incremental builds: +You can configure rustbuild to use incremental compilation with the +`--incremental` flag: ```sh $ ./x.py build --incremental @@ -150,9 +134,7 @@ The `--incremental` flag will store incremental compilation artifacts in `build//stage0-incremental`. Note that we only use incremental compilation for the stage0 -> stage1 compilation -- this is because the stage1 compiler is changing, and we don't try to cache and reuse -incremental artifacts across different versions of the compiler. For -this reason, `--incremental` defaults to `--stage 1` (though you can -manually select a higher stage, if you prefer). +incremental artifacts across different versions of the compiler. You can always drop the `--incremental` to build as normal (but you will still be using the local nightly as your bootstrap). @@ -331,8 +313,8 @@ are: `Config` struct. * Adding a sanity check? Take a look at `bootstrap/sanity.rs`. -If you have any questions feel free to reach out on `#infra` channel in the -[Rust Discord server][rust-discord] or ask on internals.rust-lang.org. When +If you have any questions feel free to reach out on the `#t-infra` channel in +the [Rust Zulip server][rust-zulip] or ask on internals.rust-lang.org. When you encounter bugs, please file issues on the rust-lang/rust issue tracker. -[rust-discord]: https://discord.gg/rust-lang +[rust-zulip]: https://rust-lang.zulipchat.com/#narrow/stream/242791-t-infra From 950006711d8095b2e7b55c246103c51757ea6f40 Mon Sep 17 00:00:00 2001 From: SlightlyOutOfPhase Date: Fri, 11 Sep 2020 21:40:02 -0400 Subject: [PATCH 0325/1052] Use `is_unstable_const_fn` where appropriate --- src/librustdoc/clean/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1bdbad4675556..0bcb11d2239e5 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -23,7 +23,7 @@ use rustc_middle::middle::stability; use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{self, AdtKind, Lift, Ty, TyCtxt}; -use rustc_mir::const_eval::is_min_const_fn; +use rustc_mir::const_eval::{is_min_const_fn, is_unstable_const_fn}; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{self, Pos}; @@ -900,7 +900,7 @@ impl Clean for doctree::Function<'_> { enter_impl_trait(cx, || (self.generics.clean(cx), (self.decl, self.body).clean(cx))); let did = cx.tcx.hir().local_def_id(self.id); - let constness = if is_min_const_fn(cx.tcx, did.to_def_id()) { + let constness = if !is_unstable_const_fn(cx.tcx, did.to_def_id()).is_some() { hir::Constness::Const } else { hir::Constness::NotConst @@ -1108,7 +1108,7 @@ impl Clean for hir::TraitItem<'_> { hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { let mut m = (sig, &self.generics, body, None).clean(cx); if m.header.constness == hir::Constness::Const - && !is_min_const_fn(cx.tcx, local_did.to_def_id()) + && is_unstable_const_fn(cx.tcx, local_did.to_def_id()).is_some() { m.header.constness = hir::Constness::NotConst; } @@ -1121,7 +1121,7 @@ impl Clean for hir::TraitItem<'_> { let (all_types, ret_types) = get_all_types(&generics, &decl, cx); let mut t = TyMethod { header: sig.header, decl, generics, all_types, ret_types }; if t.header.constness == hir::Constness::Const - && !is_min_const_fn(cx.tcx, local_did.to_def_id()) + && is_unstable_const_fn(cx.tcx, local_did.to_def_id()).is_some() { t.header.constness = hir::Constness::NotConst; } @@ -1154,7 +1154,7 @@ impl Clean for hir::ImplItem<'_> { hir::ImplItemKind::Fn(ref sig, body) => { let mut m = (sig, &self.generics, body, Some(self.defaultness)).clean(cx); if m.header.constness == hir::Constness::Const - && !is_min_const_fn(cx.tcx, local_did.to_def_id()) + && is_unstable_const_fn(cx.tcx, local_did.to_def_id()).is_some() { m.header.constness = hir::Constness::NotConst; } From 0439556eb05757a778620cc0326bcfe9a06209f5 Mon Sep 17 00:00:00 2001 From: SlightlyOutOfPhase Date: Fri, 11 Sep 2020 22:39:16 -0400 Subject: [PATCH 0326/1052] Check basic constness before unstable constness --- src/librustdoc/clean/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0bcb11d2239e5..405fbf7430599 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -23,7 +23,7 @@ use rustc_middle::middle::stability; use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{self, AdtKind, Lift, Ty, TyCtxt}; -use rustc_mir::const_eval::{is_min_const_fn, is_unstable_const_fn}; +use rustc_mir::const_eval::{is_const_fn, is_min_const_fn, is_unstable_const_fn}; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{self, Pos}; @@ -900,7 +900,8 @@ impl Clean for doctree::Function<'_> { enter_impl_trait(cx, || (self.generics.clean(cx), (self.decl, self.body).clean(cx))); let did = cx.tcx.hir().local_def_id(self.id); - let constness = if !is_unstable_const_fn(cx.tcx, did.to_def_id()).is_some() { + let constness = if is_const_fn(cx.tcx, did.to_def_id()) + && !is_unstable_const_fn(cx.tcx, did.to_def_id()).is_some() { hir::Constness::Const } else { hir::Constness::NotConst From 4284aad8fc500c6e9b19309e2ca561ec0f433555 Mon Sep 17 00:00:00 2001 From: SlightlyOutOfPhase Date: Fri, 11 Sep 2020 22:57:20 -0400 Subject: [PATCH 0327/1052] Fix formatting for tidy --- src/librustdoc/clean/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 405fbf7430599..70347ac66eb5e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -901,7 +901,8 @@ impl Clean for doctree::Function<'_> { let did = cx.tcx.hir().local_def_id(self.id); let constness = if is_const_fn(cx.tcx, did.to_def_id()) - && !is_unstable_const_fn(cx.tcx, did.to_def_id()).is_some() { + && !is_unstable_const_fn(cx.tcx, did.to_def_id()).is_some() + { hir::Constness::Const } else { hir::Constness::NotConst From b1e481d712fcf3d4b97ebf9e9a049c51701cf5e1 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Sat, 12 Sep 2020 13:35:03 +0800 Subject: [PATCH 0328/1052] Simplify iter zip struct doc --- library/core/src/iter/adapters/zip.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index e02de0ce45dff..a854f70dcd0ba 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -8,11 +8,8 @@ use super::super::{ /// An iterator that iterates two other iterators simultaneously. /// -/// This `struct` is created by the [`zip`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`zip`]: trait.Iterator.html#method.zip -/// [`Iterator`]: trait.Iterator.html +/// This `struct` is created by [`Iterator::zip`]. See its documentation +/// for more. #[derive(Clone)] #[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] From b8752fff19fdf5d6b821eefe1cf6709d4cad8cdf Mon Sep 17 00:00:00 2001 From: Andreas Jonson Date: Sat, 12 Sep 2020 08:24:09 +0200 Subject: [PATCH 0329/1052] update the version of itertools and parking_lot this is to avoid compiling multiple version of the crates in rustc --- Cargo.lock | 10 +++++----- compiler/rustc_ast_passes/Cargo.toml | 2 +- compiler/rustc_data_structures/Cargo.toml | 2 +- compiler/rustc_mir/Cargo.toml | 2 +- compiler/rustc_query_system/Cargo.toml | 2 +- src/librustdoc/Cargo.toml | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b687e714d4fa2..531859d6460a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3291,7 +3291,7 @@ dependencies = [ name = "rustc_ast_passes" version = "0.0.0" dependencies = [ - "itertools 0.8.2", + "itertools 0.9.0", "rustc_ast", "rustc_ast_pretty", "rustc_attr", @@ -3423,7 +3423,7 @@ dependencies = [ "jobserver", "libc", "measureme", - "parking_lot 0.10.2", + "parking_lot 0.11.0", "rustc-hash", "rustc-rayon", "rustc-rayon-core", @@ -3752,7 +3752,7 @@ name = "rustc_mir" version = "0.0.0" dependencies = [ "either", - "itertools 0.8.2", + "itertools 0.9.0", "log_settings", "polonius-engine", "regex", @@ -3877,7 +3877,7 @@ dependencies = [ name = "rustc_query_system" version = "0.0.0" dependencies = [ - "parking_lot 0.10.2", + "parking_lot 0.11.0", "rustc-rayon-core", "rustc_arena", "rustc_data_structures", @@ -4110,7 +4110,7 @@ name = "rustdoc" version = "0.0.0" dependencies = [ "expect-test", - "itertools 0.8.2", + "itertools 0.9.0", "minifier", "pulldown-cmark", "rustc-rayon", diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml index 7cf3e752c9256..9ed6bdc3d6a1a 100644 --- a/compiler/rustc_ast_passes/Cargo.toml +++ b/compiler/rustc_ast_passes/Cargo.toml @@ -5,7 +5,7 @@ version = "0.0.0" edition = "2018" [dependencies] -itertools = "0.8" +itertools = "0.9" tracing = "0.1" rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_attr = { path = "../rustc_attr" } diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index fcae9b936ed2a..3dc55cab95a11 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -30,7 +30,7 @@ stacker = "0.1.11" tempfile = "3.0.5" [dependencies.parking_lot] -version = "0.10" +version = "0.11" features = ["nightly"] [target.'cfg(windows)'.dependencies] diff --git a/compiler/rustc_mir/Cargo.toml b/compiler/rustc_mir/Cargo.toml index 0a22bc7d7628f..a6d22243d6df6 100644 --- a/compiler/rustc_mir/Cargo.toml +++ b/compiler/rustc_mir/Cargo.toml @@ -10,7 +10,7 @@ doctest = false [dependencies] either = "1.5.0" rustc_graphviz = { path = "../rustc_graphviz" } -itertools = "0.8" +itertools = "0.9" tracing = "0.1" log_settings = "0.1.1" polonius-engine = "0.12.0" diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml index 7defb00a8813e..f38d62dec0046 100644 --- a/compiler/rustc_query_system/Cargo.toml +++ b/compiler/rustc_query_system/Cargo.toml @@ -17,5 +17,5 @@ rustc_macros = { path = "../rustc_macros" } rustc_index = { path = "../rustc_index" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } -parking_lot = "0.10" +parking_lot = "0.11" smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index ede5239446835..90d2a18ea5819 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -15,7 +15,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" smallvec = "1.0" tempfile = "3" -itertools = "0.8" +itertools = "0.9" [dev-dependencies] expect-test = "1.0" From c32127675a4a4b3fdf23d06602187accf584b687 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Sep 2020 10:10:13 +0200 Subject: [PATCH 0330/1052] move guaranteed{ne,eq} implementation to compile-time machine --- compiler/rustc_mir/src/const_eval/machine.rs | 71 ++++++++++++++++++- .../rustc_mir/src/interpret/intrinsics.rs | 43 +---------- 2 files changed, 70 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index b0357c508a3e0..02e905505c0f5 100644 --- a/compiler/rustc_mir/src/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -11,7 +11,7 @@ use rustc_ast::Mutability; use rustc_hir::def_id::DefId; use rustc_middle::mir::AssertMessage; use rustc_session::Limit; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::{sym, Symbol}; use crate::interpret::{ self, compile_time_machine, AllocId, Allocation, Frame, GlobalId, ImmTy, InterpCx, @@ -176,6 +176,38 @@ impl interpret::MayLeak for ! { } } +impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { + fn guaranteed_eq(&mut self, a: Scalar, b: Scalar) -> bool { + match (a, b) { + // Comparisons between integers are always known. + (Scalar::Raw { .. }, Scalar::Raw { .. }) => a == b, + // Equality with integers can never be known for sure. + (Scalar::Raw { .. }, Scalar::Ptr(_)) | (Scalar::Ptr(_), Scalar::Raw { .. }) => false, + // FIXME: return `true` for when both sides are the same pointer, *except* that + // some things (like functions and vtables) do not have stable addresses + // so we need to be careful around them (see e.g. #73722). + (Scalar::Ptr(_), Scalar::Ptr(_)) => false, + } + } + + fn guaranteed_ne(&mut self, a: Scalar, b: Scalar) -> bool { + match (a, b) { + // Comparisons between integers are always known. + (Scalar::Raw { .. }, Scalar::Raw { .. }) => a != b, + // Comparisons of abstract pointers with null pointers are known if the pointer + // is in bounds, because if they are in bounds, the pointer can't be null. + (Scalar::Raw { data: 0, .. }, Scalar::Ptr(ptr)) + | (Scalar::Ptr(ptr), Scalar::Raw { data: 0, .. }) => !self.memory.ptr_may_be_null(ptr), + // Inequality with integers other than null can never be known for sure. + (Scalar::Raw { .. }, Scalar::Ptr(_)) | (Scalar::Ptr(_), Scalar::Raw { .. }) => false, + // FIXME: return `true` for at least some comparisons where we can reliably + // determine the result of runtime inequality tests at compile-time. + // Examples include comparison of addresses in different static items. + (Scalar::Ptr(_), Scalar::Ptr(_)) => false, + } + } +} + impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, 'tcx> { compile_time_machine!(<'mir, 'tcx>); @@ -234,12 +266,45 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, _unwind: Option, ) -> InterpResult<'tcx> { + // Shared intrinsics. if ecx.emulate_intrinsic(instance, args, ret)? { return Ok(()); } - // An intrinsic that we do not support let intrinsic_name = ecx.tcx.item_name(instance.def_id()); - Err(ConstEvalErrKind::NeedsRfc(format!("calling intrinsic `{}`", intrinsic_name)).into()) + + // CTFE-specific intrinsics. + let (dest, ret) = match ret { + None => { + return Err(ConstEvalErrKind::NeedsRfc(format!( + "calling intrinsic `{}`", + intrinsic_name + )) + .into()); + } + Some(p) => p, + }; + match intrinsic_name { + sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => { + let a = ecx.read_immediate(args[0])?.to_scalar()?; + let b = ecx.read_immediate(args[1])?.to_scalar()?; + let cmp = if intrinsic_name == sym::ptr_guaranteed_eq { + ecx.guaranteed_eq(a, b) + } else { + ecx.guaranteed_ne(a, b) + }; + ecx.write_scalar(Scalar::from_bool(cmp), dest)?; + } + _ => { + return Err(ConstEvalErrKind::NeedsRfc(format!( + "calling intrinsic `{}`", + intrinsic_name + )) + .into()); + } + } + + ecx.go_to_block(ret); + Ok(()) } fn assert_panic( diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index 3e0a7886f0835..47ca71d9642ba 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -88,6 +88,8 @@ crate fn eval_nullary_intrinsic<'tcx>( impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Returns `true` if emulation happened. + /// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own + /// intrinsic handling. pub fn emulate_intrinsic( &mut self, instance: ty::Instance<'tcx>, @@ -328,16 +330,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let offset_ptr = ptr.ptr_wrapping_signed_offset(offset_bytes, self); self.write_scalar(offset_ptr, dest)?; } - sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => { - let a = self.read_immediate(args[0])?.to_scalar()?; - let b = self.read_immediate(args[1])?.to_scalar()?; - let cmp = if intrinsic_name == sym::ptr_guaranteed_eq { - self.guaranteed_eq(a, b) - } else { - self.guaranteed_ne(a, b) - }; - self.write_scalar(Scalar::from_bool(cmp), dest)?; - } sym::ptr_offset_from => { let a = self.read_immediate(args[0])?.to_scalar()?; let b = self.read_immediate(args[1])?.to_scalar()?; @@ -448,37 +440,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(true) } - fn guaranteed_eq(&mut self, a: Scalar, b: Scalar) -> bool { - match (a, b) { - // Comparisons between integers are always known. - (Scalar::Raw { .. }, Scalar::Raw { .. }) => a == b, - // Equality with integers can never be known for sure. - (Scalar::Raw { .. }, Scalar::Ptr(_)) | (Scalar::Ptr(_), Scalar::Raw { .. }) => false, - // FIXME: return `true` for when both sides are the same pointer, *except* that - // some things (like functions and vtables) do not have stable addresses - // so we need to be careful around them. - (Scalar::Ptr(_), Scalar::Ptr(_)) => false, - } - } - - fn guaranteed_ne(&mut self, a: Scalar, b: Scalar) -> bool { - match (a, b) { - // Comparisons between integers are always known. - (Scalar::Raw { .. }, Scalar::Raw { .. }) => a != b, - // Comparisons of abstract pointers with null pointers are known if the pointer - // is in bounds, because if they are in bounds, the pointer can't be null. - (Scalar::Raw { data: 0, .. }, Scalar::Ptr(ptr)) - | (Scalar::Ptr(ptr), Scalar::Raw { data: 0, .. }) => !self.memory.ptr_may_be_null(ptr), - // Inequality with integers other than null can never be known for sure. - (Scalar::Raw { .. }, Scalar::Ptr(_)) | (Scalar::Ptr(_), Scalar::Raw { .. }) => false, - // FIXME: return `true` for at least some comparisons where we can reliably - // determine the result of runtime inequality tests at compile-time. - // Examples include comparison of addresses in static items, for these we can - // give reliable results. - (Scalar::Ptr(_), Scalar::Ptr(_)) => false, - } - } - pub fn exact_div( &mut self, a: ImmTy<'tcx, M::PointerTag>, From 91f7d761e762d0d9f47cf61cf5d942fd93eaf2a8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Sep 2020 10:33:49 +0200 Subject: [PATCH 0331/1052] also assert ScalarMaybeUninit size --- compiler/rustc_middle/src/mir/interpret/value.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 7d6ff3eb5c1cc..7741c76ff3e45 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -578,6 +578,9 @@ pub enum ScalarMaybeUninit { Uninit, } +#[cfg(target_arch = "x86_64")] +static_assert_size!(ScalarMaybeUninit, 24); + impl From> for ScalarMaybeUninit { #[inline(always)] fn from(s: Scalar) -> Self { From 8a261a2b342d85d11c67a8d4dd3408778bd0f5b7 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 12 Sep 2020 13:40:50 +0200 Subject: [PATCH 0332/1052] Simplify SyncOnceCell's `take` and `drop`. --- library/std/src/lazy.rs | 39 +++++++++++++-------------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/library/std/src/lazy.rs b/library/std/src/lazy.rs index 091e2091fb095..e0095e64faf31 100644 --- a/library/std/src/lazy.rs +++ b/library/std/src/lazy.rs @@ -7,7 +7,7 @@ use crate::{ cell::{Cell, UnsafeCell}, fmt, marker::PhantomData, - mem::{self, MaybeUninit}, + mem::MaybeUninit, ops::{Deref, Drop}, panic::{RefUnwindSafe, UnwindSafe}, sync::Once, @@ -316,13 +316,7 @@ impl SyncOnceCell { /// ``` #[unstable(feature = "once_cell", issue = "74465")] pub fn into_inner(mut self) -> Option { - // SAFETY: Safe because we immediately free `self` without dropping - let inner = unsafe { self.take_inner() }; - - // Don't drop this `SyncOnceCell`. We just moved out one of the fields, but didn't set - // the state to uninitialized. - mem::forget(self); - inner + self.take() } /// Takes the value out of this `SyncOnceCell`, moving it back to an uninitialized state. @@ -348,22 +342,12 @@ impl SyncOnceCell { /// ``` #[unstable(feature = "once_cell", issue = "74465")] pub fn take(&mut self) -> Option { - mem::take(self).into_inner() - } - - /// Takes the wrapped value out of a `SyncOnceCell`. - /// Afterwards the cell is no longer initialized. - /// - /// Safety: The cell must now be free'd WITHOUT dropping. No other usages of the cell - /// are valid. Only used by `into_inner` and `drop`. - unsafe fn take_inner(&mut self) -> Option { - // The mutable reference guarantees there are no other threads that can observe us - // taking out the wrapped value. - // Right after this function `self` is supposed to be freed, so it makes little sense - // to atomically set the state to uninitialized. if self.is_initialized() { - let value = mem::replace(&mut self.value, UnsafeCell::new(MaybeUninit::uninit())); - Some(value.into_inner().assume_init()) + self.once = Once::new(); + // SAFETY: `self.value` is initialized and contains a valid `T`. + // `self.once` is reset, so `is_initialized()` will be false again + // which prevents the value from being read twice. + unsafe { Some((&mut *self.value.get()).assume_init_read()) } } else { None } @@ -416,9 +400,12 @@ impl SyncOnceCell { unsafe impl<#[may_dangle] T> Drop for SyncOnceCell { fn drop(&mut self) { - // SAFETY: The cell is being dropped, so it can't be accessed again. - // We also don't touch the `T`, which validates our usage of #[may_dangle]. - unsafe { self.take_inner() }; + if self.is_initialized() { + // Safety: The cell is initialized and being dropped, so it can't + // be accessed again. We also don't touch the `T` other than + // dropping it, which validates our usage of #[may_dangle]. + unsafe { (&mut *self.value.get()).assume_init_drop() }; + } } } From fb47bda53daf8a2ace7baa1288d61312ad56975a Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sat, 12 Sep 2020 07:59:54 -0400 Subject: [PATCH 0333/1052] Add host= configuration for msvc/darwin --- .github/workflows/ci.yml | 6 +++--- src/ci/azure-pipelines/auto.yml | 2 +- src/ci/github-actions/ci.yml | 6 ++++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 445658d1b2198..8b6828fd49d27 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -444,13 +444,13 @@ jobs: os: windows-latest-xl - name: dist-x86_64-msvc env: - RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc --enable-full-tools --enable-profiler" + RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc --enable-full-tools --enable-profiler" SCRIPT: python x.py dist DIST_REQUIRE_ALL_TOOLS: 1 os: windows-latest-xl - name: dist-i686-msvc env: - RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-msvc --target=i586-pc-windows-msvc --enable-full-tools --enable-profiler" + RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-msvc --host=i686-pc-windows-msvc --target=i586-pc-windows-msvc --enable-full-tools --enable-profiler" SCRIPT: python x.py dist DIST_REQUIRE_ALL_TOOLS: 1 os: windows-latest-xl @@ -583,7 +583,7 @@ jobs: - name: dist-x86_64-apple env: SCRIPT: "./x.py dist" - RUST_CONFIGURE_ARGS: "--target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false" + RUST_CONFIGURE_ARGS: "--host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false" RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 MACOSX_DEPLOYMENT_TARGET: 10.7 NO_LLVM_ASSERTIONS: 1 diff --git a/src/ci/azure-pipelines/auto.yml b/src/ci/azure-pipelines/auto.yml index d19682c669157..2dcb55bb9731b 100644 --- a/src/ci/azure-pipelines/auto.yml +++ b/src/ci/azure-pipelines/auto.yml @@ -46,7 +46,7 @@ jobs: dist-x86_64-apple: SCRIPT: ./x.py dist - INITIAL_RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false + INITIAL_RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 MACOSX_DEPLOYMENT_TARGET: 10.7 NO_LLVM_ASSERTIONS: 1 diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index aef4374c54232..2109cdf4e86b7 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -491,7 +491,7 @@ jobs: # # We are using MinGW with POSIX threads since LLVM requires # C++'s std::thread which is disabled in libstdc++ with win32 threads. - # FIXME: Libc++ doesn't have this limitation so we can avoid + # FIXME: Libc++ doesn't have this limitation so we can avoid # winpthreads if we switch to it. # # Instead of relying on the MinGW version installed on CI we download @@ -541,6 +541,7 @@ jobs: env: RUST_CONFIGURE_ARGS: >- --build=x86_64-pc-windows-msvc + --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc --enable-full-tools --enable-profiler @@ -552,6 +553,7 @@ jobs: env: RUST_CONFIGURE_ARGS: >- --build=i686-pc-windows-msvc + --host=i686-pc-windows-msvc --target=i586-pc-windows-msvc --enable-full-tools --enable-profiler @@ -605,7 +607,7 @@ jobs: - name: dist-x86_64-apple env: SCRIPT: ./x.py dist - RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false + RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 MACOSX_DEPLOYMENT_TARGET: 10.7 NO_LLVM_ASSERTIONS: 1 From 73e0a56dde24693768d56960023f00ef61f28684 Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Fri, 4 Sep 2020 20:17:06 +0200 Subject: [PATCH 0334/1052] Make all methods of `Duration` const Make the following methods of `Duration` unstable const under `duration_const_2`: - `from_secs_f64` - `from_secs_f32` - `mul_f64` - `mul_f32` - `div_f64` - `div_f32` This results in all methods of `Duration` being (unstable) const. Also adds tests for these methods in a const context, moved the test to `library` as part of #76268. Possible because of #72449, which made the relevant `f32` and `f64` methods const. Tracking issue: #72440 --- library/core/src/time.rs | 18 +++-- library/core/tests/lib.rs | 3 + library/core/tests/time.rs | 101 ++++++++++++++++++++++++ src/test/ui/consts/duration-consts-2.rs | 67 ---------------- 4 files changed, 116 insertions(+), 73 deletions(-) delete mode 100644 src/test/ui/consts/duration-consts-2.rs diff --git a/library/core/src/time.rs b/library/core/src/time.rs index f39781788d7c0..6dc542dee58e6 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -693,7 +693,8 @@ impl Duration { /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[inline] - pub fn from_secs_f64(secs: f64) -> Duration { + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn from_secs_f64(secs: f64) -> Duration { const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f64; let nanos = secs * (NANOS_PER_SEC as f64); if !nanos.is_finite() { @@ -727,7 +728,8 @@ impl Duration { /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[inline] - pub fn from_secs_f32(secs: f32) -> Duration { + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn from_secs_f32(secs: f32) -> Duration { const MAX_NANOS_F32: f32 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f32; let nanos = secs * (NANOS_PER_SEC as f32); if !nanos.is_finite() { @@ -761,7 +763,8 @@ impl Duration { /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[inline] - pub fn mul_f64(self, rhs: f64) -> Duration { + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn mul_f64(self, rhs: f64) -> Duration { Duration::from_secs_f64(rhs * self.as_secs_f64()) } @@ -782,7 +785,8 @@ impl Duration { /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[inline] - pub fn mul_f32(self, rhs: f32) -> Duration { + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn mul_f32(self, rhs: f32) -> Duration { Duration::from_secs_f32(rhs * self.as_secs_f32()) } @@ -802,7 +806,8 @@ impl Duration { /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[inline] - pub fn div_f64(self, rhs: f64) -> Duration { + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn div_f64(self, rhs: f64) -> Duration { Duration::from_secs_f64(self.as_secs_f64() / rhs) } @@ -824,7 +829,8 @@ impl Duration { /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[inline] - pub fn div_f32(self, rhs: f32) -> Duration { + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn div_f32(self, rhs: f32) -> Duration { Duration::from_secs_f32(self.as_secs_f32() / rhs) } diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index a2e294ace1860..04402117f7da6 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -10,8 +10,11 @@ #![feature(core_private_diy_float)] #![feature(debug_non_exhaustive)] #![feature(dec2flt)] +#![feature(div_duration)] +#![feature(duration_consts_2)] #![feature(duration_constants)] #![feature(duration_saturating_ops)] +#![feature(duration_zero)] #![feature(exact_size_is_empty)] #![feature(fixed_size_array)] #![feature(flt2dec)] diff --git a/library/core/tests/time.rs b/library/core/tests/time.rs index 4f90eb63b0472..7c43885040b3e 100644 --- a/library/core/tests/time.rs +++ b/library/core/tests/time.rs @@ -321,3 +321,104 @@ fn debug_formatting_precision_high() { assert_eq!(format!("{:.10?}", Duration::new(4, 001_000_000)), "4.0010000000s"); assert_eq!(format!("{:.20?}", Duration::new(4, 001_000_000)), "4.00100000000000000000s"); } + +#[test] +fn duration_const() { + // test that the methods of `Duration` are usable in a const context + + const DURATION: Duration = Duration::new(0, 123_456_789); + + const SUB_SEC_MILLIS: u32 = DURATION.subsec_millis(); + assert_eq!(SUB_SEC_MILLIS, 123); + + const SUB_SEC_MICROS: u32 = DURATION.subsec_micros(); + assert_eq!(SUB_SEC_MICROS, 123_456); + + const SUB_SEC_NANOS: u32 = DURATION.subsec_nanos(); + assert_eq!(SUB_SEC_NANOS, 123_456_789); + + const ZERO: Duration = Duration::zero(); + assert_eq!(ZERO, Duration::new(0, 0)); + + const IS_ZERO: bool = ZERO.is_zero(); + assert!(IS_ZERO); + + const ONE: Duration = Duration::new(1, 0); + + const SECONDS: u64 = ONE.as_secs(); + assert_eq!(SECONDS, 1); + + const FROM_SECONDS: Duration = Duration::from_secs(1); + assert_eq!(FROM_SECONDS, ONE); + + const SECONDS_F32: f32 = ONE.as_secs_f32(); + assert_eq!(SECONDS_F32, 1.0); + + const FROM_SECONDS_F32: Duration = Duration::from_secs_f32(1.0); + assert_eq!(FROM_SECONDS_F32, ONE); + + const SECONDS_F64: f64 = ONE.as_secs_f64(); + assert_eq!(SECONDS_F64, 1.0); + + const FROM_SECONDS_F64: Duration = Duration::from_secs_f64(1.0); + assert_eq!(FROM_SECONDS_F64, ONE); + + const MILLIS: u128 = ONE.as_millis(); + assert_eq!(MILLIS, 1_000); + + const FROM_MILLIS: Duration = Duration::from_millis(1_000); + assert_eq!(FROM_MILLIS, ONE); + + const MICROS: u128 = ONE.as_micros(); + assert_eq!(MICROS, 1_000_000); + + const FROM_MICROS: Duration = Duration::from_micros(1_000_000); + assert_eq!(FROM_MICROS, ONE); + + const NANOS: u128 = ONE.as_nanos(); + assert_eq!(NANOS, 1_000_000_000); + + const FROM_NANOS: Duration = Duration::from_nanos(1_000_000_000); + assert_eq!(FROM_NANOS, ONE); + + const MAX: Duration = Duration::new(u64::MAX, 999_999_999); + + const CHECKED_ADD: Option = MAX.checked_add(ONE); + assert_eq!(CHECKED_ADD, None); + + const CHECKED_SUB: Option = ZERO.checked_sub(ONE); + assert_eq!(CHECKED_SUB, None); + + const CHECKED_MUL: Option = ONE.checked_mul(1); + assert_eq!(CHECKED_MUL, Some(ONE)); + + const MUL_F32: Duration = ONE.mul_f32(1.0); + assert_eq!(MUL_F32, ONE); + + const MUL_F64: Duration = ONE.mul_f64(1.0); + assert_eq!(MUL_F64, ONE); + + const CHECKED_DIV: Option = ONE.checked_div(1); + assert_eq!(CHECKED_DIV, Some(ONE)); + + const DIV_F32: Duration = ONE.div_f32(1.0); + assert_eq!(DIV_F32, ONE); + + const DIV_F64: Duration = ONE.div_f64(1.0); + assert_eq!(DIV_F64, ONE); + + const DIV_DURATION_F32: f32 = ONE.div_duration_f32(ONE); + assert_eq!(DIV_DURATION_F32, 1.0); + + const DIV_DURATION_F64: f64 = ONE.div_duration_f64(ONE); + assert_eq!(DIV_DURATION_F64, 1.0); + + const SATURATING_ADD: Duration = MAX.saturating_add(ONE); + assert_eq!(SATURATING_ADD, MAX); + + const SATURATING_SUB: Duration = ZERO.saturating_sub(ONE); + assert_eq!(SATURATING_SUB, ZERO); + + const SATURATING_MUL: Duration = MAX.saturating_mul(2); + assert_eq!(SATURATING_MUL, MAX); +} diff --git a/src/test/ui/consts/duration-consts-2.rs b/src/test/ui/consts/duration-consts-2.rs deleted file mode 100644 index bc0969e4f1fba..0000000000000 --- a/src/test/ui/consts/duration-consts-2.rs +++ /dev/null @@ -1,67 +0,0 @@ -// run-pass - -#![feature(const_panic)] -#![feature(duration_consts_2)] -#![feature(div_duration)] -#![feature(duration_saturating_ops)] - -use std::time::Duration; - -fn duration() { - const ZERO : Duration = Duration::new(0, 0); - assert_eq!(ZERO, Duration::from_secs(0)); - - const ONE : Duration = Duration::new(0, 1); - assert_eq!(ONE, Duration::from_nanos(1)); - - const MAX : Duration = Duration::new(u64::MAX, 1_000_000_000 - 1); - - const MAX_CHECKED_ADD_ZERO : Option = MAX.checked_add(ZERO); - assert_eq!(MAX_CHECKED_ADD_ZERO, Some(MAX)); - - const MAX_CHECKED_ADD_ONE : Option = MAX.checked_add(ONE); - assert_eq!(MAX_CHECKED_ADD_ONE, None); - - const ONE_CHECKED_SUB_ONE : Option = ONE.checked_sub(ONE); - assert_eq!(ONE_CHECKED_SUB_ONE, Some(ZERO)); - - const ZERO_CHECKED_SUB_ONE : Option = ZERO.checked_sub(ONE); - assert_eq!(ZERO_CHECKED_SUB_ONE, None); - - const ONE_CHECKED_MUL_ONE : Option = ONE.checked_mul(1); - assert_eq!(ONE_CHECKED_MUL_ONE, Some(ONE)); - - const MAX_CHECKED_MUL_TWO : Option = MAX.checked_mul(2); - assert_eq!(MAX_CHECKED_MUL_TWO, None); - - const ONE_CHECKED_DIV_ONE : Option = ONE.checked_div(1); - assert_eq!(ONE_CHECKED_DIV_ONE, Some(ONE)); - - const ONE_CHECKED_DIV_ZERO : Option = ONE.checked_div(0); - assert_eq!(ONE_CHECKED_DIV_ZERO, None); - - const MAX_AS_F32 : f32 = MAX.as_secs_f32(); - assert_eq!(MAX_AS_F32, 18446744000000000000.0_f32); - - const MAX_AS_F64 : f64 = MAX.as_secs_f64(); - assert_eq!(MAX_AS_F64, 18446744073709552000.0_f64); - - const ONE_AS_F32 : f32 = ONE.div_duration_f32(ONE); - assert_eq!(ONE_AS_F32, 1.0_f32); - - const ONE_AS_F64 : f64 = ONE.div_duration_f64(ONE); - assert_eq!(ONE_AS_F64, 1.0_f64); - - const MAX_SATURATING_ADD_ONE : Duration = MAX.saturating_add(ONE); - assert_eq!(MAX_SATURATING_ADD_ONE, MAX); - - const ZERO_SATURATING_SUB_ONE : Duration = ZERO.saturating_sub(ONE); - assert_eq!(ZERO_SATURATING_SUB_ONE, ZERO); - - const MAX_SATURATING_MUL_TWO : Duration = MAX.saturating_mul(2); - assert_eq!(MAX_SATURATING_MUL_TWO, MAX); -} - -fn main() { - duration(); -} From 869021e2606de502ccd8920412f1988da0e40952 Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Sat, 12 Sep 2020 15:58:30 +0200 Subject: [PATCH 0335/1052] Add mailmap entry --- .mailmap | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.mailmap b/.mailmap index cc7b2a677baf6..fa0728bd79461 100644 --- a/.mailmap +++ b/.mailmap @@ -55,6 +55,9 @@ Chris C Cerami Chris C Cerami Chris Thorn Chris Thorn Chris Vittal Christopher Vittal +Christiaan Dirkx +Christiaan Dirkx CDirkx +Christiaan Dirkx CDirkx Christian Poveda Christian Poveda Christian Poveda From e788b1a2fe181124e480b5f841fa71c61b9857f0 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sat, 12 Sep 2020 10:05:10 -0400 Subject: [PATCH 0336/1052] Print all step timings It is really painful to inspect differences in what was built in CI if things are appearing and disappearing randomly as they hover around the 100ms mark. No matter what we choose there's always going to be quite a bit of variability on CI in timing, so we're going to see things appear and vanish. --- src/bootstrap/builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 844a29fadae1e..848edd8f37fd1 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -1424,7 +1424,7 @@ impl<'a> Builder<'a> { (out, dur - deps) }; - if self.config.print_step_timings && dur > Duration::from_millis(100) { + if self.config.print_step_timings { println!("[TIMING] {:?} -- {}.{:03}", step, dur.as_secs(), dur.subsec_millis()); } From 9c1389418e547e7feb0dc8f4cb42fbdcd1089467 Mon Sep 17 00:00:00 2001 From: SlightlyOutOfPhase Date: Sat, 12 Sep 2020 10:52:12 -0400 Subject: [PATCH 0337/1052] Fix `const-display.rs` XPATH queries (#1) * Fix `const-display.rs` XPATH queries * Add `issue_76501.rs` test file * Rename issue_76501.rs to issue-76501.rs --- src/test/rustdoc/const-display.rs | 6 +++--- src/test/rustdoc/issue-76501.rs | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 src/test/rustdoc/issue-76501.rs diff --git a/src/test/rustdoc/const-display.rs b/src/test/rustdoc/const-display.rs index c5016c650e5f6..b3fbe377f0b96 100644 --- a/src/test/rustdoc/const-display.rs +++ b/src/test/rustdoc/const-display.rs @@ -12,7 +12,7 @@ #[rustc_const_unstable(feature="foo", issue = "none")] pub const unsafe fn foo() -> u32 { 42 } -// @has 'foo/fn.foo2.html' '//pre' 'pub fn foo2() -> u32' +// @has 'foo/fn.foo2.html' '//pre' 'pub const fn foo2() -> u32' #[unstable(feature = "humans", issue = "none")] pub const fn foo2() -> u32 { 42 } @@ -21,7 +21,7 @@ pub const fn foo2() -> u32 { 42 } #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn bar2() -> u32 { 42 } -// @has 'foo/fn.foo2_gated.html' '//pre' 'pub unsafe fn foo2_gated() -> u32' +// @has 'foo/fn.foo2_gated.html' '//pre' 'pub const unsafe fn foo2_gated() -> u32' #[unstable(feature = "foo2", issue = "none")] pub const unsafe fn foo2_gated() -> u32 { 42 } @@ -30,7 +30,7 @@ pub const unsafe fn foo2_gated() -> u32 { 42 } #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const unsafe fn bar2_gated() -> u32 { 42 } -// @has 'foo/fn.bar_not_gated.html' '//pre' 'pub unsafe fn bar_not_gated() -> u32' +// @has 'foo/fn.bar_not_gated.html' '//pre' 'pub const unsafe fn bar_not_gated() -> u32' pub const unsafe fn bar_not_gated() -> u32 { 42 } pub struct Foo; diff --git a/src/test/rustdoc/issue-76501.rs b/src/test/rustdoc/issue-76501.rs new file mode 100644 index 0000000000000..e2755fc0358dd --- /dev/null +++ b/src/test/rustdoc/issue-76501.rs @@ -0,0 +1,18 @@ +#![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 { + 1 +} + +/// A struct. +pub struct Struct {} + +impl Struct { + // @has 'issue_76501/struct.Struct.html' '//*[@class="method"]' 'pub const fn bloop() -> i32' + /// A useless function that always returns 1. + pub const fn bloop() -> i32 { + 1 + } +} From aa68aaa8e1b6c667987b71a83c332f1ce0988e54 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 12 Sep 2020 17:11:47 +0200 Subject: [PATCH 0338/1052] Mark Once::new as #[inline]. Without this, it was not inlined in SyncOnceCell::into_inner(), causing unecessary checks and dead code. --- library/std/src/sync/once.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs index 8fed369bffc27..29ae338cb2ec7 100644 --- a/library/std/src/sync/once.rs +++ b/library/std/src/sync/once.rs @@ -191,6 +191,7 @@ struct WaiterQueue<'a> { impl Once { /// Creates a new `Once` value. + #[inline] #[stable(feature = "once_new", since = "1.2.0")] #[rustc_const_stable(feature = "const_once_new", since = "1.32.0")] pub const fn new() -> Once { From 8a1288be747bf3a777997e260e3788f27984f93a Mon Sep 17 00:00:00 2001 From: SlightlyOutOfPhase Date: Sat, 12 Sep 2020 11:24:19 -0400 Subject: [PATCH 0339/1052] Give functions unique names --- src/test/rustdoc/issue-76501.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/rustdoc/issue-76501.rs b/src/test/rustdoc/issue-76501.rs index e2755fc0358dd..605059fe0dd8d 100644 --- a/src/test/rustdoc/issue-76501.rs +++ b/src/test/rustdoc/issue-76501.rs @@ -10,9 +10,9 @@ pub const fn bloop() -> i32 { pub struct Struct {} impl Struct { - // @has 'issue_76501/struct.Struct.html' '//*[@class="method"]' 'pub const fn bloop() -> i32' + // @has 'issue_76501/struct.Struct.html' '//*[@class="method"]' 'pub const fn blurp() -> i32' /// A useless function that always returns 1. - pub const fn bloop() -> i32 { + pub const fn blurp() -> i32 { 1 } } From 4f0047ed108889ea97ad7656307a8a829dd56636 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 12 Sep 2020 18:35:32 +0200 Subject: [PATCH 0340/1052] Add a comment on is_trivially_sized about obviously !Sized types --- compiler/rustc_middle/src/ty/sty.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 9f5fc5a2d3fbc..825221c22a8c1 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2280,6 +2280,12 @@ impl<'tcx> TyS<'tcx> { /// /// Returning true means the type is known to be sized. Returning /// `false` means nothing -- could be sized, might not be. + /// + /// Note that we could never rely on the fact that a type such as `[_]` is + /// trivially `!Sized` because we could be in a type environment with a + /// bound such as `[_]: Copy`. A function with such a bound obviously never + /// can be called, but that doesn't mean it shouldn't typecheck. This is why + /// this method doesn't return `Option`. pub fn is_trivially_sized(&self, tcx: TyCtxt<'tcx>) -> bool { match self.kind() { ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) From 75f0f7af3172cedaa01e9bf066c06017bfe9a426 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 12 Sep 2020 13:27:57 +0200 Subject: [PATCH 0341/1052] Fix a typo --- src/librustdoc/clean/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1bdbad4675556..00f27bb51ed21 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -839,7 +839,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, ty::GenericPredicates<'tcx let mut where_predicates = where_predicates.into_iter().flat_map(|p| p.clean(cx)).collect::>(); - // Type parameters and have a Sized bound by default unless removed with + // Type parameters have a Sized bound by default unless removed with // ?Sized. Scan through the predicates and mark any type parameter with // a Sized bound, removing the bounds as we find them. // From caf6c92d19216d75bf248643a11df77a598293e7 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 12 Sep 2020 13:30:21 +0200 Subject: [PATCH 0342/1052] Clean up some language trait items comparisons --- .../src/traits/error_reporting/mod.rs | 7 +------ compiler/rustc_traits/src/chalk/db.rs | 20 +++++-------------- 2 files changed, 6 insertions(+), 21 deletions(-) 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 dcd8379803319..611280b413dd7 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1507,12 +1507,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { // avoid inundating the user with unnecessary errors, but we now // check upstream for type errors and don't add the obligations to // begin with in those cases. - if self - .tcx - .lang_items() - .sized_trait() - .map_or(false, |sized_id| sized_id == trait_ref.def_id()) - { + if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) { self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0282).emit(); return; } diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index 7cc567dabb28f..2fad54013ad5b 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -110,25 +110,15 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t .map(|i| chalk_ir::AssocTypeId(i.def_id)) .collect(); - let well_known = if self - .interner - .tcx - .lang_items() - .sized_trait() - .map(|t| def_id == t) - .unwrap_or(false) - { + let well_known = if self.interner.tcx.lang_items().sized_trait() == Some(def_id) { Some(chalk_solve::rust_ir::WellKnownTrait::Sized) - } else if self.interner.tcx.lang_items().copy_trait().map(|t| def_id == t).unwrap_or(false) - { + } else if self.interner.tcx.lang_items().copy_trait() == Some(def_id) { Some(chalk_solve::rust_ir::WellKnownTrait::Copy) - } else if self.interner.tcx.lang_items().clone_trait().map(|t| def_id == t).unwrap_or(false) - { + } else if self.interner.tcx.lang_items().clone_trait() == Some(def_id) { Some(chalk_solve::rust_ir::WellKnownTrait::Clone) - } else if self.interner.tcx.lang_items().drop_trait().map(|t| def_id == t).unwrap_or(false) - { + } else if self.interner.tcx.lang_items().drop_trait() == Some(def_id) { Some(chalk_solve::rust_ir::WellKnownTrait::Drop) - } else if self.interner.tcx.lang_items().fn_trait().map(|t| def_id == t).unwrap_or(false) { + } else if self.interner.tcx.lang_items().fn_trait() == Some(def_id) { Some(chalk_solve::rust_ir::WellKnownTrait::Fn) } else if self .interner From 2e7ca7329966b9a86b4d35689cb719883dcda4e8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 12 Sep 2020 14:30:27 +0200 Subject: [PATCH 0343/1052] Don't emit an error on private doc tests when they're ignored --- src/librustdoc/passes/doc_test_lints.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/librustdoc/passes/doc_test_lints.rs b/src/librustdoc/passes/doc_test_lints.rs index cbbe86dc433f3..78af9f9b8561a 100644 --- a/src/librustdoc/passes/doc_test_lints.rs +++ b/src/librustdoc/passes/doc_test_lints.rs @@ -8,7 +8,7 @@ use crate::clean; use crate::clean::*; use crate::core::DocContext; use crate::fold::DocFolder; -use crate::html::markdown::{find_testable_code, ErrorCodes, LangString}; +use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString}; use rustc_session::lint; pub const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass { @@ -48,15 +48,11 @@ pub(crate) struct Tests { pub(crate) found_tests: usize, } -impl Tests { - pub(crate) fn new() -> Tests { - Tests { found_tests: 0 } - } -} - impl crate::doctest::Tester for Tests { - fn add_test(&mut self, _: String, _: LangString, _: usize) { - self.found_tests += 1; + fn add_test(&mut self, _: String, config: LangString, _: usize) { + if config.rust && config.ignore == Ignore::None { + self.found_tests += 1; + } } } @@ -85,7 +81,7 @@ pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { } }; - let mut tests = Tests::new(); + let mut tests = Tests { found_tests: 0 }; find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None); From 15d25a8a7272708cd841c90884f7d3626af9b6a9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 12 Sep 2020 14:30:40 +0200 Subject: [PATCH 0344/1052] Add test for ignored private doc test --- src/test/rustdoc-ui/coverage/doc-examples.stdout | 4 ++-- src/test/rustdoc-ui/private-doc-test.rs | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 src/test/rustdoc-ui/private-doc-test.rs diff --git a/src/test/rustdoc-ui/coverage/doc-examples.stdout b/src/test/rustdoc-ui/coverage/doc-examples.stdout index 10ed13c9ff566..8188740f8739b 100644 --- a/src/test/rustdoc-ui/coverage/doc-examples.stdout +++ b/src/test/rustdoc-ui/coverage/doc-examples.stdout @@ -1,7 +1,7 @@ +-------------------------------------+------------+------------+------------+------------+ | File | Documented | Percentage | Examples | Percentage | +-------------------------------------+------------+------------+------------+------------+ -| ...tdoc-ui/coverage/doc-examples.rs | 4 | 100.0% | 2 | 50.0% | +| ...tdoc-ui/coverage/doc-examples.rs | 4 | 100.0% | 1 | 25.0% | +-------------------------------------+------------+------------+------------+------------+ -| Total | 4 | 100.0% | 2 | 50.0% | +| Total | 4 | 100.0% | 1 | 25.0% | +-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/private-doc-test.rs b/src/test/rustdoc-ui/private-doc-test.rs new file mode 100644 index 0000000000000..379fa45f9fa3e --- /dev/null +++ b/src/test/rustdoc-ui/private-doc-test.rs @@ -0,0 +1,12 @@ +// check-pass + +#![deny(private_doc_tests)] + +mod foo { + /// private doc test + /// + /// ```ignore (used for testing ignored doc tests) + /// assert!(false); + /// ``` + fn bar() {} +} From 1016deb592cec6d02e963bb3ffbfbb2c4f9309b8 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 12 Sep 2020 20:50:17 +0200 Subject: [PATCH 0345/1052] Small cleanups in Windows Mutex. - Move `held` into the boxed part, since the SRW lock implementation does not use this. This makes the Mutex 50% smaller. - Use `Cell` instead of `UnsafeCell` for `held`, such that `.replace()` can be used. - Add some comments. --- library/std/src/sys/windows/mutex.rs | 64 ++++++++++++++-------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/library/std/src/sys/windows/mutex.rs b/library/std/src/sys/windows/mutex.rs index 63dfc640908e9..f2c57025a55ba 100644 --- a/library/std/src/sys/windows/mutex.rs +++ b/library/std/src/sys/windows/mutex.rs @@ -19,20 +19,25 @@ //! CriticalSection is used and we keep track of who's holding the mutex to //! detect recursive locks. -use crate::cell::UnsafeCell; +use crate::cell::{Cell, UnsafeCell}; use crate::mem::{self, MaybeUninit}; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sys::c; use crate::sys::compat; pub struct Mutex { + // This is either directly an SRWLOCK (if supported), or a Box otherwise. lock: AtomicUsize, - held: UnsafeCell, } unsafe impl Send for Mutex {} unsafe impl Sync for Mutex {} +struct Inner { + remutex: ReentrantMutex, + held: Cell, +} + #[derive(Clone, Copy)] enum Kind { SRWLock = 1, @@ -51,7 +56,6 @@ impl Mutex { // This works because SRWLOCK_INIT is 0 (wrapped in a struct), so we are also properly // initializing an SRWLOCK here. lock: AtomicUsize::new(0), - held: UnsafeCell::new(false), } } #[inline] @@ -60,10 +64,11 @@ impl Mutex { match kind() { Kind::SRWLock => c::AcquireSRWLockExclusive(raw(self)), Kind::CriticalSection => { - let re = self.remutex(); - (*re).lock(); - if !self.flag_locked() { - (*re).unlock(); + let inner = &mut *self.inner(); + inner.remutex.lock(); + if inner.held.replace(true) { + // It was already locked, so we got a recursive lock which we do not want. + inner.remutex.unlock(); panic!("cannot recursively lock a mutex"); } } @@ -73,23 +78,27 @@ impl Mutex { match kind() { Kind::SRWLock => c::TryAcquireSRWLockExclusive(raw(self)) != 0, Kind::CriticalSection => { - let re = self.remutex(); - if !(*re).try_lock() { + let inner = &mut *self.inner(); + if !inner.remutex.try_lock() { false - } else if self.flag_locked() { - true - } else { - (*re).unlock(); + } else if inner.held.replace(true) { + // It was already locked, so we got a recursive lock which we do not want. + inner.remutex.unlock(); false + } else { + true } } } } pub unsafe fn unlock(&self) { - *self.held.get() = false; match kind() { Kind::SRWLock => c::ReleaseSRWLockExclusive(raw(self)), - Kind::CriticalSection => (*self.remutex()).unlock(), + Kind::CriticalSection => { + let inner = &mut *(self.lock.load(Ordering::SeqCst) as *mut Inner); + inner.held.set(false); + inner.remutex.unlock(); + } } } pub unsafe fn destroy(&self) { @@ -98,37 +107,28 @@ impl Mutex { Kind::CriticalSection => match self.lock.load(Ordering::SeqCst) { 0 => {} n => { - Box::from_raw(n as *mut ReentrantMutex).destroy(); + Box::from_raw(n as *mut Inner).remutex.destroy(); } }, } } - unsafe fn remutex(&self) -> *mut ReentrantMutex { + unsafe fn inner(&self) -> *mut Inner { match self.lock.load(Ordering::SeqCst) { 0 => {} n => return n as *mut _, } - let re = box ReentrantMutex::uninitialized(); - re.init(); - let re = Box::into_raw(re); - match self.lock.compare_and_swap(0, re as usize, Ordering::SeqCst) { - 0 => re, + let inner = box Inner { remutex: ReentrantMutex::uninitialized(), held: Cell::new(false) }; + inner.remutex.init(); + let inner = Box::into_raw(inner); + match self.lock.compare_and_swap(0, inner as usize, Ordering::SeqCst) { + 0 => inner, n => { - Box::from_raw(re).destroy(); + Box::from_raw(inner).remutex.destroy(); n as *mut _ } } } - - unsafe fn flag_locked(&self) -> bool { - if *self.held.get() { - false - } else { - *self.held.get() = true; - true - } - } } fn kind() -> Kind { From a7b092f4188e927b3456fe6fe5ee2bd72c53cb57 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 4 Sep 2020 19:00:04 -0400 Subject: [PATCH 0346/1052] Download LLVM from CI to bootstrap --- config.toml.example | 15 ++++++ src/bootstrap/bootstrap.py | 107 ++++++++++++++++++++++++++++--------- src/bootstrap/config.rs | 57 ++++++++++++++++++++ src/bootstrap/dist.rs | 34 +++++++----- src/bootstrap/lib.rs | 4 ++ 5 files changed, 179 insertions(+), 38 deletions(-) diff --git a/config.toml.example b/config.toml.example index 2d5b3136450b9..b50406a9579f9 100644 --- a/config.toml.example +++ b/config.toml.example @@ -14,6 +14,21 @@ # ============================================================================= [llvm] +# Whether to use Rust CI built LLVM instead of locally building it. +# +# Unless you're developing for a target where Rust CI doesn't build a compiler +# toolchain or changing LLVM locally, you probably want to set this to true. +# +# It's currently false by default due to being newly added; please file bugs if +# enabling this did not work for you on Linux (macOS and Windows support is +# coming soon). +# +# We also currently only support this when building LLVM for the build triple. +# +# Note that many of the LLVM options are not currently supported for +# downloading. Currently only the "assertions" option can be toggled. +#download-ci-llvm = false + # Indicates whether LLVM rebuild should be skipped when running bootstrap. If # this is `false` then the compiler's LLVM will be rebuilt whenever the built # version doesn't have the correct hash. If it is `true` then LLVM will never diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 955c72856dcfa..44a17f75451a9 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -14,8 +14,17 @@ from time import time - -def get(url, path, verbose=False): +def support_xz(): + try: + with tempfile.NamedTemporaryFile(delete=False) as temp_file: + temp_path = temp_file.name + with tarfile.open(temp_path, "w:xz"): + pass + return True + except tarfile.CompressionError: + return False + +def get(url, path, verbose=False, do_verify=True): suffix = '.sha256' sha_url = url + suffix with tempfile.NamedTemporaryFile(delete=False) as temp_file: @@ -24,19 +33,20 @@ def get(url, path, verbose=False): sha_path = sha_file.name try: - download(sha_path, sha_url, False, verbose) - if os.path.exists(path): - if verify(path, sha_path, False): - if verbose: - print("using already-download file", path) - return - else: - if verbose: - print("ignoring already-download file", - path, "due to failed verification") - os.unlink(path) + if do_verify: + download(sha_path, sha_url, False, verbose) + if os.path.exists(path): + if verify(path, sha_path, False): + if verbose: + print("using already-download file", path) + return + else: + if verbose: + print("ignoring already-download file", + path, "due to failed verification") + os.unlink(path) download(temp_path, url, True, verbose) - if not verify(temp_path, sha_path, verbose): + if do_verify and not verify(temp_path, sha_path, verbose): raise RuntimeError("failed verification") if verbose: print("moving {} to {}".format(temp_path, path)) @@ -365,16 +375,6 @@ def download_stage0(self): cargo_channel = self.cargo_channel rustfmt_channel = self.rustfmt_channel - def support_xz(): - try: - with tempfile.NamedTemporaryFile(delete=False) as temp_file: - temp_path = temp_file.name - with tarfile.open(temp_path, "w:xz"): - pass - return True - except tarfile.CompressionError: - return False - if self.rustc().startswith(self.bin_root()) and \ (not os.path.exists(self.rustc()) or self.program_out_of_date(self.rustc_stamp())): @@ -423,6 +423,19 @@ def support_xz(): with output(self.rustfmt_stamp()) as rustfmt_stamp: rustfmt_stamp.write(self.date + self.rustfmt_channel) + if self.downloading_llvm(): + llvm_sha = subprocess.check_output(["git", "log", "--author=bors", + "--format=%H", "-n1"]).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)): + self._download_ci_llvm(llvm_sha, llvm_assertions) + with output(self.llvm_stamp()) as llvm_stamp: + llvm_stamp.write(self.date + llvm_sha + str(llvm_assertions)) + + def downloading_llvm(self): + opt = self.get_toml('download-ci-llvm', 'llvm') + return opt == "true" + def _download_stage0_helper(self, filename, pattern, tarball_suffix, date=None): if date is None: date = self.date @@ -437,6 +450,25 @@ def _download_stage0_helper(self, filename, pattern, tarball_suffix, date=None): get("{}/{}".format(url, filename), tarball, verbose=self.verbose) unpack(tarball, tarball_suffix, self.bin_root(), match=pattern, verbose=self.verbose) + def _download_ci_llvm(self, llvm_sha, llvm_assertions): + cache_prefix = "llvm-{}-{}".format(llvm_sha, llvm_assertions) + cache_dst = os.path.join(self.build_dir, "cache") + rustc_cache = os.path.join(cache_dst, cache_prefix) + if not os.path.exists(rustc_cache): + os.makedirs(rustc_cache) + + url = "https://ci-artifacts.rust-lang.org/rustc-builds/{}".format(llvm_sha) + if llvm_assertions: + url = url.replace('rustc-builds', 'rustc-builds-alt') + tarball_suffix = '.tar.xz' if support_xz() else '.tar.gz' + filename = "rust-dev-nightly-" + self.build + tarball_suffix + tarball = os.path.join(rustc_cache, filename) + if not os.path.exists(tarball): + get("{}/{}".format(url, filename), tarball, verbose=self.verbose, do_verify=False) + unpack(tarball, tarball_suffix, self.llvm_root(), + match="rust-dev", + verbose=self.verbose) + def fix_bin_or_dylib(self, fname): """Modifies the interpreter section of 'fname' to fix the dynamic linker, or the RPATH section, to fix the dynamic library search path @@ -558,6 +590,17 @@ def rustfmt_stamp(self): """ return os.path.join(self.bin_root(), '.rustfmt-stamp') + def llvm_stamp(self): + """Return the path for .rustfmt-stamp + + >>> rb = RustBuild() + >>> rb.build_dir = "build" + >>> rb.llvm_stamp() == os.path.join("build", "ci-llvm", ".llvm-stamp") + True + """ + return os.path.join(self.llvm_root(), '.llvm-stamp') + + def program_out_of_date(self, stamp_path, extra=""): """Check if the given program stamp is out of date""" if not os.path.exists(stamp_path) or self.clean: @@ -581,6 +624,22 @@ def bin_root(self): """ return os.path.join(self.build_dir, self.build, "stage0") + def llvm_root(self): + """Return the CI LLVM root directory + + >>> rb = RustBuild() + >>> rb.build_dir = "build" + >>> rb.llvm_root() == os.path.join("build", "ci-llvm") + True + + When the 'build' property is given should be a nested directory: + + >>> rb.build = "devel" + >>> rb.llvm_root() == os.path.join("build", "devel", "ci-llvm") + True + """ + return os.path.join(self.build_dir, self.build, "ci-llvm") + def get_toml(self, key, section=None): """Returns the value of the given key in config.toml, otherwise returns None diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 5a79d3db5c905..d889d04fa6fc4 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -15,9 +15,20 @@ use std::process; use crate::cache::{Interned, INTERNER}; use crate::flags::Flags; pub use crate::flags::Subcommand; +use crate::util::exe; use build_helper::t; use serde::Deserialize; +macro_rules! check_ci_llvm { + ($name:expr) => { + assert!( + $name.is_none(), + "setting {} is incompatible with download-ci-llvm.", + stringify!($name) + ); + }; +} + /// Global configuration for the entire build and/or bootstrap. /// /// This structure is derived from a combination of both `config.toml` and @@ -84,6 +95,7 @@ pub struct Config { pub llvm_version_suffix: Option, pub llvm_use_linker: Option, pub llvm_allow_old_toolchain: Option, + pub llvm_from_ci: bool, pub use_lld: bool, pub lld_enabled: bool, @@ -344,6 +356,7 @@ struct Llvm { use_libcxx: Option, use_linker: Option, allow_old_toolchain: Option, + download_ci_llvm: Option, } #[derive(Deserialize, Default, Clone)] @@ -624,6 +637,36 @@ impl Config { set(&mut config.llvm_use_libcxx, llvm.use_libcxx); config.llvm_use_linker = llvm.use_linker.clone(); config.llvm_allow_old_toolchain = llvm.allow_old_toolchain; + config.llvm_from_ci = llvm.download_ci_llvm.unwrap_or(false); + + if config.llvm_from_ci { + // None of the LLVM options, except assertions, are supported + // when using downloaded LLVM. We could just ignore these but + // that's potentially confusing, so force them to not be + // explicitly set. The defaults and CI defaults don't + // necessarily match but forcing people to match (somewhat + // arbitrary) CI configuration locally seems bad/hard. + check_ci_llvm!(llvm.optimize); + check_ci_llvm!(llvm.thin_lto); + check_ci_llvm!(llvm.release_debuginfo); + check_ci_llvm!(llvm.link_shared); + check_ci_llvm!(llvm.static_libstdcpp); + check_ci_llvm!(llvm.targets); + check_ci_llvm!(llvm.experimental_targets); + check_ci_llvm!(llvm.link_jobs); + check_ci_llvm!(llvm.link_shared); + check_ci_llvm!(llvm.clang_cl); + check_ci_llvm!(llvm.version_suffix); + check_ci_llvm!(llvm.cflags); + check_ci_llvm!(llvm.cxxflags); + check_ci_llvm!(llvm.ldflags); + check_ci_llvm!(llvm.use_libcxx); + check_ci_llvm!(llvm.use_linker); + check_ci_llvm!(llvm.allow_old_toolchain); + + // CI-built LLVM is shared + config.llvm_link_shared = true; + } } if let Some(ref rust) = toml.rust { @@ -706,6 +749,20 @@ impl Config { } } + if config.llvm_from_ci { + let triple = &config.build.triple; + let mut build_target = config + .target_config + .entry(config.build) + .or_insert_with(|| Target::from_triple(&triple)); + + check_ci_llvm!(build_target.llvm_config); + check_ci_llvm!(build_target.llvm_filecheck); + let ci_llvm_bin = config.out.join(&*config.build.triple).join("ci-llvm/bin"); + build_target.llvm_config = Some(ci_llvm_bin.join(exe("llvm-config", config.build))); + build_target.llvm_filecheck = Some(ci_llvm_bin.join(exe("FileCheck", config.build))); + } + if let Some(ref t) = toml.dist { config.dist_sign_folder = t.sign_folder.clone().map(PathBuf::from); config.dist_gpg_password_file = t.gpg_password_file.clone().map(PathBuf::from); diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index e22cdb1392836..cf73e570fa56f 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -2382,26 +2382,32 @@ impl Step for HashSign { /// Note: This function does not yet support Windows, but we also don't support /// linking LLVM tools dynamically on Windows yet. fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir: &Path) { - let src_libdir = builder.llvm_out(target).join("lib"); + if !builder.config.llvm_link_shared { + // We do not need to copy LLVM files into the sysroot if it is not + // dynamically linked; it is already included into librustc_llvm + // statically. + return; + } + // On macOS for some reason the llvm-config binary behaves differently and + // and fails on missing .a files if run without --link-shared. If run with + // that option, it still fails, but because we only ship a libLLVM.dylib + // rather than libLLVM-11-rust-....dylib file. + // + // For now just don't use llvm-config here on macOS; that will fail to + // support CI-built LLVM, but until we work out the different behavior that + // is fine as it is off by default. if target.contains("apple-darwin") { + let src_libdir = builder.llvm_out(target).join("lib"); let llvm_dylib_path = src_libdir.join("libLLVM.dylib"); if llvm_dylib_path.exists() { builder.install(&llvm_dylib_path, dst_libdir, 0o644); } - return; - } - - // Usually libLLVM.so is a symlink to something like libLLVM-6.0.so. - // Since tools link to the latter rather than the former, we have to - // follow the symlink to find out what to distribute. - let llvm_dylib_path = src_libdir.join("libLLVM.so"); - if llvm_dylib_path.exists() { - let llvm_dylib_path = llvm_dylib_path.canonicalize().unwrap_or_else(|e| { - panic!("dist: Error calling canonicalize path `{}`: {}", llvm_dylib_path.display(), e); - }); - - builder.install(&llvm_dylib_path, dst_libdir, 0o644); + } else if let Ok(llvm_config) = crate::native::prebuilt_llvm_config(builder, target) { + let files = output(Command::new(llvm_config).arg("--libfiles")); + for file in files.lines() { + builder.install(Path::new(file), dst_libdir, 0o644); + } } } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index f0224d88226fb..170c93561ef7f 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -611,6 +611,10 @@ impl Build { /// /// If no custom `llvm-config` was specified then Rust's llvm will be used. fn is_rust_llvm(&self, target: TargetSelection) -> bool { + if self.config.llvm_from_ci && target == self.config.build { + return true; + } + match self.config.target_config.get(&target) { Some(ref c) => c.llvm_config.is_none(), None => true, From 2e87a6e78dacad9c4acc5fe4fc8bf5aa1ca44a51 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sat, 12 Sep 2020 15:10:13 -0400 Subject: [PATCH 0347/1052] Set link-shared if LLVM ThinLTO is enabled in config.rs This avoids missing a shared build when uplifting LLVM artifacts into the sysroot. We were already producing a shared link anyway, though, so this is not a visible change from the end user's perspective. --- src/bootstrap/compile.rs | 2 +- src/bootstrap/config.rs | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index e0dddda83b98f..08907edef1d1e 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -593,7 +593,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS let file = compiler_file(builder, builder.cxx(target).unwrap(), target, "libstdc++.a"); cargo.env("LLVM_STATIC_STDCPP", file); } - if builder.config.llvm_link_shared || builder.config.llvm_thin_lto { + if builder.config.llvm_link_shared { cargo.env("LLVM_LINK_SHARED", "1"); } if builder.config.llvm_use_libcxx { diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index d889d04fa6fc4..000f8cef61492 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -667,6 +667,13 @@ impl Config { // CI-built LLVM is shared config.llvm_link_shared = true; } + + if config.llvm_thin_lto { + // If we're building with ThinLTO on, we want to link to LLVM + // shared, to avoid re-doing ThinLTO (which happens in the link + // step) with each stage. + config.llvm_link_shared = true; + } } if let Some(ref rust) = toml.rust { From 2eeb8f18eb493a8ec3b830aabb3e7f1723953bc0 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 12 Sep 2020 15:47:52 -0400 Subject: [PATCH 0348/1052] Remove Windows details from Unix and VmWorks symlink() docstrings This note is not relevant to other operating systems. --- library/std/src/sys/unix/ext/fs.rs | 9 --------- library/std/src/sys/vxworks/ext/fs.rs | 9 --------- 2 files changed, 18 deletions(-) diff --git a/library/std/src/sys/unix/ext/fs.rs b/library/std/src/sys/unix/ext/fs.rs index 487ac266ee9cd..4b9f4ceb29c49 100644 --- a/library/std/src/sys/unix/ext/fs.rs +++ b/library/std/src/sys/unix/ext/fs.rs @@ -836,15 +836,6 @@ impl DirEntryExt for fs::DirEntry { /// /// The `dst` path will be a symbolic link pointing to the `src` path. /// -/// # Note -/// -/// On Windows, you must specify whether a symbolic link points to a file -/// or directory. Use `os::windows::fs::symlink_file` to create a -/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a -/// symbolic link to a directory. Additionally, the process must have -/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a -/// symbolic link. -/// /// # Examples /// /// ```no_run diff --git a/library/std/src/sys/vxworks/ext/fs.rs b/library/std/src/sys/vxworks/ext/fs.rs index 9b4c64bdb6d84..68dc21b806c0f 100644 --- a/library/std/src/sys/vxworks/ext/fs.rs +++ b/library/std/src/sys/vxworks/ext/fs.rs @@ -774,15 +774,6 @@ impl DirEntryExt for fs::DirEntry { /// /// The `dst` path will be a symbolic link pointing to the `src` path. /// -/// # Note -/// -/// On Windows, you must specify whether a symbolic link points to a file -/// or directory. Use `os::windows::fs::symlink_file` to create a -/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a -/// symbolic link to a directory. Additionally, the process must have -/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a -/// symbolic link. -/// /// # Examples /// /// ```no_run From 8f27e3cb1b4140d9124d60df0850ef734e73b884 Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Sun, 13 Sep 2020 01:55:34 +0200 Subject: [PATCH 0349/1052] Make some methods of `Pin` unstable const Make the following methods unstable const under the `const_pin` feature: - `new` - `new_unchecked` - `into_inner` - `into_inner_unchecked` - `get_ref` - `into_ref` Also adds tests for these methods in a const context. Tracking issue: #76654 --- library/core/src/lib.rs | 1 + library/core/src/pin.rs | 27 ++++++++++++++++----------- library/core/tests/lib.rs | 2 ++ library/core/tests/pin.rs | 21 +++++++++++++++++++++ 4 files changed, 40 insertions(+), 11 deletions(-) create mode 100644 library/core/tests/pin.rs diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index c3cadcbb01e31..696b6a64a9fec 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -80,6 +80,7 @@ #![feature(const_int_pow)] #![feature(constctlz)] #![feature(const_panic)] +#![feature(const_pin)] #![feature(const_fn_union)] #![feature(const_generics)] #![feature(const_option)] diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 1cc1dfb014335..fa5b37edc36e6 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -471,9 +471,10 @@ impl> Pin

{ /// /// Unlike `Pin::new_unchecked`, this method is safe because the pointer /// `P` dereferences to an [`Unpin`] type, which cancels the pinning guarantees. - #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn new(pointer: P) -> Pin

{ + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + #[stable(feature = "pin", since = "1.33.0")] + pub const fn new(pointer: P) -> Pin

{ // SAFETY: the value pointed to is `Unpin`, and so has no requirements // around pinning. unsafe { Pin::new_unchecked(pointer) } @@ -483,9 +484,10 @@ impl> Pin

{ /// /// This requires that the data inside this `Pin` is [`Unpin`] so that we /// can ignore the pinning invariants when unwrapping it. - #[stable(feature = "pin_into_inner", since = "1.39.0")] #[inline(always)] - pub fn into_inner(pin: Pin

) -> P { + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + #[stable(feature = "pin_into_inner", since = "1.39.0")] + pub const fn into_inner(pin: Pin

) -> P { pin.pointer } } @@ -556,9 +558,10 @@ impl Pin

{ /// /// [`mem::swap`]: crate::mem::swap #[lang = "new_unchecked"] - #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub unsafe fn new_unchecked(pointer: P) -> Pin

{ + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + #[stable(feature = "pin", since = "1.33.0")] + pub const unsafe fn new_unchecked(pointer: P) -> Pin

{ Pin { pointer } } @@ -589,9 +592,10 @@ impl Pin

{ /// /// If the underlying data is [`Unpin`], [`Pin::into_inner`] should be used /// instead. - #[stable(feature = "pin_into_inner", since = "1.39.0")] #[inline(always)] - pub unsafe fn into_inner_unchecked(pin: Pin

) -> P { + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + #[stable(feature = "pin_into_inner", since = "1.39.0")] + pub const unsafe fn into_inner_unchecked(pin: Pin

) -> P { pin.pointer } } @@ -693,17 +697,18 @@ impl<'a, T: ?Sized> Pin<&'a T> { /// with the same lifetime as the original `Pin`. /// /// ["pinning projections"]: self#projections-and-structural-pinning - #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn get_ref(self) -> &'a T { + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + #[stable(feature = "pin", since = "1.33.0")] + pub const fn get_ref(self) -> &'a T { self.pointer } } impl<'a, T: ?Sized> Pin<&'a mut T> { /// Converts this `Pin<&mut T>` into a `Pin<&T>` with the same lifetime. - #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] + #[stable(feature = "pin", since = "1.33.0")] pub fn into_ref(self) -> Pin<&'a T> { Pin { pointer: self.pointer } } diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index a2e294ace1860..b8d67d7266543 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -39,6 +39,7 @@ #![feature(iter_order_by)] #![feature(cmp_min_max_by)] #![feature(iter_map_while)] +#![feature(const_pin)] #![feature(const_slice_from_raw_parts)] #![feature(const_raw_ptr_deref)] #![feature(never_type)] @@ -74,6 +75,7 @@ mod num; mod ops; mod option; mod pattern; +mod pin; mod ptr; mod result; mod slice; diff --git a/library/core/tests/pin.rs b/library/core/tests/pin.rs new file mode 100644 index 0000000000000..1363353163829 --- /dev/null +++ b/library/core/tests/pin.rs @@ -0,0 +1,21 @@ +use core::pin::Pin; + +#[test] +fn pin_const() { + // test that the methods of `Pin` are usable in a const context + + const POINTER: &'static usize = &2; + + const PINNED: Pin<&'static usize> = Pin::new(POINTER); + const PINNED_UNCHECKED: Pin<&'static usize> = unsafe { Pin::new_unchecked(POINTER) }; + assert_eq!(PINNED_UNCHECKED, PINNED); + + const INNER: &'static usize = Pin::into_inner(PINNED); + assert_eq!(INNER, POINTER); + + const INNER_UNCHECKED: &'static usize = unsafe { Pin::into_inner_unchecked(PINNED) }; + assert_eq!(INNER_UNCHECKED, POINTER); + + const REF: &'static usize = PINNED.get_ref(); + assert_eq!(REF, POINTER) +} From a447c21afaa00cc047e70fe4205c33c2dc4aa2cb Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 13 Sep 2020 01:58:17 +0200 Subject: [PATCH 0350/1052] Don't query unstable data when `staged_api` is off --- Cargo.lock | 1 + compiler/rustc_metadata/Cargo.toml | 1 + compiler/rustc_metadata/src/rmeta/encoder.rs | 20 ++++++++++++++++---- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b448baf425baa..9eab4ec10b418 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3703,6 +3703,7 @@ dependencies = [ "rustc_data_structures", "rustc_errors", "rustc_expand", + "rustc_feature", "rustc_hir", "rustc_hir_pretty", "rustc_index", diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index 4b144f94ea70b..f1975e78801ef 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -17,6 +17,7 @@ rustc_middle = { path = "../rustc_middle" } rustc_attr = { path = "../rustc_attr" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } +rustc_feature = { path = "../rustc_feature" } rustc_hir = { path = "../rustc_hir" } rustc_hir_pretty = { path = "../rustc_hir_pretty" } rustc_target = { path = "../rustc_target" } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index deca80f590f2f..8287666d435f8 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -40,6 +40,7 @@ use tracing::{debug, trace}; pub(super) struct EncodeContext<'a, 'tcx> { opaque: opaque::Encoder, tcx: TyCtxt<'tcx>, + feat: &'tcx rustc_feature::Features, tables: TableBuilders<'tcx>, @@ -1132,15 +1133,25 @@ impl EncodeContext<'a, 'tcx> { fn encode_stability(&mut self, def_id: DefId) { debug!("EncodeContext::encode_stability({:?})", def_id); - if let Some(stab) = self.tcx.lookup_stability(def_id) { - record!(self.tables.stability[def_id] <- stab) + + // The query lookup can take a measurable amount of time in crates with many items. Check if + // the stability attributes are even enabled before using their queries. + if self.feat.staged_api || self.tcx.sess.opts.debugging_opts.force_unstable_if_unmarked { + if let Some(stab) = self.tcx.lookup_stability(def_id) { + record!(self.tables.stability[def_id] <- stab) + } } } fn encode_const_stability(&mut self, def_id: DefId) { debug!("EncodeContext::encode_const_stability({:?})", def_id); - if let Some(stab) = self.tcx.lookup_const_stability(def_id) { - record!(self.tables.const_stability[def_id] <- stab) + + // The query lookup can take a measurable amount of time in crates with many items. Check if + // the stability attributes are even enabled before using their queries. + if self.feat.staged_api || self.tcx.sess.opts.debugging_opts.force_unstable_if_unmarked { + if let Some(stab) = self.tcx.lookup_const_stability(def_id) { + record!(self.tables.const_stability[def_id] <- stab) + } } } @@ -1979,6 +1990,7 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata { let mut ecx = EncodeContext { opaque: encoder, tcx, + feat: tcx.features(), tables: Default::default(), lazy_state: LazyState::NoNode, type_shorthands: Default::default(), From a67d248b13e8ac6f83df8994f59e7b89f064339e Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 12 Sep 2020 23:26:17 -0400 Subject: [PATCH 0351/1052] Properly encode spans with a dummy location and non-root `SyntaxContext` Previously, we would throw away the `SyntaxContext` of any span with a dummy location during metadata encoding. This commit makes metadata Span encoding consistent with incr-cache Span encoding - an 'invalid span' tag is only used when it doesn't lose any information. --- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- .../capture-macro-rules-invoke.stdout | 44 ++++----- .../dollar-crate-issue-57089.stdout | 32 +++---- .../dollar-crate-issue-62325.stdout | 44 ++++----- src/test/ui/proc-macro/dollar-crate.stdout | 96 +++++++++---------- .../group-compat-hack.stdout | 12 +-- .../ui/proc-macro/input-interpolated.stdout | 22 ++--- .../ui/proc-macro/meta-macro-hygiene.stdout | 26 ++--- src/test/ui/proc-macro/meta-macro.stdout | 2 +- .../ui/proc-macro/nested-macro-rules.stdout | 8 +- src/test/ui/proc-macro/nodelim-groups.stdout | 30 +++--- 11 files changed, 160 insertions(+), 158 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index deca80f590f2f..1786969a88905 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -162,7 +162,7 @@ impl<'a, 'tcx> Encodable> for ExpnId { impl<'a, 'tcx> Encodable> for Span { fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { - if self.is_dummy() { + if *self == rustc_span::DUMMY_SP { return TAG_INVALID_SPAN.encode(s); } diff --git a/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout b/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout index 652bf6b6b22f5..0e7b429d621ff 100644 --- a/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout +++ b/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout @@ -8,7 +8,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: $DIR/capture-macro-rules-invoke.rs:36:24: 36:28 (#0), }, ], - span: $DIR/capture-macro-rules-invoke.rs:21:21: 21:26 (#3), + span: $DIR/capture-macro-rules-invoke.rs:21:21: 21:26 (#4), }, ] PRINT-BANG INPUT (DISPLAY): 1 + 1, { "a" }, let a = 1;, String, my_name, 'a, my_val = 30, @@ -37,12 +37,12 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: $DIR/capture-macro-rules-invoke.rs:38:17: 38:18 (#0), }, ], - span: $DIR/capture-macro-rules-invoke.rs:14:29: 14:34 (#7), + span: $DIR/capture-macro-rules-invoke.rs:14:29: 14:34 (#8), }, Punct { ch: ',', spacing: Alone, - span: $DIR/capture-macro-rules-invoke.rs:14:34: 14:35 (#7), + span: $DIR/capture-macro-rules-invoke.rs:14:34: 14:35 (#8), }, Group { delimiter: None, @@ -60,12 +60,12 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: $DIR/capture-macro-rules-invoke.rs:39:13: 39:20 (#0), }, ], - span: $DIR/capture-macro-rules-invoke.rs:14:36: 14:42 (#7), + span: $DIR/capture-macro-rules-invoke.rs:14:36: 14:42 (#8), }, Punct { ch: ',', spacing: Alone, - span: $DIR/capture-macro-rules-invoke.rs:14:42: 14:43 (#7), + span: $DIR/capture-macro-rules-invoke.rs:14:42: 14:43 (#8), }, Group { delimiter: None, @@ -90,12 +90,12 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: $DIR/capture-macro-rules-invoke.rs:40:21: 40:22 (#0), }, ], - span: $DIR/capture-macro-rules-invoke.rs:14:44: 14:49 (#7), + span: $DIR/capture-macro-rules-invoke.rs:14:44: 14:49 (#8), }, Punct { ch: ',', spacing: Alone, - span: $DIR/capture-macro-rules-invoke.rs:14:49: 14:50 (#7), + span: $DIR/capture-macro-rules-invoke.rs:14:49: 14:50 (#8), }, Group { delimiter: None, @@ -105,12 +105,12 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: $DIR/capture-macro-rules-invoke.rs:41:13: 41:19 (#0), }, ], - span: $DIR/capture-macro-rules-invoke.rs:14:51: 14:54 (#7), + span: $DIR/capture-macro-rules-invoke.rs:14:51: 14:54 (#8), }, Punct { ch: ',', spacing: Alone, - span: $DIR/capture-macro-rules-invoke.rs:14:54: 14:55 (#7), + span: $DIR/capture-macro-rules-invoke.rs:14:54: 14:55 (#8), }, Group { delimiter: None, @@ -120,12 +120,12 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: $DIR/capture-macro-rules-invoke.rs:42:13: 42:20 (#0), }, ], - span: $DIR/capture-macro-rules-invoke.rs:14:56: 14:62 (#7), + span: $DIR/capture-macro-rules-invoke.rs:14:56: 14:62 (#8), }, Punct { ch: ',', spacing: Alone, - span: $DIR/capture-macro-rules-invoke.rs:14:62: 14:63 (#7), + span: $DIR/capture-macro-rules-invoke.rs:14:62: 14:63 (#8), }, Group { delimiter: None, @@ -140,12 +140,12 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: $DIR/capture-macro-rules-invoke.rs:43:13: 43:15 (#0), }, ], - span: $DIR/capture-macro-rules-invoke.rs:15:29: 15:38 (#7), + span: $DIR/capture-macro-rules-invoke.rs:15:29: 15:38 (#8), }, Punct { ch: ',', spacing: Alone, - span: $DIR/capture-macro-rules-invoke.rs:15:38: 15:39 (#7), + span: $DIR/capture-macro-rules-invoke.rs:15:38: 15:39 (#8), }, Group { delimiter: None, @@ -166,12 +166,12 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: $DIR/capture-macro-rules-invoke.rs:44:22: 44:24 (#0), }, ], - span: $DIR/capture-macro-rules-invoke.rs:15:40: 15:45 (#7), + span: $DIR/capture-macro-rules-invoke.rs:15:40: 15:45 (#8), }, Punct { ch: ',', spacing: Alone, - span: $DIR/capture-macro-rules-invoke.rs:15:45: 15:46 (#7), + span: $DIR/capture-macro-rules-invoke.rs:15:45: 15:46 (#8), }, Group { delimiter: None, @@ -209,12 +209,12 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: $DIR/capture-macro-rules-invoke.rs:45:26: 45:32 (#0), }, ], - span: $DIR/capture-macro-rules-invoke.rs:15:47: 15:52 (#7), + span: $DIR/capture-macro-rules-invoke.rs:15:47: 15:52 (#8), }, Punct { ch: ',', spacing: Alone, - span: $DIR/capture-macro-rules-invoke.rs:15:52: 15:53 (#7), + span: $DIR/capture-macro-rules-invoke.rs:15:52: 15:53 (#8), }, Group { delimiter: None, @@ -252,12 +252,12 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: $DIR/capture-macro-rules-invoke.rs:46:16: 46:31 (#0), }, ], - span: $DIR/capture-macro-rules-invoke.rs:15:54: 15:58 (#7), + span: $DIR/capture-macro-rules-invoke.rs:15:54: 15:58 (#8), }, Punct { ch: ',', spacing: Alone, - span: $DIR/capture-macro-rules-invoke.rs:15:58: 15:59 (#7), + span: $DIR/capture-macro-rules-invoke.rs:15:58: 15:59 (#8), }, Group { delimiter: Bracket, @@ -280,7 +280,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ Punct { ch: ',', spacing: Alone, - span: $DIR/capture-macro-rules-invoke.rs:15:63: 15:64 (#7), + span: $DIR/capture-macro-rules-invoke.rs:15:63: 15:64 (#8), }, Group { delimiter: None, @@ -297,7 +297,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: $DIR/capture-macro-rules-invoke.rs:48:14: 48:16 (#0), }, ], - span: $DIR/capture-macro-rules-invoke.rs:15:65: 15:69 (#7), + span: $DIR/capture-macro-rules-invoke.rs:15:65: 15:69 (#8), }, ] PRINT-BANG INPUT (DISPLAY): (a, b) @@ -325,6 +325,6 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: $DIR/capture-macro-rules-invoke.rs:52:26: 52:32 (#0), }, ], - span: $DIR/capture-macro-rules-invoke.rs:27:21: 27:25 (#11), + span: $DIR/capture-macro-rules-invoke.rs:27:21: 27:25 (#12), }, ] diff --git a/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout b/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout index 9a5afbd604f42..c0c9ed72c5ab9 100644 --- a/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout +++ b/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout @@ -2,79 +2,79 @@ PRINT-BANG INPUT (DISPLAY): struct M($crate :: S) ; PRINT-BANG INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/dollar-crate-issue-57089.rs:17:13: 17:19 (#3), + span: $DIR/dollar-crate-issue-57089.rs:17:13: 17:19 (#4), }, Ident { ident: "M", - span: $DIR/dollar-crate-issue-57089.rs:17:20: 17:21 (#3), + span: $DIR/dollar-crate-issue-57089.rs:17:20: 17:21 (#4), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/dollar-crate-issue-57089.rs:17:22: 17:28 (#3), + span: $DIR/dollar-crate-issue-57089.rs:17:22: 17:28 (#4), }, Punct { ch: ':', spacing: Joint, - span: $DIR/dollar-crate-issue-57089.rs:17:28: 17:30 (#3), + span: $DIR/dollar-crate-issue-57089.rs:17:28: 17:30 (#4), }, Punct { ch: ':', spacing: Alone, - span: $DIR/dollar-crate-issue-57089.rs:17:28: 17:30 (#3), + span: $DIR/dollar-crate-issue-57089.rs:17:28: 17:30 (#4), }, Ident { ident: "S", - span: $DIR/dollar-crate-issue-57089.rs:17:30: 17:31 (#3), + span: $DIR/dollar-crate-issue-57089.rs:17:30: 17:31 (#4), }, ], - span: $DIR/dollar-crate-issue-57089.rs:17:21: 17:32 (#3), + span: $DIR/dollar-crate-issue-57089.rs:17:21: 17:32 (#4), }, Punct { ch: ';', spacing: Alone, - span: $DIR/dollar-crate-issue-57089.rs:17:32: 17:33 (#3), + span: $DIR/dollar-crate-issue-57089.rs:17:32: 17:33 (#4), }, ] PRINT-ATTR INPUT (DISPLAY): struct A($crate :: S) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/dollar-crate-issue-57089.rs:21:9: 21:15 (#3), + span: $DIR/dollar-crate-issue-57089.rs:21:9: 21:15 (#4), }, Ident { ident: "A", - span: $DIR/dollar-crate-issue-57089.rs:21:16: 21:17 (#3), + span: $DIR/dollar-crate-issue-57089.rs:21:16: 21:17 (#4), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/dollar-crate-issue-57089.rs:21:18: 21:24 (#3), + span: $DIR/dollar-crate-issue-57089.rs:21:18: 21:24 (#4), }, Punct { ch: ':', spacing: Joint, - span: $DIR/dollar-crate-issue-57089.rs:21:24: 21:26 (#3), + span: $DIR/dollar-crate-issue-57089.rs:21:24: 21:26 (#4), }, Punct { ch: ':', spacing: Alone, - span: $DIR/dollar-crate-issue-57089.rs:21:24: 21:26 (#3), + span: $DIR/dollar-crate-issue-57089.rs:21:24: 21:26 (#4), }, Ident { ident: "S", - span: $DIR/dollar-crate-issue-57089.rs:21:26: 21:27 (#3), + span: $DIR/dollar-crate-issue-57089.rs:21:26: 21:27 (#4), }, ], - span: $DIR/dollar-crate-issue-57089.rs:21:17: 21:28 (#3), + span: $DIR/dollar-crate-issue-57089.rs:21:17: 21:28 (#4), }, Punct { ch: ';', spacing: Alone, - span: $DIR/dollar-crate-issue-57089.rs:21:28: 21:29 (#3), + span: $DIR/dollar-crate-issue-57089.rs:21:28: 21:29 (#4), }, ] diff --git a/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout b/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout index fc62eadd31376..7f133fd05d704 100644 --- a/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout +++ b/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout @@ -2,109 +2,109 @@ PRINT-ATTR INPUT (DISPLAY): struct A(identity ! ($crate :: S)) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/dollar-crate-issue-62325.rs:19:5: 19:11 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:5: 19:11 (#4), }, Ident { ident: "A", - span: $DIR/dollar-crate-issue-62325.rs:19:12: 19:13 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:12: 19:13 (#4), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "identity", - span: $DIR/dollar-crate-issue-62325.rs:19:14: 19:22 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:14: 19:22 (#4), }, Punct { ch: '!', spacing: Alone, - span: $DIR/dollar-crate-issue-62325.rs:19:22: 19:23 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:22: 19:23 (#4), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/dollar-crate-issue-62325.rs:19:24: 19:30 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:24: 19:30 (#4), }, Punct { ch: ':', spacing: Joint, - span: $DIR/dollar-crate-issue-62325.rs:19:30: 19:32 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:30: 19:32 (#4), }, Punct { ch: ':', spacing: Alone, - span: $DIR/dollar-crate-issue-62325.rs:19:30: 19:32 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:30: 19:32 (#4), }, Ident { ident: "S", - span: $DIR/dollar-crate-issue-62325.rs:19:32: 19:33 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:32: 19:33 (#4), }, ], - span: $DIR/dollar-crate-issue-62325.rs:19:23: 19:34 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:23: 19:34 (#4), }, ], - span: $DIR/dollar-crate-issue-62325.rs:19:13: 19:35 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:13: 19:35 (#4), }, Punct { ch: ';', spacing: Alone, - span: $DIR/dollar-crate-issue-62325.rs:19:35: 19:36 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:35: 19:36 (#4), }, ] PRINT-ATTR INPUT (DISPLAY): struct B(identity ! ($crate :: S)) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/auxiliary/dollar-crate-external.rs:21:5: 21:11 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:5: 21:11 (#12), }, Ident { ident: "B", - span: $DIR/auxiliary/dollar-crate-external.rs:21:12: 21:13 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:12: 21:13 (#12), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "identity", - span: $DIR/auxiliary/dollar-crate-external.rs:21:14: 21:22 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:14: 21:22 (#12), }, Punct { ch: '!', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:21:22: 21:23 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:22: 21:23 (#12), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/auxiliary/dollar-crate-external.rs:21:24: 21:30 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:24: 21:30 (#12), }, Punct { ch: ':', spacing: Joint, - span: $DIR/auxiliary/dollar-crate-external.rs:21:30: 21:32 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:30: 21:32 (#12), }, Punct { ch: ':', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:21:30: 21:32 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:30: 21:32 (#12), }, Ident { ident: "S", - span: $DIR/auxiliary/dollar-crate-external.rs:21:32: 21:33 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:32: 21:33 (#12), }, ], - span: $DIR/auxiliary/dollar-crate-external.rs:21:23: 21:34 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:23: 21:34 (#12), }, ], - span: $DIR/auxiliary/dollar-crate-external.rs:21:13: 21:35 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:13: 21:35 (#12), }, Punct { ch: ';', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:21:35: 21:36 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:35: 21:36 (#12), }, ] diff --git a/src/test/ui/proc-macro/dollar-crate.stdout b/src/test/ui/proc-macro/dollar-crate.stdout index 72fc658858304..d01fcb9d0e498 100644 --- a/src/test/ui/proc-macro/dollar-crate.stdout +++ b/src/test/ui/proc-macro/dollar-crate.stdout @@ -2,239 +2,239 @@ PRINT-BANG INPUT (DISPLAY): struct M($crate :: S) ; PRINT-BANG INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/dollar-crate.rs:20:17: 20:23 (#3), + span: $DIR/dollar-crate.rs:20:17: 20:23 (#4), }, Ident { ident: "M", - span: $DIR/dollar-crate.rs:20:24: 20:25 (#3), + span: $DIR/dollar-crate.rs:20:24: 20:25 (#4), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/dollar-crate.rs:20:26: 20:32 (#3), + span: $DIR/dollar-crate.rs:20:26: 20:32 (#4), }, Punct { ch: ':', spacing: Joint, - span: $DIR/dollar-crate.rs:20:32: 20:34 (#3), + span: $DIR/dollar-crate.rs:20:32: 20:34 (#4), }, Punct { ch: ':', spacing: Alone, - span: $DIR/dollar-crate.rs:20:32: 20:34 (#3), + span: $DIR/dollar-crate.rs:20:32: 20:34 (#4), }, Ident { ident: "S", - span: $DIR/dollar-crate.rs:20:34: 20:35 (#3), + span: $DIR/dollar-crate.rs:20:34: 20:35 (#4), }, ], - span: $DIR/dollar-crate.rs:20:25: 20:36 (#3), + span: $DIR/dollar-crate.rs:20:25: 20:36 (#4), }, Punct { ch: ';', spacing: Alone, - span: $DIR/dollar-crate.rs:20:36: 20:37 (#3), + span: $DIR/dollar-crate.rs:20:36: 20:37 (#4), }, ] PRINT-ATTR INPUT (DISPLAY): struct A($crate :: S) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/dollar-crate.rs:24:13: 24:19 (#3), + span: $DIR/dollar-crate.rs:24:13: 24:19 (#4), }, Ident { ident: "A", - span: $DIR/dollar-crate.rs:24:20: 24:21 (#3), + span: $DIR/dollar-crate.rs:24:20: 24:21 (#4), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/dollar-crate.rs:24:22: 24:28 (#3), + span: $DIR/dollar-crate.rs:24:22: 24:28 (#4), }, Punct { ch: ':', spacing: Joint, - span: $DIR/dollar-crate.rs:24:28: 24:30 (#3), + span: $DIR/dollar-crate.rs:24:28: 24:30 (#4), }, Punct { ch: ':', spacing: Alone, - span: $DIR/dollar-crate.rs:24:28: 24:30 (#3), + span: $DIR/dollar-crate.rs:24:28: 24:30 (#4), }, Ident { ident: "S", - span: $DIR/dollar-crate.rs:24:30: 24:31 (#3), + span: $DIR/dollar-crate.rs:24:30: 24:31 (#4), }, ], - span: $DIR/dollar-crate.rs:24:21: 24:32 (#3), + span: $DIR/dollar-crate.rs:24:21: 24:32 (#4), }, Punct { ch: ';', spacing: Alone, - span: $DIR/dollar-crate.rs:24:32: 24:33 (#3), + span: $DIR/dollar-crate.rs:24:32: 24:33 (#4), }, ] PRINT-DERIVE INPUT (DISPLAY): struct D($crate :: S) ; PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/dollar-crate.rs:27:13: 27:19 (#3), + span: $DIR/dollar-crate.rs:27:13: 27:19 (#4), }, Ident { ident: "D", - span: $DIR/dollar-crate.rs:27:20: 27:21 (#3), + span: $DIR/dollar-crate.rs:27:20: 27:21 (#4), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/dollar-crate.rs:27:22: 27:28 (#3), + span: $DIR/dollar-crate.rs:27:22: 27:28 (#4), }, Punct { ch: ':', spacing: Joint, - span: $DIR/dollar-crate.rs:27:28: 27:30 (#3), + span: $DIR/dollar-crate.rs:27:28: 27:30 (#4), }, Punct { ch: ':', spacing: Alone, - span: $DIR/dollar-crate.rs:27:28: 27:30 (#3), + span: $DIR/dollar-crate.rs:27:28: 27:30 (#4), }, Ident { ident: "S", - span: $DIR/dollar-crate.rs:27:30: 27:31 (#3), + span: $DIR/dollar-crate.rs:27:30: 27:31 (#4), }, ], - span: $DIR/dollar-crate.rs:27:21: 27:32 (#3), + span: $DIR/dollar-crate.rs:27:21: 27:32 (#4), }, Punct { ch: ';', spacing: Alone, - span: $DIR/dollar-crate.rs:27:32: 27:33 (#3), + span: $DIR/dollar-crate.rs:27:32: 27:33 (#4), }, ] PRINT-BANG INPUT (DISPLAY): struct M($crate :: S) ; PRINT-BANG INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/auxiliary/dollar-crate-external.rs:7:13: 7:19 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:7:13: 7:19 (#15), }, Ident { ident: "M", - span: $DIR/auxiliary/dollar-crate-external.rs:7:20: 7:21 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:7:20: 7:21 (#15), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/auxiliary/dollar-crate-external.rs:7:22: 7:28 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:7:22: 7:28 (#15), }, Punct { ch: ':', spacing: Joint, - span: $DIR/auxiliary/dollar-crate-external.rs:7:28: 7:30 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:7:28: 7:30 (#15), }, Punct { ch: ':', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:7:28: 7:30 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:7:28: 7:30 (#15), }, Ident { ident: "S", - span: $DIR/auxiliary/dollar-crate-external.rs:7:30: 7:31 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:7:30: 7:31 (#15), }, ], - span: $DIR/auxiliary/dollar-crate-external.rs:7:21: 7:32 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:7:21: 7:32 (#15), }, Punct { ch: ';', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:7:32: 7:33 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:7:32: 7:33 (#15), }, ] PRINT-ATTR INPUT (DISPLAY): struct A($crate :: S) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/auxiliary/dollar-crate-external.rs:11:9: 11:15 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:11:9: 11:15 (#15), }, Ident { ident: "A", - span: $DIR/auxiliary/dollar-crate-external.rs:11:16: 11:17 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:11:16: 11:17 (#15), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/auxiliary/dollar-crate-external.rs:11:18: 11:24 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:11:18: 11:24 (#15), }, Punct { ch: ':', spacing: Joint, - span: $DIR/auxiliary/dollar-crate-external.rs:11:24: 11:26 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:11:24: 11:26 (#15), }, Punct { ch: ':', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:11:24: 11:26 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:11:24: 11:26 (#15), }, Ident { ident: "S", - span: $DIR/auxiliary/dollar-crate-external.rs:11:26: 11:27 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:11:26: 11:27 (#15), }, ], - span: $DIR/auxiliary/dollar-crate-external.rs:11:17: 11:28 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:11:17: 11:28 (#15), }, Punct { ch: ';', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:11:28: 11:29 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:11:28: 11:29 (#15), }, ] PRINT-DERIVE INPUT (DISPLAY): struct D($crate :: S) ; PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/auxiliary/dollar-crate-external.rs:14:9: 14:15 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:14:9: 14:15 (#15), }, Ident { ident: "D", - span: $DIR/auxiliary/dollar-crate-external.rs:14:16: 14:17 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:14:16: 14:17 (#15), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/auxiliary/dollar-crate-external.rs:14:18: 14:24 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:14:18: 14:24 (#15), }, Punct { ch: ':', spacing: Joint, - span: $DIR/auxiliary/dollar-crate-external.rs:14:24: 14:26 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:14:24: 14:26 (#15), }, Punct { ch: ':', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:14:24: 14:26 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:14:24: 14:26 (#15), }, Ident { ident: "S", - span: $DIR/auxiliary/dollar-crate-external.rs:14:26: 14:27 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:14:26: 14:27 (#15), }, ], - span: $DIR/auxiliary/dollar-crate-external.rs:14:17: 14:28 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:14:17: 14:28 (#15), }, Punct { ch: ';', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:14:28: 14:29 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:14:28: 14:29 (#15), }, ] diff --git a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout index e7645280a7509..e83bc9f8fca7a 100644 --- a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout +++ b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout @@ -1,6 +1,6 @@ -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl/src/lib.rs:5:21: 5:27 (#5) }, Ident { ident: "One", span: $DIR/time-macros-impl/src/lib.rs:5:28: 5:31 (#5) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:27:18: 27:21 (#0) }], span: $DIR/time-macros-impl/src/lib.rs:5:31: 5:38 (#5) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl/src/lib.rs:5:38: 5:39 (#5) }] -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys/src/lib.rs:5:21: 5:27 (#9) }, Ident { ident: "Two", span: $DIR/js-sys/src/lib.rs:5:28: 5:31 (#9) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:28:13: 28:16 (#0) }], span: $DIR/js-sys/src/lib.rs:5:31: 5:38 (#9) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys/src/lib.rs:5:38: 5:39 (#9) }] -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:22:25: 22:31 (#13) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:22:32: 22:37 (#13) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:29:12: 29:15 (#0) }], span: $DIR/group-compat-hack.rs:22:38: 22:43 (#13) }], span: $DIR/group-compat-hack.rs:22:37: 22:44 (#13) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:22:44: 22:45 (#13) }] -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:21: 5:27 (#19) }, Ident { ident: "One", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:28: 5:31 (#19) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:43:18: 43:21 (#0) }], span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:31: 5:38 (#19) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:38: 5:39 (#19) }] -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.17/src/lib.rs:5:21: 5:27 (#23) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.17/src/lib.rs:5:28: 5:31 (#23) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:44:13: 44:16 (#0) }], span: $DIR/js-sys-0.3.17/src/lib.rs:5:31: 5:38 (#23) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.17/src/lib.rs:5:38: 5:39 (#23) }] -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:38:25: 38:31 (#27) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:38:32: 38:37 (#27) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:45:12: 45:15 (#0) }], span: $DIR/group-compat-hack.rs:38:38: 38:43 (#27) }], span: $DIR/group-compat-hack.rs:38:37: 38:44 (#27) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:38:44: 38:45 (#27) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl/src/lib.rs:5:21: 5:27 (#6) }, Ident { ident: "One", span: $DIR/time-macros-impl/src/lib.rs:5:28: 5:31 (#6) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:27:18: 27:21 (#0) }], span: $DIR/time-macros-impl/src/lib.rs:5:31: 5:38 (#6) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl/src/lib.rs:5:38: 5:39 (#6) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys/src/lib.rs:5:21: 5:27 (#10) }, Ident { ident: "Two", span: $DIR/js-sys/src/lib.rs:5:28: 5:31 (#10) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:28:13: 28:16 (#0) }], span: $DIR/js-sys/src/lib.rs:5:31: 5:38 (#10) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys/src/lib.rs:5:38: 5:39 (#10) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:22:25: 22:31 (#14) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:22:32: 22:37 (#14) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:29:12: 29:15 (#0) }], span: $DIR/group-compat-hack.rs:22:38: 22:43 (#14) }], span: $DIR/group-compat-hack.rs:22:37: 22:44 (#14) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:22:44: 22:45 (#14) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:21: 5:27 (#20) }, Ident { ident: "One", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:28: 5:31 (#20) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:43:18: 43:21 (#0) }], span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:31: 5:38 (#20) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:38: 5:39 (#20) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.17/src/lib.rs:5:21: 5:27 (#24) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.17/src/lib.rs:5:28: 5:31 (#24) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:44:13: 44:16 (#0) }], span: $DIR/js-sys-0.3.17/src/lib.rs:5:31: 5:38 (#24) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.17/src/lib.rs:5:38: 5:39 (#24) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:38:25: 38:31 (#28) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:38:32: 38:37 (#28) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:45:12: 45:15 (#0) }], span: $DIR/group-compat-hack.rs:38:38: 38:43 (#28) }], span: $DIR/group-compat-hack.rs:38:37: 38:44 (#28) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:38:44: 38:45 (#28) }] diff --git a/src/test/ui/proc-macro/input-interpolated.stdout b/src/test/ui/proc-macro/input-interpolated.stdout index a9636cfef8219..866608e4d8e1d 100644 --- a/src/test/ui/proc-macro/input-interpolated.stdout +++ b/src/test/ui/proc-macro/input-interpolated.stdout @@ -8,14 +8,14 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: #0 bytes(503..504), }, ], - span: #3 bytes(370..372), + span: #4 bytes(370..372), }, ] PRINT-ATTR INPUT (DISPLAY): const A : u8 = 0 ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "const", - span: #3 bytes(416..421), + span: #4 bytes(416..421), }, Group { delimiter: None, @@ -25,39 +25,39 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ span: #0 bytes(503..504), }, ], - span: #3 bytes(422..424), + span: #4 bytes(422..424), }, Punct { ch: ':', spacing: Alone, - span: #3 bytes(424..425), + span: #4 bytes(424..425), }, Ident { ident: "u8", - span: #3 bytes(426..428), + span: #4 bytes(426..428), }, Punct { ch: '=', spacing: Alone, - span: #3 bytes(429..430), + span: #4 bytes(429..430), }, Literal { kind: Integer, symbol: "0", suffix: None, - span: #3 bytes(431..432), + span: #4 bytes(431..432), }, Punct { ch: ';', spacing: Alone, - span: #3 bytes(432..433), + span: #4 bytes(432..433), }, ] PRINT-DERIVE INPUT (DISPLAY): struct A { } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #3 bytes(468..474), + span: #4 bytes(468..474), }, Group { delimiter: None, @@ -67,11 +67,11 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ span: #0 bytes(503..504), }, ], - span: #3 bytes(475..477), + span: #4 bytes(475..477), }, Group { delimiter: Brace, stream: TokenStream [], - span: #3 bytes(478..480), + span: #4 bytes(478..480), }, ] diff --git a/src/test/ui/proc-macro/meta-macro-hygiene.stdout b/src/test/ui/proc-macro/meta-macro-hygiene.stdout index bf5e0bce76213..e522bd258e14b 100644 --- a/src/test/ui/proc-macro/meta-macro-hygiene.stdout +++ b/src/test/ui/proc-macro/meta-macro-hygiene.stdout @@ -1,6 +1,6 @@ -Def site: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) -Input: TokenStream [Ident { ident: "$crate", span: $DIR/meta-macro-hygiene.rs:24:37: 24:43 (#3) }, Punct { ch: ':', spacing: Joint, span: $DIR/meta-macro-hygiene.rs:24:43: 24:45 (#3) }, Punct { ch: ':', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:24:43: 24:45 (#3) }, Ident { ident: "dummy", span: $DIR/meta-macro-hygiene.rs:24:45: 24:50 (#3) }, Punct { ch: '!', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:24:50: 24:51 (#3) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/meta-macro-hygiene.rs:24:51: 24:53 (#3) }] -Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }, Punct { ch: ':', spacing: Joint, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }, Punct { ch: ':', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }, Ident { ident: "dummy", span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }, Punct { ch: '!', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }] +Def site: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#5) +Input: TokenStream [Ident { ident: "$crate", span: $DIR/meta-macro-hygiene.rs:24:37: 24:43 (#4) }, Punct { ch: ':', spacing: Joint, span: $DIR/meta-macro-hygiene.rs:24:43: 24:45 (#4) }, Punct { ch: ':', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:24:43: 24:45 (#4) }, Ident { ident: "dummy", span: $DIR/meta-macro-hygiene.rs:24:45: 24:50 (#4) }, Punct { ch: '!', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:24:50: 24:51 (#4) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/meta-macro-hygiene.rs:24:51: 24:53 (#4) }] +Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#5) }, Punct { ch: ':', spacing: Joint, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#5) }, Punct { ch: ':', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#5) }, Ident { ident: "dummy", span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#5) }, Punct { ch: '!', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#5) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#5) }] #![feature /* 0#0 */(prelude_import)] // ignore-tidy-linelength // aux-build:make-macro.rs @@ -47,18 +47,20 @@ Expansions: 0: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Root 1: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) 2: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "produce_it") -3: parent: ExpnId(2), call_site_ctxt: #3, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site") -4: parent: ExpnId(3), call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy") +3: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) +4: parent: ExpnId(2), call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site") +5: parent: ExpnId(4), call_site_ctxt: #5, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy") SyntaxContexts: #0: parent: #0, outer_mark: (ExpnId(0), Opaque) #1: parent: #0, outer_mark: (ExpnId(1), Opaque) #2: parent: #0, outer_mark: (ExpnId(1), Transparent) -#3: parent: #0, outer_mark: (ExpnId(2), SemiTransparent) -#4: parent: #0, outer_mark: (ExpnId(3), Opaque) -#5: parent: #3, outer_mark: (ExpnId(3), Transparent) -#6: parent: #0, outer_mark: (ExpnId(3), SemiTransparent) -#7: parent: #0, outer_mark: (ExpnId(4), Opaque) -#8: parent: #4, outer_mark: (ExpnId(4), Transparent) -#9: parent: #4, outer_mark: (ExpnId(4), SemiTransparent) +#3: parent: #0, outer_mark: (ExpnId(3), Opaque) +#4: parent: #0, outer_mark: (ExpnId(2), SemiTransparent) +#5: parent: #0, outer_mark: (ExpnId(4), Opaque) +#6: parent: #4, outer_mark: (ExpnId(4), Transparent) +#7: parent: #0, outer_mark: (ExpnId(4), SemiTransparent) +#8: parent: #0, outer_mark: (ExpnId(5), Opaque) +#9: parent: #5, outer_mark: (ExpnId(5), Transparent) +#10: parent: #5, outer_mark: (ExpnId(5), SemiTransparent) */ diff --git a/src/test/ui/proc-macro/meta-macro.stdout b/src/test/ui/proc-macro/meta-macro.stdout index 71aa565f4dd6d..dddde482ef99b 100644 --- a/src/test/ui/proc-macro/meta-macro.stdout +++ b/src/test/ui/proc-macro/meta-macro.stdout @@ -1,3 +1,3 @@ -Def site: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#3) +Def site: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) Input: TokenStream [] Respanned: TokenStream [] diff --git a/src/test/ui/proc-macro/nested-macro-rules.stdout b/src/test/ui/proc-macro/nested-macro-rules.stdout index 7feea56c5d860..dcafe3b4bda60 100644 --- a/src/test/ui/proc-macro/nested-macro-rules.stdout +++ b/src/test/ui/proc-macro/nested-macro-rules.stdout @@ -5,10 +5,10 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "FirstStruct", - span: $DIR/auxiliary/nested-macro-rules.rs:15:14: 15:25 (#5), + span: $DIR/auxiliary/nested-macro-rules.rs:15:14: 15:25 (#7), }, ], - span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#4), + span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#6), }, ] PRINT-BANG INPUT (DISPLAY): SecondStruct @@ -18,9 +18,9 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "SecondStruct", - span: $DIR/nested-macro-rules.rs:21:38: 21:50 (#11), + span: $DIR/nested-macro-rules.rs:21:38: 21:50 (#13), }, ], - span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#10), + span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#12), }, ] diff --git a/src/test/ui/proc-macro/nodelim-groups.stdout b/src/test/ui/proc-macro/nodelim-groups.stdout index cdf851b535aa5..6b410f0bfb7e3 100644 --- a/src/test/ui/proc-macro/nodelim-groups.stdout +++ b/src/test/ui/proc-macro/nodelim-groups.stdout @@ -4,7 +4,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ kind: Str, symbol: "hi", suffix: None, - span: $DIR/nodelim-groups.rs:16:42: 16:46 (#3), + span: $DIR/nodelim-groups.rs:16:42: 16:46 (#4), }, Group { delimiter: None, @@ -44,7 +44,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: $DIR/nodelim-groups.rs:20:27: 20:28 (#0), }, ], - span: $DIR/nodelim-groups.rs:16:47: 16:51 (#3), + span: $DIR/nodelim-groups.rs:16:47: 16:51 (#4), }, Group { delimiter: Parenthesis, @@ -53,21 +53,21 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ kind: Integer, symbol: "1", suffix: None, - span: $DIR/nodelim-groups.rs:16:53: 16:54 (#3), + span: $DIR/nodelim-groups.rs:16:53: 16:54 (#4), }, Punct { ch: '+', spacing: Alone, - span: $DIR/nodelim-groups.rs:16:55: 16:56 (#3), + span: $DIR/nodelim-groups.rs:16:55: 16:56 (#4), }, Literal { kind: Integer, symbol: "1", suffix: None, - span: $DIR/nodelim-groups.rs:16:57: 16:58 (#3), + span: $DIR/nodelim-groups.rs:16:57: 16:58 (#4), }, ], - span: $DIR/nodelim-groups.rs:16:52: 16:59 (#3), + span: $DIR/nodelim-groups.rs:16:52: 16:59 (#4), }, ] PRINT-BANG INPUT (DISPLAY): "hi" "hello".len() + "world".len() (1 + 1) @@ -76,7 +76,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ kind: Str, symbol: "hi", suffix: None, - span: $DIR/nodelim-groups.rs:16:42: 16:46 (#8), + span: $DIR/nodelim-groups.rs:16:42: 16:46 (#9), }, Group { delimiter: None, @@ -105,12 +105,12 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: $DIR/nodelim-groups.rs:21:28: 21:30 (#0), }, ], - span: $DIR/nodelim-groups.rs:15:49: 15:54 (#7), + span: $DIR/nodelim-groups.rs:15:49: 15:54 (#8), }, Punct { ch: '+', spacing: Alone, - span: $DIR/nodelim-groups.rs:15:55: 15:56 (#7), + span: $DIR/nodelim-groups.rs:15:55: 15:56 (#8), }, Group { delimiter: None, @@ -136,10 +136,10 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: $DIR/nodelim-groups.rs:21:44: 21:46 (#0), }, ], - span: $DIR/nodelim-groups.rs:15:57: 15:62 (#7), + span: $DIR/nodelim-groups.rs:15:57: 15:62 (#8), }, ], - span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8), + span: $DIR/nodelim-groups.rs:16:47: 16:51 (#9), }, Group { delimiter: Parenthesis, @@ -148,20 +148,20 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ kind: Integer, symbol: "1", suffix: None, - span: $DIR/nodelim-groups.rs:16:53: 16:54 (#8), + span: $DIR/nodelim-groups.rs:16:53: 16:54 (#9), }, Punct { ch: '+', spacing: Alone, - span: $DIR/nodelim-groups.rs:16:55: 16:56 (#8), + span: $DIR/nodelim-groups.rs:16:55: 16:56 (#9), }, Literal { kind: Integer, symbol: "1", suffix: None, - span: $DIR/nodelim-groups.rs:16:57: 16:58 (#8), + span: $DIR/nodelim-groups.rs:16:57: 16:58 (#9), }, ], - span: $DIR/nodelim-groups.rs:16:52: 16:59 (#8), + span: $DIR/nodelim-groups.rs:16:52: 16:59 (#9), }, ] From 7dd4582f95f0e07349cd34be0a5417280ce1d45b Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 11 Sep 2020 03:01:25 +0000 Subject: [PATCH 0352/1052] Add ui test for 74672 and 76571 These tests will fall without the next commit. --- src/test/rustdoc/auxiliary/real_gimli.rs | 13 +++++++++++++ src/test/rustdoc/auxiliary/realcore.rs | 15 +++++++++++++++ src/test/rustdoc/issue-75588.rs | 18 ++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 src/test/rustdoc/auxiliary/real_gimli.rs create mode 100644 src/test/rustdoc/auxiliary/realcore.rs create mode 100644 src/test/rustdoc/issue-75588.rs diff --git a/src/test/rustdoc/auxiliary/real_gimli.rs b/src/test/rustdoc/auxiliary/real_gimli.rs new file mode 100644 index 0000000000000..80d5c4ba8bb09 --- /dev/null +++ b/src/test/rustdoc/auxiliary/real_gimli.rs @@ -0,0 +1,13 @@ +// aux-build:realcore.rs + +#![crate_name = "real_gimli"] +#![feature(staged_api, extremely_unstable)] +#![unstable(feature = "rustc_private", issue = "none")] + +extern crate realcore; + +#[unstable(feature = "rustc_private", issue = "none")] +pub struct EndianSlice; + +#[unstable(feature = "rustc_private", issue = "none")] +impl realcore::Deref for EndianSlice {} diff --git a/src/test/rustdoc/auxiliary/realcore.rs b/src/test/rustdoc/auxiliary/realcore.rs new file mode 100644 index 0000000000000..e0a906df002da --- /dev/null +++ b/src/test/rustdoc/auxiliary/realcore.rs @@ -0,0 +1,15 @@ +#![crate_name = "realcore"] +#![feature(staged_api)] +#![unstable(feature = "extremely_unstable", issue = "none")] + +#[unstable(feature = "extremely_unstable_foo", issue = "none")] +pub struct Foo {} + +#[unstable(feature = "extremely_unstable_foo", issue = "none")] +pub trait Join {} + +#[unstable(feature = "extremely_unstable_foo", issue = "none")] +impl Join for Foo {} + +#[stable(feature = "faked_deref", since = "1.47.0")] +pub trait Deref {} diff --git a/src/test/rustdoc/issue-75588.rs b/src/test/rustdoc/issue-75588.rs new file mode 100644 index 0000000000000..835ed02ac00db --- /dev/null +++ b/src/test/rustdoc/issue-75588.rs @@ -0,0 +1,18 @@ +// ignore-tidy-linelength +// aux-build:realcore.rs +// aux-build:real_gimli.rs + +// Ensure unstably exported traits have their Implementors sections. + +#![crate_name = "foo"] +#![feature(extremely_unstable_foo)] + +extern crate realcore; +extern crate real_gimli; + +// issue #74672 +// @!has foo/trait.Deref.html '//*[@id="impl-Deref-for-EndianSlice"]//code' 'impl Deref for EndianSlice' +pub use realcore::Deref; + +// @has foo/trait.Join.html '//*[@id="impl-Join-for-Foo"]//code' 'impl Join for Foo' +pub use realcore::Join; From c743fc43420ff09a79cc23316e484631842556dc Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Thu, 10 Sep 2020 14:05:33 +0000 Subject: [PATCH 0353/1052] Ignore rustc_private items from std docs Apply suggestions from code review Co-authored-by: Joshua Nelson --- src/librustdoc/clean/inline.rs | 19 ++++++++++--------- src/tools/linkchecker/main.rs | 10 ++++++++++ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 50cb987cf0870..f8987c6beca33 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -337,18 +337,13 @@ pub fn build_impl( // reachable in rustdoc generated documentation if !did.is_local() { if let Some(traitref) = associated_trait { - if !cx.renderinfo.borrow().access_levels.is_public(traitref.def_id) { + let did = traitref.def_id; + if !cx.renderinfo.borrow().access_levels.is_public(did) { return; } - } - // Skip foreign unstable traits from lists of trait implementations and - // such. This helps prevent dependencies of the standard library, for - // example, from getting documented as "traits `u32` implements" which - // isn't really too helpful. - if let Some(trait_did) = associated_trait { - if let Some(stab) = cx.tcx.lookup_stability(trait_did.def_id) { - if stab.level.is_unstable() { + if let Some(stab) = tcx.lookup_stability(did) { + if stab.level.is_unstable() && stab.feature == sym::rustc_private { return; } } @@ -372,6 +367,12 @@ pub fn build_impl( if !cx.renderinfo.borrow().access_levels.is_public(did) { return; } + + if let Some(stab) = tcx.lookup_stability(did) { + if stab.level.is_unstable() && stab.feature == sym::rustc_private { + return; + } + } } } diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 7ec12116c2ca1..4fe493a850d48 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -142,6 +142,16 @@ fn is_exception(file: &Path, link: &str) -> bool { if let Some(entry) = LINKCHECK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) { entry.1.contains(&link) } else { + // FIXME(#63351): Concat trait in alloc/slice reexported in primitive page + // + // NOTE: This cannot be added to `LINKCHECK_EXCEPTIONS` because the resolved path + // calculated in `check` function is outside `build//doc` dir. + // So the `strip_prefix` method just returns the old absolute broken path. + if file.ends_with("std/primitive.slice.html") { + if link.ends_with("primitive.slice.html") { + return true; + } + } false } } From e5447a22222ecc6a650e75282cb9931b910854b2 Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Sun, 13 Sep 2020 10:47:20 +0200 Subject: [PATCH 0354/1052] Fix #76432 Only insert StorageDeads if we actually removed one. Fixes an issue where we added StorageDead to a place with no StorageLive --- .../transform/simplify_comparison_integral.rs | 43 +++---- src/test/mir-opt/issue_76432.rs | 16 +++ ...76432.test.SimplifyComparisonIntegral.diff | 116 ++++++++++++++++++ 3 files changed, 154 insertions(+), 21 deletions(-) create mode 100644 src/test/mir-opt/issue_76432.rs create mode 100644 src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff diff --git a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs index a450a75d091ef..9b460c9ecb1be 100644 --- a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs +++ b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs @@ -61,26 +61,6 @@ impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral { _ => unreachable!(), } - let terminator = bb.terminator_mut(); - - // add StorageDead for the place switched on at the top of each target - for bb_idx in new_targets.iter() { - storage_deads_to_insert.push(( - *bb_idx, - Statement { - source_info: terminator.source_info, - kind: StatementKind::StorageDead(opt.to_switch_on.local), - }, - )); - } - - terminator.kind = TerminatorKind::SwitchInt { - discr: Operand::Move(opt.to_switch_on), - switch_ty: opt.branch_value_ty, - values: vec![new_value].into(), - targets: new_targets, - }; - // delete comparison statement if it the value being switched on was moved, which means it can not be user later on if opt.can_remove_bin_op_stmt { bb.statements[opt.bin_op_stmt_idx].make_nop(); @@ -106,14 +86,35 @@ impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral { } } + let terminator = bb.terminator(); + // remove StorageDead (if it exists) being used in the assign of the comparison for (stmt_idx, stmt) in bb.statements.iter().enumerate() { if !matches!(stmt.kind, StatementKind::StorageDead(local) if local == opt.to_switch_on.local) { continue; } - storage_deads_to_remove.push((stmt_idx, opt.bb_idx)) + storage_deads_to_remove.push((stmt_idx, opt.bb_idx)); + // if we have StorageDeads to remove then make sure to insert them at the top of each target + for bb_idx in new_targets.iter() { + storage_deads_to_insert.push(( + *bb_idx, + Statement { + source_info: terminator.source_info, + kind: StatementKind::StorageDead(opt.to_switch_on.local), + }, + )); + } } + + let terminator = bb.terminator_mut(); + + terminator.kind = TerminatorKind::SwitchInt { + discr: Operand::Move(opt.to_switch_on), + switch_ty: opt.branch_value_ty, + values: vec![new_value].into(), + targets: new_targets, + }; } for (idx, bb_idx) in storage_deads_to_remove { diff --git a/src/test/mir-opt/issue_76432.rs b/src/test/mir-opt/issue_76432.rs new file mode 100644 index 0000000000000..c8b405ca8eaaf --- /dev/null +++ b/src/test/mir-opt/issue_76432.rs @@ -0,0 +1,16 @@ +// Check that we do not insert StorageDead at each target if StorageDead was never seen + +// EMIT_MIR issue_76432.test.SimplifyComparisonIntegral.diff +use std::fmt::Debug; + +fn test(x: T) { + let v: &[T] = &[x, x, x]; + match v { + [ref v1, ref v2, ref v3] => [v1 as *const _, v2 as *const _, v3 as *const _], + _ => unreachable!(), + }; +} + +fn main() { + test(0u32); +} diff --git a/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff b/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff new file mode 100644 index 0000000000000..499134b69919f --- /dev/null +++ b/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff @@ -0,0 +1,116 @@ +- // MIR for `test` before SimplifyComparisonIntegral ++ // MIR for `test` after SimplifyComparisonIntegral + + fn test(_1: T) -> () { + debug x => _1; // in scope 0 at $DIR/issue_76432.rs:6:38: 6:39 + let mut _0: (); // return place in scope 0 at $DIR/issue_76432.rs:6:44: 6:44 + let _2: &[T]; // in scope 0 at $DIR/issue_76432.rs:7:9: 7:10 + let mut _3: &[T; 3]; // in scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + let _4: &[T; 3]; // in scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + let _5: [T; 3]; // in scope 0 at $DIR/issue_76432.rs:7:20: 7:29 + let mut _6: T; // in scope 0 at $DIR/issue_76432.rs:7:21: 7:22 + let mut _7: T; // in scope 0 at $DIR/issue_76432.rs:7:24: 7:25 + let mut _8: T; // in scope 0 at $DIR/issue_76432.rs:7:27: 7:28 + let _9: [*const T; 3]; // in scope 0 at $DIR/issue_76432.rs:8:5: 11:6 + let mut _10: usize; // in scope 0 at $DIR/issue_76432.rs:9:9: 9:33 + let mut _11: usize; // in scope 0 at $DIR/issue_76432.rs:9:9: 9:33 + let mut _12: bool; // in scope 0 at $DIR/issue_76432.rs:9:9: 9:33 + let mut _16: *const T; // in scope 0 at $DIR/issue_76432.rs:9:38: 9:52 + let mut _17: *const T; // in scope 0 at $DIR/issue_76432.rs:9:38: 9:52 + let mut _18: *const T; // in scope 0 at $DIR/issue_76432.rs:9:54: 9:68 + 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 + 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 + let _14: &T; // in scope 1 at $DIR/issue_76432.rs:9:18: 9:24 + let _15: &T; // in scope 1 at $DIR/issue_76432.rs:9:26: 9:32 + scope 2 { + debug v1 => _13; // in scope 2 at $DIR/issue_76432.rs:9:10: 9:16 + debug v2 => _14; // in scope 2 at $DIR/issue_76432.rs:9:18: 9:24 + debug v3 => _15; // in scope 2 at $DIR/issue_76432.rs:9:26: 9:32 + } + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/issue_76432.rs:7:9: 7:10 + StorageLive(_3); // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + StorageLive(_4); // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + StorageLive(_5); // scope 0 at $DIR/issue_76432.rs:7:20: 7:29 + StorageLive(_6); // scope 0 at $DIR/issue_76432.rs:7:21: 7:22 + _6 = _1; // scope 0 at $DIR/issue_76432.rs:7:21: 7:22 + StorageLive(_7); // scope 0 at $DIR/issue_76432.rs:7:24: 7:25 + _7 = _1; // scope 0 at $DIR/issue_76432.rs:7:24: 7:25 + StorageLive(_8); // scope 0 at $DIR/issue_76432.rs:7:27: 7:28 + _8 = _1; // scope 0 at $DIR/issue_76432.rs:7:27: 7:28 + _5 = [move _6, move _7, move _8]; // scope 0 at $DIR/issue_76432.rs:7:20: 7:29 + StorageDead(_8); // scope 0 at $DIR/issue_76432.rs:7:28: 7:29 + StorageDead(_7); // scope 0 at $DIR/issue_76432.rs:7:28: 7:29 + StorageDead(_6); // scope 0 at $DIR/issue_76432.rs:7:28: 7:29 + _4 = &_5; // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + _3 = _4; // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + _2 = move _3 as &[T] (Pointer(Unsize)); // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + StorageDead(_3); // scope 0 at $DIR/issue_76432.rs:7:28: 7:29 + StorageDead(_4); // scope 0 at $DIR/issue_76432.rs:7:29: 7:30 + StorageLive(_9); // scope 1 at $DIR/issue_76432.rs:8:5: 11:6 + _10 = Len((*_2)); // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 + _11 = const 3_usize; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 +- _12 = Eq(move _10, const 3_usize); // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 +- switchInt(move _12) -> [false: bb1, otherwise: bb2]; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 ++ nop; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 ++ switchInt(move _10) -> [3_usize: bb2, otherwise: bb1]; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 + } + + 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 + // mir::Constant + // + span: $SRC_DIR/std/src/macros.rs:LL:COL + // + literal: Const { ty: fn(&str) -> ! {std::rt::begin_panic::<&str>}, val: Value(Scalar()) } + // 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 }) + // mir::Constant + // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL + // + literal: 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 }) } + } + + bb2: { + StorageLive(_13); // scope 1 at $DIR/issue_76432.rs:9:10: 9:16 + _13 = &(*_2)[0 of 3]; // scope 1 at $DIR/issue_76432.rs:9:10: 9:16 + StorageLive(_14); // scope 1 at $DIR/issue_76432.rs:9:18: 9:24 + _14 = &(*_2)[1 of 3]; // scope 1 at $DIR/issue_76432.rs:9:18: 9:24 + StorageLive(_15); // scope 1 at $DIR/issue_76432.rs:9:26: 9:32 + _15 = &(*_2)[2 of 3]; // scope 1 at $DIR/issue_76432.rs:9:26: 9:32 + StorageLive(_16); // scope 2 at $DIR/issue_76432.rs:9:38: 9:52 + StorageLive(_17); // scope 2 at $DIR/issue_76432.rs:9:38: 9:52 + _17 = &raw const (*_13); // scope 2 at $DIR/issue_76432.rs:9:38: 9:40 + _16 = _17; // scope 2 at $DIR/issue_76432.rs:9:38: 9:52 + StorageLive(_18); // scope 2 at $DIR/issue_76432.rs:9:54: 9:68 + StorageLive(_19); // scope 2 at $DIR/issue_76432.rs:9:54: 9:68 + _19 = &raw const (*_14); // scope 2 at $DIR/issue_76432.rs:9:54: 9:56 + _18 = _19; // scope 2 at $DIR/issue_76432.rs:9:54: 9:68 + StorageLive(_20); // scope 2 at $DIR/issue_76432.rs:9:70: 9:84 + StorageLive(_21); // scope 2 at $DIR/issue_76432.rs:9:70: 9:84 + _21 = &raw const (*_15); // scope 2 at $DIR/issue_76432.rs:9:70: 9:72 + _20 = _21; // scope 2 at $DIR/issue_76432.rs:9:70: 9:84 + _9 = [move _16, move _18, move _20]; // scope 2 at $DIR/issue_76432.rs:9:37: 9:85 + StorageDead(_21); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_20); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_19); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_18); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_17); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_16); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_15); // scope 1 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_14); // scope 1 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_13); // scope 1 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_9); // scope 1 at $DIR/issue_76432.rs:11:6: 11:7 + _0 = const (); // scope 0 at $DIR/issue_76432.rs:6:44: 12:2 + StorageDead(_5); // scope 0 at $DIR/issue_76432.rs:12:1: 12:2 + StorageDead(_2); // scope 0 at $DIR/issue_76432.rs:12:1: 12:2 + return; // scope 0 at $DIR/issue_76432.rs:12:2: 12:2 + } + } + From 7ba1a8fec42ca11c169bcff3650f9c1e108b6743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sun, 13 Sep 2020 12:42:14 +0200 Subject: [PATCH 0355/1052] useless_conversion: show type in error message. changelog: useless_conversion: show type in error message. --- clippy_lints/src/useless_conversion.rs | 10 +++++----- tests/ui/useless_conversion.stderr | 22 +++++++++++----------- tests/ui/useless_conversion_try.stderr | 18 +++++++++--------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 615440e15f384..4e4a206a583a2 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -72,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - "useless conversion to the same type", + &format!("useless conversion to the same type: `{}`", b), "consider removing `.into()`", sugg, Applicability::MachineApplicable, // snippet @@ -95,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - "useless conversion to the same type", + &format!("useless conversion to the same type: `{}`", b), "consider removing `.into_iter()`", sugg, Applicability::MachineApplicable, // snippet @@ -116,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - "useless conversion to the same type", + &format!("useless conversion to the same type: `{}`", b), None, "consider removing `.try_into()`", ); @@ -147,7 +147,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - "useless conversion to the same type", + &format!("useless conversion to the same type: `{}`", b), None, &hint, ); @@ -166,7 +166,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - "useless conversion to the same type", + &format!("useless conversion to the same type: `{}`", b), &sugg_msg, sugg.to_string(), Applicability::MachineApplicable, // snippet diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr index f1e880d2696c4..11c6efb25ccea 100644 --- a/tests/ui/useless_conversion.stderr +++ b/tests/ui/useless_conversion.stderr @@ -1,4 +1,4 @@ -error: useless conversion to the same type +error: useless conversion to the same type: `T` --> $DIR/useless_conversion.rs:6:13 | LL | let _ = T::from(val); @@ -10,61 +10,61 @@ note: the lint level is defined here LL | #![deny(clippy::useless_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: useless conversion to the same type +error: useless conversion to the same type: `T` --> $DIR/useless_conversion.rs:7:5 | LL | val.into() | ^^^^^^^^^^ help: consider removing `.into()`: `val` -error: useless conversion to the same type +error: useless conversion to the same type: `i32` --> $DIR/useless_conversion.rs:19:22 | LL | let _: i32 = 0i32.into(); | ^^^^^^^^^^^ help: consider removing `.into()`: `0i32` -error: useless conversion to the same type +error: useless conversion to the same type: `std::string::String` --> $DIR/useless_conversion.rs:60:21 | LL | let _: String = "foo".to_string().into(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()` -error: useless conversion to the same type +error: useless conversion to the same type: `std::string::String` --> $DIR/useless_conversion.rs:61:21 | LL | let _: String = From::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()` -error: useless conversion to the same type +error: useless conversion to the same type: `std::string::String` --> $DIR/useless_conversion.rs:62:13 | LL | let _ = String::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()` -error: useless conversion to the same type +error: useless conversion to the same type: `std::string::String` --> $DIR/useless_conversion.rs:63: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 +error: useless conversion to the same type: `std::str::Lines` --> $DIR/useless_conversion.rs:64:13 | LL | let _ = "".lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()` -error: useless conversion to the same type +error: useless conversion to the same type: `std::vec::IntoIter` --> $DIR/useless_conversion.rs:65: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 +error: useless conversion to the same type: `std::string::String` --> $DIR/useless_conversion.rs:66:21 | LL | let _: String = format!("Hello {}", "world").into(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")` -error: useless conversion to the same type +error: useless conversion to the same type: `i32` --> $DIR/useless_conversion.rs:71:13 | LL | let _ = i32::from(a + b) * 3; diff --git a/tests/ui/useless_conversion_try.stderr b/tests/ui/useless_conversion_try.stderr index b765727c168f5..2e0d9129bfb30 100644 --- a/tests/ui/useless_conversion_try.stderr +++ b/tests/ui/useless_conversion_try.stderr @@ -1,4 +1,4 @@ -error: useless conversion to the same type +error: useless conversion to the same type: `T` --> $DIR/useless_conversion_try.rs:6:13 | LL | let _ = T::try_from(val).unwrap(); @@ -11,7 +11,7 @@ LL | #![deny(clippy::useless_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: consider removing `T::try_from()` -error: useless conversion to the same type +error: useless conversion to the same type: `T` --> $DIR/useless_conversion_try.rs:7:5 | LL | val.try_into().unwrap() @@ -19,7 +19,7 @@ LL | val.try_into().unwrap() | = help: consider removing `.try_into()` -error: useless conversion to the same type +error: useless conversion to the same type: `std::string::String` --> $DIR/useless_conversion_try.rs:29:21 | LL | let _: String = "foo".to_string().try_into().unwrap(); @@ -27,7 +27,7 @@ LL | let _: String = "foo".to_string().try_into().unwrap(); | = help: consider removing `.try_into()` -error: useless conversion to the same type +error: useless conversion to the same type: `std::string::String` --> $DIR/useless_conversion_try.rs:30:21 | LL | let _: String = TryFrom::try_from("foo".to_string()).unwrap(); @@ -35,7 +35,7 @@ LL | let _: String = TryFrom::try_from("foo".to_string()).unwrap(); | = help: consider removing `TryFrom::try_from()` -error: useless conversion to the same type +error: useless conversion to the same type: `std::string::String` --> $DIR/useless_conversion_try.rs:31:13 | LL | let _ = String::try_from("foo".to_string()).unwrap(); @@ -43,7 +43,7 @@ LL | let _ = String::try_from("foo".to_string()).unwrap(); | = help: consider removing `String::try_from()` -error: useless conversion to the same type +error: useless conversion to the same type: `std::string::String` --> $DIR/useless_conversion_try.rs:32:13 | LL | let _ = String::try_from(format!("A: {:04}", 123)).unwrap(); @@ -51,7 +51,7 @@ LL | let _ = String::try_from(format!("A: {:04}", 123)).unwrap(); | = help: consider removing `String::try_from()` -error: useless conversion to the same type +error: useless conversion to the same type: `std::string::String` --> $DIR/useless_conversion_try.rs:33:21 | LL | let _: String = format!("Hello {}", "world").try_into().unwrap(); @@ -59,7 +59,7 @@ LL | let _: String = format!("Hello {}", "world").try_into().unwrap(); | = help: consider removing `.try_into()` -error: useless conversion to the same type +error: useless conversion to the same type: `std::string::String` --> $DIR/useless_conversion_try.rs:34:21 | LL | let _: String = "".to_owned().try_into().unwrap(); @@ -67,7 +67,7 @@ LL | let _: String = "".to_owned().try_into().unwrap(); | = help: consider removing `.try_into()` -error: useless conversion to the same type +error: useless conversion to the same type: `std::string::String` --> $DIR/useless_conversion_try.rs:35:27 | LL | let _: String = match String::from("_").try_into() { From 20a2e095eca14319d233a70b87c1b4415737f94d Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Sun, 13 Sep 2020 19:20:57 +0800 Subject: [PATCH 0356/1052] Simplify iter chain struct doc --- library/core/src/iter/adapters/chain.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs index 6700ef017bde4..13c6a75d58b5c 100644 --- a/library/core/src/iter/adapters/chain.rs +++ b/library/core/src/iter/adapters/chain.rs @@ -4,11 +4,8 @@ use crate::usize; /// An iterator that links two iterators together, in a chain. /// -/// This `struct` is created by the [`chain`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`chain`]: trait.Iterator.html#method.chain -/// [`Iterator`]: trait.Iterator.html +/// This `struct` is created by [`Iterator::chain`]. See its documentation +/// for more. #[derive(Clone, Debug)] #[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] From 46767b1665245d8efa138f0a79d6ecdc7bfbdb08 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 13 Sep 2020 14:02:01 +0200 Subject: [PATCH 0357/1052] slice::from_raw_parts: explicitly mention that data must be initialized --- library/core/src/slice/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 4c027b23584bf..3ff33fab431c4 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -6680,6 +6680,8 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { /// them from other data. You can obtain a pointer that is usable as `data` /// for zero-length slices using [`NonNull::dangling()`]. /// +/// * `data` must point to `len` consecutive properly initialized values of type `T`. +/// /// * The memory referenced by the returned slice must not be mutated for the duration /// of lifetime `'a`, except inside an `UnsafeCell`. /// @@ -6767,6 +6769,8 @@ pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { /// them from other data. You can obtain a pointer that is usable as `data` /// for zero-length slices using [`NonNull::dangling()`]. /// +/// * `data` must point to `len` consecutive properly initialized values of type `T`. +/// /// * The memory referenced by the returned slice must not be accessed through any other pointer /// (not derived from the return value) for the duration of lifetime `'a`. /// Both read and write accesses are forbidden. From 458aaba08467dc6b8d04b79f955a46be779d94f1 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 19 Jul 2020 20:57:04 +0200 Subject: [PATCH 0358/1052] Add Atomic*::from_mut. The atomic equivalent of Cell::from_mut. --- library/core/src/sync/atomic.rs | 98 ++++++++++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 1 deletion(-) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 38eabaaa396e0..cdd9b3ae90bbd 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -110,6 +110,7 @@ use self::Ordering::*; use crate::cell::UnsafeCell; use crate::fmt; use crate::intrinsics; +use crate::mem::align_of; use crate::hint::spin_loop; @@ -327,6 +328,27 @@ impl AtomicBool { unsafe { &mut *(self.v.get() as *mut bool) } } + /// Get atomic access to a `&mut bool`. + /// + /// # Examples + /// + /// ``` + /// #![feature(atomic_from_mut)] + /// use std::sync::atomic::{AtomicBool, Ordering}; + /// + /// let mut some_bool = true; + /// let a = AtomicBool::from_mut(&mut some_bool); + /// a.store(false, Ordering::Relaxed); + /// assert_eq!(some_bool, false); + /// ``` + #[inline] + #[unstable(feature = "atomic_from_mut", issue = "76314")] + pub fn from_mut(v: &mut bool) -> &Self { + // SAFETY: the mutable reference guarantees unique ownership, and + // alignment of both `bool` and `Self` is 1. + unsafe { &*(v as *mut bool as *mut Self) } + } + /// Consumes the atomic and returns the contained value. /// /// This is safe because passing `self` by value guarantees that no other threads are @@ -820,6 +842,30 @@ impl AtomicPtr { unsafe { &mut *self.p.get() } } + /// Get atomic access to a pointer. + /// + /// # Examples + /// + /// ``` + /// #![feature(atomic_from_mut)] + /// use std::sync::atomic::{AtomicPtr, Ordering}; + /// + /// let mut some_ptr = &mut 123 as *mut i32; + /// let a = AtomicPtr::from_mut(&mut some_ptr); + /// a.store(&mut 456, Ordering::Relaxed); + /// assert_eq!(unsafe { *some_ptr }, 456); + /// ``` + #[inline] + #[unstable(feature = "atomic_from_mut", issue = "76314")] + pub fn from_mut(v: &mut *mut T) -> &Self { + let [] = [(); align_of::() - align_of::<*mut T>()]; + // SAFETY: + // - the mutable reference guarantees unique ownership. + // - the alignment of `*mut T` and `Self` is the same on all platforms + // supported by rust, as verified above. + unsafe { &*(v as *mut *mut T as *mut Self) } + } + /// Consumes the atomic and returns the contained value. /// /// This is safe because passing `self` by value guarantees that no other threads are @@ -1104,6 +1150,12 @@ impl From<*mut T> for AtomicPtr { } } +macro_rules! if_not_8_bit { + (u8, $($tt:tt)*) => { "" }; + (i8, $($tt:tt)*) => { "" }; + ($_:ident, $($tt:tt)*) => { $($tt)* }; +} + #[cfg(target_has_atomic_load_store = "8")] macro_rules! atomic_int { ($cfg_cas:meta, @@ -1115,7 +1167,8 @@ macro_rules! atomic_int { $stable_nand:meta, $const_stable:meta, $stable_init_const:meta, - $s_int_type:expr, $int_ref:expr, + $(from_mut: cfg($from_mut_cfg:meta),)? + $s_int_type:literal, $int_ref:expr, $extra_feature:expr, $min_fn:ident, $max_fn:ident, $align:expr, @@ -1226,6 +1279,45 @@ assert_eq!(some_var.load(Ordering::SeqCst), 5); } } + doc_comment! { + concat!("Get atomic access to a `&mut ", stringify!($int_type), "`. + +", +if_not_8_bit! { + $int_type, + concat!( + "**Note:** This function is only available on targets where `", + stringify!($int_type), "` has an alignment of ", $align, " bytes." + ) +}, +" + +# Examples + +``` +#![feature(atomic_from_mut)] +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let mut some_int = 123; +let a = ", stringify!($atomic_type), "::from_mut(&mut some_int); +a.store(100, Ordering::Relaxed); +assert_eq!(some_int, 100); +``` + "), + #[inline] + $(#[cfg($from_mut_cfg)])? + #[unstable(feature = "atomic_from_mut", issue = "76314")] + pub fn from_mut(v: &mut $int_type) -> &Self { + let [] = [(); align_of::() - align_of::<$int_type>()]; + // SAFETY: + // - the mutable reference guarantees unique ownership. + // - the alignment of `$int_type` and `Self` is the + // same on all platforms enabled by `$from_mut_cfg` + // as verified above. + unsafe { &*(v as *mut $int_type as *mut Self) } + } + } + doc_comment! { concat!("Consumes the atomic and returns the contained value. @@ -1984,6 +2076,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), + from_mut: cfg(not(target_arch = "x86")), "i64", "../../../std/primitive.i64.html", "", atomic_min, atomic_max, @@ -2002,6 +2095,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), + from_mut: cfg(not(target_arch = "x86")), "u64", "../../../std/primitive.u64.html", "", atomic_umin, atomic_umax, @@ -2020,6 +2114,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), + from_mut: cfg(not(target_arch = "x86_64")), "i128", "../../../std/primitive.i128.html", "#![feature(integer_atomics)]\n\n", atomic_min, atomic_max, @@ -2038,6 +2133,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), + from_mut: cfg(not(target_arch = "x86_64")), "u128", "../../../std/primitive.u128.html", "#![feature(integer_atomics)]\n\n", atomic_umin, atomic_umax, From 3be40b22c83491e4a4d34e2ad06aa81b804b9fad Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 12 Sep 2020 21:20:17 +0200 Subject: [PATCH 0359/1052] Fix AtomicPtr::from_mut align check: Avoid generic arg in const expr. See #76200. --- library/core/src/sync/atomic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index cdd9b3ae90bbd..920a82f5af481 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -858,7 +858,7 @@ impl AtomicPtr { #[inline] #[unstable(feature = "atomic_from_mut", issue = "76314")] pub fn from_mut(v: &mut *mut T) -> &Self { - let [] = [(); align_of::() - align_of::<*mut T>()]; + let [] = [(); align_of::>() - align_of::<*mut ()>()]; // SAFETY: // - the mutable reference guarantees unique ownership. // - the alignment of `*mut T` and `Self` is the same on all platforms From cf0720146e89a9af8759951aaf774ef19f33f556 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 13 Sep 2020 14:37:35 +0200 Subject: [PATCH 0360/1052] Fix CI LLVM to work on NixOS out of the box --- src/bootstrap/bootstrap.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 44a17f75451a9..5f78031e1c7cb 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -429,6 +429,8 @@ def download_stage0(self): llvm_assertions = self.get_toml('assertions', 'llvm') == 'true' if self.program_out_of_date(self.llvm_stamp(), llvm_sha + str(llvm_assertions)): self._download_ci_llvm(llvm_sha, llvm_assertions) + for binary in ["llvm-config", "FileCheck"]: + self.fix_bin_or_dylib("{}/bin/{}".format(self.llvm_root(), binary)) with output(self.llvm_stamp()) as llvm_stamp: llvm_stamp.write(self.date + llvm_sha + str(llvm_assertions)) From 5dc9790e10b6f57a9f92a2210bb2375cb735c228 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Sun, 13 Sep 2020 20:48:15 +0800 Subject: [PATCH 0361/1052] Add visualization of rustc span in doc It took me quite some time to figure out what Span::to means. A picture is worth a thousand words. --- compiler/rustc_span/src/lib.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index b478a1d15c506..e38cd516b91ac 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -544,6 +544,12 @@ impl Span { } /// Returns a `Span` that would enclose both `self` and `end`. + /// + /// ```text + /// ____ ___ + /// self lorem ipsum end + /// ^^^^^^^^^^^^^^^^^^^^ + /// ``` pub fn to(self, end: Span) -> Span { let span_data = self.data(); let end_data = end.data(); @@ -567,6 +573,12 @@ impl Span { } /// Returns a `Span` between the end of `self` to the beginning of `end`. + /// + /// ```text + /// ____ ___ + /// self lorem ipsum end + /// ^^^^^^^^^^^^^ + /// ``` pub fn between(self, end: Span) -> Span { let span = self.data(); let end = end.data(); @@ -577,7 +589,13 @@ impl Span { ) } - /// Returns a `Span` between the beginning of `self` to the beginning of `end`. + /// Returns a `Span` from the beginning of `self` until the beginning of `end`. + /// + /// ```text + /// ____ ___ + /// self lorem ipsum end + /// ^^^^^^^^^^^^^^^^^ + /// ``` pub fn until(self, end: Span) -> Span { let span = self.data(); let end = end.data(); From c95fa0ac76c3cbe930e021d02750aa28b169a949 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 15 Aug 2020 13:04:32 +0200 Subject: [PATCH 0362/1052] unions: test move behavior of non-Copy fields --- src/test/ui/union/union-drop.rs | 5 +++ src/test/ui/union/union-move.rs | 53 +++++++++++++++++++++++++++++ src/test/ui/union/union-move.stderr | 35 +++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 src/test/ui/union/union-move.rs create mode 100644 src/test/ui/union/union-move.stderr diff --git a/src/test/ui/union/union-drop.rs b/src/test/ui/union/union-drop.rs index daa03ce6b6fd8..d7d5610cd6a6f 100644 --- a/src/test/ui/union/union-drop.rs +++ b/src/test/ui/union/union-drop.rs @@ -49,5 +49,10 @@ fn main() { let y = Y { a: S }; } assert_eq!(CHECK, 2); // 2, dtor of Y is called + { + let y2 = Y { a: S }; + std::mem::forget(y2); + } + assert_eq!(CHECK, 2); // 2, dtor of Y *not* called for y2 } } diff --git a/src/test/ui/union/union-move.rs b/src/test/ui/union/union-move.rs new file mode 100644 index 0000000000000..b19b61282f06a --- /dev/null +++ b/src/test/ui/union/union-move.rs @@ -0,0 +1,53 @@ +//! Test the behavior of moving out of non-`Copy` union fields. +//! Avoid types that `Drop`, we want to focus on moving. +#![feature(untagged_unions)] + +use std::cell::RefCell; + +fn move_out(x: T) {} + +union U1 { + f1_nocopy: RefCell, + f2_nocopy: RefCell, + f3_copy: i32, +} + +union U2 { + f1_nocopy: RefCell, +} +impl Drop for U2 { + fn drop(&mut self) {} +} + +fn test1(x: U1) { + // Moving out of a nocopy field prevents accessing other nocopy field. + unsafe { + move_out(x.f1_nocopy); + move_out(x.f2_nocopy); //~ ERROR use of moved value: `x` + } +} + +fn test2(x: U1) { + // "Moving" out of copy field doesn't prevent later field accesses. + unsafe { + move_out(x.f3_copy); + move_out(x.f2_nocopy); // no error + } +} + +fn test3(x: U1) { + // Moving out of a nocopy field prevents accessing other copy field. + unsafe { + move_out(x.f2_nocopy); + move_out(x.f3_copy); //~ ERROR use of moved value: `x` + } +} + +fn test4(x: U2) { + // Cannot move out of union that implements `Drop`. + unsafe { + move_out(x.f1_nocopy); //~ ERROR cannot move out of type `U2`, which implements the `Drop` trait + } +} + +fn main() {} diff --git a/src/test/ui/union/union-move.stderr b/src/test/ui/union/union-move.stderr new file mode 100644 index 0000000000000..4a29f3a77f3c9 --- /dev/null +++ b/src/test/ui/union/union-move.stderr @@ -0,0 +1,35 @@ +error[E0382]: use of moved value: `x` + --> $DIR/union-move.rs:26:18 + | +LL | fn test1(x: U1) { + | - move occurs because `x` has type `U1`, which does not implement the `Copy` trait +... +LL | move_out(x.f1_nocopy); + | ----------- value moved here +LL | move_out(x.f2_nocopy); + | ^^^^^^^^^^^ value used here after move + +error[E0382]: use of moved value: `x` + --> $DIR/union-move.rs:42:18 + | +LL | fn test3(x: U1) { + | - move occurs because `x` has type `U1`, which does not implement the `Copy` trait +... +LL | move_out(x.f2_nocopy); + | ----------- value moved here +LL | move_out(x.f3_copy); + | ^^^^^^^^^ value used here after move + +error[E0509]: cannot move out of type `U2`, which implements the `Drop` trait + --> $DIR/union-move.rs:49:18 + | +LL | move_out(x.f1_nocopy); + | ^^^^^^^^^^^ + | | + | cannot move out of here + | move occurs because `x.f1_nocopy` has type `std::cell::RefCell`, which does not implement the `Copy` trait + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0382, E0509. +For more information about an error, try `rustc --explain E0382`. From 0ea53f9901d290ef3335061ee46c7853a78139c9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 15 Aug 2020 19:38:01 +0200 Subject: [PATCH 0363/1052] please tidy --- src/test/ui/union/union-move.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/union/union-move.rs b/src/test/ui/union/union-move.rs index b19b61282f06a..a0a2d0d659837 100644 --- a/src/test/ui/union/union-move.rs +++ b/src/test/ui/union/union-move.rs @@ -46,7 +46,7 @@ fn test3(x: U1) { fn test4(x: U2) { // Cannot move out of union that implements `Drop`. unsafe { - move_out(x.f1_nocopy); //~ ERROR cannot move out of type `U2`, which implements the `Drop` trait + move_out(x.f1_nocopy); //~ ERROR cannot move out of type `U2`, which implements the `Drop` } } From e55896aff7ea4e48576bed317b1a9c3d808acfae Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Aug 2020 18:59:57 +0200 Subject: [PATCH 0364/1052] make union-drop mem::forget test meaningful --- src/test/ui/union/union-drop.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/ui/union/union-drop.rs b/src/test/ui/union/union-drop.rs index d7d5610cd6a6f..4df3ed502827e 100644 --- a/src/test/ui/union/union-drop.rs +++ b/src/test/ui/union/union-drop.rs @@ -48,11 +48,11 @@ fn main() { { let y = Y { a: S }; } - assert_eq!(CHECK, 2); // 2, dtor of Y is called + assert_eq!(CHECK, 2); // 2, Y has no dtor { - let y2 = Y { a: S }; - std::mem::forget(y2); + let u2 = U { a: 1 }; + std::mem::forget(u2); } - assert_eq!(CHECK, 2); // 2, dtor of Y *not* called for y2 + assert_eq!(CHECK, 2); // 2, dtor of U *not* called for u2 } } From 9ff7e5d98413d10dd74e3b9509c7a58f6dd6818b Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Sun, 13 Sep 2020 23:23:16 +0900 Subject: [PATCH 0365/1052] Downgrade `verbose_bit_mask` to pedantic --- clippy_lints/src/bit_mask.rs | 2 +- clippy_lints/src/lib.rs | 3 +-- src/lintlist/mod.rs | 2 +- tests/ui/trailing_zeros.rs | 1 + tests/ui/trailing_zeros.stderr | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs index 81a34021e8a01..a4ee54076ee98 100644 --- a/clippy_lints/src/bit_mask.rs +++ b/clippy_lints/src/bit_mask.rs @@ -90,7 +90,7 @@ declare_clippy_lint! { /// if x & 0b1111 == 0 { } /// ``` pub VERBOSE_BIT_MASK, - style, + pedantic, "expressions where a bit mask is less readable than the corresponding method call" } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 1795fd10fa139..c017c5cb5d02c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1157,6 +1157,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(&attrs::INLINE_ALWAYS), LintId::of(&await_holding_lock::AWAIT_HOLDING_LOCK), + LintId::of(&bit_mask::VERBOSE_BIT_MASK), LintId::of(&checked_conversions::CHECKED_CONVERSIONS), LintId::of(&copies::MATCH_SAME_ARMS), LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION), @@ -1254,7 +1255,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&attrs::USELESS_ATTRIBUTE), LintId::of(&bit_mask::BAD_BIT_MASK), LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK), - LintId::of(&bit_mask::VERBOSE_BIT_MASK), LintId::of(&blacklisted_name::BLACKLISTED_NAME), LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), LintId::of(&booleans::LOGIC_BUG), @@ -1512,7 +1512,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&assign_ops::ASSIGN_OP_PATTERN), LintId::of(&attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), LintId::of(&attrs::UNKNOWN_CLIPPY_LINTS), - LintId::of(&bit_mask::VERBOSE_BIT_MASK), LintId::of(&blacklisted_name::BLACKLISTED_NAME), LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), LintId::of(&collapsible_if::COLLAPSIBLE_IF), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 04d486438b1eb..a7d38c93433d1 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2637,7 +2637,7 @@ pub static ref ALL_LINTS: Vec = vec![ }, Lint { name: "verbose_bit_mask", - group: "style", + group: "pedantic", desc: "expressions where a bit mask is less readable than the corresponding method call", deprecation: None, module: "bit_mask", diff --git a/tests/ui/trailing_zeros.rs b/tests/ui/trailing_zeros.rs index 1cef8c2cfc997..fbdc977b769a4 100644 --- a/tests/ui/trailing_zeros.rs +++ b/tests/ui/trailing_zeros.rs @@ -1,4 +1,5 @@ #![allow(unused_parens)] +#![warn(clippy::verbose_bit_mask)] fn main() { let x: i32 = 42; diff --git a/tests/ui/trailing_zeros.stderr b/tests/ui/trailing_zeros.stderr index 320d9cc3f6434..798551118309e 100644 --- a/tests/ui/trailing_zeros.stderr +++ b/tests/ui/trailing_zeros.stderr @@ -1,5 +1,5 @@ error: bit mask could be simplified with a call to `trailing_zeros` - --> $DIR/trailing_zeros.rs:5:13 + --> $DIR/trailing_zeros.rs:6:13 | LL | let _ = (x & 0b1111 == 0); // suggest trailing_zeros | ^^^^^^^^^^^^^^^^^ help: try: `x.trailing_zeros() >= 4` @@ -7,7 +7,7 @@ LL | let _ = (x & 0b1111 == 0); // suggest trailing_zeros = note: `-D clippy::verbose-bit-mask` implied by `-D warnings` error: bit mask could be simplified with a call to `trailing_zeros` - --> $DIR/trailing_zeros.rs:6:13 + --> $DIR/trailing_zeros.rs:7:13 | LL | let _ = x & 0b1_1111 == 0; // suggest trailing_zeros | ^^^^^^^^^^^^^^^^^ help: try: `x.trailing_zeros() >= 5` From 8d96cc238e571ef7d83dcf87239d525d644bbb69 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 13 Sep 2020 14:39:55 +0000 Subject: [PATCH 0366/1052] make llvm_asm options more intense --- src/doc/unstable-book/src/library-features/llvm-asm.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/unstable-book/src/library-features/llvm-asm.md b/src/doc/unstable-book/src/library-features/llvm-asm.md index da01d9228f14e..a2f029db29165 100644 --- a/src/doc/unstable-book/src/library-features/llvm-asm.md +++ b/src/doc/unstable-book/src/library-features/llvm-asm.md @@ -159,12 +159,12 @@ specify some extra info about the inline assembly: Current valid options are: -1. *volatile* - specifying this is analogous to +1. `volatile` - specifying this is analogous to `__asm__ __volatile__ (...)` in gcc/clang. -2. *alignstack* - certain instructions expect the stack to be +2. `alignstack` - certain instructions expect the stack to be aligned a certain way (i.e. SSE) and specifying this indicates to the compiler to insert its usual stack alignment code -3. *intel* - use intel syntax instead of the default AT&T. +3. `intel` - use intel syntax instead of the default AT&T. ```rust # #![feature(llvm_asm)] From 45c1e0ae07b9581d8c2d2b39315ac7cc79475d75 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 8 Sep 2020 15:09:57 -0700 Subject: [PATCH 0367/1052] Auto-generate lint documentation. --- Cargo.lock | 9 + Cargo.toml | 1 + compiler/rustc_lint/src/array_into_iter.rs | 25 + compiler/rustc_lint/src/builtin.rs | 504 ++++ compiler/rustc_lint/src/non_ascii_idents.rs | 129 + compiler/rustc_lint/src/nonstandard_style.rs | 49 + .../rustc_lint/src/redundant_semicolon.rs | 15 + compiler/rustc_lint/src/types.rs | 106 + compiler/rustc_lint/src/unused.rs | 146 ++ compiler/rustc_session/src/lint.rs | 56 +- compiler/rustc_session/src/lint/builtin.rs | 2118 +++++++++++++++++ src/bootstrap/doc.rs | 67 +- src/bootstrap/tool.rs | 1 + src/doc/rustc/src/lints/groups.md | 9 +- src/doc/rustc/src/lints/index.md | 32 + .../src/lints/listing/allowed-by-default.md | 453 +--- .../src/lints/listing/deny-by-default.md | 202 +- .../src/lints/listing/warn-by-default.md | 902 +------ src/tools/lint-docs/Cargo.toml | 13 + src/tools/lint-docs/src/groups.rs | 114 + src/tools/lint-docs/src/lib.rs | 463 ++++ src/tools/lint-docs/src/main.rs | 67 + 22 files changed, 3914 insertions(+), 1567 deletions(-) create mode 100644 src/tools/lint-docs/Cargo.toml create mode 100644 src/tools/lint-docs/src/groups.rs create mode 100644 src/tools/lint-docs/src/lib.rs create mode 100644 src/tools/lint-docs/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index b448baf425baa..1a67deacbfe03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1677,6 +1677,15 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" +[[package]] +name = "lint-docs" +version = "0.1.0" +dependencies = [ + "serde_json", + "tempfile", + "walkdir", +] + [[package]] name = "lock_api" version = "0.3.4" diff --git a/Cargo.toml b/Cargo.toml index fde1cb5a35c2e..02794d1028b50 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ members = [ "src/tools/compiletest", "src/tools/error_index_generator", "src/tools/linkchecker", + "src/tools/lint-docs", "src/tools/rustbook", "src/tools/unstable-book-gen", "src/tools/tidy", diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs index 1d27bdcb28261..e6be082da0e99 100644 --- a/compiler/rustc_lint/src/array_into_iter.rs +++ b/compiler/rustc_lint/src/array_into_iter.rs @@ -7,6 +7,31 @@ use rustc_session::lint::FutureIncompatibleInfo; use rustc_span::symbol::sym; declare_lint! { + /// The `array_into_iter` lint detects calling `into_iter` on arrays. + /// + /// ### Example + /// + /// ```rust + /// # #![allow(unused)] + /// [1, 2, 3].into_iter().for_each(|n| { *n; }); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In the future, it is planned to add an `IntoIter` implementation for + /// arrays such that it will iterate over *values* of the array instead of + /// references. Due to how method resolution works, this will change + /// existing code that uses `into_iter` on arrays. The solution to avoid + /// this warning is to use `iter()` instead of `into_iter()`. + /// + /// This is a [future-incompatible] lint to transition this to a hard error + /// in the future. See [issue #66145] for more details and a more thorough + /// description of the lint. + /// + /// [issue #66145]: https://github.com/rust-lang/rust/issues/66145 + /// [future-incompatible]: ../index.md#future-incompatible-lints pub ARRAY_INTO_ITER, Warn, "detects calling `into_iter` on arrays", diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index d18d89ed641b2..e785ba03d2201 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -61,6 +61,23 @@ use tracing::{debug, trace}; pub use rustc_session::lint::builtin::*; declare_lint! { + /// The `while_true` lint detects `while true { }`. + /// + /// ### Example + /// + /// ```rust,no_run + /// while true { + /// + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// `while true` should be replaced with `loop`. A `loop` expression is + /// the preferred way to write an infinite loop because it more directly + /// expresses the intent of the loop. WHILE_TRUE, Warn, "suggest using `loop { }` instead of `while true { }`" @@ -102,6 +119,24 @@ impl EarlyLintPass for WhileTrue { } declare_lint! { + /// The `box_pointers` lints use of the Box type. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(box_pointers)] + /// struct Foo { + /// x: Box, + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This lint is mostly historical, and not particularly useful. `Box` + /// used to be built into the language, and the only way to do heap + /// allocation. Today's Rust can call into other allocators, etc. BOX_POINTERS, Allow, "use of owned (Box type) heap memory" @@ -156,6 +191,36 @@ impl<'tcx> LateLintPass<'tcx> for BoxPointers { } declare_lint! { + /// The `non_shorthand_field_patterns` lint detects using `Struct { x: x }` + /// instead of `Struct { x }` in a pattern. + /// + /// ### Example + /// + /// ```rust + /// struct Point { + /// x: i32, + /// y: i32, + /// } + /// + /// + /// fn main() { + /// let p = Point { + /// x: 5, + /// y: 5, + /// }; + /// + /// match p { + /// Point { x: x, y: y } => (), + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The preferred style is to avoid the repetition of specifying both the + /// field name and the binding name if both identifiers are the same. NON_SHORTHAND_FIELD_PATTERNS, Warn, "using `Struct { x: x }` instead of `Struct { x }` in a pattern" @@ -216,6 +281,25 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns { } declare_lint! { + /// The `unsafe_code` lint catches usage of `unsafe` code. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unsafe_code)] + /// fn main() { + /// unsafe { + /// + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This lint is intended to restrict the usage of `unsafe`, which can be + /// difficult to use correctly. UNSAFE_CODE, Allow, "usage of `unsafe` code" @@ -303,6 +387,25 @@ impl EarlyLintPass for UnsafeCode { } declare_lint! { + /// The `missing_docs` lint detects missing documentation for public items. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(missing_docs)] + /// pub fn foo() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This lint is intended to ensure that a library is well-documented. + /// Items without documentation can be difficult for users to understand + /// how to use properly. + /// + /// This lint is "allow" by default because it can be noisy, and not all + /// projects may want to enforce everything to be documented. pub MISSING_DOCS, Allow, "detects missing documentation for public members", @@ -528,6 +631,34 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { } declare_lint! { + /// The `missing_copy_implementations` lint detects potentially-forgotten + /// implementations of [`Copy`]. + /// + /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(missing_copy_implementations)] + /// pub struct Foo { + /// pub field: i32 + /// } + /// # fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Historically (before 1.0), types were automatically marked as `Copy` + /// if possible. This was changed so that it required an explicit opt-in + /// by implementing the `Copy` trait. As part of this change, a lint was + /// added to alert if a copyable type was not marked `Copy`. + /// + /// This lint is "allow" by default because this code isn't bad; it is + /// common to write newtypes like this specifically so that a `Copy` type + /// is no longer `Copy`. `Copy` types can result in unintended copies of + /// large data which can impact performance. pub MISSING_COPY_IMPLEMENTATIONS, Allow, "detects potentially-forgotten implementations of `Copy`" @@ -584,6 +715,32 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { } declare_lint! { + /// The `missing_debug_implementations` lint detects missing + /// implementations of [`fmt::Debug`]. + /// + /// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(missing_debug_implementations)] + /// pub struct Foo; + /// # fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Having a `Debug` implementation on all types can assist with + /// debugging, as it provides a convenient way to format and display a + /// value. Using the `#[derive(Debug)]` attribute will automatically + /// generate a typical implementation, or a custom implementation can be + /// added by manually implementing the `Debug` trait. + /// + /// This lint is "allow" by default because adding `Debug` to all types can + /// have a negative impact on compile time and code size. It also requires + /// boilerplate to be added to every type, which can be an impediment. MISSING_DEBUG_IMPLEMENTATIONS, Allow, "detects missing implementations of Debug" @@ -640,6 +797,45 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations { } declare_lint! { + /// The `anonymous_parameters` lint detects anonymous parameters in trait + /// definitions. + /// + /// ### Example + /// + /// ```rust,edition2015,compile_fail + /// #![deny(anonymous_parameters)] + /// // edition 2015 + /// pub trait Foo { + /// fn foo(usize); + /// } + /// fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This syntax is mostly a historical accident, and can be worked around + /// quite easily by adding an `_` pattern or a descriptive identifier: + /// + /// ```rust + /// trait Foo { + /// fn foo(_: usize); + /// } + /// ``` + /// + /// This syntax is now a hard error in the 2018 edition. In the 2015 + /// edition, this lint is "allow" by default, because the old code is + /// still valid, and warning for all old code can be noisy. This lint + /// enables the [`cargo fix`] tool with the `--edition` flag to + /// automatically transition old code from the 2015 edition to 2018. The + /// tool will switch this lint to "warn" and will automatically apply the + /// suggested fix from the compiler (which is to add `_` to each + /// parameter). This provides a completely automated way to update old + /// code for a new edition. See [issue #41686] for more details. + /// + /// [issue #41686]: https://github.com/rust-lang/rust/issues/41686 + /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html pub ANONYMOUS_PARAMETERS, Allow, "detects anonymous parameters", @@ -806,12 +1002,54 @@ impl EarlyLintPass for UnusedDocComment { } declare_lint! { + /// The `no_mangle_const_items` lint detects any `const` items with the + /// [`no_mangle` attribute]. + /// + /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #[no_mangle] + /// const FOO: i32 = 5; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Constants do not have their symbols exported, and therefore, this + /// probably means you meant to use a [`static`], not a [`const`]. + /// + /// [`static`]: https://doc.rust-lang.org/reference/items/static-items.html + /// [`const`]: https://doc.rust-lang.org/reference/items/constant-items.html NO_MANGLE_CONST_ITEMS, Deny, "const items will not have their symbols exported" } declare_lint! { + /// The `no_mangle_generic_items` lint detects generic items that must be + /// mangled. + /// + /// ### Example + /// + /// ```rust + /// #[no_mangle] + /// fn foo(t: T) { + /// + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// An function with generics must have its symbol mangled to accommodate + /// the generic parameter. The [`no_mangle` attribute] has no effect in + /// this situation, and should be removed. + /// + /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute NO_MANGLE_GENERIC_ITEMS, Warn, "generic items must be mangled" @@ -882,6 +1120,27 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { } declare_lint! { + /// The `mutable_transmutes` lint catches transmuting from `&T` to `&mut + /// T` because it is [undefined behavior]. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// ### Example + /// + /// ```rust,compile_fail + /// unsafe { + /// let y = std::mem::transmute::<&i32, &mut i32>(&5); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Certain assumptions are made about aliasing of data, and this transmute + /// violates those assumptions. Consider using [`UnsafeCell`] instead. + /// + /// [`UnsafeCell`]: https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html MUTABLE_TRANSMUTES, Deny, "mutating transmuted &mut T from &T may cause undefined behavior" @@ -931,6 +1190,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes { } declare_lint! { + /// The `unstable_features` is deprecated and should no longer be used. UNSTABLE_FEATURES, Allow, "enabling unstable features (deprecated. do not use)" @@ -956,6 +1216,32 @@ impl<'tcx> LateLintPass<'tcx> for UnstableFeatures { } declare_lint! { + /// The `unreachable_pub` lint triggers for `pub` items not reachable from + /// the crate root. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unreachable_pub)] + /// mod foo { + /// pub mod bar { + /// + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// A bare `pub` visibility may be misleading if the item is not actually + /// publicly exported from the crate. The `pub(crate)` visibility is + /// recommended to be used instead, which more clearly expresses the intent + /// that the item is only visible within its own crate. + /// + /// This lint is "allow" by default because it will trigger for a large + /// amount existing Rust code, and has some false-positives. Eventually it + /// is desired for this to become warn-by-default. pub UNREACHABLE_PUB, Allow, "`pub` items not reachable from crate root" @@ -1035,6 +1321,21 @@ impl<'tcx> LateLintPass<'tcx> for UnreachablePub { } declare_lint! { + /// The `type_alias_bounds` lint detects bounds in type aliases. + /// + /// ### Example + /// + /// ```rust + /// type SendVec = Vec; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The trait bounds in a type alias are currently ignored, and should not + /// be included to avoid confusion. This was previously allowed + /// unintentionally; this may become a hard error in the future. TYPE_ALIAS_BOUNDS, Warn, "bounds in type aliases are not enforced" @@ -1194,6 +1495,35 @@ impl<'tcx> LateLintPass<'tcx> for UnusedBrokenConst { } declare_lint! { + /// The `trivial_bounds` lint detects trait bounds that don't depend on + /// any type parameters. + /// + /// ### Example + /// + /// ```rust + /// #![feature(trivial_bounds)] + /// pub struct A where i32: Copy; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Usually you would not write a trait bound that you know is always + /// true, or never true. However, when using macros, the macro may not + /// know whether or not the constraint would hold or not at the time when + /// generating the code. Currently, the compiler does not alert you if the + /// constraint is always true, and generates an error if it is never true. + /// The `trivial_bounds` feature changes this to be a warning in both + /// cases, giving macros more freedom and flexibility to generate code, + /// while still providing a signal when writing non-macro code that + /// something is amiss. + /// + /// See [RFC 2056] for more details. This feature is currently only + /// available on the nightly channel, see [tracking issue #48214]. + /// + /// [RFC 2056]: https://github.com/rust-lang/rfcs/blob/master/text/2056-allow-trivial-where-clause-constraints.md + /// [tracking issue #48214]: https://github.com/rust-lang/rust/issues/48214 TRIVIAL_BOUNDS, Warn, "these bounds don't depend on an type parameters" @@ -1269,6 +1599,29 @@ declare_lint_pass!( ); declare_lint! { + /// The `ellipsis_inclusive_range_patterns` lint detects the [`...` range + /// pattern], which is deprecated. + /// + /// [`...` range pattern]: https://doc.rust-lang.org/reference/patterns.html#range-patterns + /// + /// ### Example + /// + /// ```rust + /// let x = 123; + /// match x { + /// 0...100 => {} + /// _ => {} + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The `...` range pattern syntax was changed to `..=` to avoid potential + /// confusion with the [`..` range expression]. Use the new form instead. + /// + /// [`..` range expression]: https://doc.rust-lang.org/reference/expressions/range-expr.html pub ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, Warn, "`...` range patterns are deprecated" @@ -1355,6 +1708,38 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { } declare_lint! { + /// The `unnameable_test_items` lint detects [`#[test]`][test] functions + /// that are not able to be run by the test harness because they are in a + /// position where they are not nameable. + /// + /// [test]: https://doc.rust-lang.org/reference/attributes/testing.html#the-test-attribute + /// + /// ### Example + /// + /// ```rust,test + /// fn main() { + /// #[test] + /// fn foo() { + /// // This test will not fail because it does not run. + /// assert_eq!(1, 2); + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In order for the test harness to run a test, the test function must be + /// located in a position where it can be accessed from the crate root. + /// This generally means it must be defined in a module, and not anywhere + /// else such as inside another function. The compiler previously allowed + /// this without an error, so a lint was added as an alert that a test is + /// not being used. Whether or not this should be allowed has not yet been + /// decided, see [RFC 2471] and [issue #36629]. + /// + /// [RFC 2471]: https://github.com/rust-lang/rfcs/pull/2471#issuecomment-397414443 + /// [issue #36629]: https://github.com/rust-lang/rust/issues/36629 UNNAMEABLE_TEST_ITEMS, Warn, "detects an item that cannot be named being marked as `#[test_case]`", @@ -1400,6 +1785,41 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems { } declare_lint! { + /// The `keyword_idents` lint detects edition keywords being used as an + /// identifier. + /// + /// ### Example + /// + /// ```rust,edition2015,compile_fail + /// #![deny(keyword_idents)] + /// // edition 2015 + /// fn dyn() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Rust [editions] allow the language to evolve without breaking + /// backwards compatibility. This lint catches code that uses new keywords + /// that are added to the language that are used as identifiers (such as a + /// variable name, function name, etc.). If you switch the compiler to a + /// new edition without updating the code, then it will fail to compile if + /// you are using a new keyword as an identifier. + /// + /// You can manually change the identifiers to a non-keyword, or use a + /// [raw identifier], for example `r#dyn`, to transition to a new edition. + /// + /// This lint solves the problem automatically. It is "allow" by default + /// because the code is perfectly valid in older editions. The [`cargo + /// fix`] tool with the `--edition` flag will switch this lint to "warn" + /// and automatically apply the suggested fix from the compiler (which is + /// to use a raw identifier). This provides a completely automated way to + /// update old code for a new edition. + /// + /// [editions]: https://doc.rust-lang.org/edition-guide/ + /// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html + /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html pub KEYWORD_IDENTS, Allow, "detects edition keywords being used as an identifier", @@ -1801,6 +2221,26 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { } declare_lint! { + /// The `incomplete_features` lint detects unstable features enabled with + /// the [`feature` attribute] that may function improperly in some or all + /// cases. + /// + /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/ + /// + /// ### Example + /// + /// ```rust + /// #![feature(generic_associated_types)] + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Although it is encouraged for people to experiment with unstable + /// features, some of them are known to be incomplete or faulty. This lint + /// is a signal that the feature has not yet been finished, and you may + /// experience problems with it. pub INCOMPLETE_FEATURES, Warn, "incomplete features that may function improperly in some or all cases" @@ -1841,6 +2281,36 @@ impl EarlyLintPass for IncompleteFeatures { } declare_lint! { + /// The `invalid_value` lint detects creating a value that is not valid, + /// such as a NULL reference. + /// + /// ### Example + /// + /// ```rust,no_run + /// # #![allow(unused)] + /// unsafe { + /// let x: &'static i32 = std::mem::zeroed(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In some situations the compiler can detect that the code is creating + /// an invalid value, which should be avoided. + /// + /// In particular, this lint will check for improper use of + /// [`mem::zeroed`], [`mem::uninitialized`], [`mem::transmute`], and + /// [`MaybeUninit::assume_init`] that can cause [undefined behavior]. The + /// lint should provide extra information to indicate what the problem is + /// and a possible solution. + /// + /// [`mem::zeroed`]: https://doc.rust-lang.org/std/mem/fn.zeroed.html + /// [`mem::uninitialized`]: https://doc.rust-lang.org/std/mem/fn.uninitialized.html + /// [`mem::transmute`]: https://doc.rust-lang.org/std/mem/fn.transmute.html + /// [`MaybeUninit::assume_init`]: https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#method.assume_init + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html pub INVALID_VALUE, Warn, "an invalid value is being created (such as a NULL reference)" @@ -2072,6 +2542,40 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { } declare_lint! { + /// The `clashing_extern_declarations` lint detects when an `extern fn` + /// has been declared with the same name but different types. + /// + /// ### Example + /// + /// ```rust + /// mod m { + /// extern "C" { + /// fn foo(); + /// } + /// } + /// + /// extern "C" { + /// fn foo(_: u32); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Because two symbols of the same name cannot be resolved to two + /// different functions at link time, and one function cannot possibly + /// have two types, a clashing extern declaration is almost certainly a + /// mistake. Check to make sure that the `extern` definitions are correct + /// and equivalent, and possibly consider unifying them in one location. + /// + /// This lint does not run between crates because a project may have + /// dependencies which both rely on the same extern function, but declare + /// it in a different (but valid) way. For example, they may both declare + /// an opaque type for one or more of the arguments (which would end up + /// distinct types), or use types that are valid conversions in the + /// language the `extern fn` is defined in. In these cases, the compiler + /// can't say that the clashing declaration is incorrect. pub CLASHING_EXTERN_DECLARATIONS, Warn, "detects when an extern fn has been declared with the same name but different types" diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs index 2f0b2a8d68028..ecacdcde49f88 100644 --- a/compiler/rustc_lint/src/non_ascii_idents.rs +++ b/compiler/rustc_lint/src/non_ascii_idents.rs @@ -4,6 +4,32 @@ use rustc_data_structures::fx::FxHashMap; use rustc_span::symbol::Symbol; declare_lint! { + /// The `non_ascii_idents` lint detects non-ASCII identifiers. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// # #![allow(unused)] + /// #![feature(non_ascii_idents)] + /// #![deny(non_ascii_idents)] + /// fn main() { + /// let föö = 1; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Currently on stable Rust, identifiers must contain ASCII characters. + /// The [`non_ascii_idents`] nightly-only feature allows identifiers to + /// contain non-ASCII characters. This lint allows projects that wish to + /// retain the limit of only using ASCII characters to switch this lint to + /// "forbid" (for example to ease collaboration or for security reasons). + /// See [RFC 2457] for more details. + /// + /// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html + /// [RFC 2457]: https://github.com/rust-lang/rfcs/blob/master/text/2457-non-ascii-idents.md pub NON_ASCII_IDENTS, Allow, "detects non-ASCII identifiers", @@ -11,6 +37,37 @@ declare_lint! { } declare_lint! { + /// The `uncommon_codepoints` lint detects uncommon Unicode codepoints in + /// identifiers. + /// + /// ### Example + /// + /// ```rust + /// # #![allow(unused)] + /// #![feature(non_ascii_idents)] + /// const µ: f64 = 0.000001; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// With the [`non_ascii_idents`] nightly-only feature enabled, + /// identifiers are allowed to use non-ASCII characters. This lint warns + /// about using characters which are not commonly used, and may cause + /// visual confusion. + /// + /// This lint is triggered by identifiers that contain a codepoint that is + /// not part of the set of "Allowed" codepoints as described by [Unicode® + /// Technical Standard #39 Unicode Security Mechanisms Section 3.1 General + /// Security Profile for Identifiers][TR39Allowed]. + /// + /// Note that the set of uncommon codepoints may change over time. Beware + /// that if you "forbid" this lint that existing code may fail in the + /// future. + /// + /// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html + /// [TR39Allowed]: https://www.unicode.org/reports/tr39/#General_Security_Profile pub UNCOMMON_CODEPOINTS, Warn, "detects uncommon Unicode codepoints in identifiers", @@ -18,6 +75,43 @@ declare_lint! { } declare_lint! { + /// The `confusable_idents` lint detects visually confusable pairs between + /// identifiers. + /// + /// ### Example + /// + /// ```rust + /// #![feature(non_ascii_idents)] + /// + /// // Latin Capital Letter E With Caron + /// pub const Ě: i32 = 1; + /// // Latin Capital Letter E With Breve + /// pub const Ĕ: i32 = 2; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// With the [`non_ascii_idents`] nightly-only feature enabled, + /// identifiers are allowed to use non-ASCII characters. This lint warns + /// when different identifiers may appear visually similar, which can + /// cause confusion. + /// + /// The confusable detection algorithm is based on [Unicode® Technical + /// Standard #39 Unicode Security Mechanisms Section 4 Confusable + /// Detection][TR39Confusable]. For every distinct identifier X execute + /// the function `skeleton(X)`. If there exist two distinct identifiers X + /// and Y in the same crate where `skeleton(X) = skeleton(Y)` report it. + /// The compiler uses the same mechanism to check if an identifier is too + /// similar to a keyword. + /// + /// Note that the set of confusable characters may change over time. + /// Beware that if you "forbid" this lint that existing code may fail in + /// the future. + /// + /// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html + /// [TR39Confusable]: https://www.unicode.org/reports/tr39/#Confusable_Detection pub CONFUSABLE_IDENTS, Warn, "detects visually confusable pairs between identifiers", @@ -25,6 +119,41 @@ declare_lint! { } declare_lint! { + /// The `mixed_script_confusables` lint detects visually confusable + /// characters in identifiers between different [scripts]. + /// + /// [scripts]: https://en.wikipedia.org/wiki/Script_(Unicode) + /// + /// ### Example + /// + /// ```rust + /// #![feature(non_ascii_idents)] + /// + /// // The Japanese katakana character エ can be confused with the Han character 工. + /// const エ: &'static str = "アイウ"; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// With the [`non_ascii_idents`] nightly-only feature enabled, + /// identifiers are allowed to use non-ASCII characters. This lint warns + /// when characters between different scripts may appear visually similar, + /// which can cause confusion. + /// + /// If the crate contains other identifiers in the same script that have + /// non-confusable characters, then this lint will *not* be issued. For + /// example, if the example given above has another identifier with + /// katakana characters (such as `let カタカナ = 123;`), then this indicates + /// that you are intentionally using katakana, and it will not warn about + /// it. + /// + /// Note that the set of confusable characters may change over time. + /// Beware that if you "forbid" this lint that existing code may fail in + /// the future. + /// + /// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html pub MIXED_SCRIPT_CONFUSABLES, Warn, "detects Unicode scripts whose mixed script confusables codepoints are solely used", diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index f23e8c5e20888..24467f811726a 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -31,6 +31,24 @@ pub fn method_context(cx: &LateContext<'_>, id: hir::HirId) -> MethodLateContext } declare_lint! { + /// The `non_camel_case_types` lint detects types, variants, traits and + /// type parameters that don't have camel case names. + /// + /// ### Example + /// + /// ```rust + /// struct my_struct; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The preferred style for these identifiers is to use "camel case", such + /// as `MyStruct`, where the first letter should not be lowercase, and + /// should not use underscores between letters. Underscores are allowed at + /// the beginning and end of the identifier, as well as between + /// non-letters (such as `X86_64`). pub NON_CAMEL_CASE_TYPES, Warn, "types, variants, traits and type parameters should have camel case names" @@ -161,6 +179,22 @@ impl EarlyLintPass for NonCamelCaseTypes { } declare_lint! { + /// The `non_snake_case` lint detects variables, methods, functions, + /// lifetime parameters and modules that don't have snake case names. + /// + /// ### Example + /// + /// ```rust + /// let MY_VALUE = 5; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The preferred style for these identifiers is to use "snake case", + /// where all the characters are in lowercase, with words separated with a + /// single underscore, such as `my_value`. pub NON_SNAKE_CASE, Warn, "variables, methods, functions, lifetime parameters and modules should have snake case names" @@ -379,6 +413,21 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { } declare_lint! { + /// The `non_upper_case_globals` lint detects static items that don't have + /// uppercase identifiers. + /// + /// ### Example + /// + /// ```rust + /// static max_points: i32 = 5; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The preferred style is for static item names to use all uppercase + /// letters such as `MAX_POINTS`. pub NON_UPPER_CASE_GLOBALS, Warn, "static constants should have uppercase identifiers" diff --git a/compiler/rustc_lint/src/redundant_semicolon.rs b/compiler/rustc_lint/src/redundant_semicolon.rs index d4aa4968f25ee..a31deb87ff0d0 100644 --- a/compiler/rustc_lint/src/redundant_semicolon.rs +++ b/compiler/rustc_lint/src/redundant_semicolon.rs @@ -4,6 +4,21 @@ use rustc_errors::Applicability; use rustc_span::Span; declare_lint! { + /// The `redundant_semicolons` lint detects unnecessary trailing + /// semicolons. + /// + /// ### Example + /// + /// ```rust + /// let _ = 123;; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Extra semicolons are not needed, and may be removed to avoid confusion + /// and visual clutter. pub REDUNDANT_SEMICOLONS, Warn, "detects unnecessary trailing semicolons" diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index af32c16bfe8dd..a202efa6edadd 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -23,18 +23,82 @@ use std::cmp; use tracing::debug; declare_lint! { + /// The `unused_comparisons` lint detects comparisons made useless by + /// limits of the types involved. + /// + /// ### Example + /// + /// ```rust + /// fn foo(x: u8) { + /// x >= 0; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// A useless comparison may indicate a mistake, and should be fixed or + /// removed. UNUSED_COMPARISONS, Warn, "comparisons made useless by limits of the types involved" } declare_lint! { + /// The `overflowing_literals` lint detects literal out of range for its + /// type. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// let x: u8 = 1000; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is usually a mistake to use a literal that overflows the type where + /// it is used. Either use a literal that is within range, or change the + /// type to be within the range of the literal. OVERFLOWING_LITERALS, Deny, "literal out of range for its type" } declare_lint! { + /// The `variant_size_differences` lint detects enums with widely varying + /// variant sizes. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(variant_size_differences)] + /// enum En { + /// V0(u8), + /// VBig([u8; 1024]), + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It can be a mistake to add a variant to an enum that is much larger + /// than the other variants, bloating the overall size required for all + /// variants. This can impact performance and memory usage. This is + /// triggered if one variant is more than 3 times larger than the + /// second-largest variant. + /// + /// Consider placing the large variant's contents on the heap (for example + /// via [`Box`]) to keep the overall size of the enum itself down. + /// + /// This lint is "allow" by default because it can be noisy, and may not be + /// an actual problem. Decisions about this should be guided with + /// profiling and benchmarking. + /// + /// [`Box`]: https://doc.rust-lang.org/std/boxed/index.html VARIANT_SIZE_DIFFERENCES, Allow, "detects enums with widely varying variant sizes" @@ -495,6 +559,27 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits { } declare_lint! { + /// The `improper_ctypes` lint detects incorrect use of types in foreign + /// modules. + /// + /// ### Example + /// + /// ```rust + /// extern "C" { + /// static STATIC: String; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The compiler has several checks to verify that types used in `extern` + /// blocks are safe and follow certain rules to ensure proper + /// compatibility with the foreign interfaces. This lint is issued when it + /// detects a probable mistake in a definition. The lint usually should + /// provide a description of the issue, along with possibly a hint on how + /// to resolve it. IMPROPER_CTYPES, Warn, "proper use of libc types in foreign modules" @@ -503,6 +588,27 @@ declare_lint! { declare_lint_pass!(ImproperCTypesDeclarations => [IMPROPER_CTYPES]); declare_lint! { + /// The `improper_ctypes_definitions` lint detects incorrect use of + /// [`extern` function] definitions. + /// + /// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier + /// + /// ### Example + /// + /// ```rust + /// # #![allow(unused)] + /// pub extern "C" fn str_type(p: &str) { } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// There are many parameter and return types that may be specified in an + /// `extern` function that are not compatible with the given ABI. This + /// lint is an alert that these types should not be used. The lint usually + /// should provide a description of the issue, along with possibly a hint + /// on how to resolve it. IMPROPER_CTYPES_DEFINITIONS, Warn, "proper use of libc types in foreign item definitions" diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 0c06b063e41fa..1e8c30071e762 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -20,6 +20,29 @@ use rustc_span::{BytePos, Span, DUMMY_SP}; use tracing::debug; declare_lint! { + /// The `unused_must_use` lint detects unused result of a type flagged as + /// `#[must_use]`. + /// + /// ### Example + /// + /// ```rust + /// fn returns_result() -> Result<(), ()> { + /// Ok(()) + /// } + /// + /// fn main() { + /// returns_result(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The `#[must_use]` attribute is an indicator that it is a mistake to + /// ignore the value. See [the reference] for more details. + /// + /// [the reference]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute pub UNUSED_MUST_USE, Warn, "unused result of a type flagged as `#[must_use]`", @@ -27,6 +50,39 @@ declare_lint! { } declare_lint! { + /// The `unused_results` lint checks for the unused result of an + /// expression in a statement. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unused_results)] + /// fn foo() -> T { panic!() } + /// + /// fn main() { + /// foo::(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Ignoring the return value of a function may indicate a mistake. In + /// cases were it is almost certain that the result should be used, it is + /// recommended to annotate the function with the [`must_use` attribute]. + /// Failure to use such a return value will trigger the [`unused_must_use` + /// lint] which is warn-by-default. The `unused_results` lint is + /// essentially the same, but triggers for *all* return values. + /// + /// This lint is "allow" by default because it can be noisy, and may not be + /// an actual problem. For example, calling the `remove` method of a `Vec` + /// or `HashMap` returns the previous value, which you may not care about. + /// Using this lint would require explicitly ignoring or discarding such + /// values. + /// + /// [`must_use` attribute]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute + /// [`unused_must_use` lint]: warn-by-default.html#unused-must-use pub UNUSED_RESULTS, Allow, "unused result of an expression in a statement" @@ -265,6 +321,21 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { } declare_lint! { + /// The `path_statements` lint detects path statements with no effect. + /// + /// ### Example + /// + /// ```rust + /// let x = 42; + /// + /// x; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is usually a mistake to have a statement that has no effect. pub PATH_STATEMENTS, Warn, "path statements with no effect" @@ -635,6 +706,21 @@ trait UnusedDelimLint { } declare_lint! { + /// The `unused_parens` lint detects `if`, `match`, `while` and `return` + /// with parentheses; they do not need them. + /// + /// ### Examples + /// + /// ```rust + /// if(true) {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The parenthesis are not needed, and should be removed. This is the + /// preferred style for writing these expressions. pub(super) UNUSED_PARENS, Warn, "`if`, `match`, `while` and `return` do not need parentheses" @@ -808,6 +894,23 @@ impl EarlyLintPass for UnusedParens { } declare_lint! { + /// The `unused_braces` lint detects unnecessary braces around an + /// expression. + /// + /// ### Example + /// + /// ```rust + /// if { true } { + /// // ... + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The braces are not needed, and should be removed. This is the + /// preferred style for writing these expressions. pub(super) UNUSED_BRACES, Warn, "unnecessary braces around an expression" @@ -929,6 +1032,30 @@ impl EarlyLintPass for UnusedBraces { } declare_lint! { + /// The `unused_import_braces` lint catches unnecessary braces around an + /// imported item. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unused_import_braces)] + /// use test::{A}; + /// + /// pub mod test { + /// pub struct A; + /// } + /// # fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// If there is only a single item, then remove the braces (`use test::A;` + /// for example). + /// + /// This lint is "allow" by default because it is only enforcing a + /// stylistic choice. UNUSED_IMPORT_BRACES, Allow, "unnecessary braces around an imported item" @@ -978,6 +1105,25 @@ impl EarlyLintPass for UnusedImportBraces { } declare_lint! { + /// The `unused_allocation` lint detects unnecessary allocations that can + /// be eliminated. + /// + /// ### Example + /// + /// ```rust + /// #![feature(box_syntax)] + /// fn main() { + /// let a = (box [1,2,3]).len(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// When a `box` expression is immediately coerced to a reference, then + /// the allocation is unnecessary, and a reference (using `&` or `&mut`) + /// should be used instead to avoid the allocation. pub(super) UNUSED_ALLOCATION, Warn, "detects unnecessary allocations that can be eliminated" diff --git a/compiler/rustc_session/src/lint.rs b/compiler/rustc_session/src/lint.rs index 0dcbee08abea1..4a3e59f18e5c0 100644 --- a/compiler/rustc_session/src/lint.rs +++ b/compiler/rustc_session/src/lint.rs @@ -65,9 +65,15 @@ pub struct Lint { /// /// The name is written with underscores, e.g., "unused_imports". /// On the command line, underscores become dashes. + /// + /// See https://rustc-dev-guide.rust-lang.org/diagnostics.html#lint-naming + /// for naming guidelines. pub name: &'static str, /// Default level for the lint. + /// + /// See https://rustc-dev-guide.rust-lang.org/diagnostics.html#diagnostic-levels + /// for guidelines on choosing a default level. pub default_level: Level, /// Description of the lint or the issue it detects. @@ -275,17 +281,58 @@ impl LintBuffer { } /// Declares a static item of type `&'static Lint`. +/// +/// See https://rustc-dev-guide.rust-lang.org/diagnostics.html for documentation +/// and guidelines on writing lints. +/// +/// The macro call should start with a doc comment explaining the lint +/// which will be embedded in the rustc user documentation book. It should +/// be written in markdown and have a format that looks like this: +/// +/// ```rust,ignore (doc-example) +/// /// The `my_lint_name` lint detects [short explanation here]. +/// /// +/// /// ### Example +/// /// +/// /// ```rust +/// /// [insert a concise example that triggers the lint] +/// /// ``` +/// /// +/// /// {{produces}} +/// /// +/// /// ### Explanation +/// /// +/// /// This should be a detailed explanation of *why* the lint exists, +/// /// and also include suggestions on how the user should fix the problem. +/// /// Try to keep the text simple enough that a beginner can understand, +/// /// and include links to other documentation for terminology that a +/// /// beginner may not be familiar with. If this is "allow" by default, +/// /// it should explain why (are there false positives or other issues?). If +/// /// this is a future-incompatible lint, it should say so, with text that +/// /// looks roughly like this: +/// /// +/// /// This is a [future-incompatible] lint to transition this to a hard +/// /// error in the future. See [issue #xxxxx] for more details. +/// /// +/// /// [issue #xxxxx]: https://github.com/rust-lang/rust/issues/xxxxx +/// ``` +/// +/// The `{{produces}}` tag will be automatically replaced with the output from +/// the example by the build system. You can build and view the rustc book +/// with `x.py doc --stage=1 src/doc/rustc --open` (use --stage=0 if just +/// changing the wording of an existing lint). #[macro_export] macro_rules! declare_lint { - ($vis: vis $NAME: ident, $Level: ident, $desc: expr) => ( + ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr) => ( $crate::declare_lint!( - $vis $NAME, $Level, $desc, + $(#[$attr])* $vis $NAME, $Level, $desc, ); ); - ($vis: vis $NAME: ident, $Level: ident, $desc: expr, + ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr, $(@future_incompatible = $fi:expr;)? $(@feature_gate = $gate:expr;)? $($v:ident),*) => ( + $(#[$attr])* $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint { name: stringify!($NAME), default_level: $crate::lint::$Level, @@ -298,9 +345,10 @@ macro_rules! declare_lint { ..$crate::lint::Lint::default_fields_for_macro() }; ); - ($vis: vis $NAME: ident, $Level: ident, $desc: expr, + ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr, $lint_edition: expr => $edition_level: ident ) => ( + $(#[$attr])* $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint { name: stringify!($NAME), default_level: $crate::lint::$Level, diff --git a/compiler/rustc_session/src/lint/builtin.rs b/compiler/rustc_session/src/lint/builtin.rs index 0fd6cc1038284..4c0c7fae29b29 100644 --- a/compiler/rustc_session/src/lint/builtin.rs +++ b/compiler/rustc_session/src/lint/builtin.rs @@ -10,6 +10,32 @@ use rustc_span::edition::Edition; use rustc_span::symbol::sym; declare_lint! { + /// The `ill_formed_attribute_input` lint detects ill-formed attribute + /// inputs that were previously accepted and used in practice. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #[inline = "this is not valid"] + /// fn foo() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Previously, inputs for many built-in attributes weren't validated and + /// nonsensical attribute inputs were accepted. After validation was + /// added, it was determined that some existing projects made use of these + /// invalid forms. This is a [future-incompatible] lint to transition this + /// to a hard error in the future. See [issue #57571] for more details. + /// + /// Check the [attribute reference] for details on the valid inputs for + /// attributes. + /// + /// [issue #57571]: https://github.com/rust-lang/rust/issues/57571 + /// [attribute reference]: https://doc.rust-lang.org/nightly/reference/attributes.html + /// [future-incompatible]: ../index.md#future-incompatible-lints pub ILL_FORMED_ATTRIBUTE_INPUT, Deny, "ill-formed attribute inputs that were previously accepted and used in practice", @@ -21,6 +47,32 @@ declare_lint! { } declare_lint! { + /// The `conflicting_repr_hints` lint detects [`repr` attributes] with + /// conflicting hints. + /// + /// [`repr` attributes]: https://doc.rust-lang.org/reference/type-layout.html#representations + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #[repr(u32, u64)] + /// enum Foo { + /// Variant1, + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The compiler incorrectly accepted these conflicting representations in + /// the past. This is a [future-incompatible] lint to transition this to a + /// hard error in the future. See [issue #68585] for more details. + /// + /// To correct the issue, remove one of the conflicting hints. + /// + /// [issue #68585]: https://github.com/rust-lang/rust/issues/68585 + /// [future-incompatible]: ../index.md#future-incompatible-lints pub CONFLICTING_REPR_HINTS, Deny, "conflicts between `#[repr(..)]` hints that were previously accepted and used in practice", @@ -31,30 +83,198 @@ declare_lint! { } declare_lint! { + /// The `meta_variable_misuse` lint detects possible meta-variable misuse + /// in macro definitions. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(meta_variable_misuse)] + /// + /// macro_rules! foo { + /// () => {}; + /// ($( $i:ident = $($j:ident),+ );*) => { $( $( $i = $k; )+ )* }; + /// } + /// + /// fn main() { + /// foo!(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// There are quite a few different ways a [`macro_rules`] macro can be + /// improperly defined. Many of these errors were previously only detected + /// when the macro was expanded or not at all. This lint is an attempt to + /// catch some of these problems when the macro is *defined*. + /// + /// This lint is "allow" by default because it may have false positives + /// and other issues. See [issue #61053] for more details. + /// + /// [`macro_rules`]: https://doc.rust-lang.org/reference/macros-by-example.html + /// [issue #61053]: https://github.com/rust-lang/rust/issues/61053 pub META_VARIABLE_MISUSE, Allow, "possible meta-variable misuse at macro definition" } declare_lint! { + /// The `incomplete_include` lint detects the use of the [`include!`] + /// macro with a file that contains more than one expression. + /// + /// [`include!`]: https://doc.rust-lang.org/std/macro.include.html + /// + /// ### Example + /// + /// ```rust,compile_fail + /// fn main() { + /// include!("foo.txt"); + /// } + /// ``` + /// + /// where the file `foo.txt` contains: + /// + /// ```text + /// println!("hi!"); + /// ``` + /// + /// produces: + /// + /// ```text + /// error: include macro expected single expression in source + /// --> foo.txt:1:14 + /// | + /// 1 | println!("1"); + /// | ^ + /// | + /// = note: `#[deny(incomplete_include)]` on by default + /// ``` + /// + /// ### Explanation + /// + /// The [`include!`] macro is currently only intended to be used to + /// include a single [expression] or multiple [items]. Historically it + /// would ignore any contents after the first expression, but that can be + /// confusing. In the example above, the `println!` expression ends just + /// before the semicolon, making the semicolon "extra" information that is + /// ignored. Perhaps even more surprising, if the included file had + /// multiple print statements, the subsequent ones would be ignored! + /// + /// One workaround is to place the contents in braces to create a [block + /// expression]. Also consider alternatives, like using functions to + /// encapsulate the expressions, or use [proc-macros]. + /// + /// This is a lint instead of a hard error because existing projects were + /// found to hit this error. To be cautious, it is a lint for now. The + /// future semantics of the `include!` macro are also uncertain, see + /// [issue #35560]. + /// + /// [items]: https://doc.rust-lang.org/reference/items.html + /// [expression]: https://doc.rust-lang.org/reference/expressions.html + /// [block expression]: https://doc.rust-lang.org/reference/expressions/block-expr.html + /// [proc-macros]: https://doc.rust-lang.org/reference/procedural-macros.html + /// [issue #35560]: https://github.com/rust-lang/rust/issues/35560 pub INCOMPLETE_INCLUDE, Deny, "trailing content in included file" } declare_lint! { + /// The `arithmetic_overflow` lint detects that an arithmetic operation + /// will [overflow]. + /// + /// [overflow]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow + /// + /// ### Example + /// + /// ```rust,compile_fail + /// 1_i32 << 32; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is very likely a mistake to perform an arithmetic operation that + /// overflows its value. If the compiler is able to detect these kinds of + /// overflows at compile-time, it will trigger this lint. Consider + /// adjusting the expression to avoid overflow, or use a data type that + /// will not overflow. pub ARITHMETIC_OVERFLOW, Deny, "arithmetic operation overflows" } declare_lint! { + /// The `unconditional_panic` lint detects an operation that will cause a + /// panic at runtime. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// # #![allow(unused)] + /// let x = 1 / 0; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This lint detects code that is very likely incorrect. When possible, + /// the compiler will attempt to detect situations where code can be + /// evaluated at compile-time to generate more efficient code. While + /// evaluating such code, if it detects that the code will unconditionally + /// panic, this usually indicates that it is doing something incorrectly. + /// If this lint is allowed, then the code will not be evaluated at + /// compile-time, and instead continue to generate code to evaluate at + /// runtime, which may panic during runtime. pub UNCONDITIONAL_PANIC, Deny, "operation will cause a panic at runtime" } declare_lint! { + /// The `const_err` lint detects an erroneous expression while doing + /// constant evaluation. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![allow(unconditional_panic)] + /// let x: &'static i32 = &(1 / 0); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This lint detects code that is very likely incorrect. If this lint is + /// allowed, then the code will not be evaluated at compile-time, and + /// instead continue to generate code to evaluate at runtime, which may + /// panic during runtime. + /// + /// Note that this lint may trigger in either inside or outside of a + /// [const context]. Outside of a [const context], the compiler can + /// sometimes evaluate an expression at compile-time in order to generate + /// more efficient code. As the compiler becomes better at doing this, it + /// needs to decide what to do when it encounters code that it knows for + /// certain will panic or is otherwise incorrect. Making this a hard error + /// would prevent existing code that exhibited this behavior from + /// compiling, breaking backwards-compatibility. However, this is almost + /// certainly incorrect code, so this is a deny-by-default lint. For more + /// details, see [RFC 1229] and [issue #28238]. + /// + /// Note that there are several other more specific lints associated with + /// compile-time evaluation, such as [`arithmetic_overflow`], + /// [`unconditional_panic`]. + /// + /// [const context]: https://doc.rust-lang.org/reference/const_eval.html#const-context + /// [RFC 1229]: https://github.com/rust-lang/rfcs/blob/master/text/1229-compile-time-asserts.md + /// [issue #28238]: https://github.com/rust-lang/rust/issues/28238 + /// [`arithmetic_overflow`]: deny-by-default.html#arithmetic-overflow + /// [`unconditional_panic`]: deny-by-default.html#unconditional-panic pub CONST_ERR, Deny, "constant evaluation detected erroneous expression", @@ -62,18 +282,105 @@ declare_lint! { } declare_lint! { + /// The `unused_imports` lint detects imports that are never used. + /// + /// ### Example + /// + /// ```rust + /// use std::collections::HashMap; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unused imports may signal a mistake or unfinished code, and clutter + /// the code, and should be removed. If you intended to re-export the item + /// to make it available outside of the module, add a visibility modifier + /// like `pub`. pub UNUSED_IMPORTS, Warn, "imports that are never used" } declare_lint! { + /// The `unused_extern_crates` lint guards against `extern crate` items + /// that are never used. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unused_extern_crates)] + /// extern crate proc_macro; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// `extern crate` items that are unused have no effect and should be + /// removed. Note that there are some cases where specifying an `extern + /// crate` is desired for the side effect of ensuring the given crate is + /// linked, even though it is not otherwise directly referenced. The lint + /// can be silenced by aliasing the crate to an underscore, such as + /// `extern crate foo as _`. Also note that it is no longer idiomatic to + /// use `extern crate` in the [2018 edition], as extern crates are now + /// automatically added in scope. + /// + /// This lint is "allow" by default because it can be noisy, and produce + /// false-positives. If a dependency is being removed from a project, it + /// is recommended to remove it from the build configuration (such as + /// `Cargo.toml`) to ensure stale build entries aren't left behind. + /// + /// [2018 edition]: https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-clarity.html#no-more-extern-crate pub UNUSED_EXTERN_CRATES, Allow, "extern crates that are never used" } declare_lint! { + /// The `unused_crate_dependencies` lint detects crate dependencies that + /// are never used. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unused_crate_dependencies)] + /// ``` + /// + /// This will produce: + /// + /// ```text + /// error: external crate `regex` unused in `lint_example`: remove the dependency or add `use regex as _;` + /// | + /// note: the lint level is defined here + /// --> src/lib.rs:1:9 + /// | + /// 1 | #![deny(unused_crate_dependencies)] + /// | ^^^^^^^^^^^^^^^^^^^^^^^^^ + /// ``` + /// + /// ### Explanation + /// + /// After removing the code that uses a dependency, this usually also + /// requires removing the dependency from the build configuration. + /// However, sometimes that step can be missed, which leads to time wasted + /// building dependencies that are no longer used. This lint can be + /// enabled to detect dependencies that are never used (more specifically, + /// any dependency passed with the `--extern` command-line flag that is + /// never referenced via [`use`], [`extern crate`], or in any [path]). + /// + /// This lint is "allow" by default because it can provide false positives + /// depending on how the build system is configured. For example, when + /// using Cargo, a "package" consists of multiple crates (such as a + /// library and a binary), but the dependencies are defined for the + /// package as a whole. If there is a dependency that is only used in the + /// binary, but not the library, then the lint will be incorrectly issued + /// in the library. + /// + /// [path]: https://doc.rust-lang.org/reference/paths.html + /// [`use`]: https://doc.rust-lang.org/reference/items/use-declarations.html + /// [`extern crate`]: https://doc.rust-lang.org/reference/items/extern-crates.html pub UNUSED_CRATE_DEPENDENCIES, Allow, "crate dependencies that are never used", @@ -81,42 +388,174 @@ declare_lint! { } declare_lint! { + /// The `unused_qualifications` lint detects unnecessarily qualified + /// names. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unused_qualifications)] + /// mod foo { + /// pub fn bar() {} + /// } + /// + /// fn main() { + /// use foo::bar; + /// foo::bar(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// If an item from another module is already brought into scope, then + /// there is no need to qualify it in this case. You can call `bar()` + /// directly, without the `foo::`. + /// + /// This lint is "allow" by default because it is somewhat pedantic, and + /// doesn't indicate an actual problem, but rather a stylistic choice, and + /// can be noisy when refactoring or moving around code. pub UNUSED_QUALIFICATIONS, Allow, "detects unnecessarily qualified names" } declare_lint! { + /// The `unknown_lints` lint detects unrecognized lint attribute. + /// + /// ### Example + /// + /// ```rust + /// #![allow(not_a_real_lint)] + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is usually a mistake to specify a lint that does not exist. Check + /// the spelling, and check the lint listing for the correct name. Also + /// consider if you are using an old version of the compiler, and the lint + /// is only available in a newer version. pub UNKNOWN_LINTS, Warn, "unrecognized lint attribute" } declare_lint! { + /// The `unused_variables` lint detects variables which are not used in + /// any way. + /// + /// ### Example + /// + /// ```rust + /// let x = 5; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unused variables may signal a mistake or unfinished code. To silence + /// the warning for the individual variable, prefix it with an underscore + /// such as `_x`. pub UNUSED_VARIABLES, Warn, "detect variables which are not used in any way" } declare_lint! { + /// The `unused_assignments` lint detects assignments that will never be read. + /// + /// ### Example + /// + /// ```rust + /// let mut x = 5; + /// x = 6; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unused assignments may signal a mistake or unfinished code. If the + /// variable is never used after being assigned, then the assignment can + /// be removed. Variables with an underscore prefix such as `_x` will not + /// trigger this lint. pub UNUSED_ASSIGNMENTS, Warn, "detect assignments that will never be read" } declare_lint! { + /// The `dead_code` lint detects unused, unexported items. + /// + /// ### Example + /// + /// ```rust + /// fn foo() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Dead code may signal a mistake or unfinished code. To silence the + /// warning for individual items, prefix the name with an underscore such + /// as `_foo`. If it was intended to expose the item outside of the crate, + /// consider adding a visibility modifier like `pub`. Otherwise consider + /// removing the unused code. pub DEAD_CODE, Warn, "detect unused, unexported items" } declare_lint! { + /// The `unused_attributes` lint detects attributes that were not used by + /// the compiler. + /// + /// ### Example + /// + /// ```rust + /// #![macro_export] + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unused [attributes] may indicate the attribute is placed in the wrong + /// position. Consider removing it, or placing it in the correct position. + /// Also consider if you intended to use an _inner attribute_ (with a `!` + /// such as `#![allow(unused)]`) which applies to the item the attribute + /// is within, or an _outer attribute_ (without a `!` such as + /// `#[allow(unsued)]`) which applies to the item *following* the + /// attribute. + /// + /// [attributes]: https://doc.rust-lang.org/reference/attributes.html pub UNUSED_ATTRIBUTES, Warn, "detects attributes that were not used by the compiler" } declare_lint! { + /// The `unreachable_code` lint detects unreachable code paths. + /// + /// ### Example + /// + /// ```rust,no_run + /// panic!("we never go past here!"); + /// + /// let x = 5; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unreachable code may signal a mistake or unfinished code. If the code + /// is no longer in use, consider removing it. pub UNREACHABLE_CODE, Warn, "detects unreachable code paths", @@ -124,48 +563,217 @@ declare_lint! { } declare_lint! { + /// The `unreachable_patterns` lint detects unreachable patterns. + /// + /// ### Example + /// + /// ```rust + /// let x = 5; + /// match x { + /// y => (), + /// 5 => (), + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This usually indicates a mistake in how the patterns are specified or + /// ordered. In this example, the `y` pattern will always match, so the + /// five is impossible to reach. Remember, match arms match in order, you + /// probably wanted to put the `5` case above the `y` case. pub UNREACHABLE_PATTERNS, Warn, "detects unreachable patterns" } declare_lint! { + /// The `overlapping_patterns` lint detects `match` arms that have + /// [range patterns] that overlap. + /// + /// [range patterns]: https://doc.rust-lang.org/nightly/reference/patterns.html#range-patterns + /// + /// ### Example + /// + /// ```rust + /// let x = 123u8; + /// match x { + /// 0..=100 => { println!("small"); } + /// 100..=255 => { println!("large"); } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is likely a mistake to have range patterns in a match expression + /// that overlap. Check that the beginning and end values are what you + /// expect, and keep in mind that with `..=` the left and right bounds are + /// inclusive. pub OVERLAPPING_PATTERNS, Warn, "detects overlapping patterns" } declare_lint! { + /// The `bindings_with_variant_name` lint detects pattern bindings with + /// the same name as one of the matched variants. + /// + /// ### Example + /// + /// ```rust + /// pub enum Enum { + /// Foo, + /// Bar, + /// } + /// + /// pub fn foo(x: Enum) { + /// match x { + /// Foo => {} + /// Bar => {} + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is usually a mistake to specify an enum variant name as an + /// [identifier pattern]. In the example above, the `match` arms are + /// specifying a variable name to bind the value of `x` to. The second arm + /// is ignored because the first one matches *all* values. The likely + /// intent is that the arm was intended to match on the enum variant. + /// + /// Two possible solutions are: + /// + /// * Specify the enum variant using a [path pattern], such as + /// `Enum::Foo`. + /// * Bring the enum variants into local scope, such as adding `use + /// Enum::*;` to the beginning of the `foo` function in the example + /// above. + /// + /// [identifier pattern]: https://doc.rust-lang.org/reference/patterns.html#identifier-patterns + /// [path pattern]: https://doc.rust-lang.org/reference/patterns.html#path-patterns pub BINDINGS_WITH_VARIANT_NAME, Warn, "detects pattern bindings with the same name as one of the matched variants" } declare_lint! { + /// The `unused_macros` lint detects macros that were not used. + /// + /// ### Example + /// + /// ```rust + /// macro_rules! unused { + /// () => {}; + /// } + /// + /// fn main() { + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unused macros may signal a mistake or unfinished code. To silence the + /// warning for the individual macro, prefix the name with an underscore + /// such as `_my_macro`. If you intended to export the macro to make it + /// available outside of the crate, use the [`macro_export` attribute]. + /// + /// [`macro_export` attribute]: https://doc.rust-lang.org/reference/macros-by-example.html#path-based-scope pub UNUSED_MACROS, Warn, "detects macros that were not used" } declare_lint! { + /// The `warnings` lint allows you to change the level of other + /// lints which produce warnings. + /// + /// ### Example + /// + /// ```rust + /// #![deny(warnings)] + /// fn foo() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The `warnings` lint is a bit special; by changing its level, you + /// change every other warning that would produce a warning to whatever + /// value you'd like. As such, you won't ever trigger this lint in your + /// code directly. pub WARNINGS, Warn, "mass-change the level for lints which produce warnings" } declare_lint! { + /// The `unused_features` lint detects unused or unknown features found in + /// crate-level [`feature` attributes]. + /// + /// [`feature` attributes]: https://doc.rust-lang.org/nightly/unstable-book/ + /// + /// Note: This lint is currently not functional, see [issue #44232] for + /// more details. + /// + /// [issue #44232]: https://github.com/rust-lang/rust/issues/44232 pub UNUSED_FEATURES, Warn, "unused features found in crate-level `#[feature]` directives" } declare_lint! { + /// The `stable_features` lint detects a [`feature` attribute] that + /// has since been made stable. + /// + /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/ + /// + /// ### Example + /// + /// ```rust + /// #![feature(test_accepted_feature)] + /// fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// When a feature is stabilized, it is no longer necessary to include a + /// `#![feature]` attribute for it. To fix, simply remove the + /// `#![feature]` attribute. pub STABLE_FEATURES, Warn, "stable features found in `#[feature]` directive" } declare_lint! { + /// The `unknown_crate_types` lint detects an unknown crate type found in + /// a [`crate_type` attribute]. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![crate_type="lol"] + /// fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// An unknown value give to the `crate_type` attribute is almost + /// certainly a mistake. + /// + /// [`crate_type` attribute]: https://doc.rust-lang.org/reference/linkage.html pub UNKNOWN_CRATE_TYPES, Deny, "unknown crate type found in `#[crate_type]` directive", @@ -173,18 +781,104 @@ declare_lint! { } declare_lint! { + /// The `trivial_casts` lint detects trivial casts which could be replaced + /// with coercion, which may require [type ascription] or a temporary + /// variable. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(trivial_casts)] + /// let x: &u32 = &42; + /// let y = x as *const u32; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// A trivial cast is a cast `e as T` where `e` has type `U` and `U` is a + /// subtype of `T`. This type of cast is usually unnecessary, as it can be + /// usually be inferred. + /// + /// This lint is "allow" by default because there are situations, such as + /// with FFI interfaces or complex type aliases, where it triggers + /// incorrectly, or in situations where it will be more difficult to + /// clearly express the intent. It may be possible that this will become a + /// warning in the future, possibly with [type ascription] providing a + /// convenient way to work around the current issues. See [RFC 401] for + /// historical context. + /// + /// [type ascription]: https://github.com/rust-lang/rust/issues/23416 + /// [RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md pub TRIVIAL_CASTS, Allow, "detects trivial casts which could be removed" } declare_lint! { + /// The `trivial_numeric_casts` lint detects trivial numeric casts of types + /// which could be removed. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(trivial_numeric_casts)] + /// let x = 42_i32 as i32; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// A trivial numeric cast is a cast of a numeric type to the same numeric + /// type. This type of cast is usually unnecessary. + /// + /// This lint is "allow" by default because there are situations, such as + /// with FFI interfaces or complex type aliases, where it triggers + /// incorrectly, or in situations where it will be more difficult to + /// clearly express the intent. It may be possible that this will become a + /// warning in the future, possibly with [type ascription] providing a + /// convenient way to work around the current issues. See [RFC 401] for + /// historical context. + /// + /// [type ascription]: https://github.com/rust-lang/rust/issues/23416 + /// [RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md pub TRIVIAL_NUMERIC_CASTS, Allow, "detects trivial casts of numeric types which could be removed" } declare_lint! { + /// The `private_in_public` lint detects private items in public + /// interfaces not caught by the old implementation. + /// + /// ### Example + /// + /// ```rust + /// # #![allow(unused)] + /// struct SemiPriv; + /// + /// mod m1 { + /// struct Priv; + /// impl super::SemiPriv { + /// pub fn f(_: Priv) {} + /// } + /// } + /// # fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The visibility rules are intended to prevent exposing private items in + /// public interfaces. This is a [future-incompatible] lint to transition + /// this to a hard error in the future. See [issue #34537] for more + /// details. + /// + /// [issue #34537]: https://github.com/rust-lang/rust/issues/34537 + /// [future-incompatible]: ../index.md#future-incompatible-lints pub PRIVATE_IN_PUBLIC, Warn, "detect private items in public interfaces not caught by the old implementation", @@ -195,12 +889,76 @@ declare_lint! { } declare_lint! { + /// The `exported_private_dependencies` lint detects private dependencies + /// that are exposed in a public interface. + /// + /// ### Example + /// + /// ```rust,ignore (needs-dependency) + /// pub fn foo() -> Option { + /// None + /// } + /// ``` + /// + /// This will produce: + /// + /// ```text + /// warning: type `bar::Thing` from private dependency 'bar' in public interface + /// --> src/lib.rs:3:1 + /// | + /// 3 | pub fn foo() -> Option { + /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + /// | + /// = note: `#[warn(exported_private_dependencies)]` on by default + /// ``` + /// + /// ### Explanation + /// + /// Dependencies can be marked as "private" to indicate that they are not + /// exposed in the public interface of a crate. This can be used by Cargo + /// to independently resolve those dependencies because it can assume it + /// does not need to unify them with other packages using that same + /// dependency. This lint is an indication of a violation of that + /// contract. + /// + /// To fix this, avoid exposing the dependency in your public interface. + /// Or, switch the dependency to a public dependency. + /// + /// Note that support for this is only available on the nightly channel. + /// See [RFC 1977] for more details, as well as the [Cargo documentation]. + /// + /// [RFC 1977]: https://github.com/rust-lang/rfcs/blob/master/text/1977-public-private-dependencies.md + /// [Cargo documentation]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#public-dependency pub EXPORTED_PRIVATE_DEPENDENCIES, Warn, "public interface leaks type from a private dependency" } declare_lint! { + /// The `pub_use_of_private_extern_crate` lint detects a specific + /// situation of re-exporting a private `extern crate`. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// extern crate core; + /// pub use core as reexported_core; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// A public `use` declaration should not be used to publicly re-export a + /// private `extern crate`. `pub extern crate` should be used instead. + /// + /// This was historically allowed, but is not the intended behavior + /// according to the visibility rules. This is a [future-incompatible] + /// lint to transition this to a hard error in the future. See [issue + /// #34537] for more details. + /// + /// [issue #34537]: https://github.com/rust-lang/rust/issues/34537 + /// [future-incompatible]: ../index.md#future-incompatible-lints pub PUB_USE_OF_PRIVATE_EXTERN_CRATE, Deny, "detect public re-exports of private extern crates", @@ -211,6 +969,26 @@ declare_lint! { } declare_lint! { + /// The `invalid_type_param_default` lint detects type parameter defaults + /// erroneously allowed in an invalid location. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// fn foo(t: T) {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Default type parameters were only intended to be allowed in certain + /// situations, but historically the compiler allowed them everywhere. + /// This is a [future-incompatible] lint to transition this to a hard + /// error in the future. See [issue #36887] for more details. + /// + /// [issue #36887]: https://github.com/rust-lang/rust/issues/36887 + /// [future-incompatible]: ../index.md#future-incompatible-lints pub INVALID_TYPE_PARAM_DEFAULT, Deny, "type parameter default erroneously allowed in invalid location", @@ -221,24 +999,174 @@ declare_lint! { } declare_lint! { + /// The `renamed_and_removed_lints` lint detects lints that have been + /// renamed or removed. + /// + /// ### Example + /// + /// ```rust + /// #![deny(raw_pointer_derive)] + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// To fix this, either remove the lint or use the new name. This can help + /// avoid confusion about lints that are no longer valid, and help + /// maintain consistency for renamed lints. pub RENAMED_AND_REMOVED_LINTS, Warn, "lints that have been renamed or removed" } declare_lint! { + /// The `unaligned_references` lint detects unaligned references to fields + /// of [packed] structs. + /// + /// [packed]: https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unaligned_references)] + /// + /// #[repr(packed)] + /// pub struct Foo { + /// field1: u64, + /// field2: u8, + /// } + /// + /// fn main() { + /// unsafe { + /// let foo = Foo { field1: 0, field2: 0 }; + /// let _ = &foo.field1; + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Creating a reference to an insufficiently aligned packed field is + /// [undefined behavior] and should be disallowed. + /// + /// This lint is "allow" by default because there is no stable + /// alternative, and it is not yet certain how widespread existing code + /// will trigger this lint. + /// + /// See [issue #27060] for more discussion. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// [issue #27060]: https://github.com/rust-lang/rust/issues/27060 pub UNALIGNED_REFERENCES, Allow, "detects unaligned references to fields of packed structs", } declare_lint! { + /// The `const_item_mutation` lint detects attempts to mutate a `const` + /// item. + /// + /// ### Example + /// + /// ```rust + /// const FOO: [i32; 1] = [0]; + /// + /// fn main() { + /// FOO[0] = 1; + /// // This will print "[0]". + /// println!("{:?}", FOO); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Trying to directly mutate a `const` item is almost always a mistake. + /// What is happening in the example above is that a temporary copy of the + /// `const` is mutated, but the original `const` is not. Each time you + /// refer to the `const` by name (such as `FOO` in the example above), a + /// separate copy of the value is inlined at that location. + /// + /// This lint checks for writing directly to a field (`FOO.field = + /// some_value`) or array entry (`FOO[0] = val`), or taking a mutable + /// reference to the const item (`&mut FOO`), including through an + /// autoderef (`FOO.some_mut_self_method()`). + /// + /// There are various alternatives depending on what you are trying to + /// accomplish: + /// + /// * First, always reconsider using mutable globals, as they can be + /// difficult to use correctly, and can make the code more difficult to + /// use or understand. + /// * If you are trying to perform a one-time initialization of a global: + /// * If the value can be computed at compile-time, consider using + /// const-compatible values (see [Constant Evaluation]). + /// * For more complex single-initialization cases, consider using a + /// third-party crate, such as [`lazy_static`] or [`once_cell`]. + /// * If you are using the [nightly channel], consider the new + /// [`lazy`] module in the standard library. + /// * If you truly need a mutable global, consider using a [`static`], + /// which has a variety of options: + /// * Simple data types can be directly defined and mutated with an + /// [`atomic`] type. + /// * More complex types can be placed in a synchronization primitive + /// like a [`Mutex`], which can be initialized with one of the options + /// listed above. + /// * A [mutable `static`] is a low-level primitive, requiring unsafe. + /// Typically This should be avoided in preference of something + /// higher-level like one of the above. + /// + /// [Constant Evaluation]: https://doc.rust-lang.org/reference/const_eval.html + /// [`static`]: https://doc.rust-lang.org/reference/items/static-items.html + /// [mutable `static`]: https://doc.rust-lang.org/reference/items/static-items.html#mutable-statics + /// [`lazy`]: https://doc.rust-lang.org/nightly/std/lazy/index.html + /// [`lazy_static`]: https://crates.io/crates/lazy_static + /// [`once_cell`]: https://crates.io/crates/once_cell + /// [`atomic`]: https://doc.rust-lang.org/std/sync/atomic/index.html + /// [`Mutex`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html pub CONST_ITEM_MUTATION, Warn, "detects attempts to mutate a `const` item", } declare_lint! { + /// The `safe_packed_borrows` lint detects borrowing a field in the + /// interior of a packed structure with alignment other than 1. + /// + /// ### Example + /// + /// ```rust + /// #[repr(packed)] + /// pub struct Unaligned(pub T); + /// + /// pub struct Foo { + /// start: u8, + /// data: Unaligned, + /// } + /// + /// fn main() { + /// let x = Foo { start: 0, data: Unaligned(1) }; + /// let y = &x.data.0; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This type of borrow is unsafe and can cause errors on some platforms + /// and violates some assumptions made by the compiler. This was + /// previously allowed unintentionally. This is a [future-incompatible] + /// lint to transition this to a hard error in the future. See [issue + /// #46043] for more details, including guidance on how to solve the + /// problem. + /// + /// [issue #46043]: https://github.com/rust-lang/rust/issues/46043 + /// [future-incompatible]: ../index.md#future-incompatible-lints pub SAFE_PACKED_BORROWS, Warn, "safe borrows of fields of packed structs were erroneously allowed", @@ -249,6 +1177,49 @@ declare_lint! { } declare_lint! { + /// The `patterns_in_fns_without_body` lint detects `mut` identifier + /// patterns as a parameter in functions without a body. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// trait Trait { + /// fn foo(mut arg: u8); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// To fix this, remove `mut` from the parameter in the trait definition; + /// it can be used in the implementation. That is, the following is OK: + /// + /// ```rust + /// trait Trait { + /// fn foo(arg: u8); // Removed `mut` here + /// } + /// + /// impl Trait for i32 { + /// fn foo(mut arg: u8) { // `mut` here is OK + /// + /// } + /// } + /// ``` + /// + /// Trait definitions can define functions without a body to specify a + /// function that implementors must define. The parameter names in the + /// body-less functions are only allowed to be `_` or an [identifier] for + /// documentation purposes (only the type is relevant). Previous versions + /// of the compiler erroneously allowed [identifier patterns] with the + /// `mut` keyword, but this was not intended to be allowed. This is a + /// [future-incompatible] lint to transition this to a hard error in the + /// future. See [issue #35203] for more details. + /// + /// [identifier]: https://doc.rust-lang.org/reference/identifiers.html + /// [identifier patterns]: https://doc.rust-lang.org/reference/patterns.html#identifier-patterns + /// [issue #35203]: https://github.com/rust-lang/rust/issues/35203 + /// [future-incompatible]: ../index.md#future-incompatible-lints pub PATTERNS_IN_FNS_WITHOUT_BODY, Deny, "patterns in functions without body were erroneously allowed", @@ -259,6 +1230,38 @@ declare_lint! { } declare_lint! { + /// The `late_bound_lifetime_arguments` lint detects generic lifetime + /// arguments in path segments with late bound lifetime parameters. + /// + /// ### Example + /// + /// ```rust + /// struct S; + /// + /// impl S { + /// fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} + /// } + /// + /// fn main() { + /// S.late::<'static>(&0, &0); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is not clear how to provide arguments for early-bound lifetime + /// parameters if they are intermixed with late-bound parameters in the + /// same list. For now, providing any explicit arguments will trigger this + /// lint if late-bound parameters are present, so in the future a solution + /// can be adopted without hitting backward compatibility issues. This is + /// a [future-incompatible] lint to transition this to a hard error in the + /// future. See [issue #42868] for more details, along with a description + /// of the difference between early and late-bound parameters. + /// + /// [issue #42868]: https://github.com/rust-lang/rust/issues/42868 + /// [future-incompatible]: ../index.md#future-incompatible-lints pub LATE_BOUND_LIFETIME_ARGUMENTS, Warn, "detects generic lifetime arguments in path segments with late bound lifetime parameters", @@ -269,6 +1272,32 @@ declare_lint! { } declare_lint! { + /// The `order_dependent_trait_objects` lint detects a trait coherency + /// violation that would allow creating two trait impls for the same + /// dynamic trait object involving marker traits. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// pub trait Trait {} + /// + /// impl Trait for dyn Send + Sync { } + /// impl Trait for dyn Sync + Send { } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// A previous bug caused the compiler to interpret traits with different + /// orders (such as `Send + Sync` and `Sync + Send`) as distinct types + /// when they were intended to be treated the same. This allowed code to + /// define separate trait implementations when there should be a coherence + /// error. This is a [future-incompatible] lint to transition this to a + /// hard error in the future. See [issue #56484] for more details. + /// + /// [issue #56484]: https://github.com/rust-lang/rust/issues/56484 + /// [future-incompatible]: ../index.md#future-incompatible-lints pub ORDER_DEPENDENT_TRAIT_OBJECTS, Deny, "trait-object types were treated as different depending on marker-trait order", @@ -279,6 +1308,36 @@ declare_lint! { } declare_lint! { + /// The `coherence_leak_check` lint detects conflicting implementations of + /// a trait that are only distinguished by the old leak-check code. + /// + /// ### Example + /// + /// ```rust + /// trait SomeTrait { } + /// impl SomeTrait for for<'a> fn(&'a u8) { } + /// impl<'a> SomeTrait for fn(&'a u8) { } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In the past, the compiler would accept trait implementations for + /// identical functions that differed only in where the lifetime binder + /// appeared. Due to a change in the borrow checker implementation to fix + /// several bugs, this is no longer allowed. However, since this affects + /// existing code, this is a [future-incompatible] lint to transition this + /// to a hard error in the future. + /// + /// Code relying on this pattern should introduce "[newtypes]", + /// like `struct Foo(for<'a> fn(&'a u8))`. + /// + /// See [issue #56105] for more details. + /// + /// [issue #56105]: https://github.com/rust-lang/rust/issues/56105 + /// [newtypes]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#using-the-newtype-pattern-for-type-safety-and-abstraction + /// [future-incompatible]: ../index.md#future-incompatible-lints pub COHERENCE_LEAK_CHECK, Warn, "distinct impls distinguished only by the leak-check code", @@ -289,6 +1348,29 @@ declare_lint! { } declare_lint! { + /// The `deprecated` lint detects use of deprecated items. + /// + /// ### Example + /// + /// ```rust + /// #[deprecated] + /// fn foo() {} + /// + /// fn bar() { + /// foo(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Items may be marked "deprecated" with the [`deprecated` attribute] to + /// indicate that they should no longer be used. Usually the attribute + /// should include a note on what to use instead, or check the + /// documentation. + /// + /// [`deprecated` attribute]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-deprecated-attribute pub DEPRECATED, Warn, "detects use of deprecated items", @@ -296,36 +1378,158 @@ declare_lint! { } declare_lint! { + /// The `unused_unsafe` lint detects unnecessary use of an `unsafe` block. + /// + /// ### Example + /// + /// ```rust + /// unsafe {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// If nothing within the block requires `unsafe`, then remove the + /// `unsafe` marker because it is not required and may cause confusion. pub UNUSED_UNSAFE, Warn, "unnecessary use of an `unsafe` block" } declare_lint! { + /// The `unused_mut` lint detects mut variables which don't need to be + /// mutable. + /// + /// ### Example + /// + /// ```rust + /// let mut x = 5; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The preferred style is to only mark variables as `mut` if it is + /// required. pub UNUSED_MUT, Warn, "detect mut variables which don't need to be mutable" } declare_lint! { + /// The `unconditional_recursion` lint detects functions that cannot + /// return without calling themselves. + /// + /// ### Example + /// + /// ```rust + /// fn foo() { + /// foo(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is usually a mistake to have a recursive call that does not have + /// some condition to cause it to terminate. If you really intend to have + /// an infinite loop, using a `loop` expression is recommended. pub UNCONDITIONAL_RECURSION, Warn, "functions that cannot return without calling themselves" } declare_lint! { + /// The `single_use_lifetimes` lint detects lifetimes that are only used + /// once. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(single_use_lifetimes)] + /// + /// fn foo<'a>(x: &'a u32) {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Specifying an explicit lifetime like `'a` in a function or `impl` + /// should only be used to link together two things. Otherwise, you should + /// just use `'_` to indicate that the lifetime is not linked to anything, + /// or elide the lifetime altogether if possible. + /// + /// This lint is "allow" by default because it was introduced at a time + /// when `'_` and elided lifetimes were first being introduced, and this + /// lint would be too noisy. Also, there are some known false positives + /// that it produces. See [RFC 2115] for historical context, and [issue + /// #44752] for more details. + /// + /// [RFC 2115]: https://github.com/rust-lang/rfcs/blob/master/text/2115-argument-lifetimes.md + /// [issue #44752]: https://github.com/rust-lang/rust/issues/44752 pub SINGLE_USE_LIFETIMES, Allow, "detects lifetime parameters that are only used once" } declare_lint! { + /// The `unused_lifetimes` lint detects lifetime parameters that are never + /// used. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #[deny(unused_lifetimes)] + /// + /// pub fn foo<'a>() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unused lifetime parameters may signal a mistake or unfinished code. + /// Consider removing the parameter. pub UNUSED_LIFETIMES, Allow, "detects lifetime parameters that are never used" } declare_lint! { + /// The `tyvar_behind_raw_pointer` lint detects raw pointer to an + /// inference variable. + /// + /// ### Example + /// + /// ```rust,edition2015 + /// // edition 2015 + /// let data = std::ptr::null(); + /// let _ = &data as *const *const (); + /// + /// if data.is_null() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This kind of inference was previously allowed, but with the future + /// arrival of [arbitrary self types], this can introduce ambiguity. To + /// resolve this, use an explicit type instead of relying on type + /// inference. + /// + /// This is a [future-incompatible] lint to transition this to a hard + /// error in the 2018 edition. See [issue #46906] for more details. This + /// is currently a hard-error on the 2018 edition, and is "warn" by + /// default in the 2015 edition. + /// + /// [arbitrary self types]: https://github.com/rust-lang/rust/issues/44874 + /// [issue #46906]: https://github.com/rust-lang/rust/issues/46906 + /// [future-incompatible]: ../index.md#future-incompatible-lints pub TYVAR_BEHIND_RAW_POINTER, Warn, "raw pointer to an inference variable", @@ -336,6 +1540,34 @@ declare_lint! { } declare_lint! { + /// The `elided_lifetimes_in_paths` lint detects the use of hidden + /// lifetime parameters. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(elided_lifetimes_in_paths)] + /// struct Foo<'a> { + /// x: &'a u32 + /// } + /// + /// fn foo(x: &Foo) { + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Elided lifetime parameters can make it difficult to see at a glance + /// that borrowing is occurring. This lint ensures that lifetime + /// parameters are always explicitly stated, even if it is the `'_` + /// [placeholder lifetime]. + /// + /// This lint is "allow" by default because it has some known issues, and + /// may require a significant transition for old code. + /// + /// [placeholder lifetime]: https://doc.rust-lang.org/reference/lifetime-elision.html#lifetime-elision-in-functions pub ELIDED_LIFETIMES_IN_PATHS, Allow, "hidden lifetime parameters in types are deprecated", @@ -343,12 +1575,78 @@ declare_lint! { } declare_lint! { + /// The `bare_trait_objects` lint suggests using `dyn Trait` for trait + /// objects. + /// + /// ### Example + /// + /// ```rust + /// trait Trait { } + /// + /// fn takes_trait_object(_: Box) { + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Without the `dyn` indicator, it can be ambiguous or confusing when + /// reading code as to whether or not you are looking at a trait object. + /// The `dyn` keyword makes it explicit, and adds a symmetry to contrast + /// with [`impl Trait`]. + /// + /// [`impl Trait`]: https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters pub BARE_TRAIT_OBJECTS, Warn, "suggest using `dyn Trait` for trait objects" } declare_lint! { + /// The `absolute_paths_not_starting_with_crate` lint detects fully + /// qualified paths that start with a module name instead of `crate`, + /// `self`, or an extern crate name + /// + /// ### Example + /// + /// ```rust,edition2015,compile_fail + /// #![deny(absolute_paths_not_starting_with_crate)] + /// + /// mod foo { + /// pub fn bar() {} + /// } + /// + /// fn main() { + /// ::foo::bar(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Rust [editions] allow the language to evolve without breaking + /// backwards compatibility. This lint catches code that uses absolute + /// paths in the style of the 2015 edition. In the 2015 edition, absolute + /// paths (those starting with `::`) refer to either the crate root or an + /// external crate. In the 2018 edition it was changed so that they only + /// refer to external crates. The path prefix `crate::` should be used + /// instead to reference items from the crate root. + /// + /// If you switch the compiler from the 2015 to 2018 edition without + /// updating the code, then it will fail to compile if the old style paths + /// are used. You can manually change the paths to use the `crate::` + /// prefix to transition to the 2018 edition. + /// + /// This lint solves the problem automatically. It is "allow" by default + /// because the code is perfectly valid in the 2015 edition. The [`cargo + /// fix`] tool with the `--edition` flag will switch this lint to "warn" + /// and automatically apply the suggested fix from the compiler. This + /// provides a completely automated way to update old code to the 2018 + /// edition. + /// + /// [editions]: https://doc.rust-lang.org/edition-guide/ + /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html pub ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, Allow, "fully qualified paths that start with a module name \ @@ -360,6 +1658,45 @@ declare_lint! { } declare_lint! { + /// The `illegal_floating_point_literal_pattern` lint detects + /// floating-point literals used in patterns. + /// + /// ### Example + /// + /// ```rust + /// let x = 42.0; + /// + /// match x { + /// 5.0 => {} + /// _ => {} + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Previous versions of the compiler accepted floating-point literals in + /// patterns, but it was later determined this was a mistake. The + /// semantics of comparing floating-point values may not be clear in a + /// pattern when contrasted with "structural equality". Typically you can + /// work around this by using a [match guard], such as: + /// + /// ```rust + /// # let x = 42.0; + /// + /// match x { + /// y if y == 5.0 => {} + /// _ => {} + /// } + /// ``` + /// + /// This is a [future-incompatible] lint to transition this to a hard + /// error in the future. See [issue #41620] for more details. + /// + /// [issue #41620]: https://github.com/rust-lang/rust/issues/41620 + /// [match guard]: https://doc.rust-lang.org/reference/expressions/match-expr.html#match-guards + /// [future-incompatible]: ../index.md#future-incompatible-lints pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, Warn, "floating-point literals cannot be used in patterns", @@ -370,6 +1707,40 @@ declare_lint! { } declare_lint! { + /// The `unstable_name_collisions` lint detects that you have used a name + /// that the standard library plans to add in the future. + /// + /// ### Example + /// + /// ```rust + /// trait MyIterator : Iterator { + /// // is_sorted is an unstable method that already exists on the Iterator trait + /// fn is_sorted(self) -> bool where Self: Sized {true} + /// } + /// + /// impl MyIterator for T where T: Iterator { } + /// + /// let x = vec![1,2,3]; + /// let _ = x.iter().is_sorted(); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// When new methods are added to traits in the standard library, they are + /// usually added in an "unstable" form which is only available on the + /// [nightly channel] with a [`feature` attribute]. If there is any + /// pre-existing code which extends a trait to have a method with the same + /// name, then the names will collide. In the future, when the method is + /// stabilized, this will cause an error due to the ambiguity. This lint + /// is an early-warning to let you know that there may be a collision in + /// the future. This can be avoided by adding type annotations to + /// disambiguate which trait method you intend to call, such as + /// `MyIterator::is_sorted(my_iter)` or renaming or removing the method. + /// + /// [nightly channel]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html + /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/ pub UNSTABLE_NAME_COLLISIONS, Warn, "detects name collision with an existing but unstable method", @@ -382,48 +1753,267 @@ declare_lint! { } declare_lint! { + /// The `irrefutable_let_patterns` lint detects detects [irrefutable + /// patterns] in [if-let] and [while-let] statements. + /// + /// + /// + /// ### Example + /// + /// ```rust + /// if let _ = 123 { + /// println!("always runs!"); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// There usually isn't a reason to have an irrefutable pattern in an + /// if-let or while-let statement, because the pattern will always match + /// successfully. A [`let`] or [`loop`] statement will suffice. However, + /// when generating code with a macro, forbidding irrefutable patterns + /// would require awkward workarounds in situations where the macro + /// doesn't know if the pattern is refutable or not. This lint allows + /// macros to accept this form, while alerting for a possibly incorrect + /// use in normal code. + /// + /// See [RFC 2086] for more details. + /// + /// [irrefutable patterns]: https://doc.rust-lang.org/reference/patterns.html#refutability + /// [if-let]: https://doc.rust-lang.org/reference/expressions/if-expr.html#if-let-expressions + /// [while-let]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-pattern-loops + /// [`let`]: https://doc.rust-lang.org/reference/statements.html#let-statements + /// [`loop`]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#infinite-loops + /// [RFC 2086]: https://github.com/rust-lang/rfcs/blob/master/text/2086-allow-if-let-irrefutables.md pub IRREFUTABLE_LET_PATTERNS, Warn, "detects irrefutable patterns in if-let and while-let statements" } declare_lint! { + /// The `unused_labels` lint detects [labels] that are never used. + /// + /// [labels]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#loop-labels + /// + /// ### Example + /// + /// ```rust,no_run + /// 'unused_label: loop {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unused labels may signal a mistake or unfinished code. To silence the + /// warning for the individual label, prefix it with an underscore such as + /// `'_my_label:`. pub UNUSED_LABELS, Warn, "detects labels that are never used" } declare_lint! { + /// The `broken_intra_doc_links` lint detects failures in resolving + /// intra-doc link targets. This is a `rustdoc` only lint, and only works + /// on the [**nightly channel**]. + /// + /// [**nightly channel**]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html + /// + /// ### Example + /// + /// ```rust,rustdoc + /// /// This is a doc comment. + /// /// + /// /// See also [`bar`]. + /// pub fn foo() { + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// `rustdoc` allows [linking to items by name][intra] which will + /// automatically generate links in the documentation to the item. This + /// lint is issued when `rustdoc` is unable to find the named item. Check + /// that the name is correct, that it is in scope, or if you need to + /// qualify it with a path. If you intended to have square brackets appear + /// literally in the text, surround the brackets with backticks such as `` + /// `[example]` `` to indicate a code span, or prefix it with a backslash + /// such as `\[example]`. + /// + /// [intra]: https://doc.rust-lang.org/nightly/rustdoc/unstable-features.html#linking-to-items-by-name pub BROKEN_INTRA_DOC_LINKS, Warn, "failures in resolving intra-doc link targets" } declare_lint! { + /// The `invalid_codeblock_attributes` lint detects code block attributes + /// in documentation examples that have potentially mis-typed values. This + /// is a `rustdoc` only lint. + /// + /// ### Example + /// + /// ```rust,rustdoc + /// /// Example. + /// /// + /// /// ```should-panic + /// /// assert_eq!(1, 2); + /// /// ``` + /// pub fn foo() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This lint is issued when `rustdoc` detects an example code block + /// attribute that appears similar to a valid one. In the example above, + /// the correct form is `should_panic`. This helps detect typo mistakes + /// for some common attributes. pub INVALID_CODEBLOCK_ATTRIBUTES, Warn, "codeblock attribute looks a lot like a known one" } declare_lint! { + /// The `missing_crate_level_docs` lint detects if documentation is + /// missing at the crate root. This is a `rustdoc` only lint. This is a + /// `rustdoc` only lint. + /// + /// ### Example + /// + /// ```rust,rustdoc + /// #![deny(missing_crate_level_docs)] + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This lint causes `rustdoc` to check if the crate root is missing + /// documentation. This is currently "allow" by default, but it is + /// intended to make this a warning in the future. This is intended as a + /// means to introduce new users on *how* to document their crate by + /// pointing them to some instructions on how to get started. pub MISSING_CRATE_LEVEL_DOCS, Allow, "detects crates with no crate-level documentation" } declare_lint! { + /// The `missing_doc_code_examples` lint detects publicly-exported items + /// without code samples in their documentation. This is a `rustdoc` only + /// lint, and only works on the [**nightly channel**]. + /// + /// [**nightly channel**]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html + /// + /// ### Example + /// + /// ```rust,rustdoc + /// #![warn(missing_doc_code_examples)] + /// + /// /// There is no code example! + /// pub fn no_code_example() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This lint is to ensure a high level of quality for documentation. Code + /// examples can be very useful to see how to use an API. To add an + /// example, include a markdown code block with an example of how to use + /// the item, such as: + /// + /// ```rust + /// /// Adds one to the number given. + /// /// + /// /// # Examples + /// /// + /// /// ``` + /// /// let arg = 5; + /// /// let answer = my_crate::add_one(arg); + /// /// + /// /// assert_eq!(6, answer); + /// /// ``` + /// pub fn add_one(x: i32) -> i32 { + /// x + 1 + /// } + /// ``` pub MISSING_DOC_CODE_EXAMPLES, Allow, "detects publicly-exported items without code samples in their documentation" } declare_lint! { + /// The `private_doc_tests` lint detects code samples in docs of private + /// items not documented by `rustdoc`. This is a `rustdoc` only lint. + /// + /// ### Example + /// + /// ```rust,rustdoc + /// #![deny(private_doc_tests)] + /// + /// mod foo { + /// /// private doc test + /// /// + /// /// ``` + /// /// assert!(false); + /// /// ``` + /// fn bar() {} + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Because documentation examples link against the public API of the + /// crate, it is not possible for an example to access a private item. + /// This means it was likely a mistake to add a code example to a private + /// item. pub PRIVATE_DOC_TESTS, Allow, "detects code samples in docs of private items not documented by rustdoc" } declare_lint! { + /// The `where_clauses_object_safety` lint detects for [object safety] of + /// [where clauses]. + /// + /// [object safety]: https://doc.rust-lang.org/reference/items/traits.html#object-safety + /// [where clauses]: https://doc.rust-lang.org/reference/items/generics.html#where-clauses + /// + /// ### Example + /// + /// ```rust,no_run + /// trait Trait {} + /// + /// trait X { fn foo(&self) where Self: Trait; } + /// + /// impl X for () { fn foo(&self) {} } + /// + /// impl Trait for dyn X {} + /// + /// // Segfault at opt-level 0, SIGILL otherwise. + /// pub fn main() { ::foo(&()); } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The compiler previously allowed these object-unsafe bounds, which was + /// incorrect. This is a [future-incompatible] lint to transition this to + /// a hard error in the future. See [issue #51443] for more details. + /// + /// [issue #51443]: https://github.com/rust-lang/rust/issues/51443 + /// [future-incompatible]: ../index.md#future-incompatible-lints pub WHERE_CLAUSES_OBJECT_SAFETY, Warn, "checks the object safety of where clauses", @@ -434,6 +2024,63 @@ declare_lint! { } declare_lint! { + /// The `proc_macro_derive_resolution_fallback` lint detects proc macro + /// derives using inaccessible names from parent modules. + /// + /// ### Example + /// + /// ```rust,ignore (proc-macro) + /// // foo.rs + /// #![crate_type = "proc-macro"] + /// + /// extern crate proc_macro; + /// + /// use proc_macro::*; + /// + /// #[proc_macro_derive(Foo)] + /// pub fn foo1(a: TokenStream) -> TokenStream { + /// drop(a); + /// "mod __bar { static mut BAR: Option = None; }".parse().unwrap() + /// } + /// ``` + /// + /// ```rust,ignore (needs-dependency) + /// // bar.rs + /// #[macro_use] + /// extern crate foo; + /// + /// struct Something; + /// + /// #[derive(Foo)] + /// struct Another; + /// + /// fn main() {} + /// ``` + /// + /// This will produce: + /// + /// ```text + /// warning: cannot find type `Something` in this scope + /// --> src/main.rs:8:10 + /// | + /// 8 | #[derive(Foo)] + /// | ^^^ names from parent modules are not accessible without an explicit import + /// | + /// = note: `#[warn(proc_macro_derive_resolution_fallback)]` 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 #50504 + /// ``` + /// + /// ### Explanation + /// + /// If a proc-macro generates a module, the compiler unintentionally + /// allowed items in that module to refer to items in the crate root + /// without importing them. This is a [future-incompatible] lint to + /// transition this to a hard error in the future. See [issue #50504] for + /// more details. + /// + /// [issue #50504]: https://github.com/rust-lang/rust/issues/50504 + /// [future-incompatible]: ../index.md#future-incompatible-lints pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, Warn, "detects proc macro derives using inaccessible names from parent modules", @@ -444,6 +2091,53 @@ declare_lint! { } declare_lint! { + /// The `macro_use_extern_crate` lint detects the use of the + /// [`macro_use` attribute]. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(macro_use_extern_crate)] + /// + /// #[macro_use] + /// extern crate serde_json; + /// + /// fn main() { + /// let _ = json!{{}}; + /// } + /// ``` + /// + /// This will produce: + /// + /// ```text + /// error: deprecated `#[macro_use]` attribute used to import macros should be replaced at use sites with a `use` item to import the macro instead + /// --> src/main.rs:3:1 + /// | + /// 3 | #[macro_use] + /// | ^^^^^^^^^^^^ + /// | + /// note: the lint level is defined here + /// --> src/main.rs:1:9 + /// | + /// 1 | #![deny(macro_use_extern_crate)] + /// | ^^^^^^^^^^^^^^^^^^^^^^ + /// ``` + /// + /// ### Explanation + /// + /// The [`macro_use` attribute] on an [`extern crate`] item causes + /// macros in that external crate to be brought into the prelude of the + /// crate, making the macros in scope everywhere. As part of the efforts + /// to simplify handling of dependencies in the [2018 edition], the use of + /// `extern crate` is being phased out. To bring macros from extern crates + /// into scope, it is recommended to use a [`use` import]. + /// + /// This lint is "allow" by default because this is a stylistic choice + /// that has not been settled, see [issue #52043] for more information. + /// + /// [`macro_use` attribute]: https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute + /// [`use` import]: https://doc.rust-lang.org/reference/items/use-declarations.html + /// [issue #52043]: https://github.com/rust-lang/rust/issues/52043 pub MACRO_USE_EXTERN_CRATE, Allow, "the `#[macro_use]` attribute is now deprecated in favor of using macros \ @@ -451,6 +2145,44 @@ declare_lint! { } declare_lint! { + /// The `macro_expanded_macro_exports_accessed_by_absolute_paths` lint + /// detects macro-expanded [`macro_export`] macros from the current crate + /// that cannot be referred to by absolute paths. + /// + /// [`macro_export`]: https://doc.rust-lang.org/reference/macros-by-example.html#path-based-scope + /// + /// ### Example + /// + /// ```rust,compile_fail + /// macro_rules! define_exported { + /// () => { + /// #[macro_export] + /// macro_rules! exported { + /// () => {}; + /// } + /// }; + /// } + /// + /// define_exported!(); + /// + /// fn main() { + /// crate::exported!(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The intent is that all macros marked with the `#[macro_export]` + /// attribute are made available in the root of the crate. However, when a + /// `macro_rules!` definition is generated by another macro, the macro + /// expansion is unable to uphold this rule. This is a + /// [future-incompatible] lint to transition this to a hard error in the + /// future. See [issue #53495] for more details. + /// + /// [issue #53495]: https://github.com/rust-lang/rust/issues/53495 + /// [future-incompatible]: ../index.md#future-incompatible-lints pub MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, Deny, "macro-expanded `macro_export` macros from the current crate \ @@ -463,12 +2195,92 @@ declare_lint! { } declare_lint! { + /// The `explicit_outlives_requirements` lint detects unnecessary + /// lifetime bounds that can be inferred. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// # #![allow(unused)] + /// #![deny(explicit_outlives_requirements)] + /// + /// struct SharedRef<'a, T> + /// where + /// T: 'a, + /// { + /// data: &'a T, + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// If a `struct` contains a reference, such as `&'a T`, the compiler + /// requires that `T` outlives the lifetime `'a`. This historically + /// required writing an explicit lifetime bound to indicate this + /// requirement. However, this can be overly explicit, causing clutter and + /// unnecessary complexity. The language was changed to automatically + /// infer the bound if it is not specified. Specifically, if the struct + /// contains a reference, directly or indirectly, to `T` with lifetime + /// `'x`, then it will infer that `T: 'x` is a requirement. + /// + /// This lint is "allow" by default because it can be noisy for existing + /// code that already had these requirements. This is a stylistic choice, + /// as it is still valid to explicitly state the bound. It also has some + /// false positives that can cause confusion. + /// + /// See [RFC 2093] for more details. + /// + /// [RFC 2093]: https://github.com/rust-lang/rfcs/blob/master/text/2093-infer-outlives.md pub EXPLICIT_OUTLIVES_REQUIREMENTS, Allow, "outlives requirements can be inferred" } declare_lint! { + /// The `indirect_structural_match` lint detects a `const` in a pattern + /// that manually implements [`PartialEq`] and [`Eq`]. + /// + /// [`PartialEq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(indirect_structural_match)] + /// + /// struct Plus(i32, i32); + /// const ONE_PLUS_TWO: &&Plus = &&Plus(1, 2); + /// + /// impl PartialEq for Plus { + /// fn eq(&self, other: &Self) -> bool { + /// self.0 + self.1 == other.0 + other.1 + /// } + /// } + /// + /// impl Eq for Plus {} + /// + /// fn main() { + /// if let ONE_PLUS_TWO = &&Plus(3, 0) { + /// println!("semantic!"); + /// } else { + /// println!("structural!"); + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The compiler unintentionally accepted this form in the past. This is a + /// [future-incompatible] lint to transition this to a hard error in the + /// future. See [issue #62411] for a complete description of the problem, + /// and some possible solutions. + /// + /// [issue #62411]: https://github.com/rust-lang/rust/issues/62411 + /// [future-incompatible]: ../index.md#future-incompatible-lints pub INDIRECT_STRUCTURAL_MATCH, // defaulting to allow until rust-lang/rust#62614 is fixed. Allow, @@ -480,6 +2292,17 @@ declare_lint! { } declare_lint! { + /// The `deprecated_in_future` lint is internal to rustc and should not be + /// used by user code. + /// + /// This lint is only enabled in the standard library. It works with the + /// use of `#[rustc_deprecated]` with a `since` field of a version in the + /// future. This allows something to be marked as deprecated in a future + /// version, and then this lint will ensure that the item is no longer + /// used in the standard library. See the [stability documentation] for + /// more details. + /// + /// [stability documentation]: https://rustc-dev-guide.rust-lang.org/stability.html#rustc_deprecated pub DEPRECATED_IN_FUTURE, Allow, "detects use of items that will be deprecated in a future version", @@ -487,6 +2310,54 @@ declare_lint! { } declare_lint! { + /// The `ambiguous_associated_items` lint detects ambiguity between + /// [associated items] and [enum variants]. + /// + /// [associated items]: https://doc.rust-lang.org/reference/items/associated-items.html + /// [enum variants]: https://doc.rust-lang.org/reference/items/enumerations.html + /// + /// ### Example + /// + /// ```rust,compile_fail + /// enum E { + /// V + /// } + /// + /// trait Tr { + /// type V; + /// fn foo() -> Self::V; + /// } + /// + /// impl Tr for E { + /// type V = u8; + /// // `Self::V` is ambiguous because it may refer to the associated type or + /// // the enum variant. + /// fn foo() -> Self::V { 0 } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Previous versions of Rust did not allow accessing enum variants + /// through [type aliases]. When this ability was added (see [RFC 2338]), this + /// introduced some situations where it can be ambiguous what a type + /// was referring to. + /// + /// To fix this ambiguity, you should use a [qualified path] to explicitly + /// state which type to use. For example, in the above example the + /// function can be written as `fn f() -> ::V { 0 }` to + /// specifically refer to the associated type. + /// + /// This is a [future-incompatible] lint to transition this to a hard + /// error in the future. See [issue #57644] for more details. + /// + /// [issue #57644]: https://github.com/rust-lang/rust/issues/57644 + /// [type aliases]: https://doc.rust-lang.org/reference/items/type-aliases.html#type-aliases + /// [RFC 2338]: https://github.com/rust-lang/rfcs/blob/master/text/2338-type-alias-enum-variants.md + /// [qualified path]: https://doc.rust-lang.org/reference/paths.html#qualified-paths + /// [future-incompatible]: ../index.md#future-incompatible-lints pub AMBIGUOUS_ASSOCIATED_ITEMS, Deny, "ambiguous associated items", @@ -497,6 +2368,27 @@ declare_lint! { } declare_lint! { + /// The `mutable_borrow_reservation_conflict` lint detects the reservation + /// of a two-phased borrow that conflicts with other shared borrows. + /// + /// ### Example + /// + /// ```rust + /// let mut v = vec![0, 1, 2]; + /// let shared = &v; + /// v.push(shared.len()); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This is a [future-incompatible] lint to transition this to a hard error + /// in the future. See [issue #59159] for a complete description of the + /// problem, and some possible solutions. + /// + /// [issue #59159]: https://github.com/rust-lang/rust/issues/59159 + /// [future-incompatible]: ../index.md#future-incompatible-lints pub MUTABLE_BORROW_RESERVATION_CONFLICT, Warn, "reservation of a two-phased borrow conflicts with other shared borrows", @@ -507,6 +2399,38 @@ declare_lint! { } declare_lint! { + /// The `soft_unstable` lint detects unstable features that were + /// unintentionally allowed on stable. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #[cfg(test)] + /// extern crate test; + /// + /// #[bench] + /// fn name(b: &mut test::Bencher) { + /// b.iter(|| 123) + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The [`bench` attribute] was accidentally allowed to be specified on + /// the [stable release channel]. Turning this to a hard error would have + /// broken some projects. This lint allows those projects to continue to + /// build correctly when [`--cap-lints`] is used, but otherwise signal an + /// error that `#[bench]` should not be used on the stable channel. This + /// is a [future-incompatible] lint to transition this to a hard error in + /// the future. See [issue #64266] for more details. + /// + /// [issue #64266]: https://github.com/rust-lang/rust/issues/64266 + /// [`bench` attribute]: https://doc.rust-lang.org/nightly/unstable-book/library-features/test.html + /// [stable release channel]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html + /// [`--cap-lints`]: https://doc.rust-lang.org/rustc/lints/levels.html#capping-lints + /// [future-incompatible]: ../index.md#future-incompatible-lints pub SOFT_UNSTABLE, Deny, "a feature gate that doesn't break dependent crates", @@ -517,18 +2441,123 @@ declare_lint! { } declare_lint! { + /// The `inline_no_sanitize` lint detects incompatible use of + /// [`#[inline(always)]`][inline] and [`#[no_sanitize(...)]`][no_sanitize]. + /// + /// [inline]: https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute + /// [no_sanitize]: https://doc.rust-lang.org/nightly/unstable-book/language-features/no-sanitize.html + /// + /// ### Example + /// + /// ```rust + /// #![feature(no_sanitize)] + /// + /// #[inline(always)] + /// #[no_sanitize(address)] + /// fn x() {} + /// + /// fn main() { + /// x() + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The use of the [`#[inline(always)]`][inline] attribute prevents the + /// the [`#[no_sanitize(...)]`][no_sanitize] attribute from working. + /// Consider temporarily removing `inline` attribute. pub INLINE_NO_SANITIZE, Warn, "detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`", } declare_lint! { + /// The `asm_sub_register` lint detects using only a subset of a register + /// for inline asm inputs. + /// + /// ### Example + /// + /// ```rust,ignore (fails on system llvm) + /// #![feature(asm)] + /// + /// fn main() { + /// #[cfg(target_arch="x86_64")] + /// unsafe { + /// asm!("mov {0}, {0}", in(reg) 0i16); + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Registers on some architectures can use different names to refer to a + /// subset of the register. By default, the compiler will use the name for + /// the full register size. To explicitly use a subset of the register, + /// you can override the default by using a modifier on the template + /// string operand to specify when subregister to use. This lint is issued + /// if you pass in a value with a smaller data type than the default + /// register size, to alert you of possibly using the incorrect width. To + /// fix this, add the suggested modifier to the template, or cast the + /// value to the correct size. + /// + /// See [register template modifiers] for more details. + /// + /// [register template modifiers]: https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#register-template-modifiers pub ASM_SUB_REGISTER, Warn, "using only a subset of a register for inline asm inputs", } declare_lint! { + /// The `unsafe_op_in_unsafe_fn` lint detects unsafe operations in unsafe + /// functions without an explicit unsafe block. This lint only works on + /// the [**nightly channel**] with the + /// `#![feature(unsafe_block_in_unsafe_fn)]` feature. + /// + /// [**nightly channel**]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![feature(unsafe_block_in_unsafe_fn)] + /// #![deny(unsafe_op_in_unsafe_fn)] + /// + /// unsafe fn foo() {} + /// + /// unsafe fn bar() { + /// foo(); + /// } + /// + /// fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Currently, an [`unsafe fn`] allows any [unsafe] operation within its + /// body. However, this can increase the surface area of code that needs + /// to be scrutinized for proper behavior. The [`unsafe` block] provides a + /// convenient way to make it clear exactly which parts of the code are + /// performing unsafe operations. In the future, it is desired to change + /// it so that unsafe operations cannot be performed in an `unsafe fn` + /// without an `unsafe` block. + /// + /// The fix to this is to wrap the unsafe code in an `unsafe` block. + /// + /// This lint is "allow" by default because it has not yet been + /// stabilized, and is not yet complete. See [RFC #2585] and [issue + /// #71668] for more details + /// + /// [`unsafe fn`]: https://doc.rust-lang.org/reference/unsafe-functions.html + /// [`unsafe` block]: https://doc.rust-lang.org/reference/expressions/block-expr.html#unsafe-blocks + /// [unsafe]: https://doc.rust-lang.org/reference/unsafety.html + /// [RFC #2585]: https://github.com/rust-lang/rfcs/blob/master/text/2585-unsafe-block-in-unsafe-fn.md + /// [issue #71668]: https://github.com/rust-lang/rust/issues/71668 pub UNSAFE_OP_IN_UNSAFE_FN, Allow, "unsafe operations in unsafe functions without an explicit unsafe block are deprecated", @@ -536,6 +2565,48 @@ declare_lint! { } declare_lint! { + /// The `cenum_impl_drop_cast` lint detects an `as` cast of a field-less + /// `enum` that implements [`Drop`]. + /// + /// [`Drop`]: https://doc.rust-lang.org/std/ops/trait.Drop.html + /// + /// ### Example + /// + /// ```rust + /// # #![allow(unused)] + /// enum E { + /// A, + /// } + /// + /// impl Drop for E { + /// fn drop(&mut self) { + /// println!("Drop"); + /// } + /// } + /// + /// fn main() { + /// let e = E::A; + /// let i = e as u32; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Casting a field-less `enum` that does not implement [`Copy`] to an + /// integer moves the value without calling `drop`. This can result in + /// surprising behavior if it was expected that `drop` should be called. + /// Calling `drop` automatically would be inconsistent with other move + /// operations. Since neither behavior is clear or consistent, it was + /// decided that a cast of this nature will no longer be allowed. + /// + /// This is a [future-incompatible] lint to transition this to a hard error + /// in the future. See [issue #73333] for more details. + /// + /// [future-incompatible]: ../index.md#future-incompatible-lints + /// [issue #73333]: https://github.com/rust-lang/rust/issues/73333 + /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html pub CENUM_IMPL_DROP_CAST, Warn, "a C-like enum implementing Drop is cast", @@ -546,6 +2617,36 @@ declare_lint! { } declare_lint! { + /// The `const_evaluatable_unchecked` lint detects a generic constant used + /// in a type. + /// + /// ### Example + /// + /// ```rust + /// const fn foo() -> usize { + /// if std::mem::size_of::<*mut T>() < 8 { // size of *mut T does not depend on T + /// std::mem::size_of::() + /// } else { + /// 8 + /// } + /// } + /// + /// fn test() { + /// let _ = [0; foo::()]; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In the 1.43 release, some uses of generic parameters in array repeat + /// expressions were accidentally allowed. This is a [future-incompatible] + /// lint to transition this to a hard error in the future. See [issue + /// #76200] for a more detailed description and possible fixes. + /// + /// [future-incompatible]: ../index.md#future-incompatible-lints + /// [issue #76200]: https://github.com/rust-lang/rust/issues/76200 pub CONST_EVALUATABLE_UNCHECKED, Warn, "detects a generic constant is used in a type without a emitting a warning", @@ -641,6 +2742,23 @@ declare_lint_pass! { } declare_lint! { + /// The `unused_doc_comments` lint detects doc comments that aren't used + /// by `rustdoc`. + /// + /// ### Example + /// + /// ```rust + /// /// docs for x + /// let x = 12; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// `rustdoc` does not use doc comments in all positions, and so the doc + /// comment will be ignored. Try changing it to a normal comment with `//` + /// to avoid the warning. pub UNUSED_DOC_COMMENTS, Warn, "detects doc comments that aren't used by rustdoc" diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index d7f3a888edd89..be5182b939dde 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -66,7 +66,6 @@ book!( Nomicon, "src/doc/nomicon", "nomicon"; Reference, "src/doc/reference", "reference"; RustByExample, "src/doc/rust-by-example", "rust-by-example"; - RustcBook, "src/doc/rustc", "rustc"; RustdocBook, "src/doc/rustdoc", "rustdoc"; ); @@ -718,3 +717,69 @@ fn symlink_dir_force(config: &Config, src: &Path, dst: &Path) -> io::Result<()> symlink_dir(config, src, dst) } + +#[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct RustcBook { + pub compiler: Compiler, + pub target: TargetSelection, +} + +impl Step for RustcBook { + type Output = (); + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + let builder = run.builder; + run.path("src/doc/rustc").default_condition(builder.config.docs) + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(RustcBook { + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + target: run.target, + }); + } + + /// Builds the rustc book. + /// + /// The lints are auto-generated by a tool, and then merged into the book + /// in the "md-doc" directory in the build output directory. Then + /// "rustbook" is used to convert it to HTML. + fn run(self, builder: &Builder<'_>) { + let out_base = builder.md_doc_out(self.target).join("rustc"); + t!(fs::create_dir_all(&out_base)); + let out_listing = out_base.join("src/lints"); + builder.cp_r(&builder.src.join("src/doc/rustc"), &out_base); + builder.info(&format!("Generating lint docs ({})", self.target)); + let rustc = builder.rustc(self.compiler); + // The tool runs `rustc` for extracting output examples, so it needs a + // functional sysroot. + builder.ensure(compile::Std { compiler: self.compiler, target: self.target }); + let rustdoc = builder.rustdoc(self.compiler); + let mut cmd = builder.tool_cmd(Tool::LintDocs); + cmd.arg("--src"); + cmd.arg(builder.src.join("compiler")); + cmd.arg("--out"); + cmd.arg(&out_listing); + cmd.arg("--rustc"); + cmd.arg(rustc); + cmd.arg("--rustdoc"); + cmd.arg(rustdoc); + if builder.config.verbose() { + cmd.arg("--verbose"); + } + builder.run(&mut cmd); + // Run rustbook/mdbook to generate the HTML pages. + builder.ensure(RustbookSrc { + target: self.target, + name: INTERNER.intern_str("rustc"), + src: INTERNER.intern_path(out_base), + }); + if is_explicit_request(builder, "src/doc/rustc") { + let out = builder.doc_out(self.target); + let index = out.join("rustc").join("index.html"); + open(builder, &index); + } + } +} diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index a607f0fe258d4..99e33e3b006fe 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -367,6 +367,7 @@ bootstrap_tool!( RustInstaller, "src/tools/rust-installer", "fabricate", is_external_tool = true; RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes"; ExpandYamlAnchors, "src/tools/expand-yaml-anchors", "expand-yaml-anchors"; + LintDocs, "src/tools/lint-docs", "lint-docs"; ); #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)] diff --git a/src/doc/rustc/src/lints/groups.md b/src/doc/rustc/src/lints/groups.md index 049e59b651722..44cf42ff0d71b 100644 --- a/src/doc/rustc/src/lints/groups.md +++ b/src/doc/rustc/src/lints/groups.md @@ -14,14 +14,7 @@ $ rustc -D non-camel-case-types -D non-snake-case -D non-upper-case-globals Here's a list of each lint group, and the lints that they are made up of: -| group | description | lints | -|---------------------|---------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| nonstandard-style | Violation of standard naming conventions | non-camel-case-types, non-snake-case, non-upper-case-globals | -| warnings | all lints that would be issuing warnings | all lints that would be issuing warnings | -| edition-2018 | Lints that will be turned into errors in Rust 2018 | tyvar-behind-raw-pointer | -| rust-2018-idioms | Lints to nudge you toward idiomatic features of Rust 2018 | bare-trait-object, unreachable-pub | -| unused | These lints detect things being declared but not used | unused-imports, unused-variables, unused-assignments, dead-code, unused-mut, unreachable-code, unreachable-patterns, unused-must-use, unused-unsafe, path-statements, unused-attributes, unused-macros, unused-allocation, unused-doc-comment, unused-extern-crates, unused-features, unused-parens | -| future-incompatible | Lints that detect code that has future-compatibility problems | private-in-public, pub-use-of-private-extern-crate, patterns-in-fns-without-body, safe-extern-statics, invalid-type-param-default, legacy-directory-ownership, legacy-imports, legacy-constructor-visibility, missing-fragment-specifier, illegal-floating-point-literal-pattern, anonymous-parameters, parenthesized-params-in-types-and-modules, late-bound-lifetime-arguments, safe-packed-borrows, tyvar-behind-raw-pointer, unstable-name-collision | +{{groups-table}} Additionally, there's a `bad-style` lint group that's a deprecated alias for `nonstandard-style`. diff --git a/src/doc/rustc/src/lints/index.md b/src/doc/rustc/src/lints/index.md index 9010d436eb5cf..029c9edc1b5fe 100644 --- a/src/doc/rustc/src/lints/index.md +++ b/src/doc/rustc/src/lints/index.md @@ -26,3 +26,35 @@ warning: unused variable: `x` This is the `unused_variables` lint, and it tells you that you've introduced a variable that you don't use in your code. That's not *wrong*, so it's not an error, but it might be a bug, so you get a warning. + +## Future-incompatible lints + +Sometimes the compiler needs to be changed to fix an issue that can cause +existing code to stop compiling. "Future-incompatible" lints are issued in +these cases to give users of Rust a smooth transition to the new behavior. +Initially, the compiler will continue to accept the problematic code and issue +a warning. The warning has a description of the problem, a notice that this +will become an error in the future, and a link to a tracking issue that +provides detailed information and an opportunity for feedback. This gives +users some time to fix the code to accommodate the change. After some time, +the warning may become an error. + +The following is an example of what a future-incompatible looks like: + +```text +warning: borrow of packed field is unsafe and requires unsafe function or block (error E0133) + --> lint_example.rs:11:13 + | +11 | let y = &x.data.0; + | ^^^^^^^^^ + | + = note: `#[warn(safe_packed_borrows)]` 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 #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior +``` + +For more information about the process and policy of future-incompatible +changes, see [RFC 1589]. + +[RFC 1589]: https://github.com/rust-lang/rfcs/blob/master/text/1589-rustc-bug-fix-procedure.md diff --git a/src/doc/rustc/src/lints/listing/allowed-by-default.md b/src/doc/rustc/src/lints/listing/allowed-by-default.md index d2d8c471efc96..95dd60bebfbad 100644 --- a/src/doc/rustc/src/lints/listing/allowed-by-default.md +++ b/src/doc/rustc/src/lints/listing/allowed-by-default.md @@ -1,454 +1,3 @@ # Allowed-by-default lints -These lints are all set to the 'allow' level by default. As such, they won't show up -unless you set them to a higher lint level with a flag or attribute. - -## anonymous-parameters - -This lint detects anonymous parameters. Some example code that triggers this lint: - -```rust -trait Foo { - fn foo(usize); -} -``` - -When set to 'deny', this will produce: - -```text -error: use of deprecated anonymous parameter - --> src/lib.rs:5:11 - | -5 | fn foo(usize); - | ^ - | - = 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 #41686 -``` - -This syntax is mostly a historical accident, and can be worked around quite -easily: - -```rust -trait Foo { - fn foo(_: usize); -} -``` - -## bare-trait-object - -This lint suggests using `dyn Trait` for trait objects. Some example code -that triggers this lint: - -```rust -#![feature(dyn_trait)] - -trait Trait { } - -fn takes_trait_object(_: Box) { -} -``` - -When set to 'deny', this will produce: - -```text -error: trait objects without an explicit `dyn` are deprecated - --> src/lib.rs:7:30 - | -7 | fn takes_trait_object(_: Box) { - | ^^^^^ help: use `dyn`: `dyn Trait` - | -``` - -To fix it, do as the help message suggests: - -```rust -#![feature(dyn_trait)] -#![deny(bare_trait_objects)] - -trait Trait { } - -fn takes_trait_object(_: Box) { -} -``` - -## box-pointers - -This lints use of the Box type. Some example code that triggers this lint: - -```rust -struct Foo { - x: Box, -} -``` - -When set to 'deny', this will produce: - -```text -error: type uses owned (Box type) pointers: std::boxed::Box - --> src/lib.rs:6:5 - | -6 | x: Box //~ ERROR type uses owned - | ^^^^^^^^^^^^^ - | -``` - -This lint is mostly historical, and not particularly useful. `Box` used to -be built into the language, and the only way to do heap allocation. Today's -Rust can call into other allocators, etc. - -## elided-lifetime-in-path - -This lint detects the use of hidden lifetime parameters. Some example code -that triggers this lint: - -```rust -struct Foo<'a> { - x: &'a u32 -} - -fn foo(x: &Foo) { -} -``` - -When set to 'deny', this will produce: - -```text -error: hidden lifetime parameters are deprecated, try `Foo<'_>` - --> src/lib.rs:5:12 - | -5 | fn foo(x: &Foo) { - | ^^^ - | -``` - -Lifetime elision elides this lifetime, but that is being deprecated. - -## missing-copy-implementations - -This lint detects potentially-forgotten implementations of `Copy`. Some -example code that triggers this lint: - -```rust -pub struct Foo { - pub field: i32 -} -``` - -When set to 'deny', this will produce: - -```text -error: type could implement `Copy`; consider adding `impl Copy` - --> src/main.rs:3:1 - | -3 | / pub struct Foo { //~ ERROR type could implement `Copy`; consider adding `impl Copy` -4 | | pub field: i32 -5 | | } - | |_^ - | -``` - -You can fix the lint by deriving `Copy`. - -This lint is set to 'allow' because this code isn't bad; it's common to write -newtypes like this specifically so that a `Copy` type is no longer `Copy`. - -## missing-debug-implementations - -This lint detects missing implementations of `fmt::Debug`. Some example code -that triggers this lint: - -```rust -pub struct Foo; -``` - -When set to 'deny', this will produce: - -```text -error: type does not implement `fmt::Debug`; consider adding `#[derive(Debug)]` or a manual implementation - --> src/main.rs:3:1 - | -3 | pub struct Foo; - | ^^^^^^^^^^^^^^^ - | -``` - -You can fix the lint by deriving `Debug`. - -## missing-docs - -This lint detects missing documentation for public items. Some example code -that triggers this lint: - -```rust -pub fn foo() {} -``` - -When set to 'deny', this will produce: - -```text -error: missing documentation for crate - --> src/main.rs:1:1 - | -1 | / #![deny(missing_docs)] -2 | | -3 | | pub fn foo() {} -4 | | -5 | | fn main() {} - | |____________^ - | - -error: missing documentation for a function - --> src/main.rs:3:1 - | -3 | pub fn foo() {} - | ^^^^^^^^^^^^ - -``` - -To fix the lint, add documentation to all items. - -## single-use-lifetimes - -This lint detects lifetimes that are only used once. Some example code that -triggers this lint: - -```rust -struct Foo<'x> { - x: &'x u32 -} -``` - -When set to 'deny', this will produce: - -```text -error: lifetime name `'x` only used once - --> src/main.rs:3:12 - | -3 | struct Foo<'x> { - | ^^ - | -``` - -## trivial-casts - -This lint detects trivial casts which could be replaced with coercion, which may require -type ascription or a temporary variable. Some example code -that triggers this lint: - -```rust -let x: &u32 = &42; -let _ = x as *const u32; -``` - -When set to 'deny', this will produce: - -```text -error: trivial cast: `&u32` as `*const u32`. Cast can be replaced by coercion, this might require type ascription or a temporary variable - --> src/main.rs:5:13 - | -5 | let _ = x as *const u32; - | ^^^^^^^^^^^^^^^ - | -note: lint level defined here - --> src/main.rs:1:9 - | -1 | #![deny(trivial_casts)] - | ^^^^^^^^^^^^^ -``` - -## trivial-numeric-casts - -This lint detects trivial casts of numeric types which could be removed. Some -example code that triggers this lint: - -```rust -let x = 42i32 as i32; -``` - -When set to 'deny', this will produce: - -```text -error: trivial numeric cast: `i32` as `i32`. Cast can be replaced by coercion, this might require type ascription or a temporary variable - --> src/main.rs:4:13 - | -4 | let x = 42i32 as i32; - | ^^^^^^^^^^^^ - | -``` - -## unreachable-pub - -This lint triggers for `pub` items not reachable from the crate root. Some -example code that triggers this lint: - -```rust -mod foo { - pub mod bar { - - } -} -``` - -When set to 'deny', this will produce: - -```text -error: unreachable `pub` item - --> src/main.rs:4:5 - | -4 | pub mod bar { - | ---^^^^^^^^ - | | - | help: consider restricting its visibility: `pub(crate)` - | -``` - -## unsafe-code - -This lint catches usage of `unsafe` code. Some example code that triggers this lint: - -```rust -fn main() { - unsafe { - - } -} -``` - -When set to 'deny', this will produce: - -```text -error: usage of an `unsafe` block - --> src/main.rs:4:5 - | -4 | / unsafe { -5 | | -6 | | } - | |_____^ - | -``` - -## unstable-features - -This lint is deprecated and no longer used. - -## unused-extern-crates - -This lint guards against `extern crate` items that are never used. Some -example code that triggers this lint: - -```rust,ignore -extern crate semver; -``` - -When set to 'deny', this will produce: - -```text -error: unused extern crate - --> src/main.rs:3:1 - | -3 | extern crate semver; - | ^^^^^^^^^^^^^^^^^^^^ - | -``` - -## unused-import-braces - -This lint catches unnecessary braces around an imported item. Some example -code that triggers this lint: - -```rust -use test::{A}; - -pub mod test { - pub struct A; -} -# fn main() {} -``` - -When set to 'deny', this will produce: - -```text -error: braces around A is unnecessary - --> src/main.rs:3:1 - | -3 | use test::{A}; - | ^^^^^^^^^^^^^^ - | -``` - -To fix it, `use test::A;` - -## unused-qualifications - -This lint detects unnecessarily qualified names. Some example code that triggers this lint: - -```rust -mod foo { - pub fn bar() {} -} - -fn main() { - use foo::bar; - foo::bar(); -} -``` - -When set to 'deny', this will produce: - -```text -error: unnecessary qualification - --> src/main.rs:9:5 - | -9 | foo::bar(); - | ^^^^^^^^ - | -``` - -You can call `bar()` directly, without the `foo::`. - -## unused-results - -This lint checks for the unused result of an expression in a statement. Some -example code that triggers this lint: - -```rust,no_run -fn foo() -> T { panic!() } - -fn main() { - foo::(); -} -``` - -When set to 'deny', this will produce: - -```text -error: unused result - --> src/main.rs:6:5 - | -6 | foo::(); - | ^^^^^^^^^^^^^^^ - | -``` - -## variant-size-differences - -This lint detects enums with widely varying variant sizes. Some example code that triggers this lint: - -```rust -enum En { - V0(u8), - VBig([u8; 1024]), -} -``` - -When set to 'deny', this will produce: - -```text -error: enum variant is more than three times larger (1024 bytes) than the next largest - --> src/main.rs:5:5 - | -5 | VBig([u8; 1024]), //~ ERROR variant is more than three times larger - | ^^^^^^^^^^^^^^^^ - | -``` +This file is auto-generated by the lint-docs script. diff --git a/src/doc/rustc/src/lints/listing/deny-by-default.md b/src/doc/rustc/src/lints/listing/deny-by-default.md index 55714f8f4548b..3c1452d64676c 100644 --- a/src/doc/rustc/src/lints/listing/deny-by-default.md +++ b/src/doc/rustc/src/lints/listing/deny-by-default.md @@ -1,203 +1,3 @@ # Deny-by-default lints -These lints are all set to the 'deny' level by default. - -## exceeding-bitshifts - -This lint detects that a shift exceeds the type's number of bits. Some -example code that triggers this lint: - -```rust,ignore -1_i32 << 32; -``` - -This will produce: - -```text -error: bitshift exceeds the type's number of bits - --> src/main.rs:2:5 - | -2 | 1_i32 << 32; - | ^^^^^^^^^^^ - | -``` - -## invalid-type-param-default - -This lint detects type parameter default erroneously allowed in invalid location. Some -example code that triggers this lint: - -```rust,ignore -fn foo(t: T) {} -``` - -This will produce: - -```text -error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions. - --> src/main.rs:4:8 - | -4 | fn foo(t: T) {} - | ^ - | - = note: `#[deny(invalid_type_param_default)]` 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 #36887 -``` - -## mutable-transmutes - -This lint catches transmuting from `&T` to `&mut T` because it is undefined -behavior. Some example code that triggers this lint: - -```rust,ignore -unsafe { - let y = std::mem::transmute::<&i32, &mut i32>(&5); -} -``` - -This will produce: - -```text -error: mutating transmuted &mut T from &T may cause undefined behavior, consider instead using an UnsafeCell - --> src/main.rs:3:17 - | -3 | let y = std::mem::transmute::<&i32, &mut i32>(&5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -``` - - -## no-mangle-const-items - -This lint detects any `const` items with the `#[no_mangle]` attribute. -Constants do not have their symbols exported, and therefore, this probably -means you meant to use a `static`, not a `const`. Some example code that -triggers this lint: - -```rust,ignore -#[no_mangle] -const FOO: i32 = 5; -``` - -This will produce: - -```text -error: const items should never be `#[no_mangle]` - --> src/main.rs:3:1 - | -3 | const FOO: i32 = 5; - | -----^^^^^^^^^^^^^^ - | | - | help: try a static value: `pub static` - | -``` - -## overflowing-literals - -This lint detects literal out of range for its type. Some -example code that triggers this lint: - -```rust,compile_fail -let x: u8 = 1000; -``` - -This will produce: - -```text -error: literal out of range for u8 - --> src/main.rs:2:17 - | -2 | let x: u8 = 1000; - | ^^^^ - | -``` - -## patterns-in-fns-without-body - -This lint detects patterns in functions without body were that were -previously erroneously allowed. Some example code that triggers this lint: - -```rust,compile_fail -trait Trait { - fn foo(mut arg: u8); -} -``` - -This will produce: - -```text -warning: patterns aren't allowed in methods without bodies - --> src/main.rs:2:12 - | -2 | fn foo(mut arg: u8); - | ^^^^^^^ - | - = note: `#[warn(patterns_in_fns_without_body)]` 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 #35203 -``` - -To fix this, remove the pattern; it can be used in the implementation without -being used in the definition. That is: - -```rust -trait Trait { - fn foo(arg: u8); -} - -impl Trait for i32 { - fn foo(mut arg: u8) { - - } -} -``` - -## pub-use-of-private-extern-crate - -This lint detects a specific situation of re-exporting a private `extern crate`; - -## unknown-crate-types - -This lint detects an unknown crate type found in a `#[crate_type]` directive. Some -example code that triggers this lint: - -```rust,ignore -#![crate_type="lol"] -``` - -This will produce: - -```text -error: invalid `crate_type` value - --> src/lib.rs:1:1 - | -1 | #![crate_type="lol"] - | ^^^^^^^^^^^^^^^^^^^^ - | -``` - -## const-err - -This lint detects expressions that will always panic at runtime and would be an -error in a `const` context. - -```rust,ignore -let _ = [0; 4][4]; -``` - -This will produce: - -```text -error: index out of bounds: the len is 4 but the index is 4 - --> src/lib.rs:1:9 - | -1 | let _ = [0; 4][4]; - | ^^^^^^^^^ - | -``` - -## order-dependent-trait-objects - -This lint detects a trait coherency violation that would allow creating two -trait impls for the same dynamic trait object involving marker traits. +This file is auto-generated by the lint-docs script. diff --git a/src/doc/rustc/src/lints/listing/warn-by-default.md b/src/doc/rustc/src/lints/listing/warn-by-default.md index 386f6008d06aa..eebc022a82bf8 100644 --- a/src/doc/rustc/src/lints/listing/warn-by-default.md +++ b/src/doc/rustc/src/lints/listing/warn-by-default.md @@ -1,903 +1,3 @@ # Warn-by-default lints -These lints are all set to the 'warn' level by default. - -## const-err - -This lint detects an erroneous expression while doing constant evaluation. Some -example code that triggers this lint: - -```rust,ignore -let b = 200u8 + 200u8; -``` - -This will produce: - -```text -warning: attempt to add with overflow - --> src/main.rs:2:9 - | -2 | let b = 200u8 + 200u8; - | ^^^^^^^^^^^^^ - | -``` - -## dead-code - -This lint detects unused, unexported items. Some -example code that triggers this lint: - -```rust -fn foo() {} -``` - -This will produce: - -```text -warning: function is never used: `foo` - --> src/lib.rs:2:1 - | -2 | fn foo() {} - | ^^^^^^^^ - | -``` - -## deprecated - -This lint detects use of deprecated items. Some -example code that triggers this lint: - -```rust -#[deprecated] -fn foo() {} - -fn bar() { - foo(); -} -``` - -This will produce: - -```text -warning: use of deprecated item 'foo' - --> src/lib.rs:7:5 - | -7 | foo(); - | ^^^ - | -``` - -## illegal-floating-point-literal-pattern - -This lint detects floating-point literals used in patterns. Some example code -that triggers this lint: - -```rust -let x = 42.0; - -match x { - 5.0 => {}, - _ => {}, -} -``` - -This will produce: - -```text -warning: floating-point literals cannot be used in patterns - --> src/main.rs:4:9 - | -4 | 5.0 => {}, - | ^^^ - | - = 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 -``` - -## improper-ctypes - -This lint detects proper use of libc types in foreign modules. Some -example code that triggers this lint: - -```rust -extern "C" { - static STATIC: String; -} -``` - -This will produce: - -```text -warning: found struct without foreign-function-safe representation annotation in foreign module, consider adding a `#[repr(C)]` attribute to the type - --> src/main.rs:2:20 - | -2 | static STATIC: String; - | ^^^^^^ - | -``` - -## late-bound-lifetime-arguments - -This lint detects generic lifetime arguments in path segments with -late bound lifetime parameters. Some example code that triggers this lint: - -```rust -struct S; - -impl S { - fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} -} - -fn main() { - S.late::<'static>(&0, &0); -} -``` - -This will produce: - -```text -warning: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present - --> src/main.rs:8:14 - | -4 | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} - | -- the late bound lifetime parameter is introduced here -... -8 | S.late::<'static>(&0, &0); - | ^^^^^^^ - | - = note: `#[warn(late_bound_lifetime_arguments)]` 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 #42868 -``` - -## non-camel-case-types - -This lint detects types, variants, traits and type parameters that don't have -camel case names. Some example code that triggers this lint: - -```rust -struct s; -``` - -This will produce: - -```text -warning: type `s` should have a camel case name such as `S` - --> src/main.rs:1:1 - | -1 | struct s; - | ^^^^^^^^^ - | -``` - -## non-shorthand-field-patterns - -This lint detects using `Struct { x: x }` instead of `Struct { x }` in a pattern. Some -example code that triggers this lint: - -```rust -struct Point { - x: i32, - y: i32, -} - - -fn main() { - let p = Point { - x: 5, - y: 5, - }; - - match p { - Point { x: x, y: y } => (), - } -} -``` - -This will produce: - -```text -warning: the `x:` in this pattern is redundant - --> src/main.rs:14:17 - | -14 | Point { x: x, y: y } => (), - | --^^ - | | - | help: remove this - | - -warning: the `y:` in this pattern is redundant - --> src/main.rs:14:23 - | -14 | Point { x: x, y: y } => (), - | --^^ - | | - | help: remove this - -``` - -## non-snake-case - -This lint detects variables, methods, functions, lifetime parameters and -modules that don't have snake case names. Some example code that triggers -this lint: - -```rust -let X = 5; -``` - -This will produce: - -```text -warning: variable `X` should have a snake case name such as `x` - --> src/main.rs:2:9 - | -2 | let X = 5; - | ^ - | -``` - -## non-upper-case-globals - -This lint detects static constants that don't have uppercase identifiers. -Some example code that triggers this lint: - -```rust -static x: i32 = 5; -``` - -This will produce: - -```text -warning: static variable `x` should have an upper case name such as `X` - --> src/main.rs:1:1 - | -1 | static x: i32 = 5; - | ^^^^^^^^^^^^^^^^^^ - | -``` - -## no-mangle-generic-items - -This lint detects generic items must be mangled. Some -example code that triggers this lint: - -```rust -#[no_mangle] -fn foo(t: T) { - -} -``` - -This will produce: - -```text -warning: functions generic over types must be mangled - --> src/main.rs:2:1 - | -1 | #[no_mangle] - | ------------ help: remove this attribute -2 | / fn foo(t: T) { -3 | | -4 | | } - | |_^ - | -``` - -## path-statements - -This lint detects path statements with no effect. Some example code that -triggers this lint: - -```rust -let x = 42; - -x; -``` - -This will produce: - -```text -warning: path statement with no effect - --> src/main.rs:3:5 - | -3 | x; - | ^^ - | -``` - -## private-in-public - -This lint detects private items in public interfaces not caught by the old implementation. Some -example code that triggers this lint: - -```rust,ignore -pub trait Trait { - type A; -} - -pub struct S; - -mod foo { - struct Z; - - impl ::Trait for ::S { - type A = Z; - } -} -# fn main() {} -``` - -This will produce: - -```text -error[E0446]: private type `foo::Z` in public interface - --> src/main.rs:11:9 - | -11 | type A = Z; - | ^^^^^^^^^^^ can't leak private type -``` - -## private-no-mangle-fns - -This lint detects functions marked `#[no_mangle]` that are also private. -Given that private functions aren't exposed publicly, and `#[no_mangle]` -controls the public symbol, this combination is erroneous. Some example code -that triggers this lint: - -```rust -#[no_mangle] -fn foo() {} -``` - -This will produce: - -```text -warning: function is marked `#[no_mangle]`, but not exported - --> src/main.rs:2:1 - | -2 | fn foo() {} - | -^^^^^^^^^^ - | | - | help: try making it public: `pub` - | -``` - -To fix this, either make it public or remove the `#[no_mangle]`. - -## private-no-mangle-statics - -This lint detects any statics marked `#[no_mangle]` that are private. -Given that private statics aren't exposed publicly, and `#[no_mangle]` -controls the public symbol, this combination is erroneous. Some example code -that triggers this lint: - -```rust -#[no_mangle] -static X: i32 = 4; -``` - -This will produce: - -```text -warning: static is marked `#[no_mangle]`, but not exported - --> src/main.rs:2:1 - | -2 | static X: i32 = 4; - | -^^^^^^^^^^^^^^^^^ - | | - | help: try making it public: `pub` - | -``` - -To fix this, either make it public or remove the `#[no_mangle]`. - -## renamed-and-removed-lints - -This lint detects lints that have been renamed or removed. Some -example code that triggers this lint: - -```rust -#![deny(raw_pointer_derive)] -``` - -This will produce: - -```text -warning: lint raw_pointer_derive has been removed: using derive with raw pointers is ok - --> src/main.rs:1:9 - | -1 | #![deny(raw_pointer_derive)] - | ^^^^^^^^^^^^^^^^^^ - | -``` - -To fix this, either remove the lint or use the new name. - -## safe-packed-borrows - -This lint detects borrowing a field in the interior of a packed structure -with alignment other than 1. Some example code that triggers this lint: - -```rust -#[repr(packed)] -pub struct Unaligned(pub T); - -pub struct Foo { - start: u8, - data: Unaligned, -} - -fn main() { - let x = Foo { start: 0, data: Unaligned(1) }; - let y = &x.data.0; -} -``` - -This will produce: - -```text -warning: borrow of packed field requires unsafe function or block (error E0133) - --> src/main.rs:11:13 - | -11 | let y = &x.data.0; - | ^^^^^^^^^ - | - = note: `#[warn(safe_packed_borrows)]` 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 #46043 -``` - -## stable-features - -This lint detects a `#[feature]` attribute that's since been made stable. Some -example code that triggers this lint: - -```rust -#![feature(test_accepted_feature)] -``` - -This will produce: - -```text -warning: this feature has been stable since 1.0.0. Attribute no longer needed - --> src/main.rs:1:12 - | -1 | #![feature(test_accepted_feature)] - | ^^^^^^^^^^^^^^^^^^^^^ - | -``` - -To fix, simply remove the `#![feature]` attribute, as it's no longer needed. - -## type-alias-bounds - -This lint detects bounds in type aliases. These are not currently enforced. -Some example code that triggers this lint: - -```rust -#[allow(dead_code)] -type SendVec = Vec; -``` - -This will produce: - -```text -warning: bounds on generic parameters are not enforced in type aliases - --> src/lib.rs:2:17 - | -2 | type SendVec = Vec; - | ^^^^ - | - = note: `#[warn(type_alias_bounds)]` on by default - = help: the bound will not be checked when the type alias is used, and should be removed -``` - -## tyvar-behind-raw-pointer - -This lint detects raw pointer to an inference variable. Some -example code that triggers this lint: - -```rust -let data = std::ptr::null(); -let _ = &data as *const *const (); - -if data.is_null() {} -``` - -This will produce: - -```text -warning: type annotations needed - --> src/main.rs:4:13 - | -4 | if data.is_null() {} - | ^^^^^^^ - | - = note: `#[warn(tyvar_behind_raw_pointer)]` on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! - = note: for more information, see issue #46906 -``` - -## unconditional-recursion - -This lint detects functions that cannot return without calling themselves. -Some example code that triggers this lint: - -```rust -fn foo() { - foo(); -} -``` - -This will produce: - -```text -warning: function cannot return without recursing - --> src/main.rs:1:1 - | -1 | fn foo() { - | ^^^^^^^^ cannot return without recursing -2 | foo(); - | ----- recursive call site - | -``` - -## unknown-lints - -This lint detects unrecognized lint attribute. Some -example code that triggers this lint: - -```rust,ignore -#[allow(not_a_real_lint)] -``` - -This will produce: - -```text -warning: unknown lint: `not_a_real_lint` - --> src/main.rs:1:10 - | -1 | #![allow(not_a_real_lint)] - | ^^^^^^^^^^^^^^^ - | -``` - -## unreachable-code - -This lint detects unreachable code paths. Some example code that -triggers this lint: - -```rust,no_run -panic!("we never go past here!"); - -let x = 5; -``` - -This will produce: - -```text -warning: unreachable statement - --> src/main.rs:4:5 - | -4 | let x = 5; - | ^^^^^^^^^^ - | -``` - -## unreachable-patterns - -This lint detects unreachable patterns. Some -example code that triggers this lint: - -```rust -let x = 5; -match x { - y => (), - 5 => (), -} -``` - -This will produce: - -```text -warning: unreachable pattern - --> src/main.rs:5:5 - | -5 | 5 => (), - | ^ - | -``` - -The `y` pattern will always match, so the five is impossible to reach. -Remember, match arms match in order, you probably wanted to put the `5` case -above the `y` case. - -## unstable-name-collision - -This lint detects that you've used a name that the standard library plans to -add in the future, which means that your code may fail to compile without -additional type annotations in the future. Either rename, or add those -annotations now. - -## unused-allocation - -This lint detects unnecessary allocations that can be eliminated. - -## unused-assignments - -This lint detects assignments that will never be read. Some -example code that triggers this lint: - -```rust -let mut x = 5; -x = 6; -``` - -This will produce: - -```text -warning: value assigned to `x` is never read - --> src/main.rs:4:5 - | -4 | x = 6; - | ^ - | -``` - -## unused-attributes - -This lint detects attributes that were not used by the compiler. Some -example code that triggers this lint: - -```rust -#![macro_export] -``` - -This will produce: - -```text -warning: unused attribute - --> src/main.rs:1:1 - | -1 | #![macro_export] - | ^^^^^^^^^^^^^^^^ - | -``` - -## unused-comparisons - -This lint detects comparisons made useless by limits of the types involved. Some -example code that triggers this lint: - -```rust -fn foo(x: u8) { - x >= 0; -} -``` - -This will produce: - -```text -warning: comparison is useless due to type limits - --> src/main.rs:6:5 - | -6 | x >= 0; - | ^^^^^^ - | -``` - -## unused-doc-comment - -This lint detects doc comments that aren't used by rustdoc. Some -example code that triggers this lint: - -```rust -/// docs for x -let x = 12; -``` - -This will produce: - -```text -warning: doc comment not used by rustdoc - --> src/main.rs:2:5 - | -2 | /// docs for x - | ^^^^^^^^^^^^^^ - | -``` - -## unused-features - -This lint detects unused or unknown features found in crate-level `#[feature]` directives. -To fix this, simply remove the feature flag. - -## unused-imports - -This lint detects imports that are never used. Some -example code that triggers this lint: - -```rust -use std::collections::HashMap; -``` - -This will produce: - -```text -warning: unused import: `std::collections::HashMap` - --> src/main.rs:1:5 - | -1 | use std::collections::HashMap; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | -``` - -## unused-macros - -This lint detects macros that were not used. Some example code that -triggers this lint: - -```rust -macro_rules! unused { - () => {}; -} - -fn main() { -} -``` - -This will produce: - -```text -warning: unused macro definition - --> src/main.rs:1:1 - | -1 | / macro_rules! unused { -2 | | () => {}; -3 | | } - | |_^ - | -``` - -## unused-must-use - -This lint detects unused result of a type flagged as `#[must_use]`. Some -example code that triggers this lint: - -```rust -fn returns_result() -> Result<(), ()> { - Ok(()) -} - -fn main() { - returns_result(); -} -``` - -This will produce: - -```text -warning: unused `std::result::Result` that must be used - --> src/main.rs:6:5 - | -6 | returns_result(); - | ^^^^^^^^^^^^^^^^^ - | -``` - -## unused-mut - -This lint detects mut variables which don't need to be mutable. Some -example code that triggers this lint: - -```rust -let mut x = 5; -``` - -This will produce: - -```text -warning: variable does not need to be mutable - --> src/main.rs:2:9 - | -2 | let mut x = 5; - | ----^ - | | - | help: remove this `mut` - | -``` - -## unused-parens - -This lint detects `if`, `match`, `while` and `return` with parentheses; they -do not need them. Some example code that triggers this lint: - -```rust -if(true) {} -``` - -This will produce: - -```text -warning: unnecessary parentheses around `if` condition - --> src/main.rs:2:7 - | -2 | if(true) {} - | ^^^^^^ help: remove these parentheses - | -``` - -## unused-unsafe - -This lint detects unnecessary use of an `unsafe` block. Some -example code that triggers this lint: - -```rust -unsafe {} -``` - -This will produce: - -```text -warning: unnecessary `unsafe` block - --> src/main.rs:2:5 - | -2 | unsafe {} - | ^^^^^^ unnecessary `unsafe` block - | -``` - -## unused-variables - -This lint detects variables which are not used in any way. Some -example code that triggers this lint: - -```rust -let x = 5; -``` - -This will produce: - -```text -warning: unused variable: `x` - --> src/main.rs:2:9 - | -2 | let x = 5; - | ^ help: consider using `_x` instead - | -``` - -## warnings - -This lint is a bit special; by changing its level, you change every other warning -that would produce a warning to whatever value you'd like: - -```rust -#![deny(warnings)] -``` - -As such, you won't ever trigger this lint in your code directly. - -## while-true - -This lint detects `while true { }`. Some example code that triggers this -lint: - -```rust,no_run -while true { - -} -``` - -This will produce: - -```text -warning: denote infinite loops with `loop { ... }` - --> src/main.rs:2:5 - | -2 | while true { - | ^^^^^^^^^^ help: use `loop` - | -``` +This file is auto-generated by the lint-docs script. diff --git a/src/tools/lint-docs/Cargo.toml b/src/tools/lint-docs/Cargo.toml new file mode 100644 index 0000000000000..657b115671e34 --- /dev/null +++ b/src/tools/lint-docs/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "lint-docs" +version = "0.1.0" +authors = ["The Rust Project Developers"] +edition = "2018" +description = "A script to extract the lint documentation for the rustc book." + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde_json = "1.0.57" +tempfile = "3.1.0" +walkdir = "2.3.1" diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs new file mode 100644 index 0000000000000..a212459bb4dc6 --- /dev/null +++ b/src/tools/lint-docs/src/groups.rs @@ -0,0 +1,114 @@ +use crate::Lint; +use std::collections::{BTreeMap, BTreeSet}; +use std::error::Error; +use std::fmt::Write; +use std::fs; +use std::path::Path; +use std::process::Command; + +static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[ + ("unused", "Lints that detect things being declared but not used, or excess syntax"), + ("rustdoc", "Rustdoc-specific lints"), + ("rust-2018-idioms", "Lints to nudge you toward idiomatic features of Rust 2018"), + ("nonstandard-style", "Violation of standard naming conventions"), + ("future-incompatible", "Lints that detect code that has future-compatibility problems"), + ("rust-2018-compatibility", "Lints used to transition code from the 2015 edition to 2018"), +]; + +/// Updates the documentation of lint groups. +pub(crate) fn generate_group_docs( + lints: &[Lint], + rustc_path: &Path, + out_path: &Path, +) -> Result<(), Box> { + let groups = collect_groups(rustc_path)?; + let groups_path = out_path.join("groups.md"); + let contents = fs::read_to_string(&groups_path) + .map_err(|e| format!("could not read {}: {}", groups_path.display(), e))?; + let new_contents = contents.replace("{{groups-table}}", &make_groups_table(lints, &groups)?); + // Delete the output because rustbuild uses hard links in its copies. + let _ = fs::remove_file(&groups_path); + fs::write(&groups_path, new_contents) + .map_err(|e| format!("could not write to {}: {}", groups_path.display(), e))?; + Ok(()) +} + +type LintGroups = BTreeMap>; + +/// Collects the group names from rustc. +fn collect_groups(rustc: &Path) -> Result> { + let mut result = BTreeMap::new(); + let mut cmd = Command::new(rustc); + cmd.arg("-Whelp"); + let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?; + if !output.status.success() { + return Err(format!( + "failed to collect lint info: {:?}\n--- stderr\n{}--- stdout\n{}\n", + output.status, + std::str::from_utf8(&output.stderr).unwrap(), + std::str::from_utf8(&output.stdout).unwrap(), + ) + .into()); + } + let stdout = std::str::from_utf8(&output.stdout).unwrap(); + let lines = stdout.lines(); + let group_start = lines.skip_while(|line| !line.contains("groups provided")).skip(1); + let table_start = group_start.skip_while(|line| !line.contains("----")).skip(1); + for line in table_start { + if line.is_empty() { + break; + } + let mut parts = line.trim().splitn(2, ' '); + let name = parts.next().expect("name in group"); + if name == "warnings" { + // This is special. + continue; + } + let lints = + parts.next().ok_or_else(|| format!("expected lints following name, got `{}`", line))?; + let lints = lints.split(',').map(|l| l.trim().to_string()).collect(); + assert!(result.insert(name.to_string(), lints).is_none()); + } + if result.is_empty() { + return Err( + format!("expected at least one group in -Whelp output, got:\n{}", stdout).into() + ); + } + Ok(result) +} + +fn make_groups_table(lints: &[Lint], groups: &LintGroups) -> Result> { + let mut result = String::new(); + let mut to_link = Vec::new(); + result.push_str("| Group | Description | Lints |\n"); + result.push_str("|-------|-------------|-------|\n"); + result.push_str("| warnings | All lints that are set to issue warnings | See [warn-by-default] for the default set of warnings |\n"); + for (group_name, group_lints) in groups { + let description = GROUP_DESCRIPTIONS.iter().find(|(n, _)| n == group_name) + .ok_or_else(|| format!("lint group `{}` does not have a description, please update the GROUP_DESCRIPTIONS list", group_name))? + .1; + to_link.extend(group_lints); + let brackets: Vec<_> = group_lints.iter().map(|l| format!("[{}]", l)).collect(); + write!(result, "| {} | {} | {} |\n", group_name, description, brackets.join(", ")).unwrap(); + } + result.push('\n'); + result.push_str("[warn-by-default]: listing/warn-by-default.md\n"); + for lint_name in to_link { + let lint_def = + lints.iter().find(|l| l.name == lint_name.replace("-", "_")).ok_or_else(|| { + format!( + "`rustc -W help` defined lint `{}` but that lint does not appear to exist", + lint_name + ) + })?; + write!( + result, + "[{}]: listing/{}#{}\n", + lint_name, + lint_def.level.doc_filename(), + lint_name + ) + .unwrap(); + } + Ok(result) +} diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs new file mode 100644 index 0000000000000..b1e14ea6c466b --- /dev/null +++ b/src/tools/lint-docs/src/lib.rs @@ -0,0 +1,463 @@ +use std::error::Error; +use std::fmt::Write; +use std::fs; +use std::path::{Path, PathBuf}; +use std::process::Command; +use walkdir::WalkDir; + +mod groups; + +struct Lint { + name: String, + doc: Vec, + level: Level, + path: PathBuf, + lineno: usize, +} + +#[derive(Clone, Copy, PartialEq)] +enum Level { + Allow, + Warn, + Deny, +} + +impl Level { + fn doc_filename(&self) -> &str { + match self { + Level::Allow => "allowed-by-default.md", + Level::Warn => "warn-by-default.md", + Level::Deny => "deny-by-default.md", + } + } +} + +/// Collects all lints, and writes the markdown documentation at the given directory. +pub fn extract_lint_docs( + src_path: &Path, + out_path: &Path, + rustc_path: &Path, + rustdoc_path: &Path, + verbose: bool, +) -> Result<(), Box> { + let mut lints = gather_lints(src_path)?; + for lint in &mut lints { + generate_output_example(lint, rustc_path, rustdoc_path, verbose).map_err(|e| { + format!( + "failed to test example in lint docs for `{}` in {}:{}: {}", + lint.name, + lint.path.display(), + lint.lineno, + e + ) + })?; + } + save_lints_markdown(&lints, &out_path.join("listing"))?; + groups::generate_group_docs(&lints, rustc_path, out_path)?; + Ok(()) +} + +/// Collects all lints from all files in the given directory. +fn gather_lints(src_path: &Path) -> Result, Box> { + let mut lints = Vec::new(); + for entry in WalkDir::new(src_path).into_iter().filter_map(|e| e.ok()) { + if !entry.path().extension().map_or(false, |ext| ext == "rs") { + continue; + } + lints.extend(lints_from_file(entry.path())?); + } + if lints.is_empty() { + return Err("no lints were found!".into()); + } + Ok(lints) +} + +/// Collects all lints from the given file. +fn lints_from_file(path: &Path) -> Result, Box> { + let mut lints = Vec::new(); + let contents = fs::read_to_string(path) + .map_err(|e| format!("could not read {}: {}", path.display(), e))?; + let mut lines = contents.lines().enumerate(); + loop { + // Find a lint declaration. + let lint_start = loop { + match lines.next() { + Some((lineno, line)) => { + if line.trim().starts_with("declare_lint!") { + break lineno + 1; + } + } + None => return Ok(lints), + } + }; + // Read the lint. + let mut doc_lines = Vec::new(); + let (doc, name) = loop { + match lines.next() { + Some((lineno, line)) => { + let line = line.trim(); + if line.starts_with("/// ") { + doc_lines.push(line.trim()[4..].to_string()); + } else if line.starts_with("///") { + doc_lines.push("".to_string()); + } else if line.starts_with("// ") { + // Ignore comments. + continue; + } else { + let name = lint_name(line).map_err(|e| { + format!( + "could not determine lint name in {}:{}: {}, line was `{}`", + path.display(), + lineno, + e, + line + ) + })?; + if doc_lines.is_empty() { + return Err(format!( + "did not find doc lines for lint `{}` in {}", + name, + path.display() + ) + .into()); + } + break (doc_lines, name); + } + } + None => { + return Err(format!( + "unexpected EOF for lint definition at {}:{}", + path.display(), + lint_start + ) + .into()); + } + } + }; + // These lints are specifically undocumented. This should be reserved + // for internal rustc-lints only. + if name == "deprecated_in_future" { + continue; + } + // Read the level. + let level = loop { + match lines.next() { + // Ignore comments. + Some((_, line)) if line.trim().starts_with("// ") => {} + Some((lineno, line)) => match line.trim() { + "Allow," => break Level::Allow, + "Warn," => break Level::Warn, + "Deny," => break Level::Deny, + _ => { + return Err(format!( + "unexpected lint level `{}` in {}:{}", + line, + path.display(), + lineno + ) + .into()); + } + }, + None => { + return Err(format!( + "expected lint level in {}:{}, got EOF", + path.display(), + lint_start + ) + .into()); + } + } + }; + // The rest of the lint definition is ignored. + assert!(!doc.is_empty()); + lints.push(Lint { name, doc, level, path: PathBuf::from(path), lineno: lint_start }); + } +} + +/// Extracts the lint name (removing the visibility modifier, and checking validity). +fn lint_name(line: &str) -> Result { + // Skip over any potential `pub` visibility. + match line.trim().split(' ').next_back() { + Some(name) => { + if !name.ends_with(',') { + return Err("lint name should end with comma"); + } + let name = &name[..name.len() - 1]; + if !name.chars().all(|ch| ch.is_uppercase() || ch == '_') || name.is_empty() { + return Err("lint name did not have expected format"); + } + Ok(name.to_lowercase().to_string()) + } + None => Err("could not find lint name"), + } +} + +/// Mutates the lint definition to replace the `{{produces}}` marker with the +/// actual output from the compiler. +fn generate_output_example( + lint: &mut Lint, + rustc_path: &Path, + rustdoc_path: &Path, + verbose: bool, +) -> Result<(), Box> { + // Explicit list of lints that are allowed to not have an example. Please + // try to avoid adding to this list. + if matches!( + lint.name.as_str(), + "unused_features" + | "unstable_features" + | "incomplete_include" + | "unused_crate_dependencies" + | "exported_private_dependencies" + | "proc_macro_derive_resolution_fallback" + | "macro_use_extern_crate" + ) { + return Ok(()); + } + check_style(lint)?; + replace_produces(lint, rustc_path, rustdoc_path, verbose)?; + Ok(()) +} + +/// Checks the doc style of the lint. +fn check_style(lint: &Lint) -> Result<(), Box> { + for expected in &["### Example", "### Explanation", "{{produces}}"] { + if !lint.doc.iter().any(|line| line.contains(expected)) { + return Err(format!("lint docs should contain the line `{}`", expected).into()); + } + } + if let Some(first) = lint.doc.first() { + if !first.starts_with(&format!("The `{}` lint", lint.name)) { + return Err(format!( + "lint docs should start with the text \"The `{}` lint\" to introduce the lint", + lint.name + ) + .into()); + } + } + Ok(()) +} + +/// Mutates the lint docs to replace the `{{produces}}` marker with the actual +/// output from the compiler. +fn replace_produces( + lint: &mut Lint, + rustc_path: &Path, + rustdoc_path: &Path, + verbose: bool, +) -> Result<(), Box> { + let mut lines = lint.doc.iter_mut(); + loop { + // Find start of example. + let options = loop { + match lines.next() { + Some(line) if line.starts_with("```rust") => { + break line[7..].split(',').collect::>(); + } + Some(line) if line.contains("{{produces}}") => { + return Err("lint marker {{{{produces}}}} found, \ + but expected to immediately follow a rust code block" + .into()); + } + Some(_) => {} + None => return Ok(()), + } + }; + // Find the end of example. + let mut example = Vec::new(); + loop { + match lines.next() { + Some(line) if line == "```" => break, + Some(line) => example.push(line), + None => { + return Err(format!( + "did not find end of example triple ticks ```, docs were:\n{:?}", + lint.doc + ) + .into()); + } + } + } + // Find the {{produces}} line. + loop { + match lines.next() { + Some(line) if line.is_empty() => {} + Some(line) if line == "{{produces}}" => { + let output = generate_lint_output( + &lint.name, + &example, + &options, + rustc_path, + rustdoc_path, + verbose, + )?; + line.replace_range( + .., + &format!( + "This will produce:\n\ + \n\ + ```text\n\ + {}\ + ```", + output + ), + ); + break; + } + // No {{produces}} after example, find next example. + Some(_line) => break, + None => return Ok(()), + } + } + } +} + +/// Runs the compiler against the example, and extracts the output. +fn generate_lint_output( + name: &str, + example: &[&mut String], + options: &[&str], + rustc_path: &Path, + rustdoc_path: &Path, + verbose: bool, +) -> Result> { + if verbose { + eprintln!("compiling lint {}", name); + } + let tempdir = tempfile::TempDir::new()?; + let tempfile = tempdir.path().join("lint_example.rs"); + let mut source = String::new(); + let is_rustdoc = options.contains(&"rustdoc"); + let needs_main = !example.iter().any(|line| line.contains("fn main")) && !is_rustdoc; + // Remove `# ` prefix for hidden lines. + let unhidden = + example.iter().map(|line| if line.starts_with("# ") { &line[2..] } else { line }); + let mut lines = unhidden.peekable(); + while let Some(line) = lines.peek() { + if line.starts_with("#!") { + source.push_str(line); + source.push('\n'); + lines.next(); + } else { + break; + } + } + if needs_main { + source.push_str("fn main() {\n"); + } + for line in lines { + source.push_str(line); + source.push('\n') + } + if needs_main { + source.push_str("}\n"); + } + fs::write(&tempfile, source) + .map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?; + let program = if is_rustdoc { rustdoc_path } else { rustc_path }; + let mut cmd = Command::new(program); + if options.contains(&"edition2015") { + cmd.arg("--edition=2015"); + } else { + cmd.arg("--edition=2018"); + } + cmd.arg("--error-format=json"); + if options.contains(&"test") { + cmd.arg("--test"); + } + cmd.arg("lint_example.rs"); + cmd.current_dir(tempdir.path()); + let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?; + let stderr = std::str::from_utf8(&output.stderr).unwrap(); + let msgs = stderr + .lines() + .filter(|line| line.starts_with('{')) + .map(serde_json::from_str) + .collect::, _>>()?; + match msgs + .iter() + .find(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name)) + { + Some(msg) => { + let rendered = msg["rendered"].as_str().expect("rendered field should exist"); + Ok(rendered.to_string()) + } + None => { + match msgs.iter().find( + |msg| matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)), + ) { + Some(msg) => { + let rendered = msg["rendered"].as_str().expect("rendered field should exist"); + Ok(rendered.to_string()) + } + None => { + let rendered: Vec<&str> = + msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect(); + Err(format!( + "did not find lint `{}` in output of example, got:\n{}", + name, + rendered.join("\n") + ) + .into()) + } + } + } + } +} + +static ALLOWED_MD: &str = r#"# Allowed-by-default lints + +These lints are all set to the 'allow' level by default. As such, they won't show up +unless you set them to a higher lint level with a flag or attribute. + +"#; + +static WARN_MD: &str = r#"# Warn-by-default lints + +These lints are all set to the 'warn' level by default. + +"#; + +static DENY_MD: &str = r#"# Deny-by-default lints + +These lints are all set to the 'deny' level by default. + +"#; + +/// Saves the mdbook lint chapters at the given path. +fn save_lints_markdown(lints: &[Lint], out_dir: &Path) -> Result<(), Box> { + save_level(lints, Level::Allow, out_dir, ALLOWED_MD)?; + save_level(lints, Level::Warn, out_dir, WARN_MD)?; + save_level(lints, Level::Deny, out_dir, DENY_MD)?; + Ok(()) +} + +fn save_level( + lints: &[Lint], + level: Level, + out_dir: &Path, + header: &str, +) -> Result<(), Box> { + let mut result = String::new(); + result.push_str(header); + let mut these_lints: Vec<_> = lints.iter().filter(|lint| lint.level == level).collect(); + these_lints.sort_unstable_by_key(|lint| &lint.name); + for lint in &these_lints { + write!(result, "* [`{}`](#{})\n", lint.name, lint.name.replace("_", "-")).unwrap(); + } + result.push('\n'); + for lint in &these_lints { + write!(result, "## {}\n\n", lint.name.replace("_", "-")).unwrap(); + for line in &lint.doc { + result.push_str(line); + result.push('\n'); + } + result.push('\n'); + } + let out_path = out_dir.join(level.doc_filename()); + // Delete the output because rustbuild uses hard links in its copies. + let _ = fs::remove_file(&out_path); + fs::write(&out_path, result) + .map_err(|e| format!("could not write to {}: {}", out_path.display(), e))?; + Ok(()) +} diff --git a/src/tools/lint-docs/src/main.rs b/src/tools/lint-docs/src/main.rs new file mode 100644 index 0000000000000..4b824596b4673 --- /dev/null +++ b/src/tools/lint-docs/src/main.rs @@ -0,0 +1,67 @@ +use std::error::Error; +use std::path::PathBuf; + +fn main() { + if let Err(e) = doit() { + println!("error: {}", e); + std::process::exit(1); + } +} + +fn doit() -> Result<(), Box> { + let mut args = std::env::args().skip(1); + let mut src_path = None; + let mut out_path = None; + let mut rustc_path = None; + let mut rustdoc_path = None; + let mut verbose = false; + while let Some(arg) = args.next() { + match arg.as_str() { + "--src" => { + src_path = match args.next() { + Some(s) => Some(PathBuf::from(s)), + None => return Err("--src requires a value".into()), + }; + } + "--out" => { + out_path = match args.next() { + Some(s) => Some(PathBuf::from(s)), + None => return Err("--out requires a value".into()), + }; + } + "--rustc" => { + rustc_path = match args.next() { + Some(s) => Some(PathBuf::from(s)), + None => return Err("--rustc requires a value".into()), + }; + } + "--rustdoc" => { + rustdoc_path = match args.next() { + Some(s) => Some(PathBuf::from(s)), + None => return Err("--rustdoc requires a value".into()), + }; + } + "-v" | "--verbose" => verbose = true, + s => return Err(format!("unexpected argument `{}`", s).into()), + } + } + if src_path.is_none() { + return Err("--src must be specified to the directory with the compiler source".into()); + } + if out_path.is_none() { + return Err("--out must be specified to the directory with the lint listing docs".into()); + } + if rustc_path.is_none() { + return Err("--rustc must be specified to the path of rustc".into()); + } + if rustdoc_path.is_none() { + return Err("--rustdoc must be specified to the path of rustdoc".into()); + } + lint_docs::extract_lint_docs( + &src_path.unwrap(), + &out_path.unwrap(), + &rustc_path.unwrap(), + &rustdoc_path.unwrap(), + verbose, + ) +} From ce014be0b9d0325ad9e6ecb8c93b3c8186b18089 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 11 Sep 2020 08:55:59 -0700 Subject: [PATCH 0368/1052] Link rustdoc lint docs to the rustdoc book. --- compiler/rustc_session/src/lint/builtin.rs | 138 ++------------------- src/bootstrap/doc.rs | 3 - src/doc/rustdoc/src/lints.md | 58 +++++++++ src/tools/lint-docs/src/lib.rs | 36 +++--- src/tools/lint-docs/src/main.rs | 11 -- 5 files changed, 88 insertions(+), 158 deletions(-) diff --git a/compiler/rustc_session/src/lint/builtin.rs b/compiler/rustc_session/src/lint/builtin.rs index 4c0c7fae29b29..22030a842dbb8 100644 --- a/compiler/rustc_session/src/lint/builtin.rs +++ b/compiler/rustc_session/src/lint/builtin.rs @@ -1817,35 +1817,10 @@ declare_lint! { declare_lint! { /// The `broken_intra_doc_links` lint detects failures in resolving - /// intra-doc link targets. This is a `rustdoc` only lint, and only works - /// on the [**nightly channel**]. + /// intra-doc link targets. This is a `rustdoc` only lint, see the + /// documentation in the [rustdoc book]. /// - /// [**nightly channel**]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html - /// - /// ### Example - /// - /// ```rust,rustdoc - /// /// This is a doc comment. - /// /// - /// /// See also [`bar`]. - /// pub fn foo() { - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// `rustdoc` allows [linking to items by name][intra] which will - /// automatically generate links in the documentation to the item. This - /// lint is issued when `rustdoc` is unable to find the named item. Check - /// that the name is correct, that it is in scope, or if you need to - /// qualify it with a path. If you intended to have square brackets appear - /// literally in the text, surround the brackets with backticks such as `` - /// `[example]` `` to indicate a code span, or prefix it with a backslash - /// such as `\[example]`. - /// - /// [intra]: https://doc.rust-lang.org/nightly/rustdoc/unstable-features.html#linking-to-items-by-name + /// [rustdoc book]: ../../../rustdoc/lints.html#broken_intra_doc_links pub BROKEN_INTRA_DOC_LINKS, Warn, "failures in resolving intra-doc link targets" @@ -1854,27 +1829,9 @@ declare_lint! { declare_lint! { /// The `invalid_codeblock_attributes` lint detects code block attributes /// in documentation examples that have potentially mis-typed values. This - /// is a `rustdoc` only lint. - /// - /// ### Example + /// is a `rustdoc` only lint, see the documentation in the [rustdoc book]. /// - /// ```rust,rustdoc - /// /// Example. - /// /// - /// /// ```should-panic - /// /// assert_eq!(1, 2); - /// /// ``` - /// pub fn foo() {} - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// This lint is issued when `rustdoc` detects an example code block - /// attribute that appears similar to a valid one. In the example above, - /// the correct form is `should_panic`. This helps detect typo mistakes - /// for some common attributes. + /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_codeblock_attributes pub INVALID_CODEBLOCK_ATTRIBUTES, Warn, "codeblock attribute looks a lot like a known one" @@ -1882,24 +1839,10 @@ declare_lint! { declare_lint! { /// The `missing_crate_level_docs` lint detects if documentation is - /// missing at the crate root. This is a `rustdoc` only lint. This is a - /// `rustdoc` only lint. - /// - /// ### Example - /// - /// ```rust,rustdoc - /// #![deny(missing_crate_level_docs)] - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation + /// missing at the crate root. This is a `rustdoc` only lint, see the + /// documentation in the [rustdoc book]. /// - /// This lint causes `rustdoc` to check if the crate root is missing - /// documentation. This is currently "allow" by default, but it is - /// intended to make this a warning in the future. This is intended as a - /// means to introduce new users on *how* to document their crate by - /// pointing them to some instructions on how to get started. + /// [rustdoc book]: ../../../rustdoc/lints.html#missing_crate_level_docs pub MISSING_CRATE_LEVEL_DOCS, Allow, "detects crates with no crate-level documentation" @@ -1908,43 +1851,9 @@ declare_lint! { declare_lint! { /// The `missing_doc_code_examples` lint detects publicly-exported items /// without code samples in their documentation. This is a `rustdoc` only - /// lint, and only works on the [**nightly channel**]. + /// lint, see the documentation in the [rustdoc book]. /// - /// [**nightly channel**]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html - /// - /// ### Example - /// - /// ```rust,rustdoc - /// #![warn(missing_doc_code_examples)] - /// - /// /// There is no code example! - /// pub fn no_code_example() {} - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// This lint is to ensure a high level of quality for documentation. Code - /// examples can be very useful to see how to use an API. To add an - /// example, include a markdown code block with an example of how to use - /// the item, such as: - /// - /// ```rust - /// /// Adds one to the number given. - /// /// - /// /// # Examples - /// /// - /// /// ``` - /// /// let arg = 5; - /// /// let answer = my_crate::add_one(arg); - /// /// - /// /// assert_eq!(6, answer); - /// /// ``` - /// pub fn add_one(x: i32) -> i32 { - /// x + 1 - /// } - /// ``` + /// [rustdoc book]: ../../../rustdoc/lints.html#missing_doc_code_examples pub MISSING_DOC_CODE_EXAMPLES, Allow, "detects publicly-exported items without code samples in their documentation" @@ -1952,31 +1861,10 @@ declare_lint! { declare_lint! { /// The `private_doc_tests` lint detects code samples in docs of private - /// items not documented by `rustdoc`. This is a `rustdoc` only lint. - /// - /// ### Example - /// - /// ```rust,rustdoc - /// #![deny(private_doc_tests)] + /// items not documented by `rustdoc`. This is a `rustdoc` only lint, see + /// the documentation in the [rustdoc book]. /// - /// mod foo { - /// /// private doc test - /// /// - /// /// ``` - /// /// assert!(false); - /// /// ``` - /// fn bar() {} - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// Because documentation examples link against the public API of the - /// crate, it is not possible for an example to access a private item. - /// This means it was likely a mistake to add a code example to a private - /// item. + /// [rustdoc book]: ../../../rustdoc/lints.html#private_doc_tests pub PRIVATE_DOC_TESTS, Allow, "detects code samples in docs of private items not documented by rustdoc" diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index be5182b939dde..98a0119e4df12 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -756,7 +756,6 @@ impl Step for RustcBook { // The tool runs `rustc` for extracting output examples, so it needs a // functional sysroot. builder.ensure(compile::Std { compiler: self.compiler, target: self.target }); - let rustdoc = builder.rustdoc(self.compiler); let mut cmd = builder.tool_cmd(Tool::LintDocs); cmd.arg("--src"); cmd.arg(builder.src.join("compiler")); @@ -764,8 +763,6 @@ impl Step for RustcBook { cmd.arg(&out_listing); cmd.arg("--rustc"); cmd.arg(rustc); - cmd.arg("--rustdoc"); - cmd.arg(rustdoc); if builder.config.verbose() { cmd.arg("--verbose"); } diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md index 8e2869fef553e..ce292c60460cc 100644 --- a/src/doc/rustdoc/src/lints.md +++ b/src/doc/rustdoc/src/lints.md @@ -49,6 +49,30 @@ warning: missing documentation for a function | ^^^^^^^^^^^^^^^^^^^^^ ``` +## missing_crate_level_docs + +This lint is **allowed by default**. It detects if there is no documentation +at the crate root. For example: + +```rust +#![warn(missing_crate_level_docs)] +``` + +This will generate the following warning: + +```text +warning: no documentation found for this crate's top-level module + | + = help: The following guide may be of use: + https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html +``` + +This is currently "allow" by default, but it is intended to make this a +warning in the future. This is intended as a means to introduce new users on +*how* to document their crate by pointing them to some instructions on how to +get started, without providing overwhelming warnings like `missing_docs` +might. + ## missing_doc_code_examples This lint is **allowed by default** and is **nightly-only**. It detects when a documentation block @@ -117,3 +141,37 @@ warning: Documentation test in private item 8 | | /// ``` | |___________^ ``` + +## invalid_codeblock_attributes + +This lint **warns by default**. It detects code block attributes in +documentation examples that have potentially mis-typed values. For example: + +```rust +/// Example. +/// +/// ```should-panic +/// assert_eq!(1, 2); +/// ``` +pub fn foo() {} +``` + +Which will give: + +```text +warning: unknown attribute `should-panic`. Did you mean `should_panic`? + --> src/lib.rs:1:1 + | +1 | / /// Example. +2 | | /// +3 | | /// ```should-panic +4 | | /// assert_eq!(1, 2); +5 | | /// ``` + | |_______^ + | + = note: `#[warn(invalid_codeblock_attributes)]` on by default + = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running +``` + +In the example above, the correct form is `should_panic`. This helps detect +typo mistakes for some common attributes. diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index b1e14ea6c466b..a8e3278fc667e 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -15,6 +15,12 @@ struct Lint { lineno: usize, } +impl Lint { + fn doc_contains(&self, text: &str) -> bool { + self.doc.iter().any(|line| line.contains(text)) + } +} + #[derive(Clone, Copy, PartialEq)] enum Level { Allow, @@ -37,12 +43,11 @@ pub fn extract_lint_docs( src_path: &Path, out_path: &Path, rustc_path: &Path, - rustdoc_path: &Path, verbose: bool, ) -> Result<(), Box> { let mut lints = gather_lints(src_path)?; for lint in &mut lints { - generate_output_example(lint, rustc_path, rustdoc_path, verbose).map_err(|e| { + generate_output_example(lint, rustc_path, verbose).map_err(|e| { format!( "failed to test example in lint docs for `{}` in {}:{}: {}", lint.name, @@ -197,7 +202,6 @@ fn lint_name(line: &str) -> Result { fn generate_output_example( lint: &mut Lint, rustc_path: &Path, - rustdoc_path: &Path, verbose: bool, ) -> Result<(), Box> { // Explicit list of lints that are allowed to not have an example. Please @@ -214,15 +218,19 @@ fn generate_output_example( ) { return Ok(()); } + if lint.doc_contains("[rustdoc book]") && !lint.doc_contains("{{produces}}") { + // Rustdoc lints are documented in the rustdoc book, don't check these. + return Ok(()); + } check_style(lint)?; - replace_produces(lint, rustc_path, rustdoc_path, verbose)?; + replace_produces(lint, rustc_path, verbose)?; Ok(()) } /// Checks the doc style of the lint. fn check_style(lint: &Lint) -> Result<(), Box> { for expected in &["### Example", "### Explanation", "{{produces}}"] { - if !lint.doc.iter().any(|line| line.contains(expected)) { + if !lint.doc_contains(expected) { return Err(format!("lint docs should contain the line `{}`", expected).into()); } } @@ -243,7 +251,6 @@ fn check_style(lint: &Lint) -> Result<(), Box> { fn replace_produces( lint: &mut Lint, rustc_path: &Path, - rustdoc_path: &Path, verbose: bool, ) -> Result<(), Box> { let mut lines = lint.doc.iter_mut(); @@ -283,14 +290,8 @@ fn replace_produces( match lines.next() { Some(line) if line.is_empty() => {} Some(line) if line == "{{produces}}" => { - let output = generate_lint_output( - &lint.name, - &example, - &options, - rustc_path, - rustdoc_path, - verbose, - )?; + let output = + generate_lint_output(&lint.name, &example, &options, rustc_path, verbose)?; line.replace_range( .., &format!( @@ -318,7 +319,6 @@ fn generate_lint_output( example: &[&mut String], options: &[&str], rustc_path: &Path, - rustdoc_path: &Path, verbose: bool, ) -> Result> { if verbose { @@ -327,8 +327,7 @@ fn generate_lint_output( let tempdir = tempfile::TempDir::new()?; let tempfile = tempdir.path().join("lint_example.rs"); let mut source = String::new(); - let is_rustdoc = options.contains(&"rustdoc"); - let needs_main = !example.iter().any(|line| line.contains("fn main")) && !is_rustdoc; + let needs_main = !example.iter().any(|line| line.contains("fn main")); // Remove `# ` prefix for hidden lines. let unhidden = example.iter().map(|line| if line.starts_with("# ") { &line[2..] } else { line }); @@ -354,8 +353,7 @@ fn generate_lint_output( } fs::write(&tempfile, source) .map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?; - let program = if is_rustdoc { rustdoc_path } else { rustc_path }; - let mut cmd = Command::new(program); + let mut cmd = Command::new(rustc_path); if options.contains(&"edition2015") { cmd.arg("--edition=2015"); } else { diff --git a/src/tools/lint-docs/src/main.rs b/src/tools/lint-docs/src/main.rs index 4b824596b4673..45d97bd431791 100644 --- a/src/tools/lint-docs/src/main.rs +++ b/src/tools/lint-docs/src/main.rs @@ -13,7 +13,6 @@ fn doit() -> Result<(), Box> { let mut src_path = None; let mut out_path = None; let mut rustc_path = None; - let mut rustdoc_path = None; let mut verbose = false; while let Some(arg) = args.next() { match arg.as_str() { @@ -35,12 +34,6 @@ fn doit() -> Result<(), Box> { None => return Err("--rustc requires a value".into()), }; } - "--rustdoc" => { - rustdoc_path = match args.next() { - Some(s) => Some(PathBuf::from(s)), - None => return Err("--rustdoc requires a value".into()), - }; - } "-v" | "--verbose" => verbose = true, s => return Err(format!("unexpected argument `{}`", s).into()), } @@ -54,14 +47,10 @@ fn doit() -> Result<(), Box> { if rustc_path.is_none() { return Err("--rustc must be specified to the path of rustc".into()); } - if rustdoc_path.is_none() { - return Err("--rustdoc must be specified to the path of rustdoc".into()); - } lint_docs::extract_lint_docs( &src_path.unwrap(), &out_path.unwrap(), &rustc_path.unwrap(), - &rustdoc_path.unwrap(), verbose, ) } From c04973585df518edaa3bce547fe00793fa34d360 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 13 Sep 2020 08:47:24 -0700 Subject: [PATCH 0369/1052] Support `ignore` for lint examples. --- compiler/rustc_session/src/lint.rs | 6 +++-- compiler/rustc_session/src/lint/builtin.rs | 20 ++++++++++++--- src/tools/lint-docs/src/lib.rs | 29 +++++++++++++++------- 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_session/src/lint.rs b/compiler/rustc_session/src/lint.rs index 4a3e59f18e5c0..62e021d5e45bd 100644 --- a/compiler/rustc_session/src/lint.rs +++ b/compiler/rustc_session/src/lint.rs @@ -319,8 +319,10 @@ impl LintBuffer { /// /// The `{{produces}}` tag will be automatically replaced with the output from /// the example by the build system. You can build and view the rustc book -/// with `x.py doc --stage=1 src/doc/rustc --open` (use --stage=0 if just -/// changing the wording of an existing lint). +/// with `x.py doc --stage=1 src/doc/rustc --open`. If the lint example is too +/// complex to run as a simple example (for example, it needs an extern +/// crate), mark it with `ignore` and manually paste the expected output below +/// the example. #[macro_export] macro_rules! declare_lint { ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr) => ( diff --git a/compiler/rustc_session/src/lint/builtin.rs b/compiler/rustc_session/src/lint/builtin.rs index 22030a842dbb8..935e910c1e2c5 100644 --- a/compiler/rustc_session/src/lint/builtin.rs +++ b/compiler/rustc_session/src/lint/builtin.rs @@ -128,7 +128,7 @@ declare_lint! { /// /// ### Example /// - /// ```rust,compile_fail + /// ```rust,ignore (needs separate file) /// fn main() { /// include!("foo.txt"); /// } @@ -344,7 +344,7 @@ declare_lint! { /// /// ### Example /// - /// ```rust,compile_fail + /// ```rust,ignore (needs extern crate) /// #![deny(unused_crate_dependencies)] /// ``` /// @@ -1984,7 +1984,7 @@ declare_lint! { /// /// ### Example /// - /// ```rust,compile_fail + /// ```rust,ignore (needs extern crate) /// #![deny(macro_use_extern_crate)] /// /// #[macro_use] @@ -2378,7 +2378,19 @@ declare_lint! { /// } /// ``` /// - /// {{produces}} + /// This will produce: + /// + /// ```text + /// warning: formatting may not be suitable for sub-register argument + /// --> src/main.rs:6:19 + /// | + /// 6 | asm!("mov {0}, {0}", in(reg) 0i16); + /// | ^^^ ^^^ ---- for this argument + /// | + /// = note: `#[warn(asm_sub_register)]` on by default + /// = help: use the `x` modifier to have the register formatted as `ax` + /// = help: or use the `r` modifier to keep the default formatting of `rax` + /// ``` /// /// ### Explanation /// diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index a8e3278fc667e..5323bc357c09d 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -19,6 +19,13 @@ impl Lint { fn doc_contains(&self, text: &str) -> bool { self.doc.iter().any(|line| line.contains(text)) } + + fn is_ignored(&self) -> bool { + self.doc + .iter() + .filter(|line| line.starts_with("```rust")) + .all(|line| line.contains(",ignore")) + } } #[derive(Clone, Copy, PartialEq)] @@ -208,13 +215,8 @@ fn generate_output_example( // try to avoid adding to this list. if matches!( lint.name.as_str(), - "unused_features" - | "unstable_features" - | "incomplete_include" - | "unused_crate_dependencies" - | "exported_private_dependencies" - | "proc_macro_derive_resolution_fallback" - | "macro_use_extern_crate" + "unused_features" // broken lint + | "unstable_features" // deprecated ) { return Ok(()); } @@ -223,13 +225,22 @@ fn generate_output_example( return Ok(()); } check_style(lint)?; - replace_produces(lint, rustc_path, verbose)?; + // Unfortunately some lints have extra requirements that this simple test + // setup can't handle (like extern crates). An alternative is to use a + // separate test suite, and use an include mechanism such as mdbook's + // `{{#rustdoc_include}}`. + if !lint.is_ignored() { + replace_produces(lint, rustc_path, verbose)?; + } Ok(()) } /// Checks the doc style of the lint. fn check_style(lint: &Lint) -> Result<(), Box> { - for expected in &["### Example", "### Explanation", "{{produces}}"] { + for &expected in &["### Example", "### Explanation", "{{produces}}"] { + if expected == "{{produces}}" && lint.is_ignored() { + continue; + } if !lint.doc_contains(expected) { return Err(format!("lint docs should contain the line `{}`", expected).into()); } From 5dfe015ba51238e686945d8ce19caf7dee8bc78c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 13 Sep 2020 18:15:19 +0200 Subject: [PATCH 0370/1052] rebase fallout --- src/test/ui/union/union-move.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/union/union-move.stderr b/src/test/ui/union/union-move.stderr index 4a29f3a77f3c9..5679192b64194 100644 --- a/src/test/ui/union/union-move.stderr +++ b/src/test/ui/union/union-move.stderr @@ -27,7 +27,7 @@ LL | move_out(x.f1_nocopy); | ^^^^^^^^^^^ | | | cannot move out of here - | move occurs because `x.f1_nocopy` has type `std::cell::RefCell`, which does not implement the `Copy` trait + | move occurs because `x.f1_nocopy` has type `RefCell`, which does not implement the `Copy` trait error: aborting due to 3 previous errors From 9914c3beed0f4a829e78eafb36bac39d418b71f5 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 13 Sep 2020 18:34:27 +0200 Subject: [PATCH 0371/1052] Supress unused_macros error on architectures with no atomics. --- library/core/src/sync/atomic.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 920a82f5af481..9d74f537491b1 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -1150,6 +1150,7 @@ impl From<*mut T> for AtomicPtr { } } +#[allow(unused_macros)] // This macro ends up being unused on some architectures. macro_rules! if_not_8_bit { (u8, $($tt:tt)*) => { "" }; (i8, $($tt:tt)*) => { "" }; From 71a5c464d15c9e839cebc8f7a46e88fbb762fdc4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 13 Sep 2020 18:55:08 +0200 Subject: [PATCH 0372/1052] note that test_stable_pointers does not reflect a stable guarantee --- library/alloc/tests/vec.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 53b0d0a271844..5f7a9399453ea 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -1511,6 +1511,9 @@ fn test_stable_pointers() { // Test that, if we reserved enough space, adding and removing elements does not // invalidate references into the vector (such as `v0`). This test also // runs in Miri, which would detect such problems. + // Note that this test does *not* constitute a stable guarantee that all these functions do not + // reallocate! Only what is explicitly documented at + // is stably guaranteed. let mut v = Vec::with_capacity(128); v.push(13); From 49a61f59dfe14166742771025acee8b375717e09 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 13 Sep 2020 11:13:59 -0700 Subject: [PATCH 0373/1052] Make const_evaluatable_unchecked lint example not depend on the architecture pointer size. --- compiler/rustc_session/src/lint/builtin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_session/src/lint/builtin.rs b/compiler/rustc_session/src/lint/builtin.rs index 935e910c1e2c5..562df176b14a7 100644 --- a/compiler/rustc_session/src/lint/builtin.rs +++ b/compiler/rustc_session/src/lint/builtin.rs @@ -2525,7 +2525,7 @@ declare_lint! { /// ```rust /// const fn foo() -> usize { /// if std::mem::size_of::<*mut T>() < 8 { // size of *mut T does not depend on T - /// std::mem::size_of::() + /// 4 /// } else { /// 8 /// } From b7ce5b44dd2e0fa8d6f7131a246ecad77328921e Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Sun, 13 Sep 2020 22:06:06 +0200 Subject: [PATCH 0374/1052] remove orphaned files Should been part of https://github.com/rust-lang/rust/pull/74163 --- .../dist-x86_64-linux/build-git.sh | 15 ------------- .../dist-x86_64-linux/build-headers.sh | 16 -------------- .../dist-x86_64-linux/build-perl.sh | 21 ------------------- 3 files changed, 52 deletions(-) delete mode 100755 src/ci/docker/host-x86_64/dist-x86_64-linux/build-git.sh delete mode 100755 src/ci/docker/host-x86_64/dist-x86_64-linux/build-headers.sh delete mode 100755 src/ci/docker/host-x86_64/dist-x86_64-linux/build-perl.sh diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-git.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-git.sh deleted file mode 100755 index 38fea2a8094b9..0000000000000 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-git.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash - -set -ex -source shared.sh - -curl -L https://www.kernel.org/pub/software/scm/git/git-2.10.0.tar.gz | tar xzf - - -cd git-2.10.0 -make configure -hide_output ./configure --prefix=/rustroot -hide_output make -j10 -hide_output make install - -cd .. -rm -rf git-2.10.0 diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-headers.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-headers.sh deleted file mode 100755 index b623e53583b5e..0000000000000 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-headers.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash - -set -ex -source shared.sh - -curl https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.2.84.tar.xz | unxz | tar x - -cd linux-3.2.84 -hide_output make mrproper -hide_output make INSTALL_HDR_PATH=dest headers_install - -find dest/include \( -name .install -o -name ..install.cmd \) -delete -yes | cp -fr dest/include/* /usr/include - -cd .. -rm -rf linux-3.2.84 diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-perl.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-perl.sh deleted file mode 100755 index a678d353d52f5..0000000000000 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-perl.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash - -set -ex -source shared.sh - -curl https://www.cpan.org/src/5.0/perl-5.28.0.tar.gz | \ - tar xzf - - -cd perl-5.28.0 - -# Gotta do some hackery to tell python about our custom OpenSSL build, but other -# than that fairly normal. -CC=gcc \ -CFLAGS='-I /rustroot/include -fgnu89-inline' \ -LDFLAGS='-L /rustroot/lib -L /rustroot/lib64' \ - hide_output ./configure.gnu -hide_output make -j10 -hide_output make install - -cd .. -rm -rf perl-5.28.0 From 245f69ad3c16c1f7355c3901e131fa01b588bf36 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 13 Sep 2020 16:48:51 -0400 Subject: [PATCH 0375/1052] Refactor `resolve_link` into a separate function --- .../passes/collect_intra_doc_links.rs | 667 +++++++++--------- 1 file changed, 342 insertions(+), 325 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 5780610c86210..fd461925335cf 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -843,7 +843,6 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { self.mod_ids.push(item.def_id); } - let cx = self.cx; let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new); trace!("got documentation '{}'", dox); @@ -885,376 +884,394 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { }); for (ori_link, link_range) in markdown_links(&dox) { - trace!("considering link '{}'", ori_link); + self.resolve_link( + &mut item, + &dox, + ¤t_item, + parent_node, + &parent_name, + ori_link, + link_range, + ); + } - // Bail early for real links. - if ori_link.contains('/') { - continue; + if item.is_mod() && !item.attrs.inner_docs { + self.mod_ids.push(item.def_id); + } + + if item.is_mod() { + let ret = self.fold_item_recur(item); + + self.mod_ids.pop(); + + ret + } else { + self.fold_item_recur(item) + } + } +} + +impl LinkCollector<'_, '_> { + fn resolve_link( + &self, + item: &mut Item, + dox: &str, + current_item: &Option, + parent_node: Option, + parent_name: &Option, + ori_link: String, + link_range: Option>, + ) { + trace!("considering link '{}'", ori_link); + + // Bail early for real links. + if ori_link.contains('/') { + return; + } + + // [] is mostly likely not supposed to be a link + if ori_link.is_empty() { + return; + } + + let cx = self.cx; + let link = ori_link.replace("`", ""); + let parts = link.split('#').collect::>(); + let (link, extra_fragment) = if parts.len() > 2 { + anchor_failure(cx, &item, &link, dox, link_range, AnchorFailure::MultipleAnchors); + return; + } else if parts.len() == 2 { + if parts[0].trim().is_empty() { + // This is an anchor to an element of the current page, nothing to do in here! + return; + } + (parts[0], Some(parts[1].to_owned())) + } else { + (parts[0], None) + }; + let resolved_self; + let link_text; + let mut path_str; + let disambiguator; + let (mut res, mut fragment) = { + path_str = if let Ok((d, path)) = Disambiguator::from_str(&link) { + disambiguator = Some(d); + path + } else { + disambiguator = None; + &link } + .trim(); - // [] is mostly likely not supposed to be a link - if ori_link.is_empty() { - continue; + if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ch == ':' || ch == '_')) { + return; } - let link = ori_link.replace("`", ""); - let parts = link.split('#').collect::>(); - let (link, extra_fragment) = if parts.len() > 2 { - anchor_failure(cx, &item, &link, &dox, link_range, AnchorFailure::MultipleAnchors); - continue; - } else if parts.len() == 2 { - if parts[0].trim().is_empty() { - // This is an anchor to an element of the current page, nothing to do in here! - continue; - } - (parts[0], Some(parts[1].to_owned())) + // We stripped `()` and `!` when parsing the disambiguator. + // Add them back to be displayed, but not prefix disambiguators. + link_text = disambiguator + .map(|d| d.display_for(path_str)) + .unwrap_or_else(|| path_str.to_owned()); + + // In order to correctly resolve intra-doc-links we need to + // pick a base AST node to work from. If the documentation for + // this module came from an inner comment (//!) then we anchor + // our name resolution *inside* the module. If, on the other + // hand it was an outer comment (///) then we anchor the name + // resolution in the parent module on the basis that the names + // used are more likely to be intended to be parent names. For + // this, we set base_node to None for inner comments since + // we've already pushed this node onto the resolution stack but + // for outer comments we explicitly try and resolve against the + // parent_node first. + let base_node = if item.is_mod() && item.attrs.inner_docs { + self.mod_ids.last().copied() } else { - (parts[0], None) + parent_node }; - let resolved_self; - let link_text; - let mut path_str; - let disambiguator; - let (mut res, mut fragment) = { - path_str = if let Ok((d, path)) = Disambiguator::from_str(&link) { - disambiguator = Some(d); - path - } else { - disambiguator = None; - &link - } - .trim(); - if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ch == ':' || ch == '_')) { - continue; - } - - // We stripped `()` and `!` when parsing the disambiguator. - // Add them back to be displayed, but not prefix disambiguators. - link_text = disambiguator - .map(|d| d.display_for(path_str)) - .unwrap_or_else(|| path_str.to_owned()); - - // In order to correctly resolve intra-doc-links we need to - // pick a base AST node to work from. If the documentation for - // this module came from an inner comment (//!) then we anchor - // our name resolution *inside* the module. If, on the other - // hand it was an outer comment (///) then we anchor the name - // resolution in the parent module on the basis that the names - // used are more likely to be intended to be parent names. For - // this, we set base_node to None for inner comments since - // we've already pushed this node onto the resolution stack but - // for outer comments we explicitly try and resolve against the - // parent_node first. - let base_node = if item.is_mod() && item.attrs.inner_docs { - self.mod_ids.last().copied() - } else { - parent_node - }; - - // replace `Self` with suitable item's parent name - if path_str.starts_with("Self::") { - if let Some(ref name) = parent_name { - resolved_self = format!("{}::{}", name, &path_str[6..]); - path_str = &resolved_self; - } + // replace `Self` with suitable item's parent name + if path_str.starts_with("Self::") { + if let Some(ref name) = parent_name { + resolved_self = format!("{}::{}", name, &path_str[6..]); + path_str = &resolved_self; } + } - match disambiguator.map(Disambiguator::ns) { - Some(ns @ (ValueNS | TypeNS)) => { - match self.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment) - { - Ok(res) => res, - Err(ErrorKind::Resolve(box mut kind)) => { - // We only looked in one namespace. Try to give a better error if possible. - if kind.full_res().is_none() { - let other_ns = if ns == ValueNS { TypeNS } else { ValueNS }; - for &new_ns in &[other_ns, MacroNS] { - if let Some(res) = self.check_full_res( - new_ns, - path_str, - base_node, - ¤t_item, - &extra_fragment, - ) { - kind = ResolutionFailure::WrongNamespace(res, ns); - break; - } + match disambiguator.map(Disambiguator::ns) { + Some(ns @ (ValueNS | TypeNS)) => { + match self.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment) { + Ok(res) => res, + Err(ErrorKind::Resolve(box mut kind)) => { + // We only looked in one namespace. Try to give a better error if possible. + if kind.full_res().is_none() { + let other_ns = if ns == ValueNS { TypeNS } else { ValueNS }; + for &new_ns in &[other_ns, MacroNS] { + if let Some(res) = self.check_full_res( + new_ns, + path_str, + base_node, + ¤t_item, + &extra_fragment, + ) { + kind = ResolutionFailure::WrongNamespace(res, ns); + break; } } - resolution_failure( - self, - &item, - path_str, - disambiguator, - &dox, - link_range, - smallvec![kind], - ); - // This could just be a normal link or a broken link - // we could potentially check if something is - // "intra-doc-link-like" and warn in that case. - continue; - } - Err(ErrorKind::AnchorFailure(msg)) => { - anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); - continue; - } - } - } - None => { - // Try everything! - let mut candidates = PerNS { - macro_ns: self - .macro_resolve(path_str, base_node) - .map(|res| (res, extra_fragment.clone())), - type_ns: match self.resolve( - path_str, - TypeNS, - ¤t_item, - base_node, - &extra_fragment, - ) { - Ok(res) => { - debug!("got res in TypeNS: {:?}", res); - Ok(res) - } - Err(ErrorKind::AnchorFailure(msg)) => { - anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); - continue; - } - Err(ErrorKind::Resolve(box kind)) => Err(kind), - }, - value_ns: match self.resolve( - path_str, - ValueNS, - ¤t_item, - base_node, - &extra_fragment, - ) { - Ok(res) => Ok(res), - Err(ErrorKind::AnchorFailure(msg)) => { - anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); - continue; - } - Err(ErrorKind::Resolve(box kind)) => Err(kind), } - .and_then(|(res, fragment)| { - // Constructors are picked up in the type namespace. - match res { - Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) => { - Err(ResolutionFailure::WrongNamespace(res, TypeNS)) - } - _ => match (fragment, extra_fragment) { - (Some(fragment), Some(_)) => { - // Shouldn't happen but who knows? - Ok((res, Some(fragment))) - } - (fragment, None) | (None, fragment) => Ok((res, fragment)), - }, - } - }), - }; - - let len = candidates.iter().filter(|res| res.is_ok()).count(); - - if len == 0 { resolution_failure( self, &item, path_str, disambiguator, - &dox, + dox, link_range, - candidates.into_iter().filter_map(|res| res.err()).collect(), + smallvec![kind], ); - // this could just be a normal link - continue; + // This could just be a normal link or a broken link + // we could potentially check if something is + // "intra-doc-link-like" and warn in that case. + return; } - - if len == 1 { - candidates.into_iter().filter_map(|res| res.ok()).next().unwrap() - } else if len == 2 && is_derive_trait_collision(&candidates) { - candidates.type_ns.unwrap() - } else { - if is_derive_trait_collision(&candidates) { - candidates.macro_ns = Err(ResolutionFailure::Dummy); - } - // If we're reporting an ambiguity, don't mention the namespaces that failed - let candidates = - candidates.map(|candidate| candidate.ok().map(|(res, _)| res)); - ambiguity_error( - cx, - &item, - path_str, - &dox, - link_range, - candidates.present_items().collect(), - ); - continue; + Err(ErrorKind::AnchorFailure(msg)) => { + anchor_failure(cx, &item, &ori_link, dox, link_range, msg); + return; } } - Some(MacroNS) => { - match self.macro_resolve(path_str, base_node) { - Ok(res) => (res, extra_fragment), - Err(mut kind) => { - // `macro_resolve` only looks in the macro namespace. Try to give a better error if possible. - for &ns in &[TypeNS, ValueNS] { - if let Some(res) = self.check_full_res( - ns, - path_str, - base_node, - ¤t_item, - &extra_fragment, - ) { - kind = ResolutionFailure::WrongNamespace(res, MacroNS); - break; - } + } + None => { + // Try everything! + let mut candidates = PerNS { + macro_ns: self + .macro_resolve(path_str, base_node) + .map(|res| (res, extra_fragment.clone())), + type_ns: match self.resolve( + path_str, + TypeNS, + ¤t_item, + base_node, + &extra_fragment, + ) { + Ok(res) => { + debug!("got res in TypeNS: {:?}", res); + Ok(res) + } + Err(ErrorKind::AnchorFailure(msg)) => { + anchor_failure(cx, &item, &ori_link, dox, link_range, msg); + return; + } + Err(ErrorKind::Resolve(box kind)) => Err(kind), + }, + value_ns: match self.resolve( + path_str, + ValueNS, + ¤t_item, + base_node, + &extra_fragment, + ) { + Ok(res) => Ok(res), + Err(ErrorKind::AnchorFailure(msg)) => { + anchor_failure(cx, &item, &ori_link, dox, link_range, msg); + return; + } + Err(ErrorKind::Resolve(box kind)) => Err(kind), + } + .and_then(|(res, fragment)| { + // Constructors are picked up in the type namespace. + match res { + Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) => { + Err(ResolutionFailure::WrongNamespace(res, TypeNS)) } - resolution_failure( - self, - &item, - path_str, - disambiguator, - &dox, - link_range, - smallvec![kind], - ); - continue; + _ => match (fragment, extra_fragment) { + (Some(fragment), Some(_)) => { + // Shouldn't happen but who knows? + Ok((res, Some(fragment))) + } + (fragment, None) | (None, fragment) => Ok((res, fragment)), + }, } + }), + }; + + let len = candidates.iter().filter(|res| res.is_ok()).count(); + + if len == 0 { + resolution_failure( + self, + &item, + path_str, + disambiguator, + dox, + link_range, + candidates.into_iter().filter_map(|res| res.err()).collect(), + ); + // this could just be a normal link + return; + } + + if len == 1 { + candidates.into_iter().filter_map(|res| res.ok()).next().unwrap() + } else if len == 2 && is_derive_trait_collision(&candidates) { + candidates.type_ns.unwrap() + } else { + if is_derive_trait_collision(&candidates) { + candidates.macro_ns = Err(ResolutionFailure::Dummy); } + // If we're reporting an ambiguity, don't mention the namespaces that failed + let candidates = + candidates.map(|candidate| candidate.ok().map(|(res, _)| res)); + ambiguity_error( + cx, + &item, + path_str, + dox, + link_range, + candidates.present_items().collect(), + ); + return; } } - }; - - // Check for a primitive which might conflict with a module - // Report the ambiguity and require that the user specify which one they meant. - // FIXME: could there ever be a primitive not in the type namespace? - if matches!( - disambiguator, - None | Some(Disambiguator::Namespace(Namespace::TypeNS) | Disambiguator::Primitive) - ) && !matches!(res, Res::PrimTy(_)) - { - if let Some((path, prim)) = is_primitive(path_str, TypeNS) { - // `prim@char` - if matches!(disambiguator, Some(Disambiguator::Primitive)) { - if fragment.is_some() { - anchor_failure( - cx, + Some(MacroNS) => { + match self.macro_resolve(path_str, base_node) { + Ok(res) => (res, extra_fragment), + Err(mut kind) => { + // `macro_resolve` only looks in the macro namespace. Try to give a better error if possible. + for &ns in &[TypeNS, ValueNS] { + if let Some(res) = self.check_full_res( + ns, + path_str, + base_node, + ¤t_item, + &extra_fragment, + ) { + kind = ResolutionFailure::WrongNamespace(res, MacroNS); + break; + } + } + resolution_failure( + self, &item, path_str, - &dox, + disambiguator, + dox, link_range, - AnchorFailure::RustdocAnchorConflict(prim), + smallvec![kind], ); - continue; + return; } - res = prim; - fragment = Some(path.to_owned()); - } else { - // `[char]` when a `char` module is in scope - let candidates = vec![res, prim]; - ambiguity_error(cx, &item, path_str, &dox, link_range, candidates); - continue; } } } + }; - let report_mismatch = |specified: Disambiguator, resolved: Disambiguator| { - // The resolved item did not match the disambiguator; give a better error than 'not found' - let msg = format!("incompatible link kind for `{}`", path_str); - report_diagnostic(cx, &msg, &item, &dox, &link_range, |diag, sp| { - let note = format!( - "this link resolved to {} {}, which is not {} {}", - resolved.article(), - resolved.descr(), - specified.article(), - specified.descr() - ); - diag.note(¬e); - suggest_disambiguator(resolved, diag, path_str, &dox, sp, &link_range); - }); - }; - if let Res::PrimTy(_) = res { - match disambiguator { - Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => { - item.attrs.links.push(ItemLink { - link: ori_link, - link_text: path_str.to_owned(), - did: None, - fragment, - }); - } - Some(other) => { - report_mismatch(other, Disambiguator::Primitive); - continue; - } - } - } else { - debug!("intra-doc link to {} resolved to {:?}", path_str, res); - - // Disallow e.g. linking to enums with `struct@` - if let Res::Def(kind, _) = res { - debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator); - match (self.kind_side_channel.take().map(|(kind, _)| kind).unwrap_or(kind), disambiguator) { - | (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const))) - // NOTE: this allows 'method' to mean both normal functions and associated functions - // This can't cause ambiguity because both are in the same namespace. - | (DefKind::Fn | DefKind::AssocFn, Some(Disambiguator::Kind(DefKind::Fn))) - // These are namespaces; allow anything in the namespace to match - | (_, Some(Disambiguator::Namespace(_))) - // If no disambiguator given, allow anything - | (_, None) - // All of these are valid, so do nothing - => {} - (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {} - (_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => { - report_mismatch(specified, Disambiguator::Kind(kind)); - continue; - } + // Check for a primitive which might conflict with a module + // Report the ambiguity and require that the user specify which one they meant. + // FIXME: could there ever be a primitive not in the type namespace? + if matches!( + disambiguator, + None | Some(Disambiguator::Namespace(Namespace::TypeNS) | Disambiguator::Primitive) + ) && !matches!(res, Res::PrimTy(_)) + { + if let Some((path, prim)) = is_primitive(path_str, TypeNS) { + // `prim@char` + if matches!(disambiguator, Some(Disambiguator::Primitive)) { + if fragment.is_some() { + anchor_failure( + cx, + &item, + path_str, + dox, + link_range, + AnchorFailure::RustdocAnchorConflict(prim), + ); + return; } + res = prim; + fragment = Some(path.to_owned()); + } else { + // `[char]` when a `char` module is in scope + let candidates = vec![res, prim]; + ambiguity_error(cx, &item, path_str, dox, link_range, candidates); + return; } + } + } - // item can be non-local e.g. when using #[doc(primitive = "pointer")] - if let Some((src_id, dst_id)) = res - .opt_def_id() - .and_then(|def_id| def_id.as_local()) - .and_then(|dst_id| item.def_id.as_local().map(|src_id| (src_id, dst_id))) - { - use rustc_hir::def_id::LOCAL_CRATE; - - let hir_src = self.cx.tcx.hir().local_def_id_to_hir_id(src_id); - let hir_dst = self.cx.tcx.hir().local_def_id_to_hir_id(dst_id); - - if self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_src) - && !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_dst) - { - privacy_error(cx, &item, &path_str, &dox, link_range); - continue; + let report_mismatch = |specified: Disambiguator, resolved: Disambiguator| { + // The resolved item did not match the disambiguator; give a better error than 'not found' + let msg = format!("incompatible link kind for `{}`", path_str); + report_diagnostic(cx, &msg, &item, dox, &link_range, |diag, sp| { + let note = format!( + "this link resolved to {} {}, which is not {} {}", + resolved.article(), + resolved.descr(), + specified.article(), + specified.descr() + ); + diag.note(¬e); + suggest_disambiguator(resolved, diag, path_str, dox, sp, &link_range); + }); + }; + if let Res::PrimTy(_) = res { + match disambiguator { + Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => { + item.attrs.links.push(ItemLink { + link: ori_link, + link_text: path_str.to_owned(), + did: None, + fragment, + }); + } + Some(other) => { + report_mismatch(other, Disambiguator::Primitive); + return; + } + } + } else { + debug!("intra-doc link to {} resolved to {:?}", path_str, res); + + // Disallow e.g. linking to enums with `struct@` + if let Res::Def(kind, _) = res { + debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator); + match (self.kind_side_channel.take().map(|(kind, _)| kind).unwrap_or(kind), disambiguator) { + | (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const))) + // NOTE: this allows 'method' to mean both normal functions and associated functions + // This can't cause ambiguity because both are in the same namespace. + | (DefKind::Fn | DefKind::AssocFn, Some(Disambiguator::Kind(DefKind::Fn))) + // These are namespaces; allow anything in the namespace to match + | (_, Some(Disambiguator::Namespace(_))) + // If no disambiguator given, allow anything + | (_, None) + // All of these are valid, so do nothing + => {} + (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {} + (_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => { + report_mismatch(specified, Disambiguator::Kind(kind)); + return; } } - let id = register_res(cx, res); - item.attrs.links.push(ItemLink { - link: ori_link, - link_text, - did: Some(id), - fragment, - }); } - } - - if item.is_mod() && !item.attrs.inner_docs { - self.mod_ids.push(item.def_id); - } - if item.is_mod() { - let ret = self.fold_item_recur(item); + // item can be non-local e.g. when using #[doc(primitive = "pointer")] + if let Some((src_id, dst_id)) = res + .opt_def_id() + .and_then(|def_id| def_id.as_local()) + .and_then(|dst_id| item.def_id.as_local().map(|src_id| (src_id, dst_id))) + { + use rustc_hir::def_id::LOCAL_CRATE; - self.mod_ids.pop(); + let hir_src = self.cx.tcx.hir().local_def_id_to_hir_id(src_id); + let hir_dst = self.cx.tcx.hir().local_def_id_to_hir_id(dst_id); - ret - } else { - self.fold_item_recur(item) + if self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_src) + && !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_dst) + { + privacy_error(cx, &item, &path_str, dox, link_range); + return; + } + } + let id = register_res(cx, res); + item.attrs.links.push(ItemLink { link: ori_link, link_text, did: Some(id), fragment }); } } } From e5b82a56c5a9dd5c40f2abe8ee5398fc8acdd4b4 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 1 Sep 2020 14:30:16 +0200 Subject: [PATCH 0376/1052] allow concrete self types in consts --- compiler/rustc_hir/src/def.rs | 9 +++++- compiler/rustc_passes/src/dead.rs | 2 +- compiler/rustc_resolve/src/diagnostics.rs | 2 +- compiler/rustc_resolve/src/late.rs | 7 +++-- compiler/rustc_resolve/src/lib.rs | 29 +++++++++++++------ compiler/rustc_typeck/src/astconv/mod.rs | 18 ++++++++++-- src/librustdoc/clean/utils.rs | 2 +- .../min_const_generics/self-ty-in-const-1.rs | 27 +++++++++++++++++ .../self-ty-in-const-1.stderr | 24 +++++++++++++++ .../min_const_generics/self-ty-in-const-2.rs | 21 ++++++++++++++ .../self-ty-in-const-2.stderr | 18 ++++++++++++ 11 files changed, 141 insertions(+), 18 deletions(-) create mode 100644 src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.rs create mode 100644 src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr create mode 100644 src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.rs create mode 100644 src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index b019e518d0c54..730059e7eceb5 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -199,7 +199,14 @@ pub enum Res { // Type namespace PrimTy(hir::PrimTy), - SelfTy(Option /* trait */, Option /* impl */), + /// `Self`, with both an optional trait and impl `DefId`. + /// + /// HACK: impl self types also have an optional requirement to not mention + /// any generic parameters to allow the following with `min_const_generics`. + /// `impl Foo { fn test() -> [u8; std::mem::size_of::()]`. + /// + /// Once `lazy_normalization_consts` is stable, this bodge can be removed again. + SelfTy(Option /* trait */, Option<(DefId, bool)> /* impl */), ToolMod, // e.g., `rustfmt` in `#[rustfmt::skip]` // Value namespace diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index c79542342ba78..fe6653e98da89 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -104,7 +104,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { if let Some(t) = t { self.check_def_id(t); } - if let Some(i) = i { + if let Some((i, _)) = i { self.check_def_id(i); } } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 7a0503d68f348..b80da64149150 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -112,7 +112,7 @@ impl<'a> Resolver<'a> { match outer_res { Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => { if let Some(impl_span) = - maybe_impl_defid.and_then(|def_id| self.opt_span(def_id)) + maybe_impl_defid.and_then(|(def_id, _)| self.opt_span(def_id)) { err.span_label( reduce_impl_span_to_impl_keyword(sm, impl_span), diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 07f36c7b7ad36..6788df9be7820 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -110,6 +110,9 @@ crate enum RibKind<'a> { ItemRibKind(HasGenericParams), /// We're in a constant item. Can't refer to dynamic stuff. + /// + /// The `bool` indicates if this constant may reference generic parameters + /// and is used to only allow generic parameters to be used in trivial constant expressions. ConstantItemRibKind(bool), /// We passed through a module. @@ -848,7 +851,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_current_self_item(item, |this| { this.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { let item_def_id = this.r.local_def_id(item.id).to_def_id(); - this.with_self_rib(Res::SelfTy(None, Some(item_def_id)), |this| { + this.with_self_rib(Res::SelfTy(None, Some((item_def_id, false))), |this| { visit::walk_item(this, item); }); }); @@ -1215,7 +1218,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Resolve the trait reference, if necessary. this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| { let item_def_id = this.r.local_def_id(item_id).to_def_id(); - this.with_self_rib(Res::SelfTy(trait_id, Some(item_def_id)), |this| { + this.with_self_rib(Res::SelfTy(trait_id, Some((item_def_id, false))), |this| { if let Some(trait_ref) = opt_trait_reference.as_ref() { // Resolve type arguments in the trait path. visit::walk_trait_ref(this, trait_ref); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 0f5b9b518163f..1922f0d566e97 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -2539,7 +2539,7 @@ impl<'a> Resolver<'a> { &mut self, rib_index: usize, rib_ident: Ident, - res: Res, + mut res: Res, record_used: bool, span: Span, all_ribs: &[Rib<'a>], @@ -2627,15 +2627,26 @@ impl<'a> Resolver<'a> { continue; } ConstantItemRibKind(trivial) => { - // HACK(min_const_generics): We currently only allow `N` or `{ N }`. - if !trivial && self.session.features_untracked().min_const_generics { - if record_used { - self.report_error( - span, - ResolutionError::ParamInNonTrivialAnonConst(rib_ident.name), - ); + if self.session.features_untracked().min_const_generics { + // HACK(min_const_generics): We currently only allow `N` or `{ N }`. + if !trivial { + // HACK(min_const_generics): If we encounter `Self` in an anonymous constant + // we can't easily tell if it's generic at this stage, so we instead remember + // this and then enforce the self type to be concrete later on. + if let Res::SelfTy(trait_def, Some((impl_def, _))) = res { + res = Res::SelfTy(trait_def, Some((impl_def, true))); + } else { + if record_used { + self.report_error( + span, + ResolutionError::ParamInNonTrivialAnonConst( + rib_ident.name, + ), + ); + } + return Res::Err; + } } - return Res::Err; } if in_ty_param_default { diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 9e339b1082cb8..66d9d49d93fac 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -1460,7 +1460,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Find the type of the associated item, and the trait where the associated // item is declared. let bound = match (&qself_ty.kind(), qself_res) { - (_, Res::SelfTy(Some(_), Some(impl_def_id))) => { + (_, Res::SelfTy(Some(_), Some((impl_def_id, _)))) => { // `Self` in an impl of a trait -- we have a concrete self type and a // trait reference. let trait_ref = match tcx.impl_trait_ref(impl_def_id) { @@ -1917,12 +1917,24 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.prohibit_generics(path.segments); tcx.types.self_param } - Res::SelfTy(_, Some(def_id)) => { + Res::SelfTy(_, Some((def_id, forbid_generic))) => { // `Self` in impl (we know the concrete type). assert_eq!(opt_self_ty, None); self.prohibit_generics(path.segments); // Try to evaluate any array length constants. - self.normalize_ty(span, tcx.at(span).type_of(def_id)) + let normalized_ty = self.normalize_ty(span, tcx.at(span).type_of(def_id)); + if forbid_generic && normalized_ty.needs_subst() { + tcx.sess + .struct_span_err( + path.span, + "generic `Self` types are currently not permitted in anonymous constants" + ) + .span_note(tcx.def_span(def_id), "not a concrete type") + .emit(); + tcx.ty_error() + } else { + normalized_ty + } } Res::Def(DefKind::AssocTy, def_id) => { debug_assert!(path.segments.len() >= 2); diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index c577b771d6094..58b76d24a5bdb 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -601,7 +601,7 @@ pub fn register_res(cx: &DocContext<'_>, res: Res) -> DefId { }, Res::Def(DefKind::TraitAlias, i) => (i, TypeKind::TraitAlias), Res::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait), - Res::SelfTy(_, Some(impl_def_id)) => return impl_def_id, + Res::SelfTy(_, Some((impl_def_id, _))) => return impl_def_id, _ => return res.def_id(), }; if did.is_local() { diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.rs b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.rs new file mode 100644 index 0000000000000..0973b373c122c --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.rs @@ -0,0 +1,27 @@ +#![feature(min_const_generics)] + +trait Foo { + fn t1() -> [u8; std::mem::size_of::()]; //~ERROR generic parameters +} + +struct Bar(T); + +impl Bar { + fn t2() -> [u8; std::mem::size_of::()] { todo!() } // ok +} + +impl Bar { + fn t3() -> [u8; std::mem::size_of::()] {} //~ERROR generic `Self` +} + +trait Baz { + fn hey(); +} + +impl Baz for u16 { + fn hey() { + let _: [u8; std::mem::size_of::()]; // ok + } +} + +fn main() {} diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr new file mode 100644 index 0000000000000..94f67735fca44 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr @@ -0,0 +1,24 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/self-ty-in-const-1.rs:4:41 + | +LL | fn t1() -> [u8; std::mem::size_of::()]; + | ^^^^ non-trivial anonymous constants must not depend on the parameter `Self` + | + = help: it is currently only allowed to use either `Self` or `{ Self }` as generic constants + +error: generic `Self` types are currently not permitted in anonymous constants + --> $DIR/self-ty-in-const-1.rs:14:41 + | +LL | fn t3() -> [u8; std::mem::size_of::()] {} + | ^^^^ + | +note: not a concrete type + --> $DIR/self-ty-in-const-1.rs:13:1 + | +LL | / impl Bar { +LL | | fn t3() -> [u8; std::mem::size_of::()] {} +LL | | } + | |_^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.rs b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.rs new file mode 100644 index 0000000000000..e7f80d50082b3 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.rs @@ -0,0 +1,21 @@ +#![feature(min_const_generics)] + +struct Bar(T); + +trait Baz { + fn hey(); +} + +impl Baz for u16 { + fn hey() { + let _: [u8; std::mem::size_of::()]; // ok + } +} + +impl Baz for Bar { + fn hey() { + let _: [u8; std::mem::size_of::()]; //~ERROR generic `Self` + } +} + +fn main() {} diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr new file mode 100644 index 0000000000000..70f44e7de6337 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr @@ -0,0 +1,18 @@ +error: generic `Self` types are currently not permitted in anonymous constants + --> $DIR/self-ty-in-const-2.rs:17:41 + | +LL | let _: [u8; std::mem::size_of::()]; + | ^^^^ + | +note: not a concrete type + --> $DIR/self-ty-in-const-2.rs:15:1 + | +LL | / impl Baz for Bar { +LL | | fn hey() { +LL | | let _: [u8; std::mem::size_of::()]; +LL | | } +LL | | } + | |_^ + +error: aborting due to previous error + From c552717e9da86f70d49390bba1e4b305054d9ed4 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 8 Sep 2020 11:37:27 +0200 Subject: [PATCH 0377/1052] review, improve note span --- compiler/rustc_hir/src/def.rs | 10 +++--- compiler/rustc_resolve/src/lib.rs | 34 +++++++++---------- compiler/rustc_typeck/src/astconv/mod.rs | 19 +++++++---- .../self-ty-in-const-1.stderr | 8 ++--- .../self-ty-in-const-2.stderr | 10 ++---- 5 files changed, 40 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 730059e7eceb5..96fde48d96cc1 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -201,11 +201,13 @@ pub enum Res { PrimTy(hir::PrimTy), /// `Self`, with both an optional trait and impl `DefId`. /// - /// HACK: impl self types also have an optional requirement to not mention - /// any generic parameters to allow the following with `min_const_generics`. - /// `impl Foo { fn test() -> [u8; std::mem::size_of::()]`. + /// HACK(min_const_generics): impl self types also have an optional requirement to not mention + /// any generic parameters to allow the following with `min_const_generics`: + /// ```rust + /// impl Foo { fn test() -> [u8; std::mem::size_of::()] {} } + /// ``` /// - /// Once `lazy_normalization_consts` is stable, this bodge can be removed again. + /// FIXME(lazy_normalization_consts): Remove this bodge once this feature is stable. SelfTy(Option /* trait */, Option<(DefId, bool)> /* impl */), ToolMod, // e.g., `rustfmt` in `#[rustfmt::skip]` diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 1922f0d566e97..00a37d908cd07 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -2627,25 +2627,23 @@ impl<'a> Resolver<'a> { continue; } ConstantItemRibKind(trivial) => { - if self.session.features_untracked().min_const_generics { - // HACK(min_const_generics): We currently only allow `N` or `{ N }`. - if !trivial { - // HACK(min_const_generics): If we encounter `Self` in an anonymous constant - // we can't easily tell if it's generic at this stage, so we instead remember - // this and then enforce the self type to be concrete later on. - if let Res::SelfTy(trait_def, Some((impl_def, _))) = res { - res = Res::SelfTy(trait_def, Some((impl_def, true))); - } else { - if record_used { - self.report_error( - span, - ResolutionError::ParamInNonTrivialAnonConst( - rib_ident.name, - ), - ); - } - return Res::Err; + // HACK(min_const_generics): We currently only allow `N` or `{ N }`. + if !trivial && self.session.features_untracked().min_const_generics { + // HACK(min_const_generics): If we encounter `Self` in an anonymous constant + // we can't easily tell if it's generic at this stage, so we instead remember + // this and then enforce the self type to be concrete later on. + if let Res::SelfTy(trait_def, Some((impl_def, _))) = res { + res = Res::SelfTy(trait_def, Some((impl_def, true))); + } else { + if record_used { + self.report_error( + span, + ResolutionError::ParamInNonTrivialAnonConst( + rib_ident.name, + ), + ); } + return Res::Err; } } diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 66d9d49d93fac..a743dc1cd2086 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -1924,13 +1924,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Try to evaluate any array length constants. let normalized_ty = self.normalize_ty(span, tcx.at(span).type_of(def_id)); if forbid_generic && normalized_ty.needs_subst() { - tcx.sess - .struct_span_err( - path.span, - "generic `Self` types are currently not permitted in anonymous constants" - ) - .span_note(tcx.def_span(def_id), "not a concrete type") - .emit(); + let mut err = tcx.sess.struct_span_err( + path.span, + "generic `Self` types are currently not permitted in anonymous constants", + ); + if let Some(hir::Node::Item(&hir::Item { + kind: hir::ItemKind::Impl { self_ty, .. }, + .. + })) = tcx.hir().get_if_local(def_id) + { + err.span_note(self_ty.span, "not a concrete type"); + } + err.emit(); tcx.ty_error() } else { normalized_ty diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr index 94f67735fca44..89ce58564e465 100644 --- a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr +++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr @@ -13,12 +13,10 @@ LL | fn t3() -> [u8; std::mem::size_of::()] {} | ^^^^ | note: not a concrete type - --> $DIR/self-ty-in-const-1.rs:13:1 + --> $DIR/self-ty-in-const-1.rs:13:9 | -LL | / impl Bar { -LL | | fn t3() -> [u8; std::mem::size_of::()] {} -LL | | } - | |_^ +LL | impl Bar { + | ^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr index 70f44e7de6337..9ac6410a290a5 100644 --- a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr +++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr @@ -5,14 +5,10 @@ LL | let _: [u8; std::mem::size_of::()]; | ^^^^ | note: not a concrete type - --> $DIR/self-ty-in-const-2.rs:15:1 + --> $DIR/self-ty-in-const-2.rs:15:17 | -LL | / impl Baz for Bar { -LL | | fn hey() { -LL | | let _: [u8; std::mem::size_of::()]; -LL | | } -LL | | } - | |_^ +LL | impl Baz for Bar { + | ^^^^^^ error: aborting due to previous error From 90dd798cf53320b3478119d06d2d8c47880c9247 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 13 Sep 2020 23:02:43 +0200 Subject: [PATCH 0378/1052] bless tests --- .../ui/const-generics/issues/issue-62504.min.stderr | 10 +++++++--- src/test/ui/const-generics/issues/issue-62504.rs | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/test/ui/const-generics/issues/issue-62504.min.stderr b/src/test/ui/const-generics/issues/issue-62504.min.stderr index 752df17aad614..8f794312834b2 100644 --- a/src/test/ui/const-generics/issues/issue-62504.min.stderr +++ b/src/test/ui/const-generics/issues/issue-62504.min.stderr @@ -1,10 +1,14 @@ -error: generic parameters must not be used inside of non trivial constant values +error: generic `Self` types are currently not permitted in anonymous constants --> $DIR/issue-62504.rs:19:25 | LL | ArrayHolder([0; Self::SIZE]) - | ^^^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `Self` + | ^^^^^^^^^^ | - = help: it is currently only allowed to use either `Self` or `{ Self }` as generic constants +note: not a concrete type + --> $DIR/issue-62504.rs:17:22 + | +LL | impl ArrayHolder { + | ^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-62504.rs b/src/test/ui/const-generics/issues/issue-62504.rs index b520dbe4e803b..015f170f00d1c 100644 --- a/src/test/ui/const-generics/issues/issue-62504.rs +++ b/src/test/ui/const-generics/issues/issue-62504.rs @@ -18,7 +18,7 @@ impl ArrayHolder { pub const fn new() -> Self { ArrayHolder([0; Self::SIZE]) //[full]~^ ERROR constant expression depends on a generic parameter - //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values + //[min]~^^ ERROR generic `Self` types are currently } } From 7dc0d335bcc819c770320635a055c9cfe076339a Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 13 Sep 2020 17:04:44 -0400 Subject: [PATCH 0379/1052] Refactor `resolve_with_disambiguator` into a separate function --- .../passes/collect_intra_doc_links.rs | 353 ++++++++++-------- 1 file changed, 190 insertions(+), 163 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index fd461925335cf..253a2a4b850e1 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -998,169 +998,19 @@ impl LinkCollector<'_, '_> { } } - match disambiguator.map(Disambiguator::ns) { - Some(ns @ (ValueNS | TypeNS)) => { - match self.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment) { - Ok(res) => res, - Err(ErrorKind::Resolve(box mut kind)) => { - // We only looked in one namespace. Try to give a better error if possible. - if kind.full_res().is_none() { - let other_ns = if ns == ValueNS { TypeNS } else { ValueNS }; - for &new_ns in &[other_ns, MacroNS] { - if let Some(res) = self.check_full_res( - new_ns, - path_str, - base_node, - ¤t_item, - &extra_fragment, - ) { - kind = ResolutionFailure::WrongNamespace(res, ns); - break; - } - } - } - resolution_failure( - self, - &item, - path_str, - disambiguator, - dox, - link_range, - smallvec![kind], - ); - // This could just be a normal link or a broken link - // we could potentially check if something is - // "intra-doc-link-like" and warn in that case. - return; - } - Err(ErrorKind::AnchorFailure(msg)) => { - anchor_failure(cx, &item, &ori_link, dox, link_range, msg); - return; - } - } - } - None => { - // Try everything! - let mut candidates = PerNS { - macro_ns: self - .macro_resolve(path_str, base_node) - .map(|res| (res, extra_fragment.clone())), - type_ns: match self.resolve( - path_str, - TypeNS, - ¤t_item, - base_node, - &extra_fragment, - ) { - Ok(res) => { - debug!("got res in TypeNS: {:?}", res); - Ok(res) - } - Err(ErrorKind::AnchorFailure(msg)) => { - anchor_failure(cx, &item, &ori_link, dox, link_range, msg); - return; - } - Err(ErrorKind::Resolve(box kind)) => Err(kind), - }, - value_ns: match self.resolve( - path_str, - ValueNS, - ¤t_item, - base_node, - &extra_fragment, - ) { - Ok(res) => Ok(res), - Err(ErrorKind::AnchorFailure(msg)) => { - anchor_failure(cx, &item, &ori_link, dox, link_range, msg); - return; - } - Err(ErrorKind::Resolve(box kind)) => Err(kind), - } - .and_then(|(res, fragment)| { - // Constructors are picked up in the type namespace. - match res { - Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) => { - Err(ResolutionFailure::WrongNamespace(res, TypeNS)) - } - _ => match (fragment, extra_fragment) { - (Some(fragment), Some(_)) => { - // Shouldn't happen but who knows? - Ok((res, Some(fragment))) - } - (fragment, None) | (None, fragment) => Ok((res, fragment)), - }, - } - }), - }; - - let len = candidates.iter().filter(|res| res.is_ok()).count(); - - if len == 0 { - resolution_failure( - self, - &item, - path_str, - disambiguator, - dox, - link_range, - candidates.into_iter().filter_map(|res| res.err()).collect(), - ); - // this could just be a normal link - return; - } - - if len == 1 { - candidates.into_iter().filter_map(|res| res.ok()).next().unwrap() - } else if len == 2 && is_derive_trait_collision(&candidates) { - candidates.type_ns.unwrap() - } else { - if is_derive_trait_collision(&candidates) { - candidates.macro_ns = Err(ResolutionFailure::Dummy); - } - // If we're reporting an ambiguity, don't mention the namespaces that failed - let candidates = - candidates.map(|candidate| candidate.ok().map(|(res, _)| res)); - ambiguity_error( - cx, - &item, - path_str, - dox, - link_range, - candidates.present_items().collect(), - ); - return; - } - } - Some(MacroNS) => { - match self.macro_resolve(path_str, base_node) { - Ok(res) => (res, extra_fragment), - Err(mut kind) => { - // `macro_resolve` only looks in the macro namespace. Try to give a better error if possible. - for &ns in &[TypeNS, ValueNS] { - if let Some(res) = self.check_full_res( - ns, - path_str, - base_node, - ¤t_item, - &extra_fragment, - ) { - kind = ResolutionFailure::WrongNamespace(res, MacroNS); - break; - } - } - resolution_failure( - self, - &item, - path_str, - disambiguator, - dox, - link_range, - smallvec![kind], - ); - return; - } - } - } + match self.resolve_with_disambiguator( + disambiguator, + item, + dox, + path_str, + current_item, + base_node, + extra_fragment, + &ori_link, + link_range.clone(), + ) { + Some(x) => x, + None => return, } }; @@ -1274,6 +1124,183 @@ impl LinkCollector<'_, '_> { item.attrs.links.push(ItemLink { link: ori_link, link_text, did: Some(id), fragment }); } } + + fn resolve_with_disambiguator( + &self, + disambiguator: Option, + item: &mut Item, + dox: &str, + path_str: &str, + current_item: &Option, + base_node: Option, + extra_fragment: Option, + ori_link: &str, + link_range: Option>, + ) -> Option<(Res, Option)> { + match disambiguator.map(Disambiguator::ns) { + Some(ns @ (ValueNS | TypeNS)) => { + match self.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment) { + Ok(res) => Some(res), + Err(ErrorKind::Resolve(box mut kind)) => { + // We only looked in one namespace. Try to give a better error if possible. + if kind.full_res().is_none() { + let other_ns = if ns == ValueNS { TypeNS } else { ValueNS }; + for &new_ns in &[other_ns, MacroNS] { + if let Some(res) = self.check_full_res( + new_ns, + path_str, + base_node, + ¤t_item, + &extra_fragment, + ) { + kind = ResolutionFailure::WrongNamespace(res, ns); + break; + } + } + } + resolution_failure( + self, + &item, + path_str, + disambiguator, + dox, + link_range, + smallvec![kind], + ); + // This could just be a normal link or a broken link + // we could potentially check if something is + // "intra-doc-link-like" and warn in that case. + return None; + } + Err(ErrorKind::AnchorFailure(msg)) => { + anchor_failure(self.cx, &item, &ori_link, dox, link_range, msg); + return None; + } + } + } + None => { + // Try everything! + let mut candidates = PerNS { + macro_ns: self + .macro_resolve(path_str, base_node) + .map(|res| (res, extra_fragment.clone())), + type_ns: match self.resolve( + path_str, + TypeNS, + ¤t_item, + base_node, + &extra_fragment, + ) { + Ok(res) => { + debug!("got res in TypeNS: {:?}", res); + Ok(res) + } + Err(ErrorKind::AnchorFailure(msg)) => { + anchor_failure(self.cx, &item, ori_link, dox, link_range, msg); + return None; + } + Err(ErrorKind::Resolve(box kind)) => Err(kind), + }, + value_ns: match self.resolve( + path_str, + ValueNS, + ¤t_item, + base_node, + &extra_fragment, + ) { + Ok(res) => Ok(res), + Err(ErrorKind::AnchorFailure(msg)) => { + anchor_failure(self.cx, &item, ori_link, dox, link_range, msg); + return None; + } + Err(ErrorKind::Resolve(box kind)) => Err(kind), + } + .and_then(|(res, fragment)| { + // Constructors are picked up in the type namespace. + match res { + Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) => { + Err(ResolutionFailure::WrongNamespace(res, TypeNS)) + } + _ => match (fragment, extra_fragment) { + (Some(fragment), Some(_)) => { + // Shouldn't happen but who knows? + Ok((res, Some(fragment))) + } + (fragment, None) | (None, fragment) => Ok((res, fragment)), + }, + } + }), + }; + + let len = candidates.iter().filter(|res| res.is_ok()).count(); + + if len == 0 { + resolution_failure( + self, + &item, + path_str, + disambiguator, + dox, + link_range, + candidates.into_iter().filter_map(|res| res.err()).collect(), + ); + // this could just be a normal link + return None; + } + + if len == 1 { + Some(candidates.into_iter().filter_map(|res| res.ok()).next().unwrap()) + } else if len == 2 && is_derive_trait_collision(&candidates) { + Some(candidates.type_ns.unwrap()) + } else { + if is_derive_trait_collision(&candidates) { + candidates.macro_ns = Err(ResolutionFailure::Dummy); + } + // If we're reporting an ambiguity, don't mention the namespaces that failed + let candidates = candidates.map(|candidate| candidate.ok().map(|(res, _)| res)); + ambiguity_error( + self.cx, + &item, + path_str, + dox, + link_range, + candidates.present_items().collect(), + ); + return None; + } + } + Some(MacroNS) => { + match self.macro_resolve(path_str, base_node) { + Ok(res) => Some((res, extra_fragment)), + Err(mut kind) => { + // `macro_resolve` only looks in the macro namespace. Try to give a better error if possible. + for &ns in &[TypeNS, ValueNS] { + if let Some(res) = self.check_full_res( + ns, + path_str, + base_node, + ¤t_item, + &extra_fragment, + ) { + kind = ResolutionFailure::WrongNamespace(res, MacroNS); + break; + } + } + resolution_failure( + self, + &item, + path_str, + disambiguator, + dox, + link_range, + smallvec![kind], + ); + return None; + } + } + } + } + } } #[derive(Copy, Clone, Debug, PartialEq, Eq)] From 8a13fc494d4365e57d8f343219f0201458b68591 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 13 Sep 2020 17:15:40 -0400 Subject: [PATCH 0380/1052] Require `module_id` param to `resolve` to be non-empty Previously, `resolve` would immediately check that `module_id` was non-empty and give an error if not. This had two downsides: - It introduced `Option`s everywhere, even if the calling function knew it had a valid module, and - It checked the module on each namespace, which is unnecessary: it only needed to be checked once. This makes the caller responsible for checking the module exists, making the code a lot simpler. --- .../passes/collect_intra_doc_links.rs | 574 +++++++++--------- 1 file changed, 279 insertions(+), 295 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 253a2a4b850e1..5a9eeec4dfec3 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -217,7 +217,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { let kind = if let Some(intermediate) = self.check_full_res( TypeNS, &intermediate_path, - Some(module_id), + module_id, current_item, extra_fragment, ) { @@ -235,7 +235,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { fn macro_resolve( &self, path_str: &'a str, - parent_id: Option, + module_id: DefId, ) -> Result> { let cx = self.cx; let path = ast::Path::from_ident(Ident::from_str(path_str)); @@ -254,20 +254,15 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { if let Some(res) = resolver.all_macros().get(&Symbol::intern(path_str)) { return Some(Ok(res.map_id(|_| panic!("unexpected id")))); } - if let Some(module_id) = parent_id { - debug!("resolving {} as a macro in the module {:?}", path_str, module_id); - if let Ok((_, res)) = - resolver.resolve_str_path_error(DUMMY_SP, path_str, MacroNS, module_id) - { - // don't resolve builtins like `#[derive]` - if let Res::Def(..) = res { - let res = res.map_id(|_| panic!("unexpected node_id")); - return Some(Ok(res)); - } + debug!("resolving {} as a macro in the module {:?}", path_str, module_id); + if let Ok((_, res)) = + resolver.resolve_str_path_error(DUMMY_SP, path_str, MacroNS, module_id) + { + // don't resolve builtins like `#[derive]` + if let Res::Def(..) = res { + let res = res.map_id(|_| panic!("unexpected node_id")); + return Some(Ok(res)); } - } else { - debug!("attempting to resolve item without parent module: {}", path_str); - return Some(Err(ResolutionFailure::NoParentItem)); } None }) @@ -275,7 +270,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .unwrap_or_else(|| { let mut split = path_str.rsplitn(2, "::"); if let Some((parent, base)) = split.next().and_then(|x| Some((split.next()?, x))) { - if let Some(res) = self.check_full_res(TypeNS, parent, parent_id, &None, &None) { + if let Some(res) = self.check_full_res(TypeNS, parent, module_id, &None, &None) { return Err(if matches!(res, Res::PrimTy(_)) { ResolutionFailure::NoPrimitiveAssocItem { res, @@ -287,12 +282,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }); } } - Err(ResolutionFailure::NotInScope { - module_id: parent_id.expect("already saw `Some` when resolving as a macro"), - name: path_str.into(), - }) + Err(ResolutionFailure::NotInScope { module_id, name: path_str.into() }) }) } + /// Resolves a string as a path within a particular namespace. Also returns an optional /// URL fragment in the case of variants and methods. fn resolve<'path>( @@ -300,293 +293,271 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { path_str: &'path str, ns: Namespace, current_item: &Option, - parent_id: Option, + module_id: DefId, extra_fragment: &Option, ) -> Result<(Res, Option), ErrorKind<'path>> { let cx = self.cx; - // In case we're in a module, try to resolve the relative path. - if let Some(module_id) = parent_id { - let result = cx.enter_resolver(|resolver| { - resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id) - }); - debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns); - let result = match result { - Ok((_, Res::Err)) => Err(()), - x => x, - }; + let result = cx.enter_resolver(|resolver| { + resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id) + }); + debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns); + let result = match result { + Ok((_, Res::Err)) => Err(()), + x => x, + }; - if let Ok((_, res)) = result { - let res = res.map_id(|_| panic!("unexpected node_id")); - // In case this is a trait item, skip the - // early return and try looking for the trait. - let value = match res { - Res::Def(DefKind::AssocFn | DefKind::AssocConst, _) => true, - Res::Def(DefKind::AssocTy, _) => false, - Res::Def(DefKind::Variant, _) => { - return handle_variant(cx, res, extra_fragment); - } - // Not a trait item; just return what we found. - Res::PrimTy(..) => { - if extra_fragment.is_some() { - return Err(ErrorKind::AnchorFailure( - AnchorFailure::RustdocAnchorConflict(res), - )); - } - return Ok((res, Some(path_str.to_owned()))); - } - Res::Def(DefKind::Mod, _) => { - return Ok((res, extra_fragment.clone())); - } - _ => { - return Ok((res, extra_fragment.clone())); + if let Ok((_, res)) = result { + let res = res.map_id(|_| panic!("unexpected node_id")); + // In case this is a trait item, skip the + // early return and try looking for the trait. + let value = match res { + Res::Def(DefKind::AssocFn | DefKind::AssocConst, _) => true, + Res::Def(DefKind::AssocTy, _) => false, + Res::Def(DefKind::Variant, _) => { + return handle_variant(cx, res, extra_fragment); + } + // Not a trait item; just return what we found. + Res::PrimTy(..) => { + if extra_fragment.is_some() { + return Err(ErrorKind::AnchorFailure( + AnchorFailure::RustdocAnchorConflict(res), + )); } - }; - - if value != (ns == ValueNS) { - return Err(ResolutionFailure::WrongNamespace(res, ns).into()); + return Ok((res, Some(path_str.to_owned()))); + } + Res::Def(DefKind::Mod, _) => { + return Ok((res, extra_fragment.clone())); } - } else if let Some((path, prim)) = is_primitive(path_str, ns) { - if extra_fragment.is_some() { - return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict( - prim, - ))); + _ => { + return Ok((res, extra_fragment.clone())); } - return Ok((prim, Some(path.to_owned()))); + }; + + if value != (ns == ValueNS) { + return Err(ResolutionFailure::WrongNamespace(res, ns).into()); } + } else if let Some((path, prim)) = is_primitive(path_str, ns) { + if extra_fragment.is_some() { + return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(prim))); + } + return Ok((prim, Some(path.to_owned()))); + } - // Try looking for methods and associated items. - let mut split = path_str.rsplitn(2, "::"); - // this can be an `unwrap()` because we ensure the link is never empty - let item_name = Symbol::intern(split.next().unwrap()); - let path_root = split - .next() - .map(|f| { - if f == "self" || f == "Self" { - if let Some(name) = current_item.as_ref() { - return name.clone(); - } - } - f.to_owned() - }) - // If there's no `::`, it's not an associated item. - // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved. - .ok_or_else(|| { - debug!("found no `::`, assumming {} was correctly not in scope", item_name); - ResolutionFailure::NotInScope { module_id, name: item_name.to_string().into() } - })?; - - if let Some((path, prim)) = is_primitive(&path_root, TypeNS) { - let impls = primitive_impl(cx, &path) - .ok_or_else(|| ResolutionFailure::NoPrimitiveImpl(prim, path_root.into()))?; - for &impl_ in impls { - let link = cx - .tcx - .associated_items(impl_) - .find_by_name_and_namespace( - cx.tcx, - Ident::with_dummy_span(item_name), - ns, - impl_, - ) - .map(|item| match item.kind { - ty::AssocKind::Fn => "method", - ty::AssocKind::Const => "associatedconstant", - ty::AssocKind::Type => "associatedtype", - }) - .map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_name)))); - if let Some(link) = link { - return Ok(link); + // Try looking for methods and associated items. + let mut split = path_str.rsplitn(2, "::"); + // this can be an `unwrap()` because we ensure the link is never empty + let item_name = Symbol::intern(split.next().unwrap()); + let path_root = split + .next() + .map(|f| { + if f == "self" || f == "Self" { + if let Some(name) = current_item.as_ref() { + return name.clone(); } } - debug!( - "returning primitive error for {}::{} in {} namespace", - path, - item_name, - ns.descr() - ); - return Err(ResolutionFailure::NoPrimitiveAssocItem { - res: prim, - prim_name: path, - assoc_item: item_name, + f.to_owned() + }) + // If there's no `::`, it's not an associated item. + // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved. + .ok_or_else(|| { + debug!("found no `::`, assumming {} was correctly not in scope", item_name); + ResolutionFailure::NotInScope { module_id, name: item_name.to_string().into() } + })?; + + if let Some((path, prim)) = is_primitive(&path_root, TypeNS) { + let impls = primitive_impl(cx, &path) + .ok_or_else(|| ResolutionFailure::NoPrimitiveImpl(prim, path_root.into()))?; + for &impl_ in impls { + let link = cx + .tcx + .associated_items(impl_) + .find_by_name_and_namespace( + cx.tcx, + Ident::with_dummy_span(item_name), + ns, + impl_, + ) + .map(|item| match item.kind { + ty::AssocKind::Fn => "method", + ty::AssocKind::Const => "associatedconstant", + ty::AssocKind::Type => "associatedtype", + }) + .map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_name)))); + if let Some(link) = link { + return Ok(link); } - .into()); } + debug!( + "returning primitive error for {}::{} in {} namespace", + path, + item_name, + ns.descr() + ); + return Err(ResolutionFailure::NoPrimitiveAssocItem { + res: prim, + prim_name: path, + assoc_item: item_name, + } + .into()); + } - let ty_res = cx - .enter_resolver(|resolver| { - // only types can have associated items - resolver.resolve_str_path_error(DUMMY_SP, &path_root, TypeNS, module_id) - }) - .map(|(_, res)| res); - let ty_res = match ty_res { - Err(()) | Ok(Res::Err) => { - return if ns == Namespace::ValueNS { - self.variant_field(path_str, current_item, module_id, extra_fragment) - } else { - // See if it only broke because of the namespace. - let kind = cx.enter_resolver(|resolver| { - // NOTE: this doesn't use `check_full_res` because we explicitly want to ignore `TypeNS` (we already checked it) - for &ns in &[MacroNS, ValueNS] { - match resolver - .resolve_str_path_error(DUMMY_SP, &path_root, ns, module_id) - { - Ok((_, Res::Err)) | Err(()) => {} - Ok((_, res)) => { - let res = res.map_id(|_| panic!("unexpected node_id")); - return ResolutionFailure::CannotHaveAssociatedItems( - res, ns, - ); - } + let ty_res = cx + .enter_resolver(|resolver| { + // only types can have associated items + resolver.resolve_str_path_error(DUMMY_SP, &path_root, TypeNS, module_id) + }) + .map(|(_, res)| res); + let ty_res = match ty_res { + Err(()) | Ok(Res::Err) => { + return if ns == Namespace::ValueNS { + self.variant_field(path_str, current_item, module_id, extra_fragment) + } else { + // See if it only broke because of the namespace. + let kind = cx.enter_resolver(|resolver| { + // NOTE: this doesn't use `check_full_res` because we explicitly want to ignore `TypeNS` (we already checked it) + for &ns in &[MacroNS, ValueNS] { + match resolver + .resolve_str_path_error(DUMMY_SP, &path_root, ns, module_id) + { + Ok((_, Res::Err)) | Err(()) => {} + Ok((_, res)) => { + let res = res.map_id(|_| panic!("unexpected node_id")); + return ResolutionFailure::CannotHaveAssociatedItems(res, ns); } } - ResolutionFailure::NotInScope { module_id, name: path_root.into() } - }); - Err(kind.into()) - }; - } - Ok(res) => res, - }; - let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); - let res = match ty_res { - Res::Def( - DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::TyAlias, - did, - ) => { - debug!("looking for associated item named {} for item {:?}", item_name, did); - // Checks if item_name belongs to `impl SomeItem` - let assoc_item = cx - .tcx - .inherent_impls(did) - .iter() - .flat_map(|&imp| { - cx.tcx.associated_items(imp).find_by_name_and_namespace( - cx.tcx, - Ident::with_dummy_span(item_name), - ns, - imp, - ) - }) - .map(|item| (item.kind, item.def_id)) - // There should only ever be one associated item that matches from any inherent impl - .next() - // Check if item_name belongs to `impl SomeTrait for SomeItem` - // This gives precedence to `impl SomeItem`: - // Although having both would be ambiguous, use impl version for compat. sake. - // To handle that properly resolve() would have to support - // something like [`ambi_fn`](::ambi_fn) - .or_else(|| { - let kind = resolve_associated_trait_item( - did, module_id, item_name, ns, &self.cx, - ); - debug!("got associated item kind {:?}", kind); - kind - }); - - if let Some((kind, id)) = assoc_item { - let out = match kind { - ty::AssocKind::Fn => "method", - ty::AssocKind::Const => "associatedconstant", - ty::AssocKind::Type => "associatedtype", - }; - Some(if extra_fragment.is_some() { - Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict( - ty_res, - ))) - } else { - // HACK(jynelson): `clean` expects the type, not the associated item. - // but the disambiguator logic expects the associated item. - // Store the kind in a side channel so that only the disambiguator logic looks at it. - self.kind_side_channel.set(Some((kind.as_def_kind(), id))); - Ok((ty_res, Some(format!("{}.{}", out, item_name)))) - }) - } else if ns == Namespace::ValueNS { - debug!("looking for variants or fields named {} for {:?}", item_name, did); - match cx.tcx.type_of(did).kind() { - ty::Adt(def, _) => { - let field = if def.is_enum() { - def.all_fields().find(|item| item.ident.name == item_name) - } else { - def.non_enum_variant() - .fields - .iter() - .find(|item| item.ident.name == item_name) - }; - field.map(|item| { - if extra_fragment.is_some() { - let res = Res::Def( - if def.is_enum() { - DefKind::Variant - } else { - DefKind::Field - }, - item.did, - ); - Err(ErrorKind::AnchorFailure( - AnchorFailure::RustdocAnchorConflict(res), - )) - } else { - Ok(( - ty_res, - Some(format!( - "{}.{}", - if def.is_enum() { - "variant" - } else { - "structfield" - }, - item.ident - )), - )) - } - }) - } - _ => None, } - } else { - // We already know this isn't in ValueNS, so no need to check variant_field - return Err(ResolutionFailure::NoAssocItem(ty_res, item_name).into()); - } - } - Res::Def(DefKind::Trait, did) => cx + ResolutionFailure::NotInScope { module_id, name: path_root.into() } + }); + Err(kind.into()) + }; + } + Ok(res) => res, + }; + let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); + let res = match ty_res { + Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::TyAlias, did) => { + debug!("looking for associated item named {} for item {:?}", item_name, did); + // Checks if item_name belongs to `impl SomeItem` + let assoc_item = cx .tcx - .associated_items(did) - .find_by_name_and_namespace(cx.tcx, Ident::with_dummy_span(item_name), ns, did) - .map(|item| { - let kind = match item.kind { - ty::AssocKind::Const => "associatedconstant", - ty::AssocKind::Type => "associatedtype", - ty::AssocKind::Fn => { - if item.defaultness.has_value() { - "method" + .inherent_impls(did) + .iter() + .flat_map(|&imp| { + cx.tcx.associated_items(imp).find_by_name_and_namespace( + cx.tcx, + Ident::with_dummy_span(item_name), + ns, + imp, + ) + }) + .map(|item| (item.kind, item.def_id)) + // There should only ever be one associated item that matches from any inherent impl + .next() + // Check if item_name belongs to `impl SomeTrait for SomeItem` + // This gives precedence to `impl SomeItem`: + // Although having both would be ambiguous, use impl version for compat. sake. + // To handle that properly resolve() would have to support + // something like [`ambi_fn`](::ambi_fn) + .or_else(|| { + let kind = + resolve_associated_trait_item(did, module_id, item_name, ns, &self.cx); + debug!("got associated item kind {:?}", kind); + kind + }); + + if let Some((kind, id)) = assoc_item { + let out = match kind { + ty::AssocKind::Fn => "method", + ty::AssocKind::Const => "associatedconstant", + ty::AssocKind::Type => "associatedtype", + }; + Some(if extra_fragment.is_some() { + Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(ty_res))) + } else { + // HACK(jynelson): `clean` expects the type, not the associated item. + // but the disambiguator logic expects the associated item. + // Store the kind in a side channel so that only the disambiguator logic looks at it. + self.kind_side_channel.set(Some((kind.as_def_kind(), id))); + Ok((ty_res, Some(format!("{}.{}", out, item_name)))) + }) + } else if ns == Namespace::ValueNS { + debug!("looking for variants or fields named {} for {:?}", item_name, did); + match cx.tcx.type_of(did).kind() { + ty::Adt(def, _) => { + let field = if def.is_enum() { + def.all_fields().find(|item| item.ident.name == item_name) + } else { + def.non_enum_variant() + .fields + .iter() + .find(|item| item.ident.name == item_name) + }; + field.map(|item| { + if extra_fragment.is_some() { + let res = Res::Def( + if def.is_enum() { + DefKind::Variant + } else { + DefKind::Field + }, + item.did, + ); + Err(ErrorKind::AnchorFailure( + AnchorFailure::RustdocAnchorConflict(res), + )) } else { - "tymethod" + Ok(( + ty_res, + Some(format!( + "{}.{}", + if def.is_enum() { "variant" } else { "structfield" }, + item.ident + )), + )) } - } - }; - - if extra_fragment.is_some() { - Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict( - ty_res, - ))) - } else { - let res = Res::Def(item.kind.as_def_kind(), item.def_id); - Ok((res, Some(format!("{}.{}", kind, item_name)))) + }) } - }), - _ => None, - }; - res.unwrap_or_else(|| { - if ns == Namespace::ValueNS { - self.variant_field(path_str, current_item, module_id, extra_fragment) + _ => None, + } } else { - Err(ResolutionFailure::NoAssocItem(ty_res, item_name).into()) + // We already know this isn't in ValueNS, so no need to check variant_field + return Err(ResolutionFailure::NoAssocItem(ty_res, item_name).into()); } - }) - } else { - debug!("attempting to resolve item without parent module: {}", path_str); - Err(ResolutionFailure::NoParentItem.into()) - } + } + Res::Def(DefKind::Trait, did) => cx + .tcx + .associated_items(did) + .find_by_name_and_namespace(cx.tcx, Ident::with_dummy_span(item_name), ns, did) + .map(|item| { + let kind = match item.kind { + ty::AssocKind::Const => "associatedconstant", + ty::AssocKind::Type => "associatedtype", + ty::AssocKind::Fn => { + if item.defaultness.has_value() { + "method" + } else { + "tymethod" + } + } + }; + + if extra_fragment.is_some() { + Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(ty_res))) + } else { + let res = Res::Def(item.kind.as_def_kind(), item.def_id); + Ok((res, Some(format!("{}.{}", kind, item_name)))) + } + }), + _ => None, + }; + res.unwrap_or_else(|| { + if ns == Namespace::ValueNS { + self.variant_field(path_str, current_item, module_id, extra_fragment) + } else { + Err(ResolutionFailure::NoAssocItem(ty_res, item_name).into()) + } + }) } /// Used for reporting better errors. @@ -599,7 +570,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { &self, ns: Namespace, path_str: &str, - base_node: Option, + module_id: DefId, current_item: &Option, extra_fragment: &Option, ) -> Option { @@ -616,11 +587,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }; // cannot be used for macro namespace let check_full_res = |this: &Self, ns| { - let result = this.resolve(path_str, ns, current_item, base_node, extra_fragment); + let result = this.resolve(path_str, ns, current_item, module_id, extra_fragment); check_full_res_inner(this, result.map(|(res, _)| res)) }; let check_full_res_macro = |this: &Self| { - let result = this.macro_resolve(path_str, base_node); + let result = this.macro_resolve(path_str, module_id); check_full_res_inner(this, result.map_err(ErrorKind::from)) }; match ns { @@ -990,6 +961,23 @@ impl LinkCollector<'_, '_> { parent_node }; + let module_id = if let Some(id) = base_node { + id + } else { + debug!("attempting to resolve item without parent module: {}", path_str); + let err_kind = ResolutionFailure::NoParentItem.into(); + resolution_failure( + self, + &item, + path_str, + disambiguator, + dox, + link_range, + smallvec![err_kind], + ); + return; + }; + // replace `Self` with suitable item's parent name if path_str.starts_with("Self::") { if let Some(ref name) = parent_name { @@ -1004,7 +992,7 @@ impl LinkCollector<'_, '_> { dox, path_str, current_item, - base_node, + module_id, extra_fragment, &ori_link, link_range.clone(), @@ -1132,7 +1120,7 @@ impl LinkCollector<'_, '_> { dox: &str, path_str: &str, current_item: &Option, - base_node: Option, + base_node: DefId, extra_fragment: Option, ori_link: &str, link_range: Option>, @@ -1580,13 +1568,9 @@ fn resolution_failure( break; } }; - if let Some(res) = collector.check_full_res( - TypeNS, - ¤t, - Some(*module_id), - &None, - &None, - ) { + if let Some(res) = + collector.check_full_res(TypeNS, ¤t, *module_id, &None, &None) + { failure = ResolutionFailure::NoAssocItem(res, Symbol::intern(current)); break; } From 79aa9b15d7403ce2dc40b525a1d16e6c4ad1973c Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Sun, 13 Sep 2020 11:58:43 -0700 Subject: [PATCH 0381/1052] Optimize behavior of vec.split_off(0) (take all) Optimization improvement to `split_off()` so the performance meets the intuitively expected behavior when `at == 0`, avoiding the current behavior of copying the entire vector. The change honors documented behavior that the method leaves the original vector's "previous capacity unchanged". This improvement better supports the pattern for building and flushing a buffer of elements, such as the following: ```rust let mut vec = Vec::new(); loop { vec.push(something); if condition_is_met { process(vec.split_off(0)); } } ``` `Option` wrapping is the first alternative I thought of, but is much less obvious and more verbose: ```rust let mut capacity = 1; let mut vec: Option> = None; loop { vec.get_or_insert_with(|| Vec::with_capacity(capacity)).push(something); if condition_is_met { capacity = vec.capacity(); process(vec.take().unwrap()); } } ``` Directly applying `mem::replace()` could work, but `mem::` functions are typically a last resort, when a developer is actively seeking better performance than the standard library provides, for example. The benefit of the approach to this change is it does not change the existing API contract, but improves the peformance of `split_off(0)` for `Vec`, `String` (which delegates `split_off()` to `Vec`), and any other existing use cases. This change adds tests to validate the behavior of `split_off()` with regard to capacity, as originally documented, and confirm that behavior still holds, when `at == 0`. The change is an implementation detail, and does not require a documentation change, but documenting the new behavior as part of its API contract may benefit future users. (Let me know if I should make that documentation update.) Note, for future consideration: I think it would be helpful to introduce an additional method to `Vec` (if not also to `String`): ``` pub fn take_all(&mut self) -> Self { self.split_off(0) } ``` This would make it more clear how `Vec` supports the pattern, and make it easier to find, since the behavior is similar to other `take()` methods in the Rust standard library. --- library/alloc/src/vec.rs | 5 +++++ library/alloc/tests/string.rs | 4 ++++ library/alloc/tests/vec.rs | 14 ++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index eba7ffae22c4c..c939a7bb29533 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -1410,6 +1410,11 @@ impl Vec { assert_failed(at, self.len()); } + if at == 0 { + // the new vector can take over the original buffer and avoid the copy + return mem::replace(self, Vec::with_capacity(self.capacity())); + } + let other_len = self.len - at; let mut other = Vec::with_capacity(other_len); diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs index 6059bec8c5a3d..f7f78046d089b 100644 --- a/library/alloc/tests/string.rs +++ b/library/alloc/tests/string.rs @@ -278,17 +278,21 @@ fn test_split_off_mid_char() { #[test] fn test_split_off_ascii() { let mut ab = String::from("ABCD"); + let orig_capacity = ab.capacity(); let cd = ab.split_off(2); assert_eq!(ab, "AB"); assert_eq!(cd, "CD"); + assert_eq!(ab.capacity(), orig_capacity); } #[test] fn test_split_off_unicode() { let mut nihon = String::from("日本語"); + let orig_capacity = nihon.capacity(); let go = nihon.split_off("日本".len()); assert_eq!(nihon, "日本"); assert_eq!(go, "語"); + assert_eq!(nihon.capacity(), orig_capacity); } #[test] diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 53b0d0a271844..dd3a9f3584206 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -772,9 +772,23 @@ fn test_append() { #[test] fn test_split_off() { let mut vec = vec![1, 2, 3, 4, 5, 6]; + let orig_capacity = vec.capacity(); let vec2 = vec.split_off(4); assert_eq!(vec, [1, 2, 3, 4]); assert_eq!(vec2, [5, 6]); + assert_eq!(vec.capacity(), orig_capacity); +} + +#[test] +fn test_split_off_take_all() { + let mut vec = vec![1, 2, 3, 4, 5, 6]; + let orig_ptr = vec.as_ptr(); + let orig_capacity = vec.capacity(); + let vec2 = vec.split_off(0); + assert_eq!(vec, []); + assert_eq!(vec2, [1, 2, 3, 4, 5, 6]); + assert_eq!(vec.capacity(), orig_capacity); + assert_eq!(vec2.as_ptr(), orig_ptr); } #[test] From e4c28bf61a0631b6bf4bd9e53da53611399c1129 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 13 Sep 2020 20:15:01 -0400 Subject: [PATCH 0382/1052] Upgrade to pulldown-cmark 0.8.0 Thanks to marcusklaas' hard work in https://github.com/raphlinus/pulldown-cmark/pull/469, this fixes a lot of rustdoc bugs! - Get rid of unnecessary `RefCell` - Fix duplicate warnings for broken implicit reference link - Remove unnecessary copy of links --- Cargo.lock | 17 ++++++++-- src/librustdoc/Cargo.toml | 2 +- src/librustdoc/html/markdown.rs | 34 ++++++++++--------- .../rustdoc-ui/intra-link-double-anchor.rs | 7 ++++ .../intra-link-double-anchor.stderr | 10 ++++++ 5 files changed, 50 insertions(+), 20 deletions(-) create mode 100644 src/test/rustdoc-ui/intra-link-double-anchor.rs create mode 100644 src/test/rustdoc-ui/intra-link-double-anchor.stderr diff --git a/Cargo.lock b/Cargo.lock index b448baf425baa..acf7980a0354c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -534,7 +534,7 @@ dependencies = [ "if_chain", "itertools 0.9.0", "lazy_static", - "pulldown-cmark", + "pulldown-cmark 0.7.2", "quine-mc_cluskey", "quote", "regex-syntax", @@ -1844,7 +1844,7 @@ dependencies = [ "log", "memchr", "open", - "pulldown-cmark", + "pulldown-cmark 0.7.2", "regex", "serde", "serde_derive", @@ -2502,6 +2502,17 @@ dependencies = [ "unicase", ] +[[package]] +name = "pulldown-cmark" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8" +dependencies = [ + "bitflags", + "memchr", + "unicase", +] + [[package]] name = "punycode" version = "0.4.1" @@ -4112,7 +4123,7 @@ dependencies = [ "expect-test", "itertools 0.9.0", "minifier", - "pulldown-cmark", + "pulldown-cmark 0.8.0", "rustc-rayon", "serde", "serde_json", diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 90d2a18ea5819..a40a44fe27da3 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" path = "lib.rs" [dependencies] -pulldown-cmark = { version = "0.7", default-features = false } +pulldown-cmark = { version = "0.8", default-features = false } minifier = "0.0.33" rayon = { version = "0.3.0", package = "rustc-rayon" } serde = { version = "1.0", features = ["derive"] } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index a8c60e4a76df4..178c9b0fad38a 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -27,7 +27,6 @@ use rustc_session::lint; use rustc_span::edition::Edition; use rustc_span::Span; use std::borrow::Cow; -use std::cell::RefCell; use std::collections::VecDeque; use std::default::Default; use std::fmt::Write; @@ -39,7 +38,7 @@ use crate::doctest; use crate::html::highlight; use crate::html::toc::TocBuilder; -use pulldown_cmark::{html, CodeBlockKind, CowStr, Event, Options, Parser, Tag}; +use pulldown_cmark::{html, BrokenLink, CodeBlockKind, CowStr, Event, Options, Parser, Tag}; #[cfg(test)] mod tests; @@ -931,15 +930,17 @@ impl Markdown<'_> { if md.is_empty() { return String::new(); } - let replacer = |_: &str, s: &str| { - if let Some(link) = links.iter().find(|link| &*link.original_text == s) { - Some((link.href.clone(), link.new_text.clone())) + let mut replacer = |broken_link: BrokenLink<'_>| { + if let Some(link) = + links.iter().find(|link| &*link.original_text == broken_link.reference) + { + Some((CowStr::Borrowed(&link.href), CowStr::Borrowed(&link.new_text))) } else { None } }; - let p = Parser::new_with_broken_link_callback(md, opts(), Some(&replacer)); + let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut replacer)); let mut s = String::with_capacity(md.len() * 3 / 2); @@ -1009,9 +1010,11 @@ impl MarkdownSummaryLine<'_> { return String::new(); } - let replacer = |_: &str, s: &str| { - if let Some(link) = links.iter().find(|link| &*link.original_text == s) { - Some((link.href.clone(), link.new_text.clone())) + let mut replacer = |broken_link: BrokenLink<'_>| { + if let Some(link) = + links.iter().find(|link| &*link.original_text == broken_link.reference) + { + Some((CowStr::Borrowed(&link.href), CowStr::Borrowed(&link.new_text))) } else { None } @@ -1020,7 +1023,7 @@ impl MarkdownSummaryLine<'_> { let p = Parser::new_with_broken_link_callback( md, Options::ENABLE_STRIKETHROUGH, - Some(&replacer), + Some(&mut replacer), ); let mut s = String::new(); @@ -1067,7 +1070,7 @@ pub fn markdown_links(md: &str) -> Vec<(String, Option>)> { } let mut links = vec![]; - let shortcut_links = RefCell::new(vec![]); + let mut shortcut_links = vec![]; { let locate = |s: &str| unsafe { @@ -1084,11 +1087,11 @@ pub fn markdown_links(md: &str) -> Vec<(String, Option>)> { } }; - let push = |_: &str, s: &str| { - shortcut_links.borrow_mut().push((s.to_owned(), locate(s))); + let mut push = |link: BrokenLink<'_>| { + shortcut_links.push((link.reference.to_owned(), Some(link.span))); None }; - let p = Parser::new_with_broken_link_callback(md, opts(), Some(&push)); + let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut push)); // There's no need to thread an IdMap through to here because // the IDs generated aren't going to be emitted anywhere. @@ -1106,8 +1109,7 @@ pub fn markdown_links(md: &str) -> Vec<(String, Option>)> { } } - let mut shortcut_links = shortcut_links.into_inner(); - links.extend(shortcut_links.drain(..)); + links.append(&mut shortcut_links); links } diff --git a/src/test/rustdoc-ui/intra-link-double-anchor.rs b/src/test/rustdoc-ui/intra-link-double-anchor.rs new file mode 100644 index 0000000000000..a01211c4f32b1 --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-double-anchor.rs @@ -0,0 +1,7 @@ +// check-pass + +// regression test for #73264 +// should only give one error +/// docs [label][with#anchor#error] +//~^ WARNING multiple anchors +pub struct S; diff --git a/src/test/rustdoc-ui/intra-link-double-anchor.stderr b/src/test/rustdoc-ui/intra-link-double-anchor.stderr new file mode 100644 index 0000000000000..55636d5c2f4b5 --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-double-anchor.stderr @@ -0,0 +1,10 @@ +warning: `with#anchor#error` contains multiple anchors + --> $DIR/intra-link-double-anchor.rs:5:10 + | +LL | /// docs [label][with#anchor#error] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ contains invalid anchor + | + = note: `#[warn(broken_intra_doc_links)]` on by default + +warning: 1 warning emitted + From c9686cb31ad9dd9428825dbb3b362f5df72ab719 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sun, 26 Jul 2020 08:53:39 -0400 Subject: [PATCH 0383/1052] Introduce a PartitioningCx struct --- .../src/monomorphize/partitioning/default.rs | 32 +++++++++---------- .../src/monomorphize/partitioning/merging.rs | 15 ++++----- .../src/monomorphize/partitioning/mod.rs | 25 +++++++++------ 3 files changed, 38 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs index b48bae8378779..827d037f31988 100644 --- a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs @@ -11,6 +11,7 @@ use rustc_middle::ty::print::characteristic_def_id_of_type; use rustc_middle::ty::{self, DefIdTree, InstanceDef, TyCtxt}; use rustc_span::symbol::Symbol; +use super::PartitioningCx; use crate::monomorphize::collector::InliningMap; use crate::monomorphize::partitioning::merging; use crate::monomorphize::partitioning::{ @@ -22,35 +23,36 @@ pub struct DefaultPartitioning; impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { fn place_root_mono_items( &mut self, - tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, mono_items: &mut dyn Iterator>, ) -> PreInliningPartitioning<'tcx> { let mut roots = FxHashSet::default(); let mut codegen_units = FxHashMap::default(); - let is_incremental_build = tcx.sess.opts.incremental.is_some(); + let is_incremental_build = cx.tcx.sess.opts.incremental.is_some(); let mut internalization_candidates = FxHashSet::default(); // Determine if monomorphizations instantiated in this crate will be made // available to downstream crates. This depends on whether we are in // share-generics mode and whether the current crate can even have // downstream crates. - let export_generics = tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics(); + let export_generics = + cx.tcx.sess.opts.share_generics() && cx.tcx.local_crate_exports_generics(); - let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); + let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); let cgu_name_cache = &mut FxHashMap::default(); for mono_item in mono_items { - match mono_item.instantiation_mode(tcx) { + match mono_item.instantiation_mode(cx.tcx) { InstantiationMode::GloballyShared { .. } => {} InstantiationMode::LocalCopy => continue, } - let characteristic_def_id = characteristic_def_id_of_mono_item(tcx, mono_item); + let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item); let is_volatile = is_incremental_build && mono_item.is_generic_fn(); let codegen_unit_name = match characteristic_def_id { Some(def_id) => compute_codegen_unit_name( - tcx, + cx.tcx, cgu_name_builder, def_id, is_volatile, @@ -65,7 +67,7 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { let mut can_be_internalized = true; let (linkage, visibility) = mono_item_linkage_and_visibility( - tcx, + cx.tcx, &mono_item, &mut can_be_internalized, export_generics, @@ -97,17 +99,16 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { fn merge_codegen_units( &mut self, - tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, initial_partitioning: &mut PreInliningPartitioning<'tcx>, - target_cgu_count: usize, ) { - merging::merge_codegen_units(tcx, initial_partitioning, target_cgu_count); + merging::merge_codegen_units(cx, initial_partitioning); } fn place_inlined_mono_items( &mut self, + cx: &PartitioningCx<'_, 'tcx>, initial_partitioning: PreInliningPartitioning<'tcx>, - inlining_map: &InliningMap<'tcx>, ) -> PostInliningPartitioning<'tcx> { let mut new_partitioning = Vec::new(); let mut mono_item_placements = FxHashMap::default(); @@ -124,7 +125,7 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { // Collect all items that need to be available in this codegen unit. let mut reachable = FxHashSet::default(); for root in old_codegen_unit.items().keys() { - follow_inlining(*root, inlining_map, &mut reachable); + follow_inlining(*root, cx.inlining_map, &mut reachable); } let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name()); @@ -198,9 +199,8 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { fn internalize_symbols( &mut self, - _tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, partitioning: &mut PostInliningPartitioning<'tcx>, - inlining_map: &InliningMap<'tcx>, ) { if partitioning.codegen_units.len() == 1 { // Fast path for when there is only one codegen unit. In this case we @@ -218,7 +218,7 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { // Build a map from every monomorphization to all the monomorphizations that // reference it. let mut accessor_map: FxHashMap, Vec>> = Default::default(); - inlining_map.iter_accesses(|accessor, accessees| { + cx.inlining_map.iter_accesses(|accessor, accessees| { for accessee in accessees { accessor_map.entry(*accessee).or_default().push(accessor); } diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/merging.rs b/compiler/rustc_mir/src/monomorphize/partitioning/merging.rs index 1787e6df1b9c7..3f3aaa2f63ca3 100644 --- a/compiler/rustc_mir/src/monomorphize/partitioning/merging.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/merging.rs @@ -3,17 +3,16 @@ use std::cmp; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder}; -use rustc_middle::ty::TyCtxt; use rustc_span::symbol::{Symbol, SymbolStr}; +use super::PartitioningCx; use crate::monomorphize::partitioning::PreInliningPartitioning; pub fn merge_codegen_units<'tcx>( - tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, initial_partitioning: &mut PreInliningPartitioning<'tcx>, - target_cgu_count: usize, ) { - assert!(target_cgu_count >= 1); + assert!(cx.target_cgu_count >= 1); let codegen_units = &mut initial_partitioning.codegen_units; // Note that at this point in time the `codegen_units` here may not be in a @@ -32,7 +31,7 @@ pub fn merge_codegen_units<'tcx>( codegen_units.iter().map(|cgu| (cgu.name(), vec![cgu.name().as_str()])).collect(); // Merge the two smallest codegen units until the target size is reached. - while codegen_units.len() > target_cgu_count { + while codegen_units.len() > cx.target_cgu_count { // Sort small cgus to the back codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate())); let mut smallest = codegen_units.pop().unwrap(); @@ -56,9 +55,9 @@ pub fn merge_codegen_units<'tcx>( ); } - let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); + let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); - if tcx.sess.opts.incremental.is_some() { + if cx.tcx.sess.opts.incremental.is_some() { // If we are doing incremental compilation, we want CGU names to // reflect the path of the source level module they correspond to. // For CGUs that contain the code of multiple modules because of the @@ -82,7 +81,7 @@ pub fn merge_codegen_units<'tcx>( for cgu in codegen_units.iter_mut() { if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) { - if tcx.sess.opts.debugging_opts.human_readable_cgu_names { + if cx.tcx.sess.opts.debugging_opts.human_readable_cgu_names { cgu.set_name(Symbol::intern(&new_cgu_name)); } else { // If we don't require CGU names to be human-readable, we diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs index b45fe0ee010f9..f66fec37b25de 100644 --- a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs @@ -107,31 +107,35 @@ use rustc_span::symbol::Symbol; use crate::monomorphize::collector::InliningMap; use crate::monomorphize::collector::{self, MonoItemCollectionMode}; +pub struct PartitioningCx<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + target_cgu_count: usize, + inlining_map: &'a InliningMap<'tcx>, +} + trait Partitioner<'tcx> { fn place_root_mono_items( &mut self, - tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, mono_items: &mut dyn Iterator>, ) -> PreInliningPartitioning<'tcx>; fn merge_codegen_units( &mut self, - tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, initial_partitioning: &mut PreInliningPartitioning<'tcx>, - target_cgu_count: usize, ); fn place_inlined_mono_items( &mut self, + cx: &PartitioningCx<'_, 'tcx>, initial_partitioning: PreInliningPartitioning<'tcx>, - inlining_map: &InliningMap<'tcx>, ) -> PostInliningPartitioning<'tcx>; fn internalize_symbols( &mut self, - tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, partitioning: &mut PostInliningPartitioning<'tcx>, - inlining_map: &InliningMap<'tcx>, ); } @@ -156,12 +160,13 @@ pub fn partition<'tcx>( let _prof_timer = tcx.prof.generic_activity("cgu_partitioning"); let mut partitioner = get_partitioner(tcx); + let cx = &PartitioningCx { tcx, target_cgu_count: max_cgu_count, inlining_map }; // In the first step, we place all regular monomorphizations into their // respective 'home' codegen unit. Regular monomorphizations are all // functions and statics defined in the local crate. let mut initial_partitioning = { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots"); - partitioner.place_root_mono_items(tcx, mono_items) + partitioner.place_root_mono_items(cx, mono_items) }; initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx)); @@ -171,7 +176,7 @@ pub fn partition<'tcx>( // Merge until we have at most `max_cgu_count` codegen units. { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus"); - partitioner.merge_codegen_units(tcx, &mut initial_partitioning, max_cgu_count); + partitioner.merge_codegen_units(cx, &mut initial_partitioning); debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter()); } @@ -181,7 +186,7 @@ pub fn partition<'tcx>( // local functions the definition of which is marked with `#[inline]`. let mut post_inlining = { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_inline_items"); - partitioner.place_inlined_mono_items(initial_partitioning, inlining_map) + partitioner.place_inlined_mono_items(cx, initial_partitioning) }; post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx)); @@ -192,7 +197,7 @@ pub fn partition<'tcx>( // more freedom to optimize. if !tcx.sess.link_dead_code() { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols"); - partitioner.internalize_symbols(tcx, &mut post_inlining, inlining_map); + partitioner.internalize_symbols(cx, &mut post_inlining); } // Finally, sort by codegen unit name, so that we get deterministic results. From c100e726c10fe9d212a58a5494126409e7d0e10b Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 16 Jul 2020 23:58:23 -0700 Subject: [PATCH 0384/1052] Stabilize intra-doc links --- src/librustdoc/passes/collect_intra_doc_links.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 5780610c86210..c463cba31e9ba 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -2,7 +2,6 @@ use rustc_ast as ast; use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_expand::base::SyntaxExtensionKind; -use rustc_feature::UnstableFeatures; use rustc_hir as hir; use rustc_hir::def::{ DefKind, @@ -38,13 +37,8 @@ pub const COLLECT_INTRA_DOC_LINKS: Pass = Pass { }; pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_>) -> Crate { - if !UnstableFeatures::from_environment().is_nightly_build() { - krate - } else { - let mut coll = LinkCollector::new(cx); - - coll.fold_crate(krate) - } + let mut coll = LinkCollector::new(cx); + coll.fold_crate(krate) } enum ErrorKind<'a> { From 63d5beec43ff7721928821cd83f9790188b03276 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 17 Jul 2020 00:00:43 -0700 Subject: [PATCH 0385/1052] Move intra-doc-links documentation out of unstable section --- src/doc/rustdoc/src/SUMMARY.md | 1 + .../rustdoc/src/linking-to-items-by-name.md | 56 ++++++++++++++++++ src/doc/rustdoc/src/unstable-features.md | 57 ------------------- 3 files changed, 57 insertions(+), 57 deletions(-) create mode 100644 src/doc/rustdoc/src/linking-to-items-by-name.md diff --git a/src/doc/rustdoc/src/SUMMARY.md b/src/doc/rustdoc/src/SUMMARY.md index f982863e67b94..93454b4f9097a 100644 --- a/src/doc/rustdoc/src/SUMMARY.md +++ b/src/doc/rustdoc/src/SUMMARY.md @@ -5,6 +5,7 @@ - [Command-line arguments](command-line-arguments.md) - [The `#[doc]` attribute](the-doc-attribute.md) - [Documentation tests](documentation-tests.md) +- [Linking to items by name](linking-to-items-by-name.md) - [Lints](lints.md) - [Passes](passes.md) - [Advanced Features](advanced-features.md) diff --git a/src/doc/rustdoc/src/linking-to-items-by-name.md b/src/doc/rustdoc/src/linking-to-items-by-name.md new file mode 100644 index 0000000000000..e9d726fefd4b5 --- /dev/null +++ b/src/doc/rustdoc/src/linking-to-items-by-name.md @@ -0,0 +1,56 @@ +# Linking to items by name + +Rustdoc is capable of directly linking to other rustdoc pages in Markdown documentation using the path of item as a link. + +For example, in the following code all of the links will link to the rustdoc page for `Bar`: + +```rust +/// This struct is not [Bar] +pub struct Foo1; + +/// This struct is also not [bar](Bar) +pub struct Foo2; + +/// This struct is also not [bar][b] +/// +/// [b]: Bar +pub struct Foo3; + +/// This struct is also not [`Bar`] +pub struct Foo4; + +pub struct Bar; +``` + +You can refer to anything in scope, and use paths, including `Self`. You may also use `foo()` and `foo!()` to refer to methods/functions and macros respectively. + +```rust,edition2018 +use std::sync::mpsc::Receiver; + +/// This is an version of [`Receiver`], with support for [`std::future`]. +/// +/// You can obtain a [`std::future::Future`] by calling [`Self::recv()`]. +pub struct AsyncReceiver { + sender: Receiver +} + +impl AsyncReceiver { + pub async fn recv() -> T { + unimplemented!() + } +} +``` + +Paths in Rust have three namespaces: type, value, and macro. Items from these namespaces are allowed to overlap. In case of ambiguity, rustdoc will warn about the ambiguity and ask you to disambiguate, which can be done by using a prefix like `struct@`, `enum@`, `type@`, `trait@`, `union@`, `const@`, `static@`, `value@`, `function@`, `mod@`, `fn@`, `module@`, `method@` , `macro@`, or `derive@`: + +```rust +/// See also: [`Foo`](struct@Foo) +struct Bar; + +/// This is different from [`Foo`](fn@Foo) +struct Foo {} + +fn Foo() {} +``` + +Note: Because of how `macro_rules` macros are scoped in Rust, the intra-doc links of a `macro_rules` macro will be resolved relative to the crate root, as opposed to the module it is defined in. diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 2f49fc8a41552..c869d595d2db8 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -38,63 +38,6 @@ future. Attempting to use these error numbers on stable will result in the code sample being interpreted as plain text. -### Linking to items by name - -Rustdoc is capable of directly linking to other rustdoc pages in Markdown documentation using the path of item as a link. - -For example, in the following code all of the links will link to the rustdoc page for `Bar`: - -```rust -/// This struct is not [Bar] -pub struct Foo1; - -/// This struct is also not [bar](Bar) -pub struct Foo2; - -/// This struct is also not [bar][b] -/// -/// [b]: Bar -pub struct Foo3; - -/// This struct is also not [`Bar`] -pub struct Foo4; - -pub struct Bar; -``` - -You can refer to anything in scope, and use paths, including `Self`. You may also use `foo()` and `foo!()` to refer to methods/functions and macros respectively. - -```rust,edition2018 -use std::sync::mpsc::Receiver; - -/// This is an version of [`Receiver`], with support for [`std::future`]. -/// -/// You can obtain a [`std::future::Future`] by calling [`Self::recv()`]. -pub struct AsyncReceiver { - sender: Receiver -} - -impl AsyncReceiver { - pub async fn recv() -> T { - unimplemented!() - } -} -``` - -Paths in Rust have three namespaces: type, value, and macro. Items from these namespaces are allowed to overlap. In case of ambiguity, rustdoc will warn about the ambiguity and ask you to disambiguate, which can be done by using a prefix like `struct@`, `enum@`, `type@`, `trait@`, `union@`, `const@`, `static@`, `value@`, `function@`, `mod@`, `fn@`, `module@`, `method@`, `prim@`, `primitive@`, `macro@`, or `derive@`: - -```rust -/// See also: [`Foo`](struct@Foo) -struct Bar; - -/// This is different from [`Foo`](fn@Foo) -struct Foo {} - -fn Foo() {} -``` - -Note: Because of how `macro_rules` macros are scoped in Rust, the intra-doc links of a `macro_rules` macro will be resolved relative to the crate root, as opposed to the module it is defined in. - ## Extensions to the `#[doc]` attribute These features operate by extending the `#[doc]` attribute, and thus can be caught by the compiler From bc06674774e6457046e41a48dc3e8be8c5496f11 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 17 Jul 2020 10:49:51 -0700 Subject: [PATCH 0386/1052] Mention super/crate/self in docs --- src/doc/rustdoc/src/linking-to-items-by-name.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustdoc/src/linking-to-items-by-name.md b/src/doc/rustdoc/src/linking-to-items-by-name.md index e9d726fefd4b5..9871558fc47d8 100644 --- a/src/doc/rustdoc/src/linking-to-items-by-name.md +++ b/src/doc/rustdoc/src/linking-to-items-by-name.md @@ -22,7 +22,7 @@ pub struct Foo4; pub struct Bar; ``` -You can refer to anything in scope, and use paths, including `Self`. You may also use `foo()` and `foo!()` to refer to methods/functions and macros respectively. +You can refer to anything in scope, and use paths, including `Self`, `self`, `super`, and `crate`. You may also use `foo()` and `foo!()` to refer to methods/functions and macros respectively. ```rust,edition2018 use std::sync::mpsc::Receiver; From f072e4a7322e8e2b16410e3225e1afc15d132e36 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 17 Jul 2020 12:58:26 -0700 Subject: [PATCH 0387/1052] Mention URL fragments --- src/doc/rustdoc/src/linking-to-items-by-name.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/doc/rustdoc/src/linking-to-items-by-name.md b/src/doc/rustdoc/src/linking-to-items-by-name.md index 9871558fc47d8..99ca3433cc4f6 100644 --- a/src/doc/rustdoc/src/linking-to-items-by-name.md +++ b/src/doc/rustdoc/src/linking-to-items-by-name.md @@ -41,6 +41,15 @@ impl AsyncReceiver { } ``` +You can also link to sections using URL fragment specifiers: + +```rust +/// This is a special implementation of [positional parameters] +/// +/// [positional parameters]: std::fmt#formatting-parameters +struct MySpecialFormatter; +``` + Paths in Rust have three namespaces: type, value, and macro. Items from these namespaces are allowed to overlap. In case of ambiguity, rustdoc will warn about the ambiguity and ask you to disambiguate, which can be done by using a prefix like `struct@`, `enum@`, `type@`, `trait@`, `union@`, `const@`, `static@`, `value@`, `function@`, `mod@`, `fn@`, `module@`, `method@` , `macro@`, or `derive@`: ```rust From 2a98409634ec38547d03512898192b5bdce15f3d Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 29 Jul 2020 15:18:37 -0700 Subject: [PATCH 0388/1052] Fill out docs on intra-doc resolution failure lint --- src/doc/rustdoc/src/lints.md | 43 ++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md index 8e2869fef553e..7c47f74b3c118 100644 --- a/src/doc/rustdoc/src/lints.md +++ b/src/doc/rustdoc/src/lints.md @@ -13,18 +13,53 @@ Here is the list of the lints provided by `rustdoc`: ## broken_intra_doc_links -This lint **warns by default** and is **nightly-only**. This lint detects when -an intra-doc link fails to get resolved. For example: +This lint **warns by default**. This lint detects when an [intra-doc link] fails to get resolved. For example: + + [intra-doc link]: linking-to-items-by-name.html ```rust -/// I want to link to [`Inexistent`] but it doesn't exist! +/// I want to link to [`Nonexistent`] but it doesn't exist! pub fn foo() {} ``` You'll get a warning saying: ```text -error: `[`Inexistent`]` cannot be resolved, ignoring it... +warning: `[Nonexistent]` cannot be resolved, ignoring it. + --> test.rs:1:24 + | +1 | /// I want to link to [`Nonexistent`] but it doesn't exist! + | ^^^^^^^^^^^^^ cannot be resolved, ignoring +``` + +It will also warn when there is an ambiguity and suggest how to disambiguate: + +```rust +/// [`Foo`] +pub fn function() {} + +pub enum Foo {} + +pub fn Foo(){} +``` + +```text +warning: `Foo` is both an enum and a function + --> test.rs:1:6 + | +1 | /// [`Foo`] + | ^^^^^ ambiguous link + | + = note: `#[warn(intra_doc_link_resolution_failure)]` on by default +help: to link to the enum, prefix with the item type + | +1 | /// [`enum@Foo`] + | ^^^^^^^^^^ +help: to link to the function, add parentheses + | +1 | /// [`Foo()`] + | ^^^^^^^ + ``` ## missing_docs From 4e0eb0b73ba2defaf0f3c2152e9daa5c18d1603f Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sat, 8 Aug 2020 18:56:27 -0700 Subject: [PATCH 0389/1052] Update src/doc/rustdoc/src/linking-to-items-by-name.md Co-authored-by: Joshua Nelson --- src/doc/rustdoc/src/linking-to-items-by-name.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustdoc/src/linking-to-items-by-name.md b/src/doc/rustdoc/src/linking-to-items-by-name.md index 99ca3433cc4f6..6c0a548b4ff13 100644 --- a/src/doc/rustdoc/src/linking-to-items-by-name.md +++ b/src/doc/rustdoc/src/linking-to-items-by-name.md @@ -50,7 +50,7 @@ You can also link to sections using URL fragment specifiers: struct MySpecialFormatter; ``` -Paths in Rust have three namespaces: type, value, and macro. Items from these namespaces are allowed to overlap. In case of ambiguity, rustdoc will warn about the ambiguity and ask you to disambiguate, which can be done by using a prefix like `struct@`, `enum@`, `type@`, `trait@`, `union@`, `const@`, `static@`, `value@`, `function@`, `mod@`, `fn@`, `module@`, `method@` , `macro@`, or `derive@`: +Paths in Rust have three namespaces: type, value, and macro. Items from these namespaces are allowed to overlap. In case of ambiguity, rustdoc will warn about the ambiguity and ask you to disambiguate, which can be done by using a prefix like `struct@`, `enum@`, `type@`, `trait@`, `union@`, `const@`, `@constant`, `static@`, `value@`, `function@`, `mod@`, `fn@`, `module@`, `method@` , `macro@`, or `derive@`: ```rust /// See also: [`Foo`](struct@Foo) From 175e30539d5ee9364a26f89f8a03a60b53690684 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sat, 8 Aug 2020 18:57:14 -0700 Subject: [PATCH 0390/1052] Update src/doc/rustdoc/src/linking-to-items-by-name.md Co-authored-by: Joshua Nelson --- src/doc/rustdoc/src/linking-to-items-by-name.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustdoc/src/linking-to-items-by-name.md b/src/doc/rustdoc/src/linking-to-items-by-name.md index 6c0a548b4ff13..6e5241e8aefb7 100644 --- a/src/doc/rustdoc/src/linking-to-items-by-name.md +++ b/src/doc/rustdoc/src/linking-to-items-by-name.md @@ -22,7 +22,7 @@ pub struct Foo4; pub struct Bar; ``` -You can refer to anything in scope, and use paths, including `Self`, `self`, `super`, and `crate`. You may also use `foo()` and `foo!()` to refer to methods/functions and macros respectively. +You can refer to anything in scope, and use paths, including `Self`, `self`, `super`, and `crate`. You may also use `foo()` and `foo!()` to refer to methods/functions and macros respectively. Backticks around the link will be stripped. ```rust,edition2018 use std::sync::mpsc::Receiver; From 51c1351f7b9366a295dce5d63c2fd387170d5c34 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sun, 13 Sep 2020 18:14:34 -0700 Subject: [PATCH 0391/1052] Resolve some conflicts --- src/doc/rustdoc/src/linking-to-items-by-name.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustdoc/src/linking-to-items-by-name.md b/src/doc/rustdoc/src/linking-to-items-by-name.md index 6e5241e8aefb7..d48ba5f9d2bcc 100644 --- a/src/doc/rustdoc/src/linking-to-items-by-name.md +++ b/src/doc/rustdoc/src/linking-to-items-by-name.md @@ -50,7 +50,7 @@ You can also link to sections using URL fragment specifiers: struct MySpecialFormatter; ``` -Paths in Rust have three namespaces: type, value, and macro. Items from these namespaces are allowed to overlap. In case of ambiguity, rustdoc will warn about the ambiguity and ask you to disambiguate, which can be done by using a prefix like `struct@`, `enum@`, `type@`, `trait@`, `union@`, `const@`, `@constant`, `static@`, `value@`, `function@`, `mod@`, `fn@`, `module@`, `method@` , `macro@`, or `derive@`: +Paths in Rust have three namespaces: type, value, and macro. Items from these namespaces are allowed to overlap. In case of ambiguity, rustdoc will warn about the ambiguity and ask you to disambiguate, which can be done by using a prefix like `struct@`, `enum@`, `type@`, `trait@`, `union@`, `const@`, `static@`, `value@`, `function@`, `mod@`, `fn@`, `module@`, `method@`, `prim@`, `primitive@`, `macro@`, or `derive@`:: ```rust /// See also: [`Foo`](struct@Foo) From 6f1fa2b16376f586285453045788519df527a1b2 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sun, 13 Sep 2020 18:16:54 -0700 Subject: [PATCH 0392/1052] Fix lint name in docs --- src/doc/rustdoc/src/lints.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md index 7c47f74b3c118..89aeb683682ec 100644 --- a/src/doc/rustdoc/src/lints.md +++ b/src/doc/rustdoc/src/lints.md @@ -50,7 +50,7 @@ warning: `Foo` is both an enum and a function 1 | /// [`Foo`] | ^^^^^ ambiguous link | - = note: `#[warn(intra_doc_link_resolution_failure)]` on by default + = note: `#[warn(broken_intra_doc_links)]` on by default help: to link to the enum, prefix with the item type | 1 | /// [`enum@Foo`] From f7983cae7008b8f86d927ddcd83a0b4785307b24 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 13 Sep 2020 20:56:33 -0400 Subject: [PATCH 0393/1052] Don't use `link.span` yet This shows the span of the _whole_ link, including the brackets. But rustdoc only wants to warn about the link text. --- src/librustdoc/html/markdown.rs | 4 +++- src/test/rustdoc-ui/intra-link-double-anchor.stderr | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 178c9b0fad38a..a25d49c34955d 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1088,7 +1088,9 @@ pub fn markdown_links(md: &str) -> Vec<(String, Option>)> { }; let mut push = |link: BrokenLink<'_>| { - shortcut_links.push((link.reference.to_owned(), Some(link.span))); + // FIXME: use `link.span` instead of `locate` + // (doing it now includes the `[]` as well as the text) + shortcut_links.push((link.reference.to_owned(), locate(link.reference))); None }; let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut push)); diff --git a/src/test/rustdoc-ui/intra-link-double-anchor.stderr b/src/test/rustdoc-ui/intra-link-double-anchor.stderr index 55636d5c2f4b5..3282ec8b79379 100644 --- a/src/test/rustdoc-ui/intra-link-double-anchor.stderr +++ b/src/test/rustdoc-ui/intra-link-double-anchor.stderr @@ -1,8 +1,8 @@ warning: `with#anchor#error` contains multiple anchors - --> $DIR/intra-link-double-anchor.rs:5:10 + --> $DIR/intra-link-double-anchor.rs:5:18 | LL | /// docs [label][with#anchor#error] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ contains invalid anchor + | ^^^^^^^^^^^^^^^^^ contains invalid anchor | = note: `#[warn(broken_intra_doc_links)]` on by default From 6f2e1c65933702186cc681a3772862afa77dd632 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 13 Sep 2020 21:13:04 -0400 Subject: [PATCH 0394/1052] Use `.as_str()` instead of `CowStr::Borrowed` --- src/librustdoc/html/markdown.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index a25d49c34955d..6c0f1c02ac6da 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -934,7 +934,7 @@ impl Markdown<'_> { if let Some(link) = links.iter().find(|link| &*link.original_text == broken_link.reference) { - Some((CowStr::Borrowed(&link.href), CowStr::Borrowed(&link.new_text))) + Some((link.href.as_str().into(), link.new_text.as_str().into())) } else { None } @@ -1014,7 +1014,7 @@ impl MarkdownSummaryLine<'_> { if let Some(link) = links.iter().find(|link| &*link.original_text == broken_link.reference) { - Some((CowStr::Borrowed(&link.href), CowStr::Borrowed(&link.new_text))) + Some((link.href.as_str().into(), link.new_text.as_str().into())) } else { None } From d1f0f04a488d027fdf91e08cdf25df00fb677205 Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Mon, 14 Sep 2020 06:11:35 +0200 Subject: [PATCH 0395/1052] New lint: `manual-strip` Add a new lint, `manual-strip`, that suggests using the `str::strip_prefix` and `str::strip_suffix` methods introduced in Rust 1.45 when the same functionality is performed 'manually'. Closes #5734 --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 5 + clippy_lints/src/manual_strip.rs | 246 +++++++++++++++++++++++++++++++ clippy_lints/src/utils/paths.rs | 3 + src/lintlist/mod.rs | 7 + tests/ui/manual_strip.rs | 59 ++++++++ tests/ui/manual_strip.stderr | 132 +++++++++++++++++ 7 files changed, 453 insertions(+) create mode 100644 clippy_lints/src/manual_strip.rs create mode 100644 tests/ui/manual_strip.rs create mode 100644 tests/ui/manual_strip.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 285a2ff8060d2..a6fafdf535728 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1672,6 +1672,7 @@ Released 2018-09-13 [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic +[`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap [`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names [`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c017c5cb5d02c..38ddc69c8cbbc 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -230,6 +230,7 @@ mod macro_use; mod main_recursion; mod manual_async_fn; mod manual_non_exhaustive; +mod manual_strip; mod map_clone; mod map_identity; mod map_unit_fn; @@ -626,6 +627,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &main_recursion::MAIN_RECURSION, &manual_async_fn::MANUAL_ASYNC_FN, &manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE, + &manual_strip::MANUAL_STRIP, &map_clone::MAP_CLONE, &map_identity::MAP_IDENTITY, &map_unit_fn::OPTION_MAP_UNIT_FN, @@ -1109,6 +1111,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box self_assignment::SelfAssignment); store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs); store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync); + store.register_late_pass(|| box manual_strip::ManualStrip); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1335,6 +1338,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&main_recursion::MAIN_RECURSION), LintId::of(&manual_async_fn::MANUAL_ASYNC_FN), LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), + LintId::of(&manual_strip::MANUAL_STRIP), LintId::of(&map_clone::MAP_CLONE), LintId::of(&map_identity::MAP_IDENTITY), LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN), @@ -1626,6 +1630,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&loops::EXPLICIT_COUNTER_LOOP), LintId::of(&loops::MUT_RANGE_BOUND), LintId::of(&loops::WHILE_LET_LOOP), + LintId::of(&manual_strip::MANUAL_STRIP), LintId::of(&map_identity::MAP_IDENTITY), LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN), LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN), diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs new file mode 100644 index 0000000000000..127938aecd63c --- /dev/null +++ b/clippy_lints/src/manual_strip.rs @@ -0,0 +1,246 @@ +use crate::consts::{constant, Constant}; +use crate::utils::usage::mutated_variables; +use crate::utils::{ + eq_expr_value, higher, match_def_path, multispan_sugg, paths, qpath_res, snippet, span_lint_and_then, +}; + +use if_chain::if_chain; +use rustc_ast::ast::LitKind; +use rustc_hir::def::Res; +use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; +use rustc_hir::BinOpKind; +use rustc_hir::{BorrowKind, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::map::Map; +use rustc_middle::ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::source_map::Spanned; +use rustc_span::Span; + +declare_clippy_lint! { + /// **What it does:** + /// Suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing using + /// the pattern's length. + /// + /// **Why is this bad?** + /// Using `str:strip_{prefix,suffix}` is safer and may have better performance as there is no + /// slicing which may panic and the compiler does not need to insert this panic code. It is + /// also sometimes more readable as it removes the need for duplicating or storing the pattern + /// used by `str::{starts,ends}_with` and in the slicing. + /// + /// **Known problems:** + /// None. + /// + /// **Example:** + /// + /// ```rust + /// let s = "hello, world!"; + /// if s.starts_with("hello, ") { + /// assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); + /// } + /// ``` + /// Use instead: + /// ```rust + /// let s = "hello, world!"; + /// if let Some(end) = s.strip_prefix("hello, ") { + /// assert_eq!(end.to_uppercase(), "WORLD!"); + /// } + /// ``` + pub MANUAL_STRIP, + complexity, + "suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing" +} + +declare_lint_pass!(ManualStrip => [MANUAL_STRIP]); + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum StripKind { + Prefix, + Suffix, +} + +impl<'tcx> LateLintPass<'tcx> for ManualStrip { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if_chain! { + if let Some((cond, then, _)) = higher::if_block(&expr); + if let ExprKind::MethodCall(_, _, [target_arg, pattern], _) = cond.kind; + if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id); + if let ExprKind::Path(target_path) = &target_arg.kind; + then { + let strip_kind = if match_def_path(cx, method_def_id, &paths::STR_STARTS_WITH) { + StripKind::Prefix + } else if match_def_path(cx, method_def_id, &paths::STR_ENDS_WITH) { + StripKind::Suffix + } else { + return; + }; + let target_res = qpath_res(cx, &target_path, target_arg.hir_id); + if target_res == Res::Err { + return; + }; + + if_chain! { + if let Res::Local(hir_id) = target_res; + if let Some(used_mutably) = mutated_variables(then, cx); + if used_mutably.contains(&hir_id); + then { + return; + } + } + + let strippings = find_stripping(cx, strip_kind, target_res, pattern, then); + if !strippings.is_empty() { + + let kind_word = match strip_kind { + StripKind::Prefix => "prefix", + StripKind::Suffix => "suffix", + }; + + let test_span = expr.span.until(then.span); + span_lint_and_then(cx, MANUAL_STRIP, strippings[0], &format!("stripping a {} manually", kind_word), |diag| { + diag.span_note(test_span, &format!("the {} was tested here", kind_word)); + multispan_sugg( + diag, + &format!("try using the `strip_{}` method", kind_word), + vec![(test_span, + format!("if let Some() = {}.strip_{}({}) ", + snippet(cx, target_arg.span, ".."), + kind_word, + snippet(cx, pattern.span, "..")))] + .into_iter().chain(strippings.into_iter().map(|span| (span, "".into()))), + ) + }); + } + } + } + } +} + +// Returns `Some(arg)` if `expr` matches `arg.len()` and `None` otherwise. +fn len_arg<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { + if_chain! { + if let ExprKind::MethodCall(_, _, [arg], _) = expr.kind; + if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if match_def_path(cx, method_def_id, &paths::STR_LEN); + then { + Some(arg) + } + else { + None + } + } +} + +// Returns the length of the `expr` if it's a constant string or char. +fn constant_length(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { + let (value, _) = constant(cx, cx.typeck_results(), expr)?; + match value { + Constant::Str(value) => Some(value.len() as u128), + Constant::Char(value) => Some(value.len_utf8() as u128), + _ => None, + } +} + +// Tests if `expr` equals the length of the pattern. +fn eq_pattern_length<'tcx>(cx: &LateContext<'tcx>, pattern: &Expr<'_>, expr: &'tcx Expr<'_>) -> bool { + if let ExprKind::Lit(Spanned { + node: LitKind::Int(n, _), + .. + }) = expr.kind + { + constant_length(cx, pattern).map_or(false, |length| length == n) + } else { + len_arg(cx, expr).map_or(false, |arg| eq_expr_value(cx, pattern, arg)) + } +} + +// Tests if `expr` is a `&str`. +fn is_ref_str(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + match cx.typeck_results().expr_ty_adjusted(&expr).kind() { + ty::Ref(_, ty, _) => ty.is_str(), + _ => false, + } +} + +// Removes the outer `AddrOf` expression if needed. +fn peel_ref<'a>(expr: &'a Expr<'_>) -> &'a Expr<'a> { + if let ExprKind::AddrOf(BorrowKind::Ref, _, unref) = &expr.kind { + unref + } else { + expr + } +} + +// Find expressions where `target` is stripped using the length of `pattern`. +// We'll suggest replacing these expressions with the result of the `strip_{prefix,suffix}` +// method. +fn find_stripping<'tcx>( + cx: &LateContext<'tcx>, + strip_kind: StripKind, + target: Res, + pattern: &'tcx Expr<'_>, + expr: &'tcx Expr<'_>, +) -> Vec { + struct StrippingFinder<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + strip_kind: StripKind, + target: Res, + pattern: &'tcx Expr<'tcx>, + results: Vec, + } + + impl<'a, 'tcx> Visitor<'tcx> for StrippingFinder<'a, 'tcx> { + type Map = Map<'tcx>; + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } + + fn visit_expr(&mut self, ex: &'tcx Expr<'_>) { + if_chain! { + if is_ref_str(self.cx, ex); + let unref = peel_ref(ex); + if let ExprKind::Index(indexed, index) = &unref.kind; + if let Some(range) = higher::range(index); + if let higher::Range { start, end, .. } = range; + if let ExprKind::Path(path) = &indexed.kind; + if qpath_res(self.cx, path, ex.hir_id) == self.target; + then { + match (self.strip_kind, start, end) { + (StripKind::Prefix, Some(start), None) => { + if eq_pattern_length(self.cx, self.pattern, start) { + self.results.push(ex.span); + return; + } + }, + (StripKind::Suffix, None, Some(end)) => { + if_chain! { + if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, left, right) = end.kind; + if let Some(left_arg) = len_arg(self.cx, left); + if let ExprKind::Path(left_path) = &left_arg.kind; + if qpath_res(self.cx, left_path, left_arg.hir_id) == self.target; + if eq_pattern_length(self.cx, self.pattern, right); + then { + self.results.push(ex.span); + return; + } + } + }, + _ => {} + } + } + } + + walk_expr(self, ex); + } + } + + let mut finder = StrippingFinder { + cx, + strip_kind, + target, + pattern, + results: vec![], + }; + walk_expr(&mut finder, expr); + finder.results +} diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 65320d6a0e0bd..f0f7719e2fdf0 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -115,6 +115,9 @@ pub const STD_MEM_TRANSMUTE: [&str; 3] = ["std", "mem", "transmute"]; pub const STD_PTR_NULL: [&str; 3] = ["std", "ptr", "null"]; 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", "", "ends_with"]; +pub const STR_LEN: [&str; 4] = ["core", "str", "", "len"]; +pub const STR_STARTS_WITH: [&str; 4] = ["core", "str", "", "starts_with"]; pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"]; pub const TO_OWNED: [&str; 3] = ["alloc", "borrow", "ToOwned"]; pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"]; diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index a7d38c93433d1..8bceef80abffc 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1144,6 +1144,13 @@ pub static ref ALL_LINTS: Vec = vec![ 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", diff --git a/tests/ui/manual_strip.rs b/tests/ui/manual_strip.rs new file mode 100644 index 0000000000000..d1b4772c7deea --- /dev/null +++ b/tests/ui/manual_strip.rs @@ -0,0 +1,59 @@ +#![warn(clippy::manual_strip)] + +fn main() { + let s = "abc"; + + if s.starts_with("ab") { + str::to_string(&s["ab".len()..]); + s["ab".len()..].to_string(); + + str::to_string(&s[2..]); + s[2..].to_string(); + } + + if s.ends_with("bc") { + str::to_string(&s[..s.len() - "bc".len()]); + s[..s.len() - "bc".len()].to_string(); + + str::to_string(&s[..s.len() - 2]); + s[..s.len() - 2].to_string(); + } + + // Character patterns + if s.starts_with('a') { + str::to_string(&s[1..]); + s[1..].to_string(); + } + + // Variable prefix + let prefix = "ab"; + if s.starts_with(prefix) { + str::to_string(&s[prefix.len()..]); + } + + // Constant prefix + const PREFIX: &str = "ab"; + if s.starts_with(PREFIX) { + str::to_string(&s[PREFIX.len()..]); + str::to_string(&s[2..]); + } + + // Constant target + const TARGET: &str = "abc"; + if TARGET.starts_with(prefix) { + str::to_string(&TARGET[prefix.len()..]); + } + + // String target - not mutated. + let s1: String = "abc".into(); + if s1.starts_with("ab") { + s1[2..].to_uppercase(); + } + + // String target - mutated. (Don't lint.) + let mut s2: String = "abc".into(); + if s2.starts_with("ab") { + s2.push('d'); + s2[2..].to_uppercase(); + } +} diff --git a/tests/ui/manual_strip.stderr b/tests/ui/manual_strip.stderr new file mode 100644 index 0000000000000..1352a8713d4f8 --- /dev/null +++ b/tests/ui/manual_strip.stderr @@ -0,0 +1,132 @@ +error: stripping a prefix manually + --> $DIR/manual_strip.rs:7:24 + | +LL | str::to_string(&s["ab".len()..]); + | ^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::manual-strip` implied by `-D warnings` +note: the prefix was tested here + --> $DIR/manual_strip.rs:6:5 + | +LL | if s.starts_with("ab") { + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: try using the `strip_prefix` method + | +LL | if let Some() = s.strip_prefix("ab") { +LL | str::to_string(); +LL | .to_string(); +LL | +LL | str::to_string(); +LL | .to_string(); + | + +error: stripping a suffix manually + --> $DIR/manual_strip.rs:15:24 + | +LL | str::to_string(&s[..s.len() - "bc".len()]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the suffix was tested here + --> $DIR/manual_strip.rs:14:5 + | +LL | if s.ends_with("bc") { + | ^^^^^^^^^^^^^^^^^^^^^ +help: try using the `strip_suffix` method + | +LL | if let Some() = s.strip_suffix("bc") { +LL | str::to_string(); +LL | .to_string(); +LL | +LL | str::to_string(); +LL | .to_string(); + | + +error: stripping a prefix manually + --> $DIR/manual_strip.rs:24:24 + | +LL | str::to_string(&s[1..]); + | ^^^^^^^ + | +note: the prefix was tested here + --> $DIR/manual_strip.rs:23:5 + | +LL | if s.starts_with('a') { + | ^^^^^^^^^^^^^^^^^^^^^^ +help: try using the `strip_prefix` method + | +LL | if let Some() = s.strip_prefix('a') { +LL | str::to_string(); +LL | .to_string(); + | + +error: stripping a prefix manually + --> $DIR/manual_strip.rs:31:24 + | +LL | str::to_string(&s[prefix.len()..]); + | ^^^^^^^^^^^^^^^^^^ + | +note: the prefix was tested here + --> $DIR/manual_strip.rs:30:5 + | +LL | if s.starts_with(prefix) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: try using the `strip_prefix` method + | +LL | if let Some() = s.strip_prefix(prefix) { +LL | str::to_string(); + | + +error: stripping a prefix manually + --> $DIR/manual_strip.rs:37:24 + | +LL | str::to_string(&s[PREFIX.len()..]); + | ^^^^^^^^^^^^^^^^^^ + | +note: the prefix was tested here + --> $DIR/manual_strip.rs:36:5 + | +LL | if s.starts_with(PREFIX) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: try using the `strip_prefix` method + | +LL | if let Some() = s.strip_prefix(PREFIX) { +LL | str::to_string(); +LL | str::to_string(); + | + +error: stripping a prefix manually + --> $DIR/manual_strip.rs:44:24 + | +LL | str::to_string(&TARGET[prefix.len()..]); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the prefix was tested here + --> $DIR/manual_strip.rs:43:5 + | +LL | if TARGET.starts_with(prefix) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: try using the `strip_prefix` method + | +LL | if let Some() = TARGET.strip_prefix(prefix) { +LL | str::to_string(); + | + +error: stripping a prefix manually + --> $DIR/manual_strip.rs:50:9 + | +LL | s1[2..].to_uppercase(); + | ^^^^^^^ + | +note: the prefix was tested here + --> $DIR/manual_strip.rs:49:5 + | +LL | if s1.starts_with("ab") { + | ^^^^^^^^^^^^^^^^^^^^^^^^ +help: try using the `strip_prefix` method + | +LL | if let Some() = s1.strip_prefix("ab") { +LL | .to_uppercase(); + | + +error: aborting due to 7 previous errors + From 15244a88df5cfd475df010ad945474c658749192 Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Mon, 14 Sep 2020 06:11:35 +0200 Subject: [PATCH 0396/1052] Fix `manual-strip` dogfood errors --- clippy_lints/src/doc.rs | 2 +- clippy_lints/src/loops.rs | 8 +++----- clippy_lints/src/misc_early.rs | 6 +++--- clippy_lints/src/redundant_clone.rs | 5 ++--- tests/ui/let_if_seq.rs | 1 + tests/ui/let_if_seq.stderr | 8 ++++---- 6 files changed, 14 insertions(+), 16 deletions(-) diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 50121a054c798..62bb70af06e93 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -534,7 +534,7 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span) { return false; } - let s = if s.ends_with('s') { &s[..s.len() - 1] } else { s }; + let s = s.strip_suffix('s').unwrap_or(s); s.chars().all(char::is_alphanumeric) && s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1 diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 6c54c07869ad1..8f5675a61b902 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -2601,11 +2601,9 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont span, NEEDLESS_COLLECT_MSG, |diag| { - let (arg, pred) = if contains_arg.starts_with('&') { - ("x", &contains_arg[1..]) - } else { - ("&x", &*contains_arg) - }; + let (arg, pred) = contains_arg + .strip_prefix('&') + .map_or(("&x", &*contains_arg), |s| ("x", s)); diag.span_suggestion( span, "replace with", diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index 02789735c17a3..9cb1cfb915d57 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -377,8 +377,8 @@ impl EarlyLintPass for MiscEarlyLints { if let PatKind::Ident(_, ident, None) = arg.pat.kind { let arg_name = ident.to_string(); - if arg_name.starts_with('_') { - if let Some(correspondence) = registered_names.get(&arg_name[1..]) { + if let Some(arg_name) = arg_name.strip_prefix('_') { + if let Some(correspondence) = registered_names.get(arg_name) { span_lint( cx, DUPLICATE_UNDERSCORE_ARGUMENT, @@ -386,7 +386,7 @@ impl EarlyLintPass for MiscEarlyLints { &format!( "`{}` already exists, having another argument having almost the same \ name makes code comprehension and documentation more difficult", - arg_name[1..].to_owned() + arg_name ), ); } diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 57a45e628db61..1a7f36fbdadbb 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -239,10 +239,9 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { ); let mut app = Applicability::MaybeIncorrect; - let mut call_snip = &snip[dot + 1..]; + let call_snip = &snip[dot + 1..]; // Machine applicable when `call_snip` looks like `foobar()` - if call_snip.ends_with("()") { - call_snip = call_snip[..call_snip.len()-2].trim(); + if let Some(call_snip) = call_snip.strip_suffix("()").map(str::trim) { if call_snip.as_bytes().iter().all(|b| b.is_ascii_alphabetic() || *b == b'_') { app = Applicability::MachineApplicable; } diff --git a/tests/ui/let_if_seq.rs b/tests/ui/let_if_seq.rs index 802beeb4be6b1..32a67f181df43 100644 --- a/tests/ui/let_if_seq.rs +++ b/tests/ui/let_if_seq.rs @@ -33,6 +33,7 @@ fn issue985_alt() -> i32 { x } +#[allow(clippy::manual_strip)] fn issue975() -> String { let mut udn = "dummy".to_string(); if udn.starts_with("uuid:") { diff --git a/tests/ui/let_if_seq.stderr b/tests/ui/let_if_seq.stderr index c53a63a541bc9..7de560c73486b 100644 --- a/tests/ui/let_if_seq.stderr +++ b/tests/ui/let_if_seq.stderr @@ -1,5 +1,5 @@ error: `if _ { .. } else { .. }` is an expression - --> $DIR/let_if_seq.rs:63:5 + --> $DIR/let_if_seq.rs:64:5 | LL | / let mut foo = 0; LL | | if f() { @@ -11,7 +11,7 @@ LL | | } = note: you might not need `mut` at all error: `if _ { .. } else { .. }` is an expression - --> $DIR/let_if_seq.rs:68:5 + --> $DIR/let_if_seq.rs:69:5 | LL | / let mut bar = 0; LL | | if f() { @@ -25,7 +25,7 @@ LL | | } = note: you might not need `mut` at all error: `if _ { .. } else { .. }` is an expression - --> $DIR/let_if_seq.rs:76:5 + --> $DIR/let_if_seq.rs:77:5 | LL | / let quz; LL | | if f() { @@ -36,7 +36,7 @@ LL | | } | |_____^ help: it is more idiomatic to write: `let quz = if f() { 42 } else { 0 };` error: `if _ { .. } else { .. }` is an expression - --> $DIR/let_if_seq.rs:105:5 + --> $DIR/let_if_seq.rs:106:5 | LL | / let mut baz = 0; LL | | if f() { From 0eac38b7a65c29734f4b2d34f35ee0aa9cb00a74 Mon Sep 17 00:00:00 2001 From: iximeow Date: Sun, 13 Sep 2020 20:55:06 -0700 Subject: [PATCH 0397/1052] fix syntax error in suggesting generic constraint in trait parameter suggest `where T: Foo` for the first bound on a trait, then suggest `, T: Foo` when the suggested bound would add to an existing set of `where` clauses. `where T: Foo` may be the first bound if `T` has a default, because we'd rather suggest ``` trait A where T: Copy ``` than ``` trait A ``` for legibility reasons. --- compiler/rustc_middle/src/ty/diagnostics.rs | 66 +++++++++++++------ .../ui/trait-impl-bound-suggestions.fixed | 20 ++++++ src/test/ui/trait-impl-bound-suggestions.rs | 20 ++++++ .../ui/trait-impl-bound-suggestions.stderr | 17 +++++ src/test/ui/type/type-check-defaults.stderr | 4 +- 5 files changed, 105 insertions(+), 22 deletions(-) create mode 100644 src/test/ui/trait-impl-bound-suggestions.fixed create mode 100644 src/test/ui/trait-impl-bound-suggestions.rs create mode 100644 src/test/ui/trait-impl-bound-suggestions.stderr diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index bc51c8b6cd41c..0416ef9e64387 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -202,33 +202,59 @@ pub fn suggest_constraining_type_param( // Suggestion: // fn foo(t: T) where T: Foo, T: Bar {... } // - insert: `, T: Zar` + // + // Additionally, there may be no `where` clause whatsoever in the case that this was + // reached becauase the generic parameter has a default: + // + // Message: + // trait Foo {... } + // - help: consider further restricting this type parameter with `where T: Zar` + // + // Suggestion: + // trait Foo where T: Zar {... } + // - insert: `where T: Zar` - let mut param_spans = Vec::new(); + if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. }) + && generics.where_clause.predicates.len() == 0 + { + // Suggest a bound, but there are no existing where clauses for this ``, so + // suggest adding one. + err.span_suggestion_verbose( + generics.where_clause.tail_span_for_suggestion(), + &msg_restrict_type_further, + format!(" where {}: {}", param_name, constraint), + Applicability::MachineApplicable, + ); + } else { + let mut param_spans = Vec::new(); - for predicate in generics.where_clause.predicates { - if let WherePredicate::BoundPredicate(WhereBoundPredicate { - span, bounded_ty, .. - }) = predicate - { - if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind { - if let Some(segment) = path.segments.first() { - if segment.ident.to_string() == param_name { - param_spans.push(span); + for predicate in generics.where_clause.predicates { + if let WherePredicate::BoundPredicate(WhereBoundPredicate { + span, + bounded_ty, + .. + }) = predicate + { + if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind { + if let Some(segment) = path.segments.first() { + if segment.ident.to_string() == param_name { + param_spans.push(span); + } } } } } - } - match ¶m_spans[..] { - &[¶m_span] => suggest_restrict(param_span.shrink_to_hi()), - _ => { - err.span_suggestion_verbose( - generics.where_clause.tail_span_for_suggestion(), - &msg_restrict_type_further, - format!(", {}: {}", param_name, constraint), - Applicability::MachineApplicable, - ); + match ¶m_spans[..] { + &[¶m_span] => suggest_restrict(param_span.shrink_to_hi()), + _ => { + err.span_suggestion_verbose( + generics.where_clause.tail_span_for_suggestion(), + &msg_restrict_type_further, + format!(", {}: {}", param_name, constraint), + Applicability::MachineApplicable, + ); + } } } diff --git a/src/test/ui/trait-impl-bound-suggestions.fixed b/src/test/ui/trait-impl-bound-suggestions.fixed new file mode 100644 index 0000000000000..db3a95f5c4f61 --- /dev/null +++ b/src/test/ui/trait-impl-bound-suggestions.fixed @@ -0,0 +1,20 @@ +// run-rustfix + +#[allow(unused)] +use std::fmt::Debug; +// Rustfix should add this, or use `std::fmt::Debug` instead. + +#[allow(dead_code)] +struct ConstrainedStruct { + x: X +} + +#[allow(dead_code)] +trait InsufficientlyConstrainedGeneric where X: Copy { + fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct { + //~^ ERROR the trait bound `X: Copy` is not satisfied + ConstrainedStruct { x } + } +} + +pub fn main() { } diff --git a/src/test/ui/trait-impl-bound-suggestions.rs b/src/test/ui/trait-impl-bound-suggestions.rs new file mode 100644 index 0000000000000..bf75175179efd --- /dev/null +++ b/src/test/ui/trait-impl-bound-suggestions.rs @@ -0,0 +1,20 @@ +// run-rustfix + +#[allow(unused)] +use std::fmt::Debug; +// Rustfix should add this, or use `std::fmt::Debug` instead. + +#[allow(dead_code)] +struct ConstrainedStruct { + x: X +} + +#[allow(dead_code)] +trait InsufficientlyConstrainedGeneric { + fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct { + //~^ ERROR the trait bound `X: Copy` is not satisfied + ConstrainedStruct { x } + } +} + +pub fn main() { } diff --git a/src/test/ui/trait-impl-bound-suggestions.stderr b/src/test/ui/trait-impl-bound-suggestions.stderr new file mode 100644 index 0000000000000..3a21e9c6b2ad4 --- /dev/null +++ b/src/test/ui/trait-impl-bound-suggestions.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `X: Copy` is not satisfied + --> $DIR/trait-impl-bound-suggestions.rs:14:52 + | +LL | struct ConstrainedStruct { + | ---- required by this bound in `ConstrainedStruct` +... +LL | fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct { + | ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `X` + | +help: consider further restricting type parameter `X` + | +LL | trait InsufficientlyConstrainedGeneric where X: Copy { + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/type/type-check-defaults.stderr b/src/test/ui/type/type-check-defaults.stderr index fa6f342241025..d8c7f595e62ef 100644 --- a/src/test/ui/type/type-check-defaults.stderr +++ b/src/test/ui/type/type-check-defaults.stderr @@ -56,8 +56,8 @@ LL | trait Base: Super { } | help: consider further restricting type parameter `T` | -LL | trait Base: Super, T: Copy { } - | ^^^^^^^^^ +LL | trait Base: Super where T: Copy { } + | ^^^^^^^^^^^^^ error[E0277]: cannot add `u8` to `i32` --> $DIR/type-check-defaults.rs:24:66 From dd57275c3e4d52b443090d0d75a9a3443bc5ce5c Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 14 Sep 2020 09:45:02 +0200 Subject: [PATCH 0398/1052] shrink const infer error --- .../infer/error_reporting/need_type_info.rs | 15 ++++++++----- .../cannot-infer-const-args.full.stderr | 0 .../cannot-infer-const-args.min.stderr | 0 .../{ => infer}/cannot-infer-const-args.rs | 0 .../infer/method-chain.full.stderr | 11 ++++++++++ .../infer/method-chain.min.stderr | 11 ++++++++++ .../ui/const-generics/infer/method-chain.rs | 22 +++++++++++++++++++ .../{ => infer}/uninferred-consts.full.stderr | 4 ++-- .../{ => infer}/uninferred-consts.min.stderr | 4 ++-- .../{ => infer}/uninferred-consts.rs | 0 10 files changed, 57 insertions(+), 10 deletions(-) rename src/test/ui/const-generics/{ => infer}/cannot-infer-const-args.full.stderr (100%) rename src/test/ui/const-generics/{ => infer}/cannot-infer-const-args.min.stderr (100%) rename src/test/ui/const-generics/{ => infer}/cannot-infer-const-args.rs (100%) create mode 100644 src/test/ui/const-generics/infer/method-chain.full.stderr create mode 100644 src/test/ui/const-generics/infer/method-chain.min.stderr create mode 100644 src/test/ui/const-generics/infer/method-chain.rs rename src/test/ui/const-generics/{ => infer}/uninferred-consts.full.stderr (80%) rename src/test/ui/const-generics/{ => infer}/uninferred-consts.min.stderr (80%) rename src/test/ui/const-generics/{ => infer}/uninferred-consts.rs (100%) diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 4de84e5ba399c..9be234a7bb8bd 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -8,7 +8,7 @@ use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, Pat}; use rustc_middle::hir::map::Map; use rustc_middle::ty::print::Print; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; -use rustc_middle::ty::{self, DefIdTree, Ty}; +use rustc_middle::ty::{self, DefIdTree, InferConst, Ty}; use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::kw; use rustc_span::Span; @@ -569,12 +569,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { local_visitor.visit_expr(expr); } + let span = if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val { + self.inner.borrow_mut().const_unification_table().probe_value(vid).origin.span + } else { + local_visitor.target_span + }; + let error_code = error_code.into(); - let mut err = self.tcx.sess.struct_span_err_with_code( - local_visitor.target_span, - "type annotations needed", - error_code, - ); + let mut err = + self.tcx.sess.struct_span_err_with_code(span, "type annotations needed", error_code); err.note("unable to infer the value of a const parameter"); diff --git a/src/test/ui/const-generics/cannot-infer-const-args.full.stderr b/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr similarity index 100% rename from src/test/ui/const-generics/cannot-infer-const-args.full.stderr rename to src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr diff --git a/src/test/ui/const-generics/cannot-infer-const-args.min.stderr b/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr similarity index 100% rename from src/test/ui/const-generics/cannot-infer-const-args.min.stderr rename to src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr diff --git a/src/test/ui/const-generics/cannot-infer-const-args.rs b/src/test/ui/const-generics/infer/cannot-infer-const-args.rs similarity index 100% rename from src/test/ui/const-generics/cannot-infer-const-args.rs rename to src/test/ui/const-generics/infer/cannot-infer-const-args.rs diff --git a/src/test/ui/const-generics/infer/method-chain.full.stderr b/src/test/ui/const-generics/infer/method-chain.full.stderr new file mode 100644 index 0000000000000..06e4c2e7bc6bc --- /dev/null +++ b/src/test/ui/const-generics/infer/method-chain.full.stderr @@ -0,0 +1,11 @@ +error[E0282]: type annotations needed + --> $DIR/method-chain.rs:21:33 + | +LL | Foo.bar().bar().bar().bar().baz(); + | ^^^ + | + = note: unable to infer the value of a const parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/const-generics/infer/method-chain.min.stderr b/src/test/ui/const-generics/infer/method-chain.min.stderr new file mode 100644 index 0000000000000..06e4c2e7bc6bc --- /dev/null +++ b/src/test/ui/const-generics/infer/method-chain.min.stderr @@ -0,0 +1,11 @@ +error[E0282]: type annotations needed + --> $DIR/method-chain.rs:21:33 + | +LL | Foo.bar().bar().bar().bar().baz(); + | ^^^ + | + = note: unable to infer the value of a const parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/const-generics/infer/method-chain.rs b/src/test/ui/const-generics/infer/method-chain.rs new file mode 100644 index 0000000000000..b3184642f36b4 --- /dev/null +++ b/src/test/ui/const-generics/infer/method-chain.rs @@ -0,0 +1,22 @@ +// revisions: full min + +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] + +struct Foo; + +impl Foo { + fn bar(self) -> Foo { + Foo + } + + fn baz(self) -> Foo { + println!("baz: {}", N); + Foo + } +} + +fn main() { + Foo.bar().bar().bar().bar().baz(); //~ ERROR type annotations needed +} \ No newline at end of file diff --git a/src/test/ui/const-generics/uninferred-consts.full.stderr b/src/test/ui/const-generics/infer/uninferred-consts.full.stderr similarity index 80% rename from src/test/ui/const-generics/uninferred-consts.full.stderr rename to src/test/ui/const-generics/infer/uninferred-consts.full.stderr index 2c5af9e65f827..6af49ba64523b 100644 --- a/src/test/ui/const-generics/uninferred-consts.full.stderr +++ b/src/test/ui/const-generics/infer/uninferred-consts.full.stderr @@ -1,8 +1,8 @@ error[E0282]: type annotations needed - --> $DIR/uninferred-consts.rs:14:5 + --> $DIR/uninferred-consts.rs:14:9 | LL | Foo.foo(); - | ^^^^^^^^^ + | ^^^ | = note: unable to infer the value of a const parameter diff --git a/src/test/ui/const-generics/uninferred-consts.min.stderr b/src/test/ui/const-generics/infer/uninferred-consts.min.stderr similarity index 80% rename from src/test/ui/const-generics/uninferred-consts.min.stderr rename to src/test/ui/const-generics/infer/uninferred-consts.min.stderr index 2c5af9e65f827..6af49ba64523b 100644 --- a/src/test/ui/const-generics/uninferred-consts.min.stderr +++ b/src/test/ui/const-generics/infer/uninferred-consts.min.stderr @@ -1,8 +1,8 @@ error[E0282]: type annotations needed - --> $DIR/uninferred-consts.rs:14:5 + --> $DIR/uninferred-consts.rs:14:9 | LL | Foo.foo(); - | ^^^^^^^^^ + | ^^^ | = note: unable to infer the value of a const parameter diff --git a/src/test/ui/const-generics/uninferred-consts.rs b/src/test/ui/const-generics/infer/uninferred-consts.rs similarity index 100% rename from src/test/ui/const-generics/uninferred-consts.rs rename to src/test/ui/const-generics/infer/uninferred-consts.rs From 035f8791668406bc49fc315253835cbdec247549 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 14 Sep 2020 10:08:32 +0200 Subject: [PATCH 0399/1052] improve const infer err --- .../src/infer/error_reporting/need_type_info.rs | 14 ++++++++++++-- compiler/rustc_middle/src/infer/unify_key.rs | 1 + .../infer/cannot-infer-const-args.full.stderr | 2 +- .../infer/cannot-infer-const-args.min.stderr | 2 +- .../const-generics/infer/method-chain.full.stderr | 2 +- .../const-generics/infer/method-chain.min.stderr | 2 +- src/test/ui/const-generics/infer/method-chain.rs | 2 +- .../infer/uninferred-consts.full.stderr | 2 +- .../infer/uninferred-consts.min.stderr | 2 +- 9 files changed, 20 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 9be234a7bb8bd..f87406c2ce469 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -6,6 +6,7 @@ use rustc_hir::def::{DefKind, Namespace}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, Pat}; use rustc_middle::hir::map::Map; +use rustc_middle::infer::unify_key::ConstVariableOriginKind; use rustc_middle::ty::print::Print; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; use rustc_middle::ty::{self, DefIdTree, InferConst, Ty}; @@ -569,8 +570,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { local_visitor.visit_expr(expr); } + let mut param_name = None; let span = if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val { - self.inner.borrow_mut().const_unification_table().probe_value(vid).origin.span + let origin = self.inner.borrow_mut().const_unification_table().probe_value(vid).origin; + if let ConstVariableOriginKind::ConstParameterDefinition(param) = origin.kind { + param_name = Some(param); + } + origin.span } else { local_visitor.target_span }; @@ -579,7 +585,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let mut err = self.tcx.sess.struct_span_err_with_code(span, "type annotations needed", error_code); - err.note("unable to infer the value of a const parameter"); + if let Some(param_name) = param_name { + err.note(&format!("cannot infer the value of the const parameter `{}`", param_name)); + } else { + err.note("unable to infer the value of a const parameter"); + } err } diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs index 2580ac6bebd86..a60a17befeffd 100644 --- a/compiler/rustc_middle/src/infer/unify_key.rs +++ b/compiler/rustc_middle/src/infer/unify_key.rs @@ -124,6 +124,7 @@ pub struct ConstVariableOrigin { pub enum ConstVariableOriginKind { MiscVariable, ConstInference, + // FIXME(const_generics): Consider storing the `DefId` of the param here. ConstParameterDefinition(Symbol), SubstitutionPlaceholder, } diff --git a/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr b/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr index 053139787edf9..84e75cc376416 100644 --- a/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr +++ b/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | foo(); | ^^^ | - = note: unable to infer the value of a const parameter + = note: cannot infer the value of the const parameter `X` error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr b/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr index 053139787edf9..84e75cc376416 100644 --- a/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr +++ b/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | foo(); | ^^^ | - = note: unable to infer the value of a const parameter + = note: cannot infer the value of the const parameter `X` error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/method-chain.full.stderr b/src/test/ui/const-generics/infer/method-chain.full.stderr index 06e4c2e7bc6bc..e65bc3f109681 100644 --- a/src/test/ui/const-generics/infer/method-chain.full.stderr +++ b/src/test/ui/const-generics/infer/method-chain.full.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | Foo.bar().bar().bar().bar().baz(); | ^^^ | - = note: unable to infer the value of a const parameter + = note: cannot infer the value of the const parameter `N` error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/method-chain.min.stderr b/src/test/ui/const-generics/infer/method-chain.min.stderr index 06e4c2e7bc6bc..e65bc3f109681 100644 --- a/src/test/ui/const-generics/infer/method-chain.min.stderr +++ b/src/test/ui/const-generics/infer/method-chain.min.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | Foo.bar().bar().bar().bar().baz(); | ^^^ | - = note: unable to infer the value of a const parameter + = note: cannot infer the value of the const parameter `N` error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/method-chain.rs b/src/test/ui/const-generics/infer/method-chain.rs index b3184642f36b4..9389ca20d106f 100644 --- a/src/test/ui/const-generics/infer/method-chain.rs +++ b/src/test/ui/const-generics/infer/method-chain.rs @@ -19,4 +19,4 @@ impl Foo { fn main() { Foo.bar().bar().bar().bar().baz(); //~ ERROR type annotations needed -} \ No newline at end of file +} diff --git a/src/test/ui/const-generics/infer/uninferred-consts.full.stderr b/src/test/ui/const-generics/infer/uninferred-consts.full.stderr index 6af49ba64523b..e47b6bd5dc691 100644 --- a/src/test/ui/const-generics/infer/uninferred-consts.full.stderr +++ b/src/test/ui/const-generics/infer/uninferred-consts.full.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | Foo.foo(); | ^^^ | - = note: unable to infer the value of a const parameter + = note: cannot infer the value of the const parameter `N` error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/uninferred-consts.min.stderr b/src/test/ui/const-generics/infer/uninferred-consts.min.stderr index 6af49ba64523b..e47b6bd5dc691 100644 --- a/src/test/ui/const-generics/infer/uninferred-consts.min.stderr +++ b/src/test/ui/const-generics/infer/uninferred-consts.min.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | Foo.foo(); | ^^^ | - = note: unable to infer the value of a const parameter + = note: cannot infer the value of the const parameter `N` error: aborting due to previous error From d069c7e928ab2ac95e3f524ea4d56de518aa2329 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 20 Aug 2020 13:35:00 +0200 Subject: [PATCH 0400/1052] Stabilize doc_alias feature --- compiler/rustc_ast_passes/src/feature_gate.rs | 1 - compiler/rustc_feature/src/accepted.rs | 2 ++ compiler/rustc_feature/src/active.rs | 3 --- library/core/src/lib.rs | 2 +- library/std/src/lib.rs | 2 +- src/doc/rustdoc/src/advanced-features.md | 14 +++++++++++ src/doc/rustdoc/src/unstable-features.md | 16 ------------- .../src/language-features/doc-alias.md | 23 ------------------- .../feature-gates/feature-gate-doc_alias.rs | 4 ---- .../feature-gate-doc_alias.stderr | 12 ---------- 10 files changed, 18 insertions(+), 61 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/doc-alias.md delete mode 100644 src/test/ui/feature-gates/feature-gate-doc_alias.rs delete mode 100644 src/test/ui/feature-gates/feature-gate-doc_alias.stderr diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 40643da2881a0..00d3db73766ac 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -260,7 +260,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { cfg => doc_cfg masked => doc_masked spotlight => doc_spotlight - alias => doc_alias keyword => doc_keyword ); } diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index d16f023c00a62..0477f6f149b87 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -268,6 +268,8 @@ declare_features! ( /// Allows `#[track_caller]` to be used which provides /// accurate caller location reporting during panic (RFC 2091). (accepted, track_caller, "1.46.0", Some(47809), None), + /// Allows `#[doc(alias = "...")]`. + (accepted, doc_alias, "1.48.0", Some(50146), None), // ------------------------------------------------------------------------- // feature-group-end: accepted features diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 1aeb0bd5ad9aa..d4664292a0cbd 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -404,9 +404,6 @@ declare_features! ( /// Allows dereferencing raw pointers during const eval. (active, const_raw_ptr_deref, "1.27.0", Some(51911), None), - /// Allows `#[doc(alias = "...")]`. - (active, doc_alias, "1.27.0", Some(50146), None), - /// Allows inconsistent bounds in where clauses. (active, trivial_bounds, "1.28.0", Some(48214), None), diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index c3cadcbb01e31..3bddc3772e600 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -131,7 +131,7 @@ #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(variant_count)] -#![feature(doc_alias)] +#![cfg_attr(bootstrap, feature(doc_alias))] #![feature(mmx_target_feature)] #![feature(tbm_target_feature)] #![feature(sse4a_target_feature)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 307e222f713b7..b834361b750eb 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -245,7 +245,7 @@ #![feature(core_intrinsics)] #![feature(custom_test_frameworks)] #![feature(decl_macro)] -#![feature(doc_alias)] +#![cfg_attr(bootstrap, feature(doc_alias))] #![feature(doc_cfg)] #![feature(doc_keyword)] #![feature(doc_masked)] diff --git a/src/doc/rustdoc/src/advanced-features.md b/src/doc/rustdoc/src/advanced-features.md index 7c12d23e6495c..c9a0dff5ab303 100644 --- a/src/doc/rustdoc/src/advanced-features.md +++ b/src/doc/rustdoc/src/advanced-features.md @@ -32,3 +32,17 @@ pub struct UnixToken; Here, the respective tokens can only be used by dependent crates on their respective platforms, but they will both appear in documentation. + +## Add aliases for an item in documentation search + +This feature allows you to add alias(es) to an item when using the `rustdoc` search through the +`doc(alias)` attribute. Example: + +```rust,no_run +#[doc(alias = "x")] +#[doc(alias = "big")] +pub struct BigX; +``` + +Then, when looking for it through the `rustdoc` search, if you enter "x" or +"big", search will show the `BigX` struct first. diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 2f49fc8a41552..cd8edbcd1a4ba 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -207,22 +207,6 @@ issue][issue-include]. [unstable-include]: ../unstable-book/language-features/external-doc.html [issue-include]: https://github.com/rust-lang/rust/issues/44732 -### Add aliases for an item in documentation search - -This feature allows you to add alias(es) to an item when using the `rustdoc` search through the -`doc(alias)` attribute. Example: - -```rust,no_run -#![feature(doc_alias)] - -#[doc(alias = "x")] -#[doc(alias = "big")] -pub struct BigX; -``` - -Then, when looking for it through the `rustdoc` search, if you enter "x" or -"big", search will show the `BigX` struct first. - ## Unstable command-line arguments These features are enabled by passing a command-line flag to Rustdoc, but the flags in question are diff --git a/src/doc/unstable-book/src/language-features/doc-alias.md b/src/doc/unstable-book/src/language-features/doc-alias.md deleted file mode 100644 index 647ac0cf663fd..0000000000000 --- a/src/doc/unstable-book/src/language-features/doc-alias.md +++ /dev/null @@ -1,23 +0,0 @@ -# `doc_alias` - -The tracking issue for this feature is: [#50146] - -[#50146]: https://github.com/rust-lang/rust/issues/50146 - ------------------------- - -You can add alias(es) to an item when using the `rustdoc` search through the -`doc(alias)` attribute. Example: - -```rust,no_run -#![feature(doc_alias)] - -#[doc(alias = "x")] -#[doc(alias = "big")] -pub struct BigX; -``` - -Then, when looking for it through the `rustdoc` search, if you enter "x" or -"big", search will show the `BigX` struct first. - -Note that this feature is currently hidden behind the `feature(doc_alias)` gate. diff --git a/src/test/ui/feature-gates/feature-gate-doc_alias.rs b/src/test/ui/feature-gates/feature-gate-doc_alias.rs deleted file mode 100644 index c95722102d9b6..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-doc_alias.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[doc(alias = "foo")] //~ ERROR: `#[doc(alias)]` is experimental -pub struct Foo; - -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-doc_alias.stderr b/src/test/ui/feature-gates/feature-gate-doc_alias.stderr deleted file mode 100644 index f66d1602ba253..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-doc_alias.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: `#[doc(alias)]` is experimental - --> $DIR/feature-gate-doc_alias.rs:1:1 - | -LL | #[doc(alias = "foo")] - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #50146 for more information - = help: add `#![feature(doc_alias)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. From 5bc8b181954e3a4cbce91466e44027600d4c94ef Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sun, 6 Sep 2020 19:38:26 -0400 Subject: [PATCH 0401/1052] Make bootstrap build on stable This is generally a good idea, and will help with being able to build bootstrap without Python over time as it means we can "just" build with cargo +beta build rather than needing the user to set environment variables. This is a minor step, but a necessary one on that road. --- src/bootstrap/bootstrap.py | 1 - src/bootstrap/lib.rs | 2 -- src/bootstrap/tool.rs | 6 ++++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index c3f1bac177de7..4ab23b40ac34b 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -714,7 +714,6 @@ def build_bootstrap(self): # See also: . if "CARGO_BUILD_TARGET" in env: del env["CARGO_BUILD_TARGET"] - env["RUSTC_BOOTSTRAP"] = '1' env["CARGO_TARGET_DIR"] = build_dir env["RUSTC"] = self.rustc() env["LD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \ diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 1b655f55fb071..3b8c9c2d58e0d 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -103,8 +103,6 @@ //! More documentation can be found in each respective module below, and you can //! also check out the `src/bootstrap/README.md` file for more information. -#![feature(drain_filter)] - use std::cell::{Cell, RefCell}; use std::collections::{HashMap, HashSet}; use std::env; diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index fe3f1e78029d7..e8d7de7a5dcaa 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -162,13 +162,15 @@ impl Step for ToolBuild { "the following dependencies are duplicated although they \ have the same features enabled:" ); - for (id, cur, prev) in duplicates.drain_filter(|(_, cur, prev)| cur.2 == prev.2) { + let (same, different): (Vec<_>, Vec<_>) = + duplicates.into_iter().partition(|(_, cur, prev)| cur.2 == prev.2); + for (id, cur, prev) in same { println!(" {}", id); // same features println!(" `{}` ({:?})\n `{}` ({:?})", cur.0, cur.1, prev.0, prev.1); } println!("the following dependencies have different features:"); - for (id, cur, prev) in duplicates { + for (id, cur, prev) in different { println!(" {}", id); let cur_features: HashSet<_> = cur.2.into_iter().collect(); let prev_features: HashSet<_> = prev.2.into_iter().collect(); From ed20eff92be7bcd29ddc74f6bfa603f6698c9504 Mon Sep 17 00:00:00 2001 From: Joe Ellis Date: Tue, 4 Aug 2020 11:18:13 +0100 Subject: [PATCH 0402/1052] Implementation of peer credentials for Unix sockets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code in `ucred.rs` is based on the work done in PR 13 in the tokio-uds repository on GitHub. Link below for reference: https://github.com/tokio-rs/tokio-uds/pull/13 Credit to Martin Habovštiak (GitHub username Kixunil) and contributors for this work! --- library/std/src/sys/unix/ext/mod.rs | 12 ++++ library/std/src/sys/unix/ext/net.rs | 41 ++++++++++++ library/std/src/sys/unix/ext/ucred.rs | 92 +++++++++++++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 library/std/src/sys/unix/ext/ucred.rs diff --git a/library/std/src/sys/unix/ext/mod.rs b/library/std/src/sys/unix/ext/mod.rs index cbdb1c1004984..f43546880983a 100644 --- a/library/std/src/sys/unix/ext/mod.rs +++ b/library/std/src/sys/unix/ext/mod.rs @@ -37,6 +37,18 @@ pub mod process; pub mod raw; pub mod thread; +#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] +pub mod ucred; + /// A prelude for conveniently writing platform-specific code. /// /// Includes all extension traits, and some important type definitions. diff --git a/library/std/src/sys/unix/ext/net.rs b/library/std/src/sys/unix/ext/net.rs index 0e07106f5ce5c..930a67970005b 100644 --- a/library/std/src/sys/unix/ext/net.rs +++ b/library/std/src/sys/unix/ext/net.rs @@ -30,6 +30,29 @@ use crate::sys::{self, cvt}; use crate::sys_common::{self, AsInner, FromInner, IntoInner}; use crate::time::Duration; +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] +use crate::os::unix::ucred; + +#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] +pub use ucred::UCred; + #[cfg(any( target_os = "linux", target_os = "android", @@ -405,6 +428,24 @@ impl UnixStream { SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) } + /// Gets the peer credentials for this Unix domain socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let peer_cred = socket.peer_cred().expect("Couldn't get peer credentials"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] + pub fn peer_cred(&self) -> io::Result { + ucred::peer_cred(self) + } + /// Sets the read timeout for the socket. /// /// If the provided value is [`None`], then [`read`] calls will block diff --git a/library/std/src/sys/unix/ext/ucred.rs b/library/std/src/sys/unix/ext/ucred.rs new file mode 100644 index 0000000000000..dec97ade126b1 --- /dev/null +++ b/library/std/src/sys/unix/ext/ucred.rs @@ -0,0 +1,92 @@ +//! Unix peer credentials. + +// NOTE: Code in this file is heavily based on work done in PR 13 from the tokio-uds repository on +// GitHub. +// +// For reference, the link is here: https://github.com/tokio-rs/tokio-uds/pull/13 +// Credit to Martin Habovštiak (GitHub username Kixunil) and contributors for this work. + +use libc::{gid_t, uid_t}; + +/// Credentials for a UNIX process for credentials passing. +#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct UCred { + pub uid: uid_t, + pub gid: gid_t, +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +pub use self::impl_linux::peer_cred; + +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] +pub use self::impl_bsd::peer_cred; + +#[cfg(any(target_os = "linux", target_os = "android"))] +pub mod impl_linux { + use super::UCred; + use crate::mem::MaybeUninit; + use crate::os::unix::io::AsRawFd; + use crate::os::unix::net::UnixStream; + use crate::{io, mem}; + + pub fn peer_cred(socket: &UnixStream) -> io::Result { + use libc::{c_void, ucred}; + + let ucred_size = mem::size_of::(); + + // Trivial sanity checks. + assert!(mem::size_of::() <= mem::size_of::()); + assert!(ucred_size <= u32::max_value() as usize); + + let mut ucred_size = ucred_size as u32; + + unsafe { + let mut ucred: ucred = MaybeUninit::uninit().assume_init(); + let ret = libc::getsockopt( + socket.as_raw_fd(), + libc::SOL_SOCKET, + libc::SO_PEERCRED, + &mut ucred as *mut ucred as *mut c_void, + &mut ucred_size, + ); + + if ret == 0 && ucred_size as usize == mem::size_of::() { + Ok(UCred { uid: ucred.uid, gid: ucred.gid }) + } else { + Err(io::Error::last_os_error()) + } + } + } +} + +#[cfg(any( + target_os = "dragonfly", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "openbsd" +))] +pub mod impl_bsd { + use super::UCred; + use crate::io; + use crate::mem::MaybeUninit; + use crate::os::unix::io::AsRawFd; + use crate::os::unix::net::UnixStream; + + pub fn peer_cred(socket: &UnixStream) -> io::Result { + unsafe { + // Create `cred` and attempt to populate it. + let mut cred: UCred = MaybeUninit::uninit().assume_init(); + let ret = libc::getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid); + + if ret == 0 { Ok(cred) } else { Err(io::Error::last_os_error()) } + } + } +} From a9ec61db17b68c07816ef1be90e5d138597899e4 Mon Sep 17 00:00:00 2001 From: Joe Ellis Date: Wed, 5 Aug 2020 12:18:32 +0100 Subject: [PATCH 0403/1052] Remove use of `MaybeUninit` in `ucred.rs` We can simply init the struct directly. There is no real need to use uninit memory here. --- library/std/src/sys/unix/ext/net.rs | 1 + library/std/src/sys/unix/ext/ucred.rs | 7 ++----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys/unix/ext/net.rs b/library/std/src/sys/unix/ext/net.rs index 930a67970005b..ac8d6cf53ff8c 100644 --- a/library/std/src/sys/unix/ext/net.rs +++ b/library/std/src/sys/unix/ext/net.rs @@ -433,6 +433,7 @@ impl UnixStream { /// # Examples /// /// ```no_run + /// #![feature(peer_credentials_unix_socket)] /// use std::os::unix::net::UnixStream; /// /// fn main() -> std::io::Result<()> { diff --git a/library/std/src/sys/unix/ext/ucred.rs b/library/std/src/sys/unix/ext/ucred.rs index dec97ade126b1..efaa4d94437f9 100644 --- a/library/std/src/sys/unix/ext/ucred.rs +++ b/library/std/src/sys/unix/ext/ucred.rs @@ -31,7 +31,6 @@ pub use self::impl_bsd::peer_cred; #[cfg(any(target_os = "linux", target_os = "android"))] pub mod impl_linux { use super::UCred; - use crate::mem::MaybeUninit; use crate::os::unix::io::AsRawFd; use crate::os::unix::net::UnixStream; use crate::{io, mem}; @@ -46,9 +45,9 @@ pub mod impl_linux { assert!(ucred_size <= u32::max_value() as usize); let mut ucred_size = ucred_size as u32; + let mut ucred: ucred = ucred { pid: 1, uid: 1, gid: 1 }; unsafe { - let mut ucred: ucred = MaybeUninit::uninit().assume_init(); let ret = libc::getsockopt( socket.as_raw_fd(), libc::SOL_SOCKET, @@ -76,14 +75,12 @@ pub mod impl_linux { pub mod impl_bsd { use super::UCred; use crate::io; - use crate::mem::MaybeUninit; use crate::os::unix::io::AsRawFd; use crate::os::unix::net::UnixStream; pub fn peer_cred(socket: &UnixStream) -> io::Result { + let mut cred = UCred { uid: 1, gid: 1 }; unsafe { - // Create `cred` and attempt to populate it. - let mut cred: UCred = MaybeUninit::uninit().assume_init(); let ret = libc::getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid); if ret == 0 { Ok(cred) } else { Err(io::Error::last_os_error()) } From be2637aba7e12474a7044b5ed9ba4a6978d46462 Mon Sep 17 00:00:00 2001 From: Joe Ellis Date: Wed, 5 Aug 2020 12:19:05 +0100 Subject: [PATCH 0404/1052] Add basic test for Unix peer credentials --- library/std/src/sys/unix/ext/ucred.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/library/std/src/sys/unix/ext/ucred.rs b/library/std/src/sys/unix/ext/ucred.rs index efaa4d94437f9..c737a6a34fd70 100644 --- a/library/std/src/sys/unix/ext/ucred.rs +++ b/library/std/src/sys/unix/ext/ucred.rs @@ -87,3 +87,23 @@ pub mod impl_bsd { } } } + +#[cfg(test)] +mod test { + use crate::os::unix::net::UnixStream; + use libc::{getegid, geteuid}; + + #[test] + fn test_socket_pair() { + // Create two connected sockets and get their peer credentials. They should be equal. + let (sock_a, sock_b) = UnixStream::pair().unwrap(); + let (cred_a, cred_b) = (sock_a.peer_cred().unwrap(), sock_b.peer_cred().unwrap()); + assert_eq!(cred_a, cred_b); + + // Check that the UID and GIDs match up. + let uid = unsafe { geteuid() }; + let gid = unsafe { getegid() }; + assert_eq!(cred_a.uid, uid); + assert_eq!(cred_a.gid, gid); + } +} From cbcf3877b528ff0304e3da6da03349c8a30beed5 Mon Sep 17 00:00:00 2001 From: Joe Ellis Date: Wed, 5 Aug 2020 15:47:45 +0100 Subject: [PATCH 0405/1052] Use `u32::MAX` instead of `u32::max_value` Co-authored-by: lzutao --- library/std/src/sys/unix/ext/ucred.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/ext/ucred.rs b/library/std/src/sys/unix/ext/ucred.rs index c737a6a34fd70..44df834e8d7c4 100644 --- a/library/std/src/sys/unix/ext/ucred.rs +++ b/library/std/src/sys/unix/ext/ucred.rs @@ -42,7 +42,7 @@ pub mod impl_linux { // Trivial sanity checks. assert!(mem::size_of::() <= mem::size_of::()); - assert!(ucred_size <= u32::max_value() as usize); + assert!(ucred_size <= u32::MAX as usize); let mut ucred_size = ucred_size as u32; let mut ucred: ucred = ucred { pid: 1, uid: 1, gid: 1 }; From 40a830321d82ae1dcb97cd2b964ae52a4ebc9c6a Mon Sep 17 00:00:00 2001 From: Joe Ellis Date: Tue, 8 Sep 2020 09:41:23 +0100 Subject: [PATCH 0406/1052] Add pid as an option to UCred struct Currently, PID will be populated for Linux, and set to None for BSDs. --- library/std/src/sys/unix/ext/ucred.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/unix/ext/ucred.rs b/library/std/src/sys/unix/ext/ucred.rs index 44df834e8d7c4..8cce968b35ad4 100644 --- a/library/std/src/sys/unix/ext/ucred.rs +++ b/library/std/src/sys/unix/ext/ucred.rs @@ -6,7 +6,7 @@ // For reference, the link is here: https://github.com/tokio-rs/tokio-uds/pull/13 // Credit to Martin Habovštiak (GitHub username Kixunil) and contributors for this work. -use libc::{gid_t, uid_t}; +use libc::{gid_t, pid_t, uid_t}; /// Credentials for a UNIX process for credentials passing. #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] @@ -14,6 +14,8 @@ use libc::{gid_t, uid_t}; pub struct UCred { pub uid: uid_t, pub gid: gid_t, + // pid field is an option because it is not supported on some platforms. + pub pid: Option, } #[cfg(any(target_os = "android", target_os = "linux"))] @@ -57,7 +59,7 @@ pub mod impl_linux { ); if ret == 0 && ucred_size as usize == mem::size_of::() { - Ok(UCred { uid: ucred.uid, gid: ucred.gid }) + Ok(UCred { uid: ucred.uid, gid: ucred.gid, pid: Some(ucred.pid) }) } else { Err(io::Error::last_os_error()) } @@ -79,7 +81,7 @@ pub mod impl_bsd { use crate::os::unix::net::UnixStream; pub fn peer_cred(socket: &UnixStream) -> io::Result { - let mut cred = UCred { uid: 1, gid: 1 }; + let mut cred = UCred { uid: 1, gid: 1, pid: None }; unsafe { let ret = libc::getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid); From 7c20be387b1d9447289c0ddd1cd3300bf3199b35 Mon Sep 17 00:00:00 2001 From: Joe Ellis Date: Tue, 8 Sep 2020 10:31:56 +0100 Subject: [PATCH 0407/1052] Move Unix peer credentials tests to their own file --- library/std/src/sys/unix/ext/ucred.rs | 20 -------------------- library/std/src/sys/unix/ext/ucred/tests.rs | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 20 deletions(-) create mode 100644 library/std/src/sys/unix/ext/ucred/tests.rs diff --git a/library/std/src/sys/unix/ext/ucred.rs b/library/std/src/sys/unix/ext/ucred.rs index 8cce968b35ad4..f7af9f5e96e32 100644 --- a/library/std/src/sys/unix/ext/ucred.rs +++ b/library/std/src/sys/unix/ext/ucred.rs @@ -89,23 +89,3 @@ pub mod impl_bsd { } } } - -#[cfg(test)] -mod test { - use crate::os::unix::net::UnixStream; - use libc::{getegid, geteuid}; - - #[test] - fn test_socket_pair() { - // Create two connected sockets and get their peer credentials. They should be equal. - let (sock_a, sock_b) = UnixStream::pair().unwrap(); - let (cred_a, cred_b) = (sock_a.peer_cred().unwrap(), sock_b.peer_cred().unwrap()); - assert_eq!(cred_a, cred_b); - - // Check that the UID and GIDs match up. - let uid = unsafe { geteuid() }; - let gid = unsafe { getegid() }; - assert_eq!(cred_a.uid, uid); - assert_eq!(cred_a.gid, gid); - } -} diff --git a/library/std/src/sys/unix/ext/ucred/tests.rs b/library/std/src/sys/unix/ext/ucred/tests.rs new file mode 100644 index 0000000000000..efe9946721029 --- /dev/null +++ b/library/std/src/sys/unix/ext/ucred/tests.rs @@ -0,0 +1,16 @@ +use crate::os::unix::net::UnixStream; +use libc::{getegid, geteuid}; + +#[test] +fn test_socket_pair() { + // Create two connected sockets and get their peer credentials. They should be equal. + let (sock_a, sock_b) = UnixStream::pair().unwrap(); + let (cred_a, cred_b) = (sock_a.peer_cred().unwrap(), sock_b.peer_cred().unwrap()); + assert_eq!(cred_a, cred_b); + + // Check that the UID and GIDs match up. + let uid = unsafe { geteuid() }; + let gid = unsafe { getegid() }; + assert_eq!(cred_a.uid, uid); + assert_eq!(cred_a.gid, gid); +} From fa697dfa8179b7f5c5a1207935828e3a938f2fea Mon Sep 17 00:00:00 2001 From: Joe Ellis Date: Tue, 8 Sep 2020 13:11:13 +0100 Subject: [PATCH 0408/1052] Add documentation to public fields of UCred struct --- library/std/src/sys/unix/ext/ucred.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/ext/ucred.rs b/library/std/src/sys/unix/ext/ucred.rs index f7af9f5e96e32..97f10e52b066c 100644 --- a/library/std/src/sys/unix/ext/ucred.rs +++ b/library/std/src/sys/unix/ext/ucred.rs @@ -12,9 +12,16 @@ use libc::{gid_t, pid_t, uid_t}; #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct UCred { + /// The UID part of the peer credential. This is the effective UID of the process at the domain + /// socket's endpoint. pub uid: uid_t, + /// The GID part of the peer credential. This is the effective GID of the process at the domain + /// socket's endpoint. pub gid: gid_t, - // pid field is an option because it is not supported on some platforms. + /// The PID part of the peer credential. This field is optional because the PID part of the + /// peer credentials is not supported on every platform. On platforms where the mechanism to + /// discover the PID exists, this field will be populated to the PID of the process at the + /// domain socket's endpoint. Otherwise, it will be set to None. pub pid: Option, } From 72eef6168f2a5427ccd398a60db7ee56e419b393 Mon Sep 17 00:00:00 2001 From: Joe Ellis Date: Tue, 8 Sep 2020 16:08:21 +0100 Subject: [PATCH 0409/1052] Conditionally compile peer credentials feature for supported platforms --- library/std/src/sys/unix/ext/net.rs | 9 +++++++++ library/std/src/sys/unix/ext/ucred/tests.rs | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/library/std/src/sys/unix/ext/net.rs b/library/std/src/sys/unix/ext/net.rs index ac8d6cf53ff8c..f664a072c6512 100644 --- a/library/std/src/sys/unix/ext/net.rs +++ b/library/std/src/sys/unix/ext/net.rs @@ -443,6 +443,15 @@ impl UnixStream { /// } /// ``` #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] + #[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" + ))] pub fn peer_cred(&self) -> io::Result { ucred::peer_cred(self) } diff --git a/library/std/src/sys/unix/ext/ucred/tests.rs b/library/std/src/sys/unix/ext/ucred/tests.rs index efe9946721029..451b534b266e3 100644 --- a/library/std/src/sys/unix/ext/ucred/tests.rs +++ b/library/std/src/sys/unix/ext/ucred/tests.rs @@ -2,6 +2,15 @@ use crate::os::unix::net::UnixStream; use libc::{getegid, geteuid}; #[test] +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] fn test_socket_pair() { // Create two connected sockets and get their peer credentials. They should be equal. let (sock_a, sock_b) = UnixStream::pair().unwrap(); From 68ff495afa7687677cf9facf83c5130db24d3acd Mon Sep 17 00:00:00 2001 From: Joe Ellis Date: Thu, 10 Sep 2020 09:11:49 +0100 Subject: [PATCH 0410/1052] Fix peer credentials for Android --- library/std/src/sys/unix/ext/ucred.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/library/std/src/sys/unix/ext/ucred.rs b/library/std/src/sys/unix/ext/ucred.rs index 97f10e52b066c..ed7516c7f28f8 100644 --- a/library/std/src/sys/unix/ext/ucred.rs +++ b/library/std/src/sys/unix/ext/ucred.rs @@ -43,24 +43,23 @@ pub mod impl_linux { use crate::os::unix::io::AsRawFd; use crate::os::unix::net::UnixStream; use crate::{io, mem}; + use libc::{c_void, getsockopt, socklen_t, ucred, SOL_SOCKET, SO_PEERCRED}; pub fn peer_cred(socket: &UnixStream) -> io::Result { - use libc::{c_void, ucred}; - let ucred_size = mem::size_of::(); // Trivial sanity checks. assert!(mem::size_of::() <= mem::size_of::()); assert!(ucred_size <= u32::MAX as usize); - let mut ucred_size = ucred_size as u32; + let mut ucred_size = ucred_size as socklen_t; let mut ucred: ucred = ucred { pid: 1, uid: 1, gid: 1 }; unsafe { - let ret = libc::getsockopt( + let ret = getsockopt( socket.as_raw_fd(), - libc::SOL_SOCKET, - libc::SO_PEERCRED, + SOL_SOCKET, + SO_PEERCRED, &mut ucred as *mut ucred as *mut c_void, &mut ucred_size, ); From f376443b8f2e8935c33f1edd08586ec7f29a900c Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Thu, 3 Sep 2020 15:51:57 +0000 Subject: [PATCH 0411/1052] Move iterator impls to a new module --- library/core/src/slice/iter.rs | 2495 ++++++++++++++++++ library/core/src/slice/iter/macros.rs | 407 +++ library/core/src/slice/mod.rs | 3366 ++----------------------- 3 files changed, 3152 insertions(+), 3116 deletions(-) create mode 100644 library/core/src/slice/iter.rs create mode 100644 library/core/src/slice/iter/macros.rs diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs new file mode 100644 index 0000000000000..2e8c3cd43e999 --- /dev/null +++ b/library/core/src/slice/iter.rs @@ -0,0 +1,2495 @@ +//! Definitions of a bunch of iterators for `[T]`. + +#[macro_use] // import iterator! and forward_iterator! +mod macros; + +use crate::cmp; +use crate::cmp::Ordering; +use crate::fmt; +use crate::intrinsics::{assume, exact_div, unchecked_sub}; +use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccess}; +use crate::marker::{self, Send, Sized, Sync}; +use crate::mem; +use crate::ptr::NonNull; + +use super::{from_raw_parts, from_raw_parts_mut}; + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> IntoIterator for &'a [T] { + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> IntoIterator for &'a mut [T] { + type Item = &'a mut T; + type IntoIter = IterMut<'a, T>; + + fn into_iter(self) -> IterMut<'a, T> { + self.iter_mut() + } +} + +// Macro helper functions +#[inline(always)] +fn size_from_ptr(_: *const T) -> usize { + mem::size_of::() +} + +/// Immutable slice iterator +/// +/// This struct is created by the [`iter`] method on [slices]. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// // First, we declare a type which has `iter` method to get the `Iter` struct (&[usize here]): +/// let slice = &[1, 2, 3]; +/// +/// // Then, we iterate over it: +/// for element in slice.iter() { +/// println!("{}", element); +/// } +/// ``` +/// +/// [`iter`]: ../../std/primitive.slice.html#method.iter +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Iter<'a, T: 'a> { + pub(super) ptr: NonNull, + pub(super) end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that + // ptr == end is a quick test for the Iterator being empty, that works + // for both ZST and non-ZST. + pub(super) _marker: marker::PhantomData<&'a T>, +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for Iter<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("Iter").field(&self.as_slice()).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Sync for Iter<'_, T> {} +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Send for Iter<'_, T> {} + +impl<'a, T> Iter<'a, T> { + /// Views the underlying data as a subslice of the original data. + /// + /// This has the same lifetime as the original slice, and so the + /// iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // First, we declare a type which has the `iter` method to get the `Iter` + /// // struct (&[usize here]): + /// let slice = &[1, 2, 3]; + /// + /// // Then, we get the iterator: + /// let mut iter = slice.iter(); + /// // So if we print what `as_slice` method returns here, we have "[1, 2, 3]": + /// println!("{:?}", iter.as_slice()); + /// + /// // Next, we move to the second element of the slice: + /// iter.next(); + /// // Now `as_slice` returns "[2, 3]": + /// println!("{:?}", iter.as_slice()); + /// ``` + #[stable(feature = "iter_to_slice", since = "1.4.0")] + pub fn as_slice(&self) -> &'a [T] { + self.make_slice() + } +} + +iterator! {struct Iter -> *const T, &'a T, const, {/* no mut */}, { + fn is_sorted_by(self, mut compare: F) -> bool + where + Self: Sized, + F: FnMut(&Self::Item, &Self::Item) -> Option, + { + self.as_slice().windows(2).all(|w| { + compare(&&w[0], &&w[1]).map(|o| o != Ordering::Greater).unwrap_or(false) + }) + } +}} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Iter<'_, T> { + fn clone(&self) -> Self { + Iter { ptr: self.ptr, end: self.end, _marker: self._marker } + } +} + +#[stable(feature = "slice_iter_as_ref", since = "1.13.0")] +impl AsRef<[T]> for Iter<'_, T> { + fn as_ref(&self) -> &[T] { + self.as_slice() + } +} + +/// Mutable slice iterator. +/// +/// This struct is created by the [`iter_mut`] method on [slices]. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// // First, we declare a type which has `iter_mut` method to get the `IterMut` +/// // struct (&[usize here]): +/// let mut slice = &mut [1, 2, 3]; +/// +/// // Then, we iterate over it and increment each element value: +/// for element in slice.iter_mut() { +/// *element += 1; +/// } +/// +/// // We now have "[2, 3, 4]": +/// println!("{:?}", slice); +/// ``` +/// +/// [`iter_mut`]: ../../std/primitive.slice.html#method.iter_mut +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct IterMut<'a, T: 'a> { + pub(super) ptr: NonNull, + pub(super) end: *mut T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that + // ptr == end is a quick test for the Iterator being empty, that works + // for both ZST and non-ZST. + pub(super) _marker: marker::PhantomData<&'a mut T>, +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for IterMut<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("IterMut").field(&self.make_slice()).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Sync for IterMut<'_, T> {} +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Send for IterMut<'_, T> {} + +impl<'a, T> IterMut<'a, T> { + /// Views the underlying data as a subslice of the original data. + /// + /// To avoid creating `&mut` references that alias, this is forced + /// to consume the iterator. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // First, we declare a type which has `iter_mut` method to get the `IterMut` + /// // struct (&[usize here]): + /// let mut slice = &mut [1, 2, 3]; + /// + /// { + /// // Then, we get the iterator: + /// let mut iter = slice.iter_mut(); + /// // We move to next element: + /// iter.next(); + /// // So if we print what `into_slice` method returns here, we have "[2, 3]": + /// println!("{:?}", iter.into_slice()); + /// } + /// + /// // Now let's modify a value of the slice: + /// { + /// // First we get back the iterator: + /// let mut iter = slice.iter_mut(); + /// // We change the value of the first element of the slice returned by the `next` method: + /// *iter.next().unwrap() += 1; + /// } + /// // Now slice is "[2, 2, 3]": + /// println!("{:?}", slice); + /// ``` + #[stable(feature = "iter_to_slice", since = "1.4.0")] + pub fn into_slice(self) -> &'a mut [T] { + // SAFETY: the iterator was created from a mutable slice with pointer + // `self.ptr` and length `len!(self)`. This guarantees that all the prerequisites + // for `from_raw_parts_mut` are fulfilled. + unsafe { from_raw_parts_mut(self.ptr.as_ptr(), len!(self)) } + } + + /// Views the underlying data as a subslice of the original data. + /// + /// To avoid creating `&mut [T]` references that alias, the returned slice + /// borrows its lifetime from the iterator the method is applied on. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(slice_iter_mut_as_slice)] + /// let mut slice: &mut [usize] = &mut [1, 2, 3]; + /// + /// // First, we get the iterator: + /// let mut iter = slice.iter_mut(); + /// // So if we check what the `as_slice` method returns here, we have "[1, 2, 3]": + /// assert_eq!(iter.as_slice(), &[1, 2, 3]); + /// + /// // Next, we move to the second element of the slice: + /// iter.next(); + /// // Now `as_slice` returns "[2, 3]": + /// assert_eq!(iter.as_slice(), &[2, 3]); + /// ``` + #[unstable(feature = "slice_iter_mut_as_slice", reason = "recently added", issue = "58957")] + pub fn as_slice(&self) -> &[T] { + self.make_slice() + } +} + +iterator! {struct IterMut -> *mut T, &'a mut T, mut, {mut}, {}} + +/// An internal abstraction over the splitting iterators, so that +/// splitn, splitn_mut etc can be implemented once. +#[doc(hidden)] +pub(super) trait SplitIter: DoubleEndedIterator { + /// Marks the underlying iterator as complete, extracting the remaining + /// portion of the slice. + fn finish(&mut self) -> Option; +} + +/// An iterator over subslices separated by elements that match a predicate +/// function. +/// +/// This struct is created by the [`split`] method on [slices]. +/// +/// [`split`]: ../../std/primitive.slice.html#method.split +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Split<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + pub(super) v: &'a [T], + pub(super) pred: P, + pub(super) finished: bool, +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for Split<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Split").field("v", &self.v).field("finished", &self.finished).finish() + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Split<'_, T, P> +where + P: Clone + FnMut(&T) -> bool, +{ + fn clone(&self) -> Self { + Split { v: self.v, pred: self.pred.clone(), finished: self.finished } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, P> Iterator for Split<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + if self.finished { + return None; + } + + match self.v.iter().position(|x| (self.pred)(x)) { + None => self.finish(), + Some(idx) => { + let ret = Some(&self.v[..idx]); + self.v = &self.v[idx + 1..]; + ret + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.finished { (0, Some(0)) } else { (1, Some(self.v.len() + 1)) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, P> DoubleEndedIterator for Split<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + if self.finished { + return None; + } + + match self.v.iter().rposition(|x| (self.pred)(x)) { + None => self.finish(), + Some(idx) => { + let ret = Some(&self.v[idx + 1..]); + self.v = &self.v[..idx]; + ret + } + } + } +} + +impl<'a, T, P> SplitIter for Split<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn finish(&mut self) -> Option<&'a [T]> { + if self.finished { + None + } else { + self.finished = true; + Some(self.v) + } + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Split<'_, T, P> where P: FnMut(&T) -> bool {} + +/// An iterator over subslices separated by elements that match a predicate +/// function. Unlike `Split`, it contains the matched part as a terminator +/// of the subslice. +/// +/// This struct is created by the [`split_inclusive`] method on [slices]. +/// +/// [`split_inclusive`]: ../../std/primitive.slice.html#method.split_inclusive +/// [slices]: ../../std/primitive.slice.html +#[unstable(feature = "split_inclusive", issue = "72360")] +pub struct SplitInclusive<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + pub(super) v: &'a [T], + pub(super) pred: P, + pub(super) finished: bool, +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl fmt::Debug for SplitInclusive<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SplitInclusive") + .field("v", &self.v) + .field("finished", &self.finished) + .finish() + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[unstable(feature = "split_inclusive", issue = "72360")] +impl Clone for SplitInclusive<'_, T, P> +where + P: Clone + FnMut(&T) -> bool, +{ + fn clone(&self) -> Self { + SplitInclusive { v: self.v, pred: self.pred.clone(), finished: self.finished } + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl<'a, T, P> Iterator for SplitInclusive<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + if self.finished { + return None; + } + + let idx = + self.v.iter().position(|x| (self.pred)(x)).map(|idx| idx + 1).unwrap_or(self.v.len()); + if idx == self.v.len() { + self.finished = true; + } + let ret = Some(&self.v[..idx]); + self.v = &self.v[idx..]; + ret + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.finished { (0, Some(0)) } else { (1, Some(self.v.len() + 1)) } + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl<'a, T, P> DoubleEndedIterator for SplitInclusive<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + if self.finished { + return None; + } + + // The last index of self.v is already checked and found to match + // by the last iteration, so we start searching a new match + // one index to the left. + let remainder = if self.v.is_empty() { &[] } else { &self.v[..(self.v.len() - 1)] }; + let idx = remainder.iter().rposition(|x| (self.pred)(x)).map(|idx| idx + 1).unwrap_or(0); + if idx == 0 { + self.finished = true; + } + let ret = Some(&self.v[idx..]); + self.v = &self.v[..idx]; + ret + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl FusedIterator for SplitInclusive<'_, T, P> where P: FnMut(&T) -> bool {} + +/// An iterator over the mutable subslices of the vector which are separated +/// by elements that match `pred`. +/// +/// This struct is created by the [`split_mut`] method on [slices]. +/// +/// [`split_mut`]: ../../std/primitive.slice.html#method.split_mut +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct SplitMut<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + pub(super) v: &'a mut [T], + pub(super) pred: P, + pub(super) finished: bool, +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for SplitMut<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SplitMut").field("v", &self.v).field("finished", &self.finished).finish() + } +} + +impl<'a, T, P> SplitIter for SplitMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn finish(&mut self) -> Option<&'a mut [T]> { + if self.finished { + None + } else { + self.finished = true; + Some(mem::replace(&mut self.v, &mut [])) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, P> Iterator for SplitMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + if self.finished { + return None; + } + + let idx_opt = { + // work around borrowck limitations + let pred = &mut self.pred; + self.v.iter().position(|x| (*pred)(x)) + }; + match idx_opt { + None => self.finish(), + Some(idx) => { + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(idx); + self.v = &mut tail[1..]; + Some(head) + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.finished { + (0, Some(0)) + } else { + // if the predicate doesn't match anything, we yield one slice + // if it matches every element, we yield len+1 empty slices. + (1, Some(self.v.len() + 1)) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, P> DoubleEndedIterator for SplitMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + if self.finished { + return None; + } + + let idx_opt = { + // work around borrowck limitations + let pred = &mut self.pred; + self.v.iter().rposition(|x| (*pred)(x)) + }; + match idx_opt { + None => self.finish(), + Some(idx) => { + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(idx); + self.v = head; + Some(&mut tail[1..]) + } + } + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for SplitMut<'_, T, P> where P: FnMut(&T) -> bool {} + +/// An iterator over the mutable subslices of the vector which are separated +/// by elements that match `pred`. Unlike `SplitMut`, it contains the matched +/// parts in the ends of the subslices. +/// +/// This struct is created by the [`split_inclusive_mut`] method on [slices]. +/// +/// [`split_inclusive_mut`]: ../../std/primitive.slice.html#method.split_inclusive_mut +/// [slices]: ../../std/primitive.slice.html +#[unstable(feature = "split_inclusive", issue = "72360")] +pub struct SplitInclusiveMut<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + pub(super) v: &'a mut [T], + pub(super) pred: P, + pub(super) finished: bool, +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl fmt::Debug for SplitInclusiveMut<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SplitInclusiveMut") + .field("v", &self.v) + .field("finished", &self.finished) + .finish() + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl<'a, T, P> Iterator for SplitInclusiveMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + if self.finished { + return None; + } + + let idx_opt = { + // work around borrowck limitations + let pred = &mut self.pred; + self.v.iter().position(|x| (*pred)(x)) + }; + let idx = idx_opt.map(|idx| idx + 1).unwrap_or(self.v.len()); + if idx == self.v.len() { + self.finished = true; + } + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(idx); + self.v = tail; + Some(head) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.finished { + (0, Some(0)) + } else { + // if the predicate doesn't match anything, we yield one slice + // if it matches every element, we yield len+1 empty slices. + (1, Some(self.v.len() + 1)) + } + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl<'a, T, P> DoubleEndedIterator for SplitInclusiveMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + if self.finished { + return None; + } + + let idx_opt = if self.v.is_empty() { + None + } else { + // work around borrowck limitations + let pred = &mut self.pred; + + // The last index of self.v is already checked and found to match + // by the last iteration, so we start searching a new match + // one index to the left. + let remainder = &self.v[..(self.v.len() - 1)]; + remainder.iter().rposition(|x| (*pred)(x)) + }; + let idx = idx_opt.map(|idx| idx + 1).unwrap_or(0); + if idx == 0 { + self.finished = true; + } + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(idx); + self.v = head; + Some(tail) + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl FusedIterator for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool {} + +/// An iterator over subslices separated by elements that match a predicate +/// function, starting from the end of the slice. +/// +/// This struct is created by the [`rsplit`] method on [slices]. +/// +/// [`rsplit`]: ../../std/primitive.slice.html#method.rsplit +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "slice_rsplit", since = "1.27.0")] +#[derive(Clone)] // Is this correct, or does it incorrectly require `T: Clone`? +pub struct RSplit<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + pub(super) inner: Split<'a, T, P>, +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl fmt::Debug for RSplit<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RSplit") + .field("v", &self.inner.v) + .field("finished", &self.inner.finished) + .finish() + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl<'a, T, P> Iterator for RSplit<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + self.inner.next_back() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl<'a, T, P> DoubleEndedIterator for RSplit<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + self.inner.next() + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl<'a, T, P> SplitIter for RSplit<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn finish(&mut self) -> Option<&'a [T]> { + self.inner.finish() + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl FusedIterator for RSplit<'_, T, P> where P: FnMut(&T) -> bool {} + +/// An iterator over the subslices of the vector which are separated +/// by elements that match `pred`, starting from the end of the slice. +/// +/// This struct is created by the [`rsplit_mut`] method on [slices]. +/// +/// [`rsplit_mut`]: ../../std/primitive.slice.html#method.rsplit_mut +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "slice_rsplit", since = "1.27.0")] +pub struct RSplitMut<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + pub(super) inner: SplitMut<'a, T, P>, +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl fmt::Debug for RSplitMut<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RSplitMut") + .field("v", &self.inner.v) + .field("finished", &self.inner.finished) + .finish() + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl<'a, T, P> SplitIter for RSplitMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn finish(&mut self) -> Option<&'a mut [T]> { + self.inner.finish() + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl<'a, T, P> Iterator for RSplitMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + self.inner.next_back() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + self.inner.next() + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl FusedIterator for RSplitMut<'_, T, P> where P: FnMut(&T) -> bool {} + +/// An private iterator over subslices separated by elements that +/// match a predicate function, splitting at most a fixed number of +/// times. +#[derive(Debug)] +pub(super) struct GenericSplitN { + pub(super) iter: I, + pub(super) count: usize, +} + +impl> Iterator for GenericSplitN { + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + match self.count { + 0 => None, + 1 => { + self.count -= 1; + self.iter.finish() + } + _ => { + self.count -= 1; + self.iter.next() + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (lower, upper_opt) = self.iter.size_hint(); + (lower, upper_opt.map(|upper| cmp::min(self.count, upper))) + } +} + +/// An iterator over subslices separated by elements that match a predicate +/// function, limited to a given number of splits. +/// +/// This struct is created by the [`splitn`] method on [slices]. +/// +/// [`splitn`]: ../../std/primitive.slice.html#method.splitn +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct SplitN<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + pub(super) inner: GenericSplitN>, +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for SplitN<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SplitN").field("inner", &self.inner).finish() + } +} + +/// An iterator over subslices separated by elements that match a +/// predicate function, limited to a given number of splits, starting +/// from the end of the slice. +/// +/// This struct is created by the [`rsplitn`] method on [slices]. +/// +/// [`rsplitn`]: ../../std/primitive.slice.html#method.rsplitn +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct RSplitN<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + pub(super) inner: GenericSplitN>, +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for RSplitN<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RSplitN").field("inner", &self.inner).finish() + } +} + +/// An iterator over subslices separated by elements that match a predicate +/// function, limited to a given number of splits. +/// +/// This struct is created by the [`splitn_mut`] method on [slices]. +/// +/// [`splitn_mut`]: ../../std/primitive.slice.html#method.splitn_mut +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct SplitNMut<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + pub(super) inner: GenericSplitN>, +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for SplitNMut<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SplitNMut").field("inner", &self.inner).finish() + } +} + +/// An iterator over subslices separated by elements that match a +/// predicate function, limited to a given number of splits, starting +/// from the end of the slice. +/// +/// This struct is created by the [`rsplitn_mut`] method on [slices]. +/// +/// [`rsplitn_mut`]: ../../std/primitive.slice.html#method.rsplitn_mut +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct RSplitNMut<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + pub(super) inner: GenericSplitN>, +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for RSplitNMut<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RSplitNMut").field("inner", &self.inner).finish() + } +} + +forward_iterator! { SplitN: T, &'a [T] } +forward_iterator! { RSplitN: T, &'a [T] } +forward_iterator! { SplitNMut: T, &'a mut [T] } +forward_iterator! { RSplitNMut: T, &'a mut [T] } + +/// An iterator over overlapping subslices of length `size`. +/// +/// This struct is created by the [`windows`] method on [slices]. +/// +/// [`windows`]: ../../std/primitive.slice.html#method.windows +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Windows<'a, T: 'a> { + pub(super) v: &'a [T], + pub(super) size: usize, +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Windows<'_, T> { + fn clone(&self) -> Self { + Windows { v: self.v, size: self.size } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Iterator for Windows<'a, T> { + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + if self.size > self.v.len() { + None + } else { + let ret = Some(&self.v[..self.size]); + self.v = &self.v[1..]; + ret + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.size > self.v.len() { + (0, Some(0)) + } else { + let size = self.v.len() - self.size + 1; + (size, Some(size)) + } + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + let (end, overflow) = self.size.overflowing_add(n); + if end > self.v.len() || overflow { + self.v = &[]; + None + } else { + let nth = &self.v[n..end]; + self.v = &self.v[n + 1..]; + Some(nth) + } + } + + #[inline] + fn last(self) -> Option { + if self.size > self.v.len() { + None + } else { + let start = self.v.len() - self.size; + Some(&self.v[start..]) + } + } + + #[doc(hidden)] + unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + // SAFETY: since the caller guarantees that `i` is in bounds, + // which means that `i` cannot overflow an `isize`, and the + // slice created by `from_raw_parts` is a subslice of `self.v` + // thus is guaranteed to be valid for the lifetime `'a` of `self.v`. + unsafe { from_raw_parts(self.v.as_ptr().add(idx), self.size) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> DoubleEndedIterator for Windows<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + if self.size > self.v.len() { + None + } else { + let ret = Some(&self.v[self.v.len() - self.size..]); + self.v = &self.v[..self.v.len() - 1]; + ret + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let (end, overflow) = self.v.len().overflowing_sub(n); + if end < self.size || overflow { + self.v = &[]; + None + } else { + let ret = &self.v[end - self.size..end]; + self.v = &self.v[..end - 1]; + Some(ret) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Windows<'_, T> {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Windows<'_, T> {} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Windows<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for Windows<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a +/// time), starting at the beginning of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last slice +/// of the iteration will be the remainder. +/// +/// This struct is created by the [`chunks`] method on [slices]. +/// +/// [`chunks`]: ../../std/primitive.slice.html#method.chunks +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Chunks<'a, T: 'a> { + pub(super) v: &'a [T], + pub(super) chunk_size: usize, +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Chunks<'_, T> { + fn clone(&self) -> Self { + Chunks { v: self.v, chunk_size: self.chunk_size } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Iterator for Chunks<'a, T> { + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + if self.v.is_empty() { + None + } else { + let chunksz = cmp::min(self.v.len(), self.chunk_size); + let (fst, snd) = self.v.split_at(chunksz); + self.v = snd; + Some(fst) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.v.is_empty() { + (0, Some(0)) + } else { + let n = self.v.len() / self.chunk_size; + let rem = self.v.len() % self.chunk_size; + let n = if rem > 0 { n + 1 } else { n }; + (n, Some(n)) + } + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + let (start, overflow) = n.overflowing_mul(self.chunk_size); + if start >= self.v.len() || overflow { + self.v = &[]; + None + } else { + let end = match start.checked_add(self.chunk_size) { + Some(sum) => cmp::min(self.v.len(), sum), + None => self.v.len(), + }; + let nth = &self.v[start..end]; + self.v = &self.v[end..]; + Some(nth) + } + } + + #[inline] + fn last(self) -> Option { + if self.v.is_empty() { + None + } else { + let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size; + Some(&self.v[start..]) + } + } + + #[doc(hidden)] + unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + let start = idx * self.chunk_size; + let end = match start.checked_add(self.chunk_size) { + None => self.v.len(), + Some(end) => cmp::min(end, self.v.len()), + }; + // SAFETY: the caller guarantees that `i` is in bounds, + // which means that `start` must be in bounds of the + // underlying `self.v` slice, and we made sure that `end` + // is also in bounds of `self.v`. Thus, `start` cannot overflow + // an `isize`, and the slice constructed by `from_raw_parts` + // is a subslice of `self.v` which is guaranteed to be valid + // for the lifetime `'a` of `self.v`. + unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> DoubleEndedIterator for Chunks<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + if self.v.is_empty() { + None + } else { + let remainder = self.v.len() % self.chunk_size; + let chunksz = if remainder != 0 { remainder } else { self.chunk_size }; + let (fst, snd) = self.v.split_at(self.v.len() - chunksz); + self.v = fst; + Some(snd) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &[]; + None + } else { + let start = (len - 1 - n) * self.chunk_size; + let end = match start.checked_add(self.chunk_size) { + Some(res) => cmp::min(res, self.v.len()), + None => self.v.len(), + }; + let nth_back = &self.v[start..end]; + self.v = &self.v[..start]; + Some(nth_back) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Chunks<'_, T> {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Chunks<'_, T> {} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Chunks<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for Chunks<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` +/// elements at a time), starting at the beginning of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last slice +/// of the iteration will be the remainder. +/// +/// This struct is created by the [`chunks_mut`] method on [slices]. +/// +/// [`chunks_mut`]: ../../std/primitive.slice.html#method.chunks_mut +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct ChunksMut<'a, T: 'a> { + pub(super) v: &'a mut [T], + pub(super) chunk_size: usize, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Iterator for ChunksMut<'a, T> { + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + if self.v.is_empty() { + None + } else { + let sz = cmp::min(self.v.len(), self.chunk_size); + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(sz); + self.v = tail; + Some(head) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.v.is_empty() { + (0, Some(0)) + } else { + let n = self.v.len() / self.chunk_size; + let rem = self.v.len() % self.chunk_size; + let n = if rem > 0 { n + 1 } else { n }; + (n, Some(n)) + } + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { + let (start, overflow) = n.overflowing_mul(self.chunk_size); + if start >= self.v.len() || overflow { + self.v = &mut []; + None + } else { + let end = match start.checked_add(self.chunk_size) { + Some(sum) => cmp::min(self.v.len(), sum), + None => self.v.len(), + }; + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(end); + let (_, nth) = head.split_at_mut(start); + self.v = tail; + Some(nth) + } + } + + #[inline] + fn last(self) -> Option { + if self.v.is_empty() { + None + } else { + let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size; + Some(&mut self.v[start..]) + } + } + + #[doc(hidden)] + unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + let start = idx * self.chunk_size; + let end = match start.checked_add(self.chunk_size) { + None => self.v.len(), + Some(end) => cmp::min(end, self.v.len()), + }; + // SAFETY: see comments for `Chunks::get_unchecked`. + // + // Also note that the caller also guarantees that we're never called + // with the same index again, and that no other methods that will + // access this subslice are called, so it is valid for the returned + // slice to be mutable. + unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + if self.v.is_empty() { + None + } else { + let remainder = self.v.len() % self.chunk_size; + let sz = if remainder != 0 { remainder } else { self.chunk_size }; + let tmp = mem::replace(&mut self.v, &mut []); + let tmp_len = tmp.len(); + let (head, tail) = tmp.split_at_mut(tmp_len - sz); + self.v = head; + Some(tail) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &mut []; + None + } else { + let start = (len - 1 - n) * self.chunk_size; + let end = match start.checked_add(self.chunk_size) { + Some(res) => cmp::min(res, self.v.len()), + None => self.v.len(), + }; + let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); + let (head, nth_back) = temp.split_at_mut(start); + self.v = head; + Some(nth_back) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for ChunksMut<'_, T> {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for ChunksMut<'_, T> {} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for ChunksMut<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a +/// time), starting at the beginning of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last +/// up to `chunk_size-1` elements will be omitted but can be retrieved from +/// the [`remainder`] function from the iterator. +/// +/// This struct is created by the [`chunks_exact`] method on [slices]. +/// +/// [`chunks_exact`]: ../../std/primitive.slice.html#method.chunks_exact +/// [`remainder`]: ChunksExact::remainder +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "chunks_exact", since = "1.31.0")] +pub struct ChunksExact<'a, T: 'a> { + pub(super) v: &'a [T], + pub(super) rem: &'a [T], + pub(super) chunk_size: usize, +} + +impl<'a, T> ChunksExact<'a, T> { + /// Returns the remainder of the original slice that is not going to be + /// returned by the iterator. The returned slice has at most `chunk_size-1` + /// elements. + #[stable(feature = "chunks_exact", since = "1.31.0")] + pub fn remainder(&self) -> &'a [T] { + self.rem + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl Clone for ChunksExact<'_, T> { + fn clone(&self) -> Self { + ChunksExact { v: self.v, rem: self.rem, chunk_size: self.chunk_size } + } +} + +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl<'a, T> Iterator for ChunksExact<'a, T> { + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let (fst, snd) = self.v.split_at(self.chunk_size); + self.v = snd; + Some(fst) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let n = self.v.len() / self.chunk_size; + (n, Some(n)) + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + let (start, overflow) = n.overflowing_mul(self.chunk_size); + if start >= self.v.len() || overflow { + self.v = &[]; + None + } else { + let (_, snd) = self.v.split_at(start); + self.v = snd; + self.next() + } + } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } + + #[doc(hidden)] + unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + let start = idx * self.chunk_size; + // SAFETY: mostly identical to `Chunks::get_unchecked`. + unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) } + } +} + +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl<'a, T> DoubleEndedIterator for ChunksExact<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let (fst, snd) = self.v.split_at(self.v.len() - self.chunk_size); + self.v = fst; + Some(snd) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &[]; + None + } else { + let start = (len - 1 - n) * self.chunk_size; + let end = start + self.chunk_size; + let nth_back = &self.v[start..end]; + self.v = &self.v[..start]; + Some(nth_back) + } + } +} + +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl ExactSizeIterator for ChunksExact<'_, T> { + fn is_empty(&self) -> bool { + self.v.is_empty() + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for ChunksExact<'_, T> {} + +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl FusedIterator for ChunksExact<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` +/// elements at a time), starting at the beginning of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last up to +/// `chunk_size-1` elements will be omitted but can be retrieved from the +/// [`into_remainder`] function from the iterator. +/// +/// This struct is created by the [`chunks_exact_mut`] method on [slices]. +/// +/// [`chunks_exact_mut`]: ../../std/primitive.slice.html#method.chunks_exact_mut +/// [`into_remainder`]: ChunksExactMut::into_remainder +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "chunks_exact", since = "1.31.0")] +pub struct ChunksExactMut<'a, T: 'a> { + pub(super) v: &'a mut [T], + pub(super) rem: &'a mut [T], + pub(super) chunk_size: usize, +} + +impl<'a, T> ChunksExactMut<'a, T> { + /// Returns the remainder of the original slice that is not going to be + /// returned by the iterator. The returned slice has at most `chunk_size-1` + /// elements. + #[stable(feature = "chunks_exact", since = "1.31.0")] + pub fn into_remainder(self) -> &'a mut [T] { + self.rem + } +} + +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl<'a, T> Iterator for ChunksExactMut<'a, T> { + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(self.chunk_size); + self.v = tail; + Some(head) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let n = self.v.len() / self.chunk_size; + (n, Some(n)) + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { + let (start, overflow) = n.overflowing_mul(self.chunk_size); + if start >= self.v.len() || overflow { + self.v = &mut []; + None + } else { + let tmp = mem::replace(&mut self.v, &mut []); + let (_, snd) = tmp.split_at_mut(start); + self.v = snd; + self.next() + } + } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } + + #[doc(hidden)] + unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + let start = idx * self.chunk_size; + // SAFETY: see comments for `ChunksMut::get_unchecked`. + unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) } + } +} + +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let tmp = mem::replace(&mut self.v, &mut []); + let tmp_len = tmp.len(); + let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size); + self.v = head; + Some(tail) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &mut []; + None + } else { + let start = (len - 1 - n) * self.chunk_size; + let end = start + self.chunk_size; + let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); + let (head, nth_back) = temp.split_at_mut(start); + self.v = head; + Some(nth_back) + } + } +} + +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl ExactSizeIterator for ChunksExactMut<'_, T> { + fn is_empty(&self) -> bool { + self.v.is_empty() + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for ChunksExactMut<'_, T> {} + +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl FusedIterator for ChunksExactMut<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) chunks (`N` elements at a +/// time), starting at the beginning of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last +/// up to `N-1` elements will be omitted but can be retrieved from +/// the [`remainder`] function from the iterator. +/// +/// This struct is created by the [`array_chunks`] method on [slices]. +/// +/// [`array_chunks`]: ../../std/primitive.slice.html#method.array_chunks +/// [`remainder`]: ArrayChunks::remainder +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[unstable(feature = "array_chunks", issue = "74985")] +pub struct ArrayChunks<'a, T: 'a, const N: usize> { + pub(super) iter: Iter<'a, [T; N]>, + pub(super) rem: &'a [T], +} + +impl<'a, T, const N: usize> ArrayChunks<'a, T, N> { + /// Returns the remainder of the original slice that is not going to be + /// returned by the iterator. The returned slice has at most `N-1` + /// elements. + #[unstable(feature = "array_chunks", issue = "74985")] + pub fn remainder(&self) -> &'a [T] { + self.rem + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[unstable(feature = "array_chunks", issue = "74985")] +impl Clone for ArrayChunks<'_, T, N> { + fn clone(&self) -> Self { + ArrayChunks { iter: self.iter.clone(), rem: self.rem } + } +} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl<'a, T, const N: usize> Iterator for ArrayChunks<'a, T, N> { + type Item = &'a [T; N]; + + #[inline] + fn next(&mut self) -> Option<&'a [T; N]> { + self.iter.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[inline] + fn count(self) -> usize { + self.iter.count() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + self.iter.nth(n) + } + + #[inline] + fn last(self) -> Option { + self.iter.last() + } + + unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T; N] { + // SAFETY: The safety guarantees of `get_unchecked` are transferred to + // the caller. + unsafe { self.iter.get_unchecked(i) } + } +} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunks<'a, T, N> { + #[inline] + fn next_back(&mut self) -> Option<&'a [T; N]> { + self.iter.next_back() + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + self.iter.nth_back(n) + } +} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl ExactSizeIterator for ArrayChunks<'_, T, N> { + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for ArrayChunks<'_, T, N> {} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl FusedIterator for ArrayChunks<'_, T, N> {} + +#[doc(hidden)] +#[unstable(feature = "array_chunks", issue = "74985")] +unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) mutable chunks (`N` elements +/// at a time), starting at the beginning of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last +/// up to `N-1` elements will be omitted but can be retrieved from +/// the [`into_remainder`] function from the iterator. +/// +/// This struct is created by the [`array_chunks_mut`] method on [slices]. +/// +/// [`array_chunks_mut`]: ../../std/primitive.slice.html#method.array_chunks_mut +/// [`into_remainder`]: ../../std/slice/struct.ArrayChunksMut.html#method.into_remainder +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[unstable(feature = "array_chunks", issue = "74985")] +pub struct ArrayChunksMut<'a, T: 'a, const N: usize> { + pub(super) iter: IterMut<'a, [T; N]>, + pub(super) rem: &'a mut [T], +} + +impl<'a, T, const N: usize> ArrayChunksMut<'a, T, N> { + /// Returns the remainder of the original slice that is not going to be + /// returned by the iterator. The returned slice has at most `N-1` + /// elements. + #[unstable(feature = "array_chunks", issue = "74985")] + pub fn into_remainder(self) -> &'a mut [T] { + self.rem + } +} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl<'a, T, const N: usize> Iterator for ArrayChunksMut<'a, T, N> { + type Item = &'a mut [T; N]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T; N]> { + self.iter.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[inline] + fn count(self) -> usize { + self.iter.count() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + self.iter.nth(n) + } + + #[inline] + fn last(self) -> Option { + self.iter.last() + } + + unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T; N] { + // SAFETY: The safety guarantees of `get_unchecked` are transferred to + // the caller. + unsafe { self.iter.get_unchecked(i) } + } +} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunksMut<'a, T, N> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T; N]> { + self.iter.next_back() + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + self.iter.nth_back(n) + } +} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl ExactSizeIterator for ArrayChunksMut<'_, T, N> { + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for ArrayChunksMut<'_, T, N> {} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl FusedIterator for ArrayChunksMut<'_, T, N> {} + +#[doc(hidden)] +#[unstable(feature = "array_chunks", issue = "74985")] +unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunksMut<'a, T, N> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a +/// time), starting at the end of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last slice +/// of the iteration will be the remainder. +/// +/// This struct is created by the [`rchunks`] method on [slices]. +/// +/// [`rchunks`]: ../../std/primitive.slice.html#method.rchunks +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "rchunks", since = "1.31.0")] +pub struct RChunks<'a, T: 'a> { + pub(super) v: &'a [T], + pub(super) chunk_size: usize, +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[stable(feature = "rchunks", since = "1.31.0")] +impl Clone for RChunks<'_, T> { + fn clone(&self) -> Self { + RChunks { v: self.v, chunk_size: self.chunk_size } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> Iterator for RChunks<'a, T> { + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + if self.v.is_empty() { + None + } else { + let chunksz = cmp::min(self.v.len(), self.chunk_size); + let (fst, snd) = self.v.split_at(self.v.len() - chunksz); + self.v = fst; + Some(snd) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.v.is_empty() { + (0, Some(0)) + } else { + let n = self.v.len() / self.chunk_size; + let rem = self.v.len() % self.chunk_size; + let n = if rem > 0 { n + 1 } else { n }; + (n, Some(n)) + } + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + let (end, overflow) = n.overflowing_mul(self.chunk_size); + if end >= self.v.len() || overflow { + self.v = &[]; + None + } else { + // Can't underflow because of the check above + let end = self.v.len() - end; + let start = match end.checked_sub(self.chunk_size) { + Some(sum) => sum, + None => 0, + }; + let nth = &self.v[start..end]; + self.v = &self.v[0..start]; + Some(nth) + } + } + + #[inline] + fn last(self) -> Option { + if self.v.is_empty() { + None + } else { + let rem = self.v.len() % self.chunk_size; + let end = if rem == 0 { self.chunk_size } else { rem }; + Some(&self.v[0..end]) + } + } + + #[doc(hidden)] + unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + let end = self.v.len() - idx * self.chunk_size; + let start = match end.checked_sub(self.chunk_size) { + None => 0, + Some(start) => start, + }; + // SAFETY: mostly identical to `Chunks::get_unchecked`. + unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> DoubleEndedIterator for RChunks<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + if self.v.is_empty() { + None + } else { + let remainder = self.v.len() % self.chunk_size; + let chunksz = if remainder != 0 { remainder } else { self.chunk_size }; + let (fst, snd) = self.v.split_at(chunksz); + self.v = snd; + Some(fst) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &[]; + None + } else { + // can't underflow because `n < len` + let offset_from_end = (len - 1 - n) * self.chunk_size; + let end = self.v.len() - offset_from_end; + let start = end.saturating_sub(self.chunk_size); + let nth_back = &self.v[start..end]; + self.v = &self.v[end..]; + Some(nth_back) + } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl ExactSizeIterator for RChunks<'_, T> {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for RChunks<'_, T> {} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl FusedIterator for RChunks<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` +/// elements at a time), starting at the end of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last slice +/// of the iteration will be the remainder. +/// +/// This struct is created by the [`rchunks_mut`] method on [slices]. +/// +/// [`rchunks_mut`]: ../../std/primitive.slice.html#method.rchunks_mut +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "rchunks", since = "1.31.0")] +pub struct RChunksMut<'a, T: 'a> { + pub(super) v: &'a mut [T], + pub(super) chunk_size: usize, +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> Iterator for RChunksMut<'a, T> { + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + if self.v.is_empty() { + None + } else { + let sz = cmp::min(self.v.len(), self.chunk_size); + let tmp = mem::replace(&mut self.v, &mut []); + let tmp_len = tmp.len(); + let (head, tail) = tmp.split_at_mut(tmp_len - sz); + self.v = head; + Some(tail) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.v.is_empty() { + (0, Some(0)) + } else { + let n = self.v.len() / self.chunk_size; + let rem = self.v.len() % self.chunk_size; + let n = if rem > 0 { n + 1 } else { n }; + (n, Some(n)) + } + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { + let (end, overflow) = n.overflowing_mul(self.chunk_size); + if end >= self.v.len() || overflow { + self.v = &mut []; + None + } else { + // Can't underflow because of the check above + let end = self.v.len() - end; + let start = match end.checked_sub(self.chunk_size) { + Some(sum) => sum, + None => 0, + }; + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(start); + let (nth, _) = tail.split_at_mut(end - start); + self.v = head; + Some(nth) + } + } + + #[inline] + fn last(self) -> Option { + if self.v.is_empty() { + None + } else { + let rem = self.v.len() % self.chunk_size; + let end = if rem == 0 { self.chunk_size } else { rem }; + Some(&mut self.v[0..end]) + } + } + + #[doc(hidden)] + unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + let end = self.v.len() - idx * self.chunk_size; + let start = match end.checked_sub(self.chunk_size) { + None => 0, + Some(start) => start, + }; + // SAFETY: see comments for `RChunks::get_unchecked` and `ChunksMut::get_unchecked` + unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + if self.v.is_empty() { + None + } else { + let remainder = self.v.len() % self.chunk_size; + let sz = if remainder != 0 { remainder } else { self.chunk_size }; + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(sz); + self.v = tail; + Some(head) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &mut []; + None + } else { + // can't underflow because `n < len` + let offset_from_end = (len - 1 - n) * self.chunk_size; + let end = self.v.len() - offset_from_end; + let start = end.saturating_sub(self.chunk_size); + let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); + let (_, nth_back) = tmp.split_at_mut(start); + self.v = tail; + Some(nth_back) + } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl ExactSizeIterator for RChunksMut<'_, T> {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for RChunksMut<'_, T> {} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl FusedIterator for RChunksMut<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a +/// time), starting at the end of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last +/// up to `chunk_size-1` elements will be omitted but can be retrieved from +/// the [`remainder`] function from the iterator. +/// +/// This struct is created by the [`rchunks_exact`] method on [slices]. +/// +/// [`rchunks_exact`]: ../../std/primitive.slice.html#method.rchunks_exact +/// [`remainder`]: ChunksExact::remainder +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "rchunks", since = "1.31.0")] +pub struct RChunksExact<'a, T: 'a> { + pub(super) v: &'a [T], + pub(super) rem: &'a [T], + pub(super) chunk_size: usize, +} + +impl<'a, T> RChunksExact<'a, T> { + /// Returns the remainder of the original slice that is not going to be + /// returned by the iterator. The returned slice has at most `chunk_size-1` + /// elements. + #[stable(feature = "rchunks", since = "1.31.0")] + pub fn remainder(&self) -> &'a [T] { + self.rem + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> Clone for RChunksExact<'a, T> { + fn clone(&self) -> RChunksExact<'a, T> { + RChunksExact { v: self.v, rem: self.rem, chunk_size: self.chunk_size } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> Iterator for RChunksExact<'a, T> { + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let (fst, snd) = self.v.split_at(self.v.len() - self.chunk_size); + self.v = fst; + Some(snd) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let n = self.v.len() / self.chunk_size; + (n, Some(n)) + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + let (end, overflow) = n.overflowing_mul(self.chunk_size); + if end >= self.v.len() || overflow { + self.v = &[]; + None + } else { + let (fst, _) = self.v.split_at(self.v.len() - end); + self.v = fst; + self.next() + } + } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } + + #[doc(hidden)] + unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + let end = self.v.len() - idx * self.chunk_size; + let start = end - self.chunk_size; + // SAFETY: + // SAFETY: mostmy identical to `Chunks::get_unchecked`. + unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> DoubleEndedIterator for RChunksExact<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let (fst, snd) = self.v.split_at(self.chunk_size); + self.v = snd; + Some(fst) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &[]; + None + } else { + // now that we know that `n` corresponds to a chunk, + // none of these operations can underflow/overflow + let offset = (len - n) * self.chunk_size; + let start = self.v.len() - offset; + let end = start + self.chunk_size; + let nth_back = &self.v[start..end]; + self.v = &self.v[end..]; + Some(nth_back) + } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> ExactSizeIterator for RChunksExact<'a, T> { + fn is_empty(&self) -> bool { + self.v.is_empty() + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for RChunksExact<'_, T> {} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl FusedIterator for RChunksExact<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` +/// elements at a time), starting at the end of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last up to +/// `chunk_size-1` elements will be omitted but can be retrieved from the +/// [`into_remainder`] function from the iterator. +/// +/// This struct is created by the [`rchunks_exact_mut`] method on [slices]. +/// +/// [`rchunks_exact_mut`]: ../../std/primitive.slice.html#method.rchunks_exact_mut +/// [`into_remainder`]: ChunksExactMut::into_remainder +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "rchunks", since = "1.31.0")] +pub struct RChunksExactMut<'a, T: 'a> { + pub(super) v: &'a mut [T], + pub(super) rem: &'a mut [T], + pub(super) chunk_size: usize, +} + +impl<'a, T> RChunksExactMut<'a, T> { + /// Returns the remainder of the original slice that is not going to be + /// returned by the iterator. The returned slice has at most `chunk_size-1` + /// elements. + #[stable(feature = "rchunks", since = "1.31.0")] + pub fn into_remainder(self) -> &'a mut [T] { + self.rem + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> Iterator for RChunksExactMut<'a, T> { + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let tmp = mem::replace(&mut self.v, &mut []); + let tmp_len = tmp.len(); + let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size); + self.v = head; + Some(tail) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let n = self.v.len() / self.chunk_size; + (n, Some(n)) + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { + let (end, overflow) = n.overflowing_mul(self.chunk_size); + if end >= self.v.len() || overflow { + self.v = &mut []; + None + } else { + let tmp = mem::replace(&mut self.v, &mut []); + let tmp_len = tmp.len(); + let (fst, _) = tmp.split_at_mut(tmp_len - end); + self.v = fst; + self.next() + } + } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } + + #[doc(hidden)] + unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + let end = self.v.len() - idx * self.chunk_size; + let start = end - self.chunk_size; + // SAFETY: see comments for `RChunksMut::get_unchecked`. + unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(self.chunk_size); + self.v = tail; + Some(head) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &mut []; + None + } else { + // now that we know that `n` corresponds to a chunk, + // none of these operations can underflow/overflow + let offset = (len - n) * self.chunk_size; + let start = self.v.len() - offset; + let end = start + self.chunk_size; + let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); + let (_, nth_back) = tmp.split_at_mut(start); + self.v = tail; + Some(nth_back) + } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl ExactSizeIterator for RChunksExactMut<'_, T> { + fn is_empty(&self) -> bool { + self.v.is_empty() + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for RChunksExactMut<'_, T> {} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl FusedIterator for RChunksExactMut<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs new file mode 100644 index 0000000000000..9fcc7a71af8ad --- /dev/null +++ b/library/core/src/slice/iter/macros.rs @@ -0,0 +1,407 @@ +//! Macros used by iterators of slice. + +// Inlining is_empty and len makes a huge performance difference +macro_rules! is_empty { + // The way we encode the length of a ZST iterator, this works both for ZST + // and non-ZST. + ($self: ident) => { + $self.ptr.as_ptr() as *const T == $self.end + }; +} + +// To get rid of some bounds checks (see `position`), we compute the length in a somewhat +// unexpected way. (Tested by `codegen/slice-position-bounds-check`.) +macro_rules! len { + ($self: ident) => {{ + #![allow(unused_unsafe)] // we're sometimes used within an unsafe block + + let start = $self.ptr; + let size = size_from_ptr(start.as_ptr()); + if size == 0 { + // This _cannot_ use `unchecked_sub` because we depend on wrapping + // to represent the length of long ZST slice iterators. + ($self.end as usize).wrapping_sub(start.as_ptr() as usize) + } else { + // We know that `start <= end`, so can do better than `offset_from`, + // which needs to deal in signed. By setting appropriate flags here + // we can tell LLVM this, which helps it remove bounds checks. + // SAFETY: By the type invariant, `start <= end` + let diff = unsafe { unchecked_sub($self.end as usize, start.as_ptr() as usize) }; + // By also telling LLVM that the pointers are apart by an exact + // multiple of the type size, it can optimize `len() == 0` down to + // `start == end` instead of `(end - start) < size`. + // SAFETY: By the type invariant, the pointers are aligned so the + // distance between them must be a multiple of pointee size + unsafe { exact_div(diff, size) } + } + }}; +} + +// The shared definition of the `Iter` and `IterMut` iterators +macro_rules! iterator { + ( + struct $name:ident -> $ptr:ty, + $elem:ty, + $raw_mut:tt, + {$( $mut_:tt )?}, + {$($extra:tt)*} + ) => { + // Returns the first element and moves the start of the iterator forwards by 1. + // Greatly improves performance compared to an inlined function. The iterator + // must not be empty. + macro_rules! next_unchecked { + ($self: ident) => {& $( $mut_ )? *$self.post_inc_start(1)} + } + + // Returns the last element and moves the end of the iterator backwards by 1. + // Greatly improves performance compared to an inlined function. The iterator + // must not be empty. + macro_rules! next_back_unchecked { + ($self: ident) => {& $( $mut_ )? *$self.pre_dec_end(1)} + } + + // Shrinks the iterator when T is a ZST, by moving the end of the iterator + // backwards by `n`. `n` must not exceed `self.len()`. + macro_rules! zst_shrink { + ($self: ident, $n: ident) => { + $self.end = ($self.end as * $raw_mut u8).wrapping_offset(-$n) as * $raw_mut T; + } + } + + impl<'a, T> $name<'a, T> { + // Helper function for creating a slice from the iterator. + #[inline(always)] + fn make_slice(&self) -> &'a [T] { + // SAFETY: the iterator was created from a slice with pointer + // `self.ptr` and length `len!(self)`. This guarantees that all + // the prerequisites for `from_raw_parts` are fulfilled. + unsafe { from_raw_parts(self.ptr.as_ptr(), len!(self)) } + } + + // Helper function for moving the start of the iterator forwards by `offset` elements, + // returning the old start. + // Unsafe because the offset must not exceed `self.len()`. + #[inline(always)] + unsafe fn post_inc_start(&mut self, offset: isize) -> * $raw_mut T { + if mem::size_of::() == 0 { + zst_shrink!(self, offset); + self.ptr.as_ptr() + } else { + let old = self.ptr.as_ptr(); + // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`, + // so this new pointer is inside `self` and thus guaranteed to be non-null. + self.ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().offset(offset)) }; + old + } + } + + // Helper function for moving the end of the iterator backwards by `offset` elements, + // returning the new end. + // Unsafe because the offset must not exceed `self.len()`. + #[inline(always)] + unsafe fn pre_dec_end(&mut self, offset: isize) -> * $raw_mut T { + if mem::size_of::() == 0 { + zst_shrink!(self, offset); + self.ptr.as_ptr() + } else { + // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`, + // which is guaranteed to not overflow an `isize`. Also, the resulting pointer + // is in bounds of `slice`, which fulfills the other requirements for `offset`. + self.end = unsafe { self.end.offset(-offset) }; + self.end + } + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl ExactSizeIterator for $name<'_, T> { + #[inline(always)] + fn len(&self) -> usize { + len!(self) + } + + #[inline(always)] + fn is_empty(&self) -> bool { + is_empty!(self) + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, T> Iterator for $name<'a, T> { + type Item = $elem; + + #[inline] + fn next(&mut self) -> Option<$elem> { + // could be implemented with slices, but this avoids bounds checks + + // SAFETY: `assume` calls are safe since a slice's start pointer + // must be non-null, and slices over non-ZSTs must also have a + // non-null end pointer. The call to `next_unchecked!` is safe + // since we check if the iterator is empty first. + unsafe { + assume(!self.ptr.as_ptr().is_null()); + if mem::size_of::() != 0 { + assume(!self.end.is_null()); + } + if is_empty!(self) { + None + } else { + Some(next_unchecked!(self)) + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let exact = len!(self); + (exact, Some(exact)) + } + + #[inline] + fn count(self) -> usize { + len!(self) + } + + #[inline] + fn nth(&mut self, n: usize) -> Option<$elem> { + if n >= len!(self) { + // This iterator is now empty. + if mem::size_of::() == 0 { + // We have to do it this way as `ptr` may never be 0, but `end` + // could be (due to wrapping). + self.end = self.ptr.as_ptr(); + } else { + // SAFETY: end can't be 0 if T isn't ZST because ptr isn't 0 and end >= ptr + unsafe { + self.ptr = NonNull::new_unchecked(self.end as *mut T); + } + } + return None; + } + // SAFETY: We are in bounds. `post_inc_start` does the right thing even for ZSTs. + unsafe { + self.post_inc_start(n as isize); + Some(next_unchecked!(self)) + } + } + + #[inline] + fn last(mut self) -> Option<$elem> { + self.next_back() + } + + // We override the default implementation, which uses `try_fold`, + // because this simple implementation generates less LLVM IR and is + // faster to compile. + #[inline] + fn for_each(mut self, mut f: F) + where + Self: Sized, + F: FnMut(Self::Item), + { + while let Some(x) = self.next() { + f(x); + } + } + + // We override the default implementation, which uses `try_fold`, + // because this simple implementation generates less LLVM IR and is + // faster to compile. + #[inline] + fn all(&mut self, mut f: F) -> bool + where + Self: Sized, + F: FnMut(Self::Item) -> bool, + { + while let Some(x) = self.next() { + if !f(x) { + return false; + } + } + true + } + + // We override the default implementation, which uses `try_fold`, + // because this simple implementation generates less LLVM IR and is + // faster to compile. + #[inline] + fn any(&mut self, mut f: F) -> bool + where + Self: Sized, + F: FnMut(Self::Item) -> bool, + { + while let Some(x) = self.next() { + if f(x) { + return true; + } + } + false + } + + // We override the default implementation, which uses `try_fold`, + // because this simple implementation generates less LLVM IR and is + // faster to compile. + #[inline] + fn find

(&mut self, mut predicate: P) -> Option + where + Self: Sized, + P: FnMut(&Self::Item) -> bool, + { + while let Some(x) = self.next() { + if predicate(&x) { + return Some(x); + } + } + None + } + + // We override the default implementation, which uses `try_fold`, + // because this simple implementation generates less LLVM IR and is + // faster to compile. + #[inline] + fn find_map(&mut self, mut f: F) -> Option + where + Self: Sized, + F: FnMut(Self::Item) -> Option, + { + while let Some(x) = self.next() { + if let Some(y) = f(x) { + return Some(y); + } + } + None + } + + // We override the default implementation, which uses `try_fold`, + // because this simple implementation generates less LLVM IR and is + // faster to compile. Also, the `assume` avoids a bounds check. + #[inline] + #[rustc_inherit_overflow_checks] + fn position

(&mut self, mut predicate: P) -> Option where + Self: Sized, + P: FnMut(Self::Item) -> bool, + { + let n = len!(self); + let mut i = 0; + while let Some(x) = self.next() { + if predicate(x) { + // SAFETY: we are guaranteed to be in bounds by the loop invariant: + // when `i >= n`, `self.next()` returns `None` and the loop breaks. + unsafe { assume(i < n) }; + return Some(i); + } + i += 1; + } + None + } + + // We override the default implementation, which uses `try_fold`, + // because this simple implementation generates less LLVM IR and is + // faster to compile. Also, the `assume` avoids a bounds check. + #[inline] + fn rposition

(&mut self, mut predicate: P) -> Option where + P: FnMut(Self::Item) -> bool, + Self: Sized + ExactSizeIterator + DoubleEndedIterator + { + let n = len!(self); + let mut i = n; + while let Some(x) = self.next_back() { + i -= 1; + if predicate(x) { + // SAFETY: `i` must be lower than `n` since it starts at `n` + // and is only decreasing. + unsafe { assume(i < n) }; + return Some(i); + } + } + None + } + + #[doc(hidden)] + unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + // SAFETY: the caller must guarantee that `i` is in bounds of + // the underlying slice, so `i` cannot overflow an `isize`, and + // the returned references is guaranteed to refer to an element + // of the slice and thus guaranteed to be valid. + // + // Also note that the caller also guarantees that we're never + // called with the same index again, and that no other methods + // that will access this subslice are called, so it is valid + // for the returned reference to be mutable in the case of + // `IterMut` + unsafe { & $( $mut_ )? * self.ptr.as_ptr().add(idx) } + } + + $($extra)* + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, T> DoubleEndedIterator for $name<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<$elem> { + // could be implemented with slices, but this avoids bounds checks + + // SAFETY: `assume` calls are safe since a slice's start pointer must be non-null, + // and slices over non-ZSTs must also have a non-null end pointer. + // The call to `next_back_unchecked!` is safe since we check if the iterator is + // empty first. + unsafe { + assume(!self.ptr.as_ptr().is_null()); + if mem::size_of::() != 0 { + assume(!self.end.is_null()); + } + if is_empty!(self) { + None + } else { + Some(next_back_unchecked!(self)) + } + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option<$elem> { + if n >= len!(self) { + // This iterator is now empty. + self.end = self.ptr.as_ptr(); + return None; + } + // SAFETY: We are in bounds. `pre_dec_end` does the right thing even for ZSTs. + unsafe { + self.pre_dec_end(n as isize); + Some(next_back_unchecked!(self)) + } + } + } + + #[stable(feature = "fused", since = "1.26.0")] + impl FusedIterator for $name<'_, T> {} + + #[unstable(feature = "trusted_len", issue = "37572")] + unsafe impl TrustedLen for $name<'_, T> {} + } +} + +macro_rules! forward_iterator { + ($name:ident: $elem:ident, $iter_of:ty) => { + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, $elem, P> Iterator for $name<'a, $elem, P> + where + P: FnMut(&T) -> bool, + { + type Item = $iter_of; + + #[inline] + fn next(&mut self) -> Option<$iter_of> { + self.inner.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + } + + #[stable(feature = "fused", since = "1.26.0")] + impl<'a, $elem, P> FusedIterator for $name<'a, $elem, P> where P: FnMut(&T) -> bool {} + }; +} diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 3ff33fab431c4..bbaf0fae05afb 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -24,10 +24,9 @@ use crate::cmp; use crate::cmp::Ordering::{self, Equal, Greater, Less}; -use crate::fmt; -use crate::intrinsics::{assume, exact_div, is_aligned_and_not_null, unchecked_sub}; +use crate::intrinsics::{assume, is_aligned_and_not_null}; use crate::iter::*; -use crate::marker::{self, Copy, Send, Sized, Sync}; +use crate::marker::{self, Copy, Sized}; use crate::mem; use crate::ops::{self, Bound, FnMut, Range, RangeBounds}; use crate::option::Option; @@ -44,9 +43,34 @@ use crate::result::Result::{Err, Ok}; /// Pure rust memchr implementation, taken from rust-memchr pub mod memchr; +mod iter; mod rotate; mod sort; +use iter::GenericSplitN; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use iter::{Chunks, ChunksMut, Windows}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use iter::{Iter, IterMut}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use iter::{RSplitN, RSplitNMut, Split, SplitMut, SplitN, SplitNMut}; + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +pub use iter::{RSplit, RSplitMut}; + +#[stable(feature = "chunks_exact", since = "1.31.0")] +pub use iter::{ChunksExact, ChunksExactMut}; + +#[stable(feature = "rchunks", since = "1.31.0")] +pub use iter::{RChunks, RChunksExact, RChunksExactMut, RChunksMut}; + +#[unstable(feature = "array_chunks", issue = "74985")] +pub use iter::{ArrayChunks, ArrayChunksMut}; + +#[unstable(feature = "split_inclusive", issue = "72360")] +pub use iter::{SplitInclusive, SplitInclusiveMut}; + // // Extension traits // @@ -3783,3129 +3807,255 @@ impl Default for &mut [T] { } // -// Iterators +// Free functions // +/// Forms a slice from a pointer and a length. +/// +/// The `len` argument is the number of **elements**, not the number of bytes. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `data` must be [valid] for reads for `len * mem::size_of::()` many bytes, +/// and it must be properly aligned. This means in particular: +/// +/// * The entire memory range of this slice must be contained within a single allocated object! +/// Slices can never span across multiple allocated objects. See [below](#incorrect-usage) +/// for an example incorrectly not taking this into account. +/// * `data` must be non-null and aligned even for zero-length slices. One +/// reason for this is that enum layout optimizations may rely on references +/// (including slices of any length) being aligned and non-null to distinguish +/// them from other data. You can obtain a pointer that is usable as `data` +/// for zero-length slices using [`NonNull::dangling()`]. +/// +/// * `data` must point to `len` consecutive properly initialized values of type `T`. +/// +/// * The memory referenced by the returned slice must not be mutated for the duration +/// of lifetime `'a`, except inside an `UnsafeCell`. +/// +/// * The total size `len * mem::size_of::()` of the slice must be no larger than `isize::MAX`. +/// See the safety documentation of [`pointer::offset`]. +/// +/// # Caveat +/// +/// The lifetime for the returned slice is inferred from its usage. To +/// prevent accidental misuse, it's suggested to tie the lifetime to whichever +/// source lifetime is safe in the context, such as by providing a helper +/// function taking the lifetime of a host value for the slice, or by explicit +/// annotation. +/// +/// # Examples +/// +/// ``` +/// use std::slice; +/// +/// // manifest a slice for a single element +/// let x = 42; +/// let ptr = &x as *const _; +/// let slice = unsafe { slice::from_raw_parts(ptr, 1) }; +/// assert_eq!(slice[0], 42); +/// ``` +/// +/// ### Incorrect usage +/// +/// The following `join_slices` function is **unsound** ⚠️ +/// +/// ```rust,no_run +/// use std::slice; +/// +/// fn join_slices<'a, T>(fst: &'a [T], snd: &'a [T]) -> &'a [T] { +/// let fst_end = fst.as_ptr().wrapping_add(fst.len()); +/// let snd_start = snd.as_ptr(); +/// assert_eq!(fst_end, snd_start, "Slices must be contiguous!"); +/// unsafe { +/// // The assertion above ensures `fst` and `snd` are contiguous, but they might +/// // still be contained within _different allocated objects_, in which case +/// // creating this slice is undefined behavior. +/// slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len()) +/// } +/// } +/// +/// fn main() { +/// // `a` and `b` are different allocated objects... +/// let a = 42; +/// let b = 27; +/// // ... which may nevertheless be laid out contiguously in memory: | a | b | +/// let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB +/// } +/// ``` +/// +/// [valid]: ptr#safety +/// [`NonNull::dangling()`]: ptr::NonNull::dangling +/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset +#[inline] #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a [T] { - type Item = &'a T; - type IntoIter = Iter<'a, T>; - - fn into_iter(self) -> Iter<'a, T> { - self.iter() - } +pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { + debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice"); + debug_assert!( + mem::size_of::().saturating_mul(len) <= isize::MAX as usize, + "attempt to create slice covering at least half the address space" + ); + // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. + unsafe { &*ptr::slice_from_raw_parts(data, len) } } +/// Performs the same functionality as [`from_raw_parts`], except that a +/// mutable slice is returned. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `data` must be [valid] for boths reads and writes for `len * mem::size_of::()` many bytes, +/// and it must be properly aligned. This means in particular: +/// +/// * The entire memory range of this slice must be contained within a single allocated object! +/// Slices can never span across multiple allocated objects. +/// * `data` must be non-null and aligned even for zero-length slices. One +/// reason for this is that enum layout optimizations may rely on references +/// (including slices of any length) being aligned and non-null to distinguish +/// them from other data. You can obtain a pointer that is usable as `data` +/// for zero-length slices using [`NonNull::dangling()`]. +/// +/// * `data` must point to `len` consecutive properly initialized values of type `T`. +/// +/// * The memory referenced by the returned slice must not be accessed through any other pointer +/// (not derived from the return value) for the duration of lifetime `'a`. +/// Both read and write accesses are forbidden. +/// +/// * The total size `len * mem::size_of::()` of the slice must be no larger than `isize::MAX`. +/// See the safety documentation of [`pointer::offset`]. +/// +/// [valid]: ptr#safety +/// [`NonNull::dangling()`]: ptr::NonNull::dangling +/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset +#[inline] #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a mut [T] { - type Item = &'a mut T; - type IntoIter = IterMut<'a, T>; +pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] { + debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice"); + debug_assert!( + mem::size_of::().saturating_mul(len) <= isize::MAX as usize, + "attempt to create slice covering at least half the address space" + ); + // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. + unsafe { &mut *ptr::slice_from_raw_parts_mut(data, len) } +} - fn into_iter(self) -> IterMut<'a, T> { - self.iter_mut() - } +/// Converts a reference to T into a slice of length 1 (without copying). +#[stable(feature = "from_ref", since = "1.28.0")] +pub fn from_ref(s: &T) -> &[T] { + // SAFETY: a reference is guaranteed to be valid for reads. The returned + // reference cannot be mutated as it is an immutable reference. + // `mem::size_of::()` cannot be larger than `isize::MAX`. + // Thus the call to `from_raw_parts` is safe. + unsafe { from_raw_parts(s, 1) } } -// Macro helper functions -#[inline(always)] -fn size_from_ptr(_: *const T) -> usize { - mem::size_of::() +/// Converts a reference to T into a slice of length 1 (without copying). +#[stable(feature = "from_ref", since = "1.28.0")] +pub fn from_mut(s: &mut T) -> &mut [T] { + // SAFETY: a mutable reference is guaranteed to be valid for writes. + // The reference cannot be accessed by another pointer as it is an mutable reference. + // `mem::size_of::()` cannot be larger than `isize::MAX`. + // Thus the call to `from_raw_parts_mut` is safe. + unsafe { from_raw_parts_mut(s, 1) } } -// Inlining is_empty and len makes a huge performance difference -macro_rules! is_empty { - // The way we encode the length of a ZST iterator, this works both for ZST - // and non-ZST. - ($self: ident) => { - $self.ptr.as_ptr() as *const T == $self.end - }; +// This function is public only because there is no other way to unit test heapsort. +#[unstable(feature = "sort_internals", reason = "internal to sort module", issue = "none")] +#[doc(hidden)] +pub fn heapsort(v: &mut [T], mut is_less: F) +where + F: FnMut(&T, &T) -> bool, +{ + sort::heapsort(v, &mut is_less); } -// To get rid of some bounds checks (see `position`), we compute the length in a somewhat -// unexpected way. (Tested by `codegen/slice-position-bounds-check`.) -macro_rules! len { - ($self: ident) => {{ - #![allow(unused_unsafe)] // we're sometimes used within an unsafe block +// +// Comparison traits +// - let start = $self.ptr; - let size = size_from_ptr(start.as_ptr()); - if size == 0 { - // This _cannot_ use `unchecked_sub` because we depend on wrapping - // to represent the length of long ZST slice iterators. - ($self.end as usize).wrapping_sub(start.as_ptr() as usize) - } else { - // We know that `start <= end`, so can do better than `offset_from`, - // which needs to deal in signed. By setting appropriate flags here - // we can tell LLVM this, which helps it remove bounds checks. - // SAFETY: By the type invariant, `start <= end` - let diff = unsafe { unchecked_sub($self.end as usize, start.as_ptr() as usize) }; - // By also telling LLVM that the pointers are apart by an exact - // multiple of the type size, it can optimize `len() == 0` down to - // `start == end` instead of `(end - start) < size`. - // SAFETY: By the type invariant, the pointers are aligned so the - // distance between them must be a multiple of pointee size - unsafe { exact_div(diff, size) } - } - }}; +extern "C" { + /// Calls implementation provided memcmp. + /// + /// Interprets the data as u8. + /// + /// Returns 0 for equal, < 0 for less than and > 0 for greater + /// than. + // FIXME(#32610): Return type should be c_int + fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32; } -// The shared definition of the `Iter` and `IterMut` iterators -macro_rules! iterator { - ( - struct $name:ident -> $ptr:ty, - $elem:ty, - $raw_mut:tt, - {$( $mut_:tt )?}, - {$($extra:tt)*} - ) => { - // Returns the first element and moves the start of the iterator forwards by 1. - // Greatly improves performance compared to an inlined function. The iterator - // must not be empty. - macro_rules! next_unchecked { - ($self: ident) => {& $( $mut_ )? *$self.post_inc_start(1)} - } +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq<[B]> for [A] +where + A: PartialEq, +{ + fn eq(&self, other: &[B]) -> bool { + SlicePartialEq::equal(self, other) + } - // Returns the last element and moves the end of the iterator backwards by 1. - // Greatly improves performance compared to an inlined function. The iterator - // must not be empty. - macro_rules! next_back_unchecked { - ($self: ident) => {& $( $mut_ )? *$self.pre_dec_end(1)} - } + fn ne(&self, other: &[B]) -> bool { + SlicePartialEq::not_equal(self, other) + } +} - // Shrinks the iterator when T is a ZST, by moving the end of the iterator - // backwards by `n`. `n` must not exceed `self.len()`. - macro_rules! zst_shrink { - ($self: ident, $n: ident) => { - $self.end = ($self.end as * $raw_mut u8).wrapping_offset(-$n) as * $raw_mut T; - } - } +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for [T] {} - impl<'a, T> $name<'a, T> { - // Helper function for creating a slice from the iterator. - #[inline(always)] - fn make_slice(&self) -> &'a [T] { - // SAFETY: the iterator was created from a slice with pointer - // `self.ptr` and length `len!(self)`. This guarantees that all - // the prerequisites for `from_raw_parts` are fulfilled. - unsafe { from_raw_parts(self.ptr.as_ptr(), len!(self)) } - } +/// Implements comparison of vectors lexicographically. +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for [T] { + fn cmp(&self, other: &[T]) -> Ordering { + SliceOrd::compare(self, other) + } +} - // Helper function for moving the start of the iterator forwards by `offset` elements, - // returning the old start. - // Unsafe because the offset must not exceed `self.len()`. - #[inline(always)] - unsafe fn post_inc_start(&mut self, offset: isize) -> * $raw_mut T { - if mem::size_of::() == 0 { - zst_shrink!(self, offset); - self.ptr.as_ptr() - } else { - let old = self.ptr.as_ptr(); - // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`, - // so this new pointer is inside `self` and thus guaranteed to be non-null. - self.ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().offset(offset)) }; - old - } - } +/// Implements comparison of vectors lexicographically. +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for [T] { + fn partial_cmp(&self, other: &[T]) -> Option { + SlicePartialOrd::partial_compare(self, other) + } +} - // Helper function for moving the end of the iterator backwards by `offset` elements, - // returning the new end. - // Unsafe because the offset must not exceed `self.len()`. - #[inline(always)] - unsafe fn pre_dec_end(&mut self, offset: isize) -> * $raw_mut T { - if mem::size_of::() == 0 { - zst_shrink!(self, offset); - self.ptr.as_ptr() - } else { - // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`, - // which is guaranteed to not overflow an `isize`. Also, the resulting pointer - // is in bounds of `slice`, which fulfills the other requirements for `offset`. - self.end = unsafe { self.end.offset(-offset) }; - self.end - } - } - } +#[doc(hidden)] +// intermediate trait for specialization of slice's PartialEq +trait SlicePartialEq { + fn equal(&self, other: &[B]) -> bool; - #[stable(feature = "rust1", since = "1.0.0")] - impl ExactSizeIterator for $name<'_, T> { - #[inline(always)] - fn len(&self) -> usize { - len!(self) - } + fn not_equal(&self, other: &[B]) -> bool { + !self.equal(other) + } +} - #[inline(always)] - fn is_empty(&self) -> bool { - is_empty!(self) - } +// Generic slice equality +impl SlicePartialEq for [A] +where + A: PartialEq, +{ + default fn equal(&self, other: &[B]) -> bool { + if self.len() != other.len() { + return false; } - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, T> Iterator for $name<'a, T> { - type Item = $elem; + self.iter().zip(other.iter()).all(|(x, y)| x == y) + } +} - #[inline] - fn next(&mut self) -> Option<$elem> { - // could be implemented with slices, but this avoids bounds checks - - // SAFETY: `assume` calls are safe since a slice's start pointer - // must be non-null, and slices over non-ZSTs must also have a - // non-null end pointer. The call to `next_unchecked!` is safe - // since we check if the iterator is empty first. - unsafe { - assume(!self.ptr.as_ptr().is_null()); - if mem::size_of::() != 0 { - assume(!self.end.is_null()); - } - if is_empty!(self) { - None - } else { - Some(next_unchecked!(self)) - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let exact = len!(self); - (exact, Some(exact)) - } - - #[inline] - fn count(self) -> usize { - len!(self) - } - - #[inline] - fn nth(&mut self, n: usize) -> Option<$elem> { - if n >= len!(self) { - // This iterator is now empty. - if mem::size_of::() == 0 { - // We have to do it this way as `ptr` may never be 0, but `end` - // could be (due to wrapping). - self.end = self.ptr.as_ptr(); - } else { - // SAFETY: end can't be 0 if T isn't ZST because ptr isn't 0 and end >= ptr - unsafe { - self.ptr = NonNull::new_unchecked(self.end as *mut T); - } - } - return None; - } - // SAFETY: We are in bounds. `post_inc_start` does the right thing even for ZSTs. - unsafe { - self.post_inc_start(n as isize); - Some(next_unchecked!(self)) - } - } - - #[inline] - fn last(mut self) -> Option<$elem> { - self.next_back() - } - - // We override the default implementation, which uses `try_fold`, - // because this simple implementation generates less LLVM IR and is - // faster to compile. - #[inline] - fn for_each(mut self, mut f: F) - where - Self: Sized, - F: FnMut(Self::Item), - { - while let Some(x) = self.next() { - f(x); - } - } - - // We override the default implementation, which uses `try_fold`, - // because this simple implementation generates less LLVM IR and is - // faster to compile. - #[inline] - fn all(&mut self, mut f: F) -> bool - where - Self: Sized, - F: FnMut(Self::Item) -> bool, - { - while let Some(x) = self.next() { - if !f(x) { - return false; - } - } - true - } - - // We override the default implementation, which uses `try_fold`, - // because this simple implementation generates less LLVM IR and is - // faster to compile. - #[inline] - fn any(&mut self, mut f: F) -> bool - where - Self: Sized, - F: FnMut(Self::Item) -> bool, - { - while let Some(x) = self.next() { - if f(x) { - return true; - } - } - false - } - - // We override the default implementation, which uses `try_fold`, - // because this simple implementation generates less LLVM IR and is - // faster to compile. - #[inline] - fn find

(&mut self, mut predicate: P) -> Option - where - Self: Sized, - P: FnMut(&Self::Item) -> bool, - { - while let Some(x) = self.next() { - if predicate(&x) { - return Some(x); - } - } - None - } - - // We override the default implementation, which uses `try_fold`, - // because this simple implementation generates less LLVM IR and is - // faster to compile. - #[inline] - fn find_map(&mut self, mut f: F) -> Option - where - Self: Sized, - F: FnMut(Self::Item) -> Option, - { - while let Some(x) = self.next() { - if let Some(y) = f(x) { - return Some(y); - } - } - None - } - - // We override the default implementation, which uses `try_fold`, - // because this simple implementation generates less LLVM IR and is - // faster to compile. Also, the `assume` avoids a bounds check. - #[inline] - #[rustc_inherit_overflow_checks] - fn position

(&mut self, mut predicate: P) -> Option where - Self: Sized, - P: FnMut(Self::Item) -> bool, - { - let n = len!(self); - let mut i = 0; - while let Some(x) = self.next() { - if predicate(x) { - // SAFETY: we are guaranteed to be in bounds by the loop invariant: - // when `i >= n`, `self.next()` returns `None` and the loop breaks. - unsafe { assume(i < n) }; - return Some(i); - } - i += 1; - } - None - } - - // We override the default implementation, which uses `try_fold`, - // because this simple implementation generates less LLVM IR and is - // faster to compile. Also, the `assume` avoids a bounds check. - #[inline] - fn rposition

+ + diff --git a/src/test/mir-opt/spanview_statement.main.mir_map.0.html.mir b/src/test/mir-opt/spanview_statement.main.mir_map.0.html.mir new file mode 100644 index 0000000000000..072d22473a991 --- /dev/null +++ b/src/test/mir-opt/spanview_statement.main.mir_map.0.html.mir @@ -0,0 +1,67 @@ + + + + coverage_of_if_else - Code Regions + + + +
fn main() 0[0]⦊{}⦉0[0]0:Goto⦊⦉0:Goto2:Return⦊⦉2:Return
+ + diff --git a/src/test/mir-opt/spanview_terminator.main.mir_map.0.html.mir b/src/test/mir-opt/spanview_terminator.main.mir_map.0.html.mir new file mode 100644 index 0000000000000..e023f0f8aeac9 --- /dev/null +++ b/src/test/mir-opt/spanview_terminator.main.mir_map.0.html.mir @@ -0,0 +1,66 @@ + + + + coverage_of_if_else - Code Regions + + + +
fn main() {}0:Goto⦊⦉0:Goto2:Return⦊⦉2:Return
+ + diff --git a/src/test/mir-opt/unusual_item_types.E-V-{{constant}}.mir_map.0.mir.64bit b/src/test/mir-opt/unusual_item_types.E-V-{{constant}}.mir_map.0.64bit.mir similarity index 100% rename from src/test/mir-opt/unusual_item_types.E-V-{{constant}}.mir_map.0.mir.64bit rename to src/test/mir-opt/unusual_item_types.E-V-{{constant}}.mir_map.0.64bit.mir diff --git a/src/test/mir-opt/unusual_item_types.Test-X-{{constructor}}.mir_map.0.mir.64bit b/src/test/mir-opt/unusual_item_types.Test-X-{{constructor}}.mir_map.0.64bit.mir similarity index 100% rename from src/test/mir-opt/unusual_item_types.Test-X-{{constructor}}.mir_map.0.mir.64bit rename to src/test/mir-opt/unusual_item_types.Test-X-{{constructor}}.mir_map.0.64bit.mir diff --git a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir.64bit b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir similarity index 100% rename from src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir.64bit rename to src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir diff --git a/src/test/mir-opt/unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.mir.64bit b/src/test/mir-opt/unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir similarity index 100% rename from src/test/mir-opt/unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.mir.64bit rename to src/test/mir-opt/unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.64bit b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff similarity index 100% rename from src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.64bit rename to src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.64bit b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir similarity index 100% rename from src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.64bit rename to src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir From 8e9ad31178064993ed2f59719b873ef9d9a3a0de Mon Sep 17 00:00:00 2001 From: Denis Vasilik Date: Thu, 17 Sep 2020 22:43:13 +0200 Subject: [PATCH 0557/1052] Use intra-doc links --- library/core/src/task/wake.rs | 29 +++-------------------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 92057209d8bfd..668a028a3f1ea 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -8,10 +8,8 @@ use crate::marker::{PhantomData, Unpin}; /// /// [vtable]: https://en.wikipedia.org/wiki/Virtual_method_table /// -/// It consists of a data pointer and a [virtual function pointer table (vtable)][vtable] that -/// customizes the behavior of the `RawWaker`. -/// -/// [`Waker`]: struct.Waker.html +/// It consists of a data pointer and a [virtual function pointer table (vtable)][vtable] +/// that customizes the behavior of the `RawWaker`. #[derive(PartialEq, Debug)] #[stable(feature = "futures_api", since = "1.36.0")] pub struct RawWaker { @@ -52,12 +50,10 @@ impl RawWaker { /// The pointer passed to all functions inside the vtable is the `data` pointer /// from the enclosing [`RawWaker`] object. /// -/// The functions inside this struct are only intended be called on the `data` +/// The functions inside this struct are only intended to be called on the `data` /// pointer of a properly constructed [`RawWaker`] object from inside the /// [`RawWaker`] implementation. Calling one of the contained functions using /// any other `data` pointer will cause undefined behavior. -/// -/// [`RawWaker`]: struct.RawWaker.html #[stable(feature = "futures_api", since = "1.36.0")] #[derive(PartialEq, Copy, Clone, Debug)] pub struct RawWakerVTable { @@ -68,9 +64,6 @@ pub struct RawWakerVTable { /// required for this additional instance of a [`RawWaker`] and associated /// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup /// of the same task that would have been awoken by the original [`RawWaker`]. - /// - /// [`Waker`]: struct.Waker.html - /// [`RawWaker`]: struct.RawWaker.html clone: unsafe fn(*const ()) -> RawWaker, /// This function will be called when `wake` is called on the [`Waker`]. @@ -79,9 +72,6 @@ pub struct RawWakerVTable { /// The implementation of this function must make sure to release any /// resources that are associated with this instance of a [`RawWaker`] and /// associated task. - /// - /// [`Waker`]: struct.Waker.html - /// [`RawWaker`]: struct.RawWaker.html wake: unsafe fn(*const ()), /// This function will be called when `wake_by_ref` is called on the [`Waker`]. @@ -89,9 +79,6 @@ pub struct RawWakerVTable { /// /// This function is similar to `wake`, but must not consume the provided data /// pointer. - /// - /// [`Waker`]: struct.Waker.html - /// [`RawWaker`]: struct.RawWaker.html wake_by_ref: unsafe fn(*const ()), /// This function gets called when a [`RawWaker`] gets dropped. @@ -99,8 +86,6 @@ pub struct RawWakerVTable { /// The implementation of this function must make sure to release any /// resources that are associated with this instance of a [`RawWaker`] and /// associated task. - /// - /// [`RawWaker`]: struct.RawWaker.html drop: unsafe fn(*const ()), } @@ -142,9 +127,6 @@ impl RawWakerVTable { /// The implementation of this function must make sure to release any /// resources that are associated with this instance of a [`RawWaker`] and /// associated task. - /// - /// [`Waker`]: struct.Waker.html - /// [`RawWaker`]: struct.RawWaker.html #[rustc_promotable] #[stable(feature = "futures_api", since = "1.36.0")] // `rustc_allow_const_fn_ptr` is a hack that should not be used anywhere else @@ -208,8 +190,6 @@ impl fmt::Debug for Context<'_> { /// executor-specific wakeup behavior. /// /// Implements [`Clone`], [`Send`], and [`Sync`]. -/// -/// [`RawWaker`]: struct.RawWaker.html #[repr(transparent)] #[stable(feature = "futures_api", since = "1.36.0")] pub struct Waker { @@ -275,9 +255,6 @@ impl Waker { /// The behavior of the returned `Waker` is undefined if the contract defined /// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld. /// Therefore this method is unsafe. - /// - /// [`RawWaker`]: struct.RawWaker.html - /// [`RawWakerVTable`]: struct.RawWakerVTable.html #[inline] #[stable(feature = "futures_api", since = "1.36.0")] pub unsafe fn from_raw(waker: RawWaker) -> Waker { From 3c7593e69ffaf3362a598f1c359829387365bd98 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Thu, 17 Sep 2020 21:49:21 +0100 Subject: [PATCH 0558/1052] Rename 32 bit mir files to be more tool friendly See #75746 --- ...is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir} | 0 ....diff.32bit => combine_array_len.norm2.InstCombine.32bit.diff} | 0 ....mir.32bit => const_allocation.main.ConstProp.after.32bit.mir} | 0 ...mir.32bit => const_allocation2.main.ConstProp.after.32bit.mir} | 0 ...mir.32bit => const_allocation3.main.ConstProp.after.32bit.mir} | 0 ...ConstProp.diff.32bit => array_index.main.ConstProp.32bit.diff} | 0 ...bit => bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff} | 0 ...onstProp.diff.32bit => discriminant.main.ConstProp.32bit.diff} | 0 ...rop.diff.32bit => large_array_index.main.ConstProp.32bit.diff} | 0 ...ff.32bit => optimizes_into_variable.main.ConstProp.32bit.diff} | 0 ...> optimizes_into_variable.main.SimplifyLocals.after.32bit.mir} | 0 ...main.ConstProp.diff.32bit => repeat.main.ConstProp.32bit.diff} | 0 ...n.ConstProp.diff.32bit => slice_len.main.ConstProp.32bit.diff} | 0 ...ne.diff.32bit => inline_into_box_place.main.Inline.32bit.diff} | 0 ...mpl}}-{{constant}}.SimplifyCfg-promote-consts.after.32bit.mir} | 0 ...ar.mir_map.0.mir.32bit => issue_72181.bar.mir_map.0.32bit.mir} | 0 ...oo.mir_map.0.mir.32bit => issue_72181.foo.mir_map.0.32bit.mir} | 0 ...n.mir_map.0.mir.32bit => issue_72181.main.mir_map.0.32bit.mir} | 0 ...eCodegen.diff.32bit => issue_73223.main.PreCodegen.32bit.diff} | 0 ...diff.32bit => issue_73223.main.SimplifyArmIdentity.32bit.diff} | 0 ...ches_reduce_branches.bar.MatchBranchSimplification.32bit.diff} | 0 ...ches_reduce_branches.foo.MatchBranchSimplification.32bit.diff} | 0 ...ches_u8.exhaustive_match.MatchBranchSimplification.32bit.diff} | 0 ...s_u8.exhaustive_match_i8.MatchBranchSimplification.32bit.diff} | 0 ...ll.0.mir.32bit => region_subtyping_basic.main.nll.0.32bit.mir} | 0 ...drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir} | 0 ...ap.0.mir.32bit => simple_match.match_bool.mir_map.0.32bit.mir} | 0 ... => simplify_arm_identity.main.SimplifyArmIdentity.32bit.diff} | 0 ...moves_unused_discriminant_reads.map.SimplifyLocals.32bit.diff} | 0 ...rop_in_place.[String].AddMovesForPackedDrops.before.32bit.mir} | 0 ...it => unusual_item_types.E-V-{{constant}}.mir_map.0.32bit.mir} | 0 ...unusual_item_types.Test-X-{{constructor}}.mir_map.0.32bit.mir} | 0 ...rop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir} | 0 ...l_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir} | 0 ...2bit => while_let_loops.change_loop_body.ConstProp.32bit.diff} | 0 ...> while_let_loops.change_loop_body.PreCodegen.after.32bit.mir} | 0 36 files changed, 0 insertions(+), 0 deletions(-) rename src/test/mir-opt/{array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.32bit => array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir} (100%) rename src/test/mir-opt/{combine_array_len.norm2.InstCombine.diff.32bit => combine_array_len.norm2.InstCombine.32bit.diff} (100%) rename src/test/mir-opt/{const_allocation.main.ConstProp.after.mir.32bit => const_allocation.main.ConstProp.after.32bit.mir} (100%) rename src/test/mir-opt/{const_allocation2.main.ConstProp.after.mir.32bit => const_allocation2.main.ConstProp.after.32bit.mir} (100%) rename src/test/mir-opt/{const_allocation3.main.ConstProp.after.mir.32bit => const_allocation3.main.ConstProp.after.32bit.mir} (100%) rename src/test/mir-opt/const_prop/{array_index.main.ConstProp.diff.32bit => array_index.main.ConstProp.32bit.diff} (100%) rename src/test/mir-opt/const_prop/{bad_op_unsafe_oob_for_slices.main.ConstProp.diff.32bit => bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff} (100%) rename src/test/mir-opt/const_prop/{discriminant.main.ConstProp.diff.32bit => discriminant.main.ConstProp.32bit.diff} (100%) rename src/test/mir-opt/const_prop/{large_array_index.main.ConstProp.diff.32bit => large_array_index.main.ConstProp.32bit.diff} (100%) rename src/test/mir-opt/const_prop/{optimizes_into_variable.main.ConstProp.diff.32bit => optimizes_into_variable.main.ConstProp.32bit.diff} (100%) rename src/test/mir-opt/const_prop/{optimizes_into_variable.main.SimplifyLocals.after.mir.32bit => optimizes_into_variable.main.SimplifyLocals.after.32bit.mir} (100%) rename src/test/mir-opt/const_prop/{repeat.main.ConstProp.diff.32bit => repeat.main.ConstProp.32bit.diff} (100%) rename src/test/mir-opt/const_prop/{slice_len.main.ConstProp.diff.32bit => slice_len.main.ConstProp.32bit.diff} (100%) rename src/test/mir-opt/inline/{inline_into_box_place.main.Inline.diff.32bit => inline_into_box_place.main.Inline.32bit.diff} (100%) rename src/test/mir-opt/{issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.32bit => issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.32bit.mir} (100%) rename src/test/mir-opt/{issue_72181.bar.mir_map.0.mir.32bit => issue_72181.bar.mir_map.0.32bit.mir} (100%) rename src/test/mir-opt/{issue_72181.foo.mir_map.0.mir.32bit => issue_72181.foo.mir_map.0.32bit.mir} (100%) rename src/test/mir-opt/{issue_72181.main.mir_map.0.mir.32bit => issue_72181.main.mir_map.0.32bit.mir} (100%) rename src/test/mir-opt/{issue_73223.main.PreCodegen.diff.32bit => issue_73223.main.PreCodegen.32bit.diff} (100%) rename src/test/mir-opt/{issue_73223.main.SimplifyArmIdentity.diff.32bit => issue_73223.main.SimplifyArmIdentity.32bit.diff} (100%) rename src/test/mir-opt/{matches_reduce_branches.bar.MatchBranchSimplification.diff.32bit => matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff} (100%) rename src/test/mir-opt/{matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit => matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff} (100%) rename src/test/mir-opt/{matches_u8.exhaustive_match.MatchBranchSimplification.diff.32bit => matches_u8.exhaustive_match.MatchBranchSimplification.32bit.diff} (100%) rename src/test/mir-opt/{matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.32bit => matches_u8.exhaustive_match_i8.MatchBranchSimplification.32bit.diff} (100%) rename src/test/mir-opt/nll/{region_subtyping_basic.main.nll.0.mir.32bit => region_subtyping_basic.main.nll.0.32bit.mir} (100%) rename src/test/mir-opt/{packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir.32bit => packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir} (100%) rename src/test/mir-opt/{simple_match.match_bool.mir_map.0.mir.32bit => simple_match.match_bool.mir_map.0.32bit.mir} (100%) rename src/test/mir-opt/{simplify_arm_identity.main.SimplifyArmIdentity.diff.32bit => simplify_arm_identity.main.SimplifyArmIdentity.32bit.diff} (100%) rename src/test/mir-opt/{simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.32bit => simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff} (100%) rename src/test/mir-opt/{slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir.32bit => slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.32bit.mir} (100%) rename src/test/mir-opt/{unusual_item_types.E-V-{{constant}}.mir_map.0.mir.32bit => unusual_item_types.E-V-{{constant}}.mir_map.0.32bit.mir} (100%) rename src/test/mir-opt/{unusual_item_types.Test-X-{{constructor}}.mir_map.0.mir.32bit => unusual_item_types.Test-X-{{constructor}}.mir_map.0.32bit.mir} (100%) rename src/test/mir-opt/{unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir.32bit => unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir} (100%) rename src/test/mir-opt/{unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.mir.32bit => unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir} (100%) rename src/test/mir-opt/{while_let_loops.change_loop_body.ConstProp.diff.32bit => while_let_loops.change_loop_body.ConstProp.32bit.diff} (100%) rename src/test/mir-opt/{while_let_loops.change_loop_body.PreCodegen.after.mir.32bit => while_let_loops.change_loop_body.PreCodegen.after.32bit.mir} (100%) diff --git a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.32bit b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir similarity index 100% rename from src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.32bit rename to src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir diff --git a/src/test/mir-opt/combine_array_len.norm2.InstCombine.diff.32bit b/src/test/mir-opt/combine_array_len.norm2.InstCombine.32bit.diff similarity index 100% rename from src/test/mir-opt/combine_array_len.norm2.InstCombine.diff.32bit rename to src/test/mir-opt/combine_array_len.norm2.InstCombine.32bit.diff diff --git a/src/test/mir-opt/const_allocation.main.ConstProp.after.mir.32bit b/src/test/mir-opt/const_allocation.main.ConstProp.after.32bit.mir similarity index 100% rename from src/test/mir-opt/const_allocation.main.ConstProp.after.mir.32bit rename to src/test/mir-opt/const_allocation.main.ConstProp.after.32bit.mir diff --git a/src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.32bit b/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir similarity index 100% rename from src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.32bit rename to src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir diff --git a/src/test/mir-opt/const_allocation3.main.ConstProp.after.mir.32bit b/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir similarity index 100% rename from src/test/mir-opt/const_allocation3.main.ConstProp.after.mir.32bit rename to src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir diff --git a/src/test/mir-opt/const_prop/array_index.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff similarity index 100% rename from src/test/mir-opt/const_prop/array_index.main.ConstProp.diff.32bit rename to src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff similarity index 100% rename from src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.diff.32bit rename to src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff diff --git a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff similarity index 100% rename from src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.32bit rename to src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff diff --git a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.diff similarity index 100% rename from src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.32bit rename to src/test/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.diff diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff similarity index 100% rename from src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.32bit rename to src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.mir.32bit b/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.32bit.mir similarity index 100% rename from src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.mir.32bit rename to src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.32bit.mir diff --git a/src/test/mir-opt/const_prop/repeat.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/repeat.main.ConstProp.32bit.diff similarity index 100% rename from src/test/mir-opt/const_prop/repeat.main.ConstProp.diff.32bit rename to src/test/mir-opt/const_prop/repeat.main.ConstProp.32bit.diff diff --git a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff similarity index 100% rename from src/test/mir-opt/const_prop/slice_len.main.ConstProp.diff.32bit rename to src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff.32bit b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff similarity index 100% rename from src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff.32bit rename to src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff diff --git a/src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.32bit b/src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.32bit.mir similarity index 100% rename from src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.32bit rename to src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.32bit.mir diff --git a/src/test/mir-opt/issue_72181.bar.mir_map.0.mir.32bit b/src/test/mir-opt/issue_72181.bar.mir_map.0.32bit.mir similarity index 100% rename from src/test/mir-opt/issue_72181.bar.mir_map.0.mir.32bit rename to src/test/mir-opt/issue_72181.bar.mir_map.0.32bit.mir diff --git a/src/test/mir-opt/issue_72181.foo.mir_map.0.mir.32bit b/src/test/mir-opt/issue_72181.foo.mir_map.0.32bit.mir similarity index 100% rename from src/test/mir-opt/issue_72181.foo.mir_map.0.mir.32bit rename to src/test/mir-opt/issue_72181.foo.mir_map.0.32bit.mir diff --git a/src/test/mir-opt/issue_72181.main.mir_map.0.mir.32bit b/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir similarity index 100% rename from src/test/mir-opt/issue_72181.main.mir_map.0.mir.32bit rename to src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.diff.32bit b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff similarity index 100% rename from src/test/mir-opt/issue_73223.main.PreCodegen.diff.32bit rename to src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.32bit b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff similarity index 100% rename from src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.32bit rename to src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.32bit b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff similarity index 100% rename from src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.32bit rename to src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff similarity index 100% rename from src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit rename to src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff diff --git a/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff.32bit b/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.32bit.diff similarity index 100% rename from src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff.32bit rename to src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.32bit.diff diff --git a/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.32bit b/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.32bit.diff similarity index 100% rename from src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.32bit rename to src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.32bit.diff diff --git a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.mir.32bit b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir similarity index 100% rename from src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.mir.32bit rename to src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir diff --git a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir.32bit b/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir similarity index 100% rename from src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir.32bit rename to src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir diff --git a/src/test/mir-opt/simple_match.match_bool.mir_map.0.mir.32bit b/src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir similarity index 100% rename from src/test/mir-opt/simple_match.match_bool.mir_map.0.mir.32bit rename to src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir diff --git a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.32bit b/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.32bit.diff similarity index 100% rename from src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.32bit rename to src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.32bit.diff diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.32bit b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff similarity index 100% rename from src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.32bit rename to src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff diff --git a/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir.32bit b/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.32bit.mir similarity index 100% rename from src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir.32bit rename to src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.32bit.mir diff --git a/src/test/mir-opt/unusual_item_types.E-V-{{constant}}.mir_map.0.mir.32bit b/src/test/mir-opt/unusual_item_types.E-V-{{constant}}.mir_map.0.32bit.mir similarity index 100% rename from src/test/mir-opt/unusual_item_types.E-V-{{constant}}.mir_map.0.mir.32bit rename to src/test/mir-opt/unusual_item_types.E-V-{{constant}}.mir_map.0.32bit.mir diff --git a/src/test/mir-opt/unusual_item_types.Test-X-{{constructor}}.mir_map.0.mir.32bit b/src/test/mir-opt/unusual_item_types.Test-X-{{constructor}}.mir_map.0.32bit.mir similarity index 100% rename from src/test/mir-opt/unusual_item_types.Test-X-{{constructor}}.mir_map.0.mir.32bit rename to src/test/mir-opt/unusual_item_types.Test-X-{{constructor}}.mir_map.0.32bit.mir diff --git a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir.32bit b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir similarity index 100% rename from src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir.32bit rename to src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir diff --git a/src/test/mir-opt/unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.mir.32bit b/src/test/mir-opt/unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir similarity index 100% rename from src/test/mir-opt/unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.mir.32bit rename to src/test/mir-opt/unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.32bit b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.32bit.diff similarity index 100% rename from src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.32bit rename to src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.32bit.diff diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.32bit b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir similarity index 100% rename from src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.32bit rename to src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir From ee1e9343b35c169a100654a511e21c47eb2cb0bc Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 18 Sep 2020 00:18:19 +0200 Subject: [PATCH 0559/1052] Distribute rustc sources as part of `rustc-dev` --- src/bootstrap/dist.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index cf73e570fa56f..debe6e36a9b2e 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -793,6 +793,18 @@ impl Step for RustcDev { let stamp = compile::librustc_stamp(builder, compiler_to_use, target); copy_target_libs(builder, target, &image, &stamp); + // Copy compiler sources. + let dst_src = image.join("lib/rustlib/rustc-src/rust"); + t!(fs::create_dir_all(&dst_src)); + + let src_files = ["Cargo.lock"]; + // This is the reduced set of paths which will become the rustc-dev component + // (essentially the compiler crates and all of their path dependencies). + copy_src_dirs(builder, &builder.src, &["compiler"], &[], &dst_src); + for file in src_files.iter() { + builder.copy(&builder.src.join(file), &dst_src.join(file)); + } + let mut cmd = rust_installer(builder); cmd.arg("generate") .arg("--product-name=Rust") From 735776d115e7e842a0c52f70a181ac9211003d55 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Thu, 17 Sep 2020 22:25:33 +0100 Subject: [PATCH 0560/1052] Fix --bless for mir-opt 32/64 bit file --- src/tools/compiletest/src/runtest.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 7fcbfe9bd0d5f..acad316d807a3 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -3156,12 +3156,12 @@ impl<'test> TestCx<'test> { if self.config.bless { for e in - glob(&format!("{}/{}.*.mir{}", test_dir.display(), test_crate, bit_width)).unwrap() + glob(&format!("{}/{}.*{}.mir", test_dir.display(), test_crate, bit_width)).unwrap() { std::fs::remove_file(e.unwrap()).unwrap(); } for e in - glob(&format!("{}/{}.*.diff{}", test_dir.display(), test_crate, bit_width)).unwrap() + glob(&format!("{}/{}.*{}.diff", test_dir.display(), test_crate, bit_width)).unwrap() { std::fs::remove_file(e.unwrap()).unwrap(); } @@ -3199,7 +3199,8 @@ impl<'test> TestCx<'test> { from_file = format!("{}.{}.mir", test_name, first_pass); to_file = Some(second_file); } else { - expected_file = format!("{}{}.mir", test_name.trim_end_matches(".mir"), bit_width); + expected_file = + format!("{}{}.mir", test_name.trim_end_matches(".mir"), bit_width); from_file = test_name.to_string(); assert!( test_names.next().is_none(), From 3323a261441e1d65cafa7f7d16929656ad6f28a7 Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi Date: Fri, 18 Sep 2020 01:17:10 +0800 Subject: [PATCH 0561/1052] Fixed some intra-docs links in library/core --- library/core/src/ascii.rs | 4 ---- library/core/src/option.rs | 2 -- library/core/src/str/mod.rs | 21 +++++---------------- library/core/src/str/pattern.rs | 2 +- 4 files changed, 6 insertions(+), 23 deletions(-) diff --git a/library/core/src/ascii.rs b/library/core/src/ascii.rs index e78dfd1ed4abf..a8a25f927163c 100644 --- a/library/core/src/ascii.rs +++ b/library/core/src/ascii.rs @@ -6,8 +6,6 @@ //! //! The [`escape_default`] function provides an iterator over the bytes of an //! escaped version of the character given. -//! -//! [`escape_default`]: fn.escape_default.html #![stable(feature = "core_ascii", since = "1.26.0")] @@ -20,8 +18,6 @@ use crate::str::from_utf8_unchecked; /// /// This `struct` is created by the [`escape_default`] function. See its /// documentation for more. -/// -/// [`escape_default`]: fn.escape_default.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] pub struct EscapeDefault { diff --git a/library/core/src/option.rs b/library/core/src/option.rs index dd7556758be7d..7e560d63fe23b 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1502,8 +1502,6 @@ unsafe impl
TrustedLen for IterMut<'_, A> {} /// The iterator yields one value if the [`Option`] is a [`Some`], otherwise none. /// /// This `struct` is created by the [`Option::into_iter`] function. -/// -/// [`Option::into_iter`]: enum.Option.html#method.into_iter #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index ab9afeb25e0ce..6dc14f9125fef 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -4,7 +4,7 @@ //! //! For more details, see the [`std::str`] module. //! -//! [`std::str`]: self +//! [`std::str`]: ../../std/str/index.html #![stable(feature = "rust1", since = "1.0.0")] @@ -84,9 +84,6 @@ pub trait FromStr: Sized { /// when the string is ill-formatted return an error specific to the /// inside [`Err`]. The error type is specific to implementation of the trait. /// - /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok - /// [`Err`]: ../../std/result/enum.Result.html#variant.Err - /// /// # Examples /// /// Basic usage with [`i32`][ithirtytwo], a type that implements `FromStr`: @@ -269,11 +266,9 @@ impl Utf8Error { /// /// If you are sure that the byte slice is valid UTF-8, and you don't want to /// incur the overhead of the validity check, there is an unsafe version of -/// this function, [`from_utf8_unchecked`][fromutf8u], which has the same +/// this function, [`from_utf8_unchecked`], which has the same /// behavior but skips the check. /// -/// [fromutf8u]: fn.from_utf8_unchecked.html -/// /// If you need a `String` instead of a `&str`, consider /// [`String::from_utf8`][string]. /// @@ -318,11 +313,9 @@ impl Utf8Error { /// assert!(str::from_utf8(&sparkle_heart).is_err()); /// ``` /// -/// See the docs for [`Utf8Error`][error] for more details on the kinds of +/// See the docs for [`Utf8Error`] for more details on the kinds of /// errors that can be returned. /// -/// [error]: struct.Utf8Error.html -/// /// A "stack allocated string": /// /// ``` @@ -371,10 +364,8 @@ pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { /// /// assert!(str::from_utf8_mut(&mut invalid).is_err()); /// ``` -/// See the docs for [`Utf8Error`][error] for more details on the kinds of +/// See the docs for [`Utf8Error`] for more details on the kinds of /// errors that can be returned. -/// -/// [error]: struct.Utf8Error.html #[stable(feature = "str_mut_extras", since = "1.20.0")] pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { run_utf8_validation(v)?; @@ -385,9 +376,7 @@ pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { /// Converts a slice of bytes to a string slice without checking /// that the string contains valid UTF-8. /// -/// See the safe version, [`from_utf8`][fromutf8], for more information. -/// -/// [fromutf8]: fn.from_utf8.html +/// See the safe version, [`from_utf8`], for more information. /// /// # Safety /// diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs index 1cc2de5b8756a..508c522e71aa2 100644 --- a/library/core/src/str/pattern.rs +++ b/library/core/src/str/pattern.rs @@ -28,7 +28,7 @@ //! assert_eq!(s.find(|c: char| c.is_ascii_punctuation()), Some(35)); //! ``` //! -//! [pattern-impls]: trait.Pattern.html#implementors +//! [pattern-impls]: Pattern#implementors #![unstable( feature = "pattern", From 878dfa67182ca52eb1c8b638cee5dad4e94b6398 Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi Date: Fri, 18 Sep 2020 07:50:22 +0800 Subject: [PATCH 0562/1052] Fixed intra-docs links in library/std/src/collections/hash/map.rs --- library/std/src/collections/hash/map.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 1a3a493fbb8f6..61d71d55d6593 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -1298,9 +1298,7 @@ pub struct RawEntryBuilderMut<'a, K: 'a, V: 'a, S: 'a> { /// This `enum` is constructed through the [`raw_entry_mut`] method on [`HashMap`], /// then calling one of the methods of that [`RawEntryBuilderMut`]. /// -/// [`Entry`]: enum.Entry.html /// [`raw_entry_mut`]: HashMap::raw_entry_mut -/// [`RawEntryBuilderMut`]: struct.RawEntryBuilderMut.html #[unstable(feature = "hash_raw_entry", issue = "56167")] pub enum RawEntryMut<'a, K: 'a, V: 'a, S: 'a> { /// An occupied entry. @@ -1705,8 +1703,6 @@ impl Debug for Entry<'_, K, V> { /// A view into an occupied entry in a `HashMap`. /// It is part of the [`Entry`] enum. -/// -/// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] pub struct OccupiedEntry<'a, K: 'a, V: 'a> { base: base::RustcOccupiedEntry<'a, K, V>, @@ -1721,8 +1717,6 @@ impl Debug for OccupiedEntry<'_, K, V> { /// A view into a vacant entry in a `HashMap`. /// It is part of the [`Entry`] enum. -/// -/// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] pub struct VacantEntry<'a, K: 'a, V: 'a> { base: base::RustcVacantEntry<'a, K, V>, From 2f3296192bb5be5fcb02975395052ee8c3b2bd68 Mon Sep 17 00:00:00 2001 From: Valerii Lashmanov Date: Tue, 15 Sep 2020 09:37:19 -0500 Subject: [PATCH 0563/1052] Only visit types once when walking the type tree This fixes #72408. Nested closures were resulting in exponential compilation time. As a performance optimization this change introduces MiniSet, which is a simple small storage optimized set. --- Cargo.lock | 1 + .../rustc_infer/src/infer/outlives/verify.rs | 40 +++++++--- compiler/rustc_middle/Cargo.toml | 1 + compiler/rustc_middle/src/ty/outlives.rs | 33 +++++--- compiler/rustc_middle/src/ty/walk.rs | 80 +++++++++++++++++-- ...issue-72408-nested-closures-exponential.rs | 59 ++++++++++++++ src/test/ui/issues/issue-22638.rs | 2 +- src/test/ui/issues/issue-22638.stderr | 12 ++- src/test/ui/type_length_limit.rs | 2 +- src/test/ui/type_length_limit.stderr | 2 +- 10 files changed, 193 insertions(+), 39 deletions(-) create mode 100644 src/test/ui/closures/issue-72408-nested-closures-exponential.rs diff --git a/Cargo.lock b/Cargo.lock index 9b5a4c24d25ed..05d3a9c56219c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3733,6 +3733,7 @@ dependencies = [ name = "rustc_middle" version = "0.0.0" dependencies = [ + "arrayvec", "bitflags", "chalk-ir", "measureme", diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index d6f1ca3cf9536..e06bfb5958086 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -3,6 +3,7 @@ use crate::infer::{GenericKind, VerifyBound}; use rustc_data_structures::captures::Captures; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; +use rustc_middle::ty::walk::MiniSet; use rustc_middle::ty::{self, Ty, TyCtxt}; /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a` @@ -31,16 +32,23 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { /// Returns a "verify bound" that encodes what we know about /// `generic` and the regions it outlives. pub fn generic_bound(&self, generic: GenericKind<'tcx>) -> VerifyBound<'tcx> { + let mut visited = MiniSet::new(); match generic { GenericKind::Param(param_ty) => self.param_bound(param_ty), - GenericKind::Projection(projection_ty) => self.projection_bound(projection_ty), + GenericKind::Projection(projection_ty) => { + self.projection_bound(projection_ty, &mut visited) + } } } - fn type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> { + fn type_bound( + &self, + ty: Ty<'tcx>, + visited: &mut MiniSet>, + ) -> VerifyBound<'tcx> { match *ty.kind() { ty::Param(p) => self.param_bound(p), - ty::Projection(data) => self.projection_bound(data), + ty::Projection(data) => self.projection_bound(data, visited), ty::FnDef(_, substs) => { // HACK(eddyb) ignore lifetimes found shallowly in `substs`. // This is inconsistent with `ty::Adt` (including all substs), @@ -50,9 +58,9 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { let mut bounds = substs .iter() .filter_map(|child| match child.unpack() { - GenericArgKind::Type(ty) => Some(self.type_bound(ty)), + GenericArgKind::Type(ty) => Some(self.type_bound(ty, visited)), GenericArgKind::Lifetime(_) => None, - GenericArgKind::Const(_) => Some(self.recursive_bound(child)), + GenericArgKind::Const(_) => Some(self.recursive_bound(child, visited)), }) .filter(|bound| { // Remove bounds that must hold, since they are not interesting. @@ -66,7 +74,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { ), } } - _ => self.recursive_bound(ty.into()), + _ => self.recursive_bound(ty.into(), visited), } } @@ -137,7 +145,11 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { self.declared_projection_bounds_from_trait(projection_ty) } - pub fn projection_bound(&self, projection_ty: ty::ProjectionTy<'tcx>) -> VerifyBound<'tcx> { + pub fn projection_bound( + &self, + projection_ty: ty::ProjectionTy<'tcx>, + visited: &mut MiniSet>, + ) -> VerifyBound<'tcx> { debug!("projection_bound(projection_ty={:?})", projection_ty); let projection_ty_as_ty = @@ -166,21 +178,25 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // see the extensive comment in projection_must_outlive let ty = self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs); - let recursive_bound = self.recursive_bound(ty.into()); + let recursive_bound = self.recursive_bound(ty.into(), visited); VerifyBound::AnyBound(env_bounds.chain(trait_bounds).collect()).or(recursive_bound) } - fn recursive_bound(&self, parent: GenericArg<'tcx>) -> VerifyBound<'tcx> { + fn recursive_bound( + &self, + parent: GenericArg<'tcx>, + visited: &mut MiniSet>, + ) -> VerifyBound<'tcx> { let mut bounds = parent - .walk_shallow() + .walk_shallow(visited) .filter_map(|child| match child.unpack() { - GenericArgKind::Type(ty) => Some(self.type_bound(ty)), + GenericArgKind::Type(ty) => Some(self.type_bound(ty, visited)), GenericArgKind::Lifetime(lt) => { // Ignore late-bound regions. if !lt.is_late_bound() { Some(VerifyBound::OutlivedBy(lt)) } else { None } } - GenericArgKind::Const(_) => Some(self.recursive_bound(child)), + GenericArgKind::Const(_) => Some(self.recursive_bound(child, visited)), }) .filter(|bound| { // Remove bounds that must hold, since they are not interesting. diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index a5a860a38b3e8..1d84ddad7f52d 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -28,5 +28,6 @@ rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } chalk-ir = "0.21.0" smallvec = { version = "1.0", features = ["union", "may_dangle"] } +arrayvec = { version = "0.5.1", default-features = false } measureme = "0.7.1" rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_middle/src/ty/outlives.rs b/compiler/rustc_middle/src/ty/outlives.rs index 783f116a87d38..01649f44c8861 100644 --- a/compiler/rustc_middle/src/ty/outlives.rs +++ b/compiler/rustc_middle/src/ty/outlives.rs @@ -3,6 +3,7 @@ // RFC for reference. use crate::ty::subst::{GenericArg, GenericArgKind}; +use crate::ty::walk::MiniSet; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; use smallvec::SmallVec; @@ -50,12 +51,18 @@ impl<'tcx> TyCtxt<'tcx> { /// Push onto `out` all the things that must outlive `'a` for the condition /// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**. pub fn push_outlives_components(self, ty0: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) { - compute_components(self, ty0, out); + let mut visited = MiniSet::new(); + compute_components(self, ty0, out, &mut visited); debug!("components({:?}) = {:?}", ty0, out); } } -fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) { +fn compute_components( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + out: &mut SmallVec<[Component<'tcx>; 4]>, + visited: &mut MiniSet>, +) { // Descend through the types, looking for the various "base" // components and collecting them into `out`. This is not written // with `collect()` because of the need to sometimes skip subtrees @@ -73,11 +80,11 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo for child in substs { match child.unpack() { GenericArgKind::Type(ty) => { - compute_components(tcx, ty, out); + compute_components(tcx, ty, out, visited); } GenericArgKind::Lifetime(_) => {} GenericArgKind::Const(_) => { - compute_components_recursive(tcx, child, out); + compute_components_recursive(tcx, child, out, visited); } } } @@ -85,19 +92,19 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo ty::Array(element, _) => { // Don't look into the len const as it doesn't affect regions - compute_components(tcx, element, out); + compute_components(tcx, element, out, visited); } ty::Closure(_, ref substs) => { for upvar_ty in substs.as_closure().upvar_tys() { - compute_components(tcx, upvar_ty, out); + compute_components(tcx, upvar_ty, out, visited); } } ty::Generator(_, ref substs, _) => { // Same as the closure case for upvar_ty in substs.as_generator().upvar_tys() { - compute_components(tcx, upvar_ty, out); + compute_components(tcx, upvar_ty, out, visited); } // We ignore regions in the generator interior as we don't @@ -135,7 +142,8 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo // OutlivesProjectionComponents. Continue walking // through and constrain Pi. let mut subcomponents = smallvec![]; - compute_components_recursive(tcx, ty.into(), &mut subcomponents); + let mut subvisited = MiniSet::new(); + compute_components_recursive(tcx, ty.into(), &mut subcomponents, &mut subvisited); out.push(Component::EscapingProjection(subcomponents.into_iter().collect())); } } @@ -177,7 +185,7 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo // the "bound regions list". In our representation, no such // list is maintained explicitly, because bound regions // themselves can be readily identified. - compute_components_recursive(tcx, ty.into(), out); + compute_components_recursive(tcx, ty.into(), out, visited); } } } @@ -186,11 +194,12 @@ fn compute_components_recursive( tcx: TyCtxt<'tcx>, parent: GenericArg<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>, + visited: &mut MiniSet>, ) { - for child in parent.walk_shallow() { + for child in parent.walk_shallow(visited) { match child.unpack() { GenericArgKind::Type(ty) => { - compute_components(tcx, ty, out); + compute_components(tcx, ty, out, visited); } GenericArgKind::Lifetime(lt) => { // Ignore late-bound regions. @@ -199,7 +208,7 @@ fn compute_components_recursive( } } GenericArgKind::Const(_) => { - compute_components_recursive(tcx, child, out); + compute_components_recursive(tcx, child, out, visited); } } } diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 4f55517c6f435..7afa6e6cc056d 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -3,7 +3,50 @@ use crate::ty; use crate::ty::subst::{GenericArg, GenericArgKind}; +use arrayvec::ArrayVec; +use rustc_data_structures::fx::FxHashSet; use smallvec::{self, SmallVec}; +use std::hash::Hash; + +/// Small-storage-optimized implementation of a set +/// made specifically for walking type tree. +/// +/// Stores elements in a small array up to a certain length +/// and switches to `HashSet` when that length is exceeded. +pub enum MiniSet { + Array(ArrayVec<[T; 8]>), + Set(FxHashSet), +} + +impl MiniSet { + /// Creates an empty `MiniSet`. + pub fn new() -> Self { + MiniSet::Array(ArrayVec::new()) + } + + /// Adds a value to the set. + /// + /// If the set did not have this value present, true is returned. + /// + /// If the set did have this value present, false is returned. + pub fn insert(&mut self, elem: T) -> bool { + match self { + MiniSet::Array(array) => { + if array.iter().any(|e| *e == elem) { + false + } else { + if array.try_push(elem).is_err() { + let mut set: FxHashSet = array.iter().copied().collect(); + set.insert(elem); + *self = MiniSet::Set(set); + } + true + } + } + MiniSet::Set(set) => set.insert(elem), + } + } +} // The TypeWalker's stack is hot enough that it's worth going to some effort to // avoid heap allocations. @@ -12,11 +55,20 @@ type TypeWalkerStack<'tcx> = SmallVec<[GenericArg<'tcx>; 8]>; pub struct TypeWalker<'tcx> { stack: TypeWalkerStack<'tcx>, last_subtree: usize, + visited: MiniSet>, } +/// An iterator for walking the type tree. +/// +/// It's very easy to produce a deeply +/// nested type tree with a lot of +/// identical subtrees. In order to work efficiently +/// in this situation walker only visits each type once. +/// It maintains a set of visited types and +/// skips any types that are already there. impl<'tcx> TypeWalker<'tcx> { - pub fn new(root: GenericArg<'tcx>) -> TypeWalker<'tcx> { - TypeWalker { stack: smallvec![root], last_subtree: 1 } + pub fn new(root: GenericArg<'tcx>) -> Self { + Self { stack: smallvec![root], last_subtree: 1, visited: MiniSet::new() } } /// Skips the subtree corresponding to the last type @@ -41,11 +93,15 @@ impl<'tcx> Iterator for TypeWalker<'tcx> { fn next(&mut self) -> Option> { debug!("next(): stack={:?}", self.stack); - let next = self.stack.pop()?; - self.last_subtree = self.stack.len(); - push_inner(&mut self.stack, next); - debug!("next: stack={:?}", self.stack); - Some(next) + loop { + let next = self.stack.pop()?; + self.last_subtree = self.stack.len(); + if self.visited.insert(next) { + push_inner(&mut self.stack, next); + debug!("next: stack={:?}", self.stack); + return Some(next); + } + } } } @@ -67,9 +123,17 @@ impl GenericArg<'tcx> { /// Iterator that walks the immediate children of `self`. Hence /// `Foo, u32>` yields the sequence `[Bar, u32]` /// (but not `i32`, like `walk`). - pub fn walk_shallow(self) -> impl Iterator> { + /// + /// Iterator only walks items once. + /// It accepts visited set, updates it with all visited types + /// and skips any types that are already there. + pub fn walk_shallow( + self, + visited: &mut MiniSet>, + ) -> impl Iterator> { let mut stack = SmallVec::new(); push_inner(&mut stack, self); + stack.retain(|a| visited.insert(*a)); stack.into_iter() } } diff --git a/src/test/ui/closures/issue-72408-nested-closures-exponential.rs b/src/test/ui/closures/issue-72408-nested-closures-exponential.rs new file mode 100644 index 0000000000000..2d6ba936572d5 --- /dev/null +++ b/src/test/ui/closures/issue-72408-nested-closures-exponential.rs @@ -0,0 +1,59 @@ +// build-pass + +// Closures include captured types twice in a type tree. +// +// Wrapping one closure with another leads to doubling +// the amount of types in the type tree. +// +// This test ensures that rust can handle +// deeply nested type trees with a lot +// of duplicated subtrees. + +fn dup(f: impl Fn(i32) -> i32) -> impl Fn(i32) -> i32 { + move |a| f(a * 2) +} + +fn main() { + let f = |a| a; + + let f = dup(f); + let f = dup(f); + let f = dup(f); + let f = dup(f); + let f = dup(f); + + let f = dup(f); + let f = dup(f); + let f = dup(f); + let f = dup(f); + let f = dup(f); + + let f = dup(f); + let f = dup(f); + let f = dup(f); + let f = dup(f); + let f = dup(f); + + let f = dup(f); + let f = dup(f); + let f = dup(f); + let f = dup(f); + let f = dup(f); + + // Compiler dies around here if it tries + // to walk the tree exhaustively. + + let f = dup(f); + let f = dup(f); + let f = dup(f); + let f = dup(f); + let f = dup(f); + + let f = dup(f); + let f = dup(f); + let f = dup(f); + let f = dup(f); + let f = dup(f); + + println!("Type size was at least {}", f(1)); +} diff --git a/src/test/ui/issues/issue-22638.rs b/src/test/ui/issues/issue-22638.rs index 72c16fddb4b12..89137538425bf 100644 --- a/src/test/ui/issues/issue-22638.rs +++ b/src/test/ui/issues/issue-22638.rs @@ -51,9 +51,9 @@ struct D (Box); impl D { pub fn matches(&self, f: &F) { - //~^ ERROR reached the type-length limit while instantiating `D::matches::<[closure let &D(ref a) = self; a.matches(f) + //~^ ERROR reached the recursion limit while instantiating `A::matches::<[closure } } diff --git a/src/test/ui/issues/issue-22638.stderr b/src/test/ui/issues/issue-22638.stderr index b0df46b11fadb..c4255b95b704e 100644 --- a/src/test/ui/issues/issue-22638.stderr +++ b/src/test/ui/issues/issue-22638.stderr @@ -1,10 +1,14 @@ -error: reached the type-length limit while instantiating `D::matches::$CLOSURE` - --> $DIR/issue-22638.rs:53:5 +error: reached the recursion limit while instantiating `A::matches::$CLOSURE` + --> $DIR/issue-22638.rs:55:9 + | +LL | a.matches(f) + | ^^^^^^^^^^^^ + | +note: `A::matches` defined here + --> $DIR/issue-22638.rs:14:5 | LL | pub fn matches(&self, f: &F) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: consider adding a `#![type_length_limit="30408681"]` attribute to your crate error: aborting due to previous error diff --git a/src/test/ui/type_length_limit.rs b/src/test/ui/type_length_limit.rs index 1f1c8ad962690..921cded5037b6 100644 --- a/src/test/ui/type_length_limit.rs +++ b/src/test/ui/type_length_limit.rs @@ -4,7 +4,7 @@ // Test that the type length limit can be changed. #![allow(dead_code)] -#![type_length_limit="256"] +#![type_length_limit="4"] macro_rules! link { ($id:ident, $t:ty) => { diff --git a/src/test/ui/type_length_limit.stderr b/src/test/ui/type_length_limit.stderr index f12f259d2f6e2..e8fddfd4ece15 100644 --- a/src/test/ui/type_length_limit.stderr +++ b/src/test/ui/type_length_limit.stderr @@ -4,7 +4,7 @@ error: reached the type-length limit while instantiating `std::mem::drop::(_x: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: consider adding a `#![type_length_limit="1094"]` attribute to your crate + = note: consider adding a `#![type_length_limit="8"]` attribute to your crate error: aborting due to previous error From 17d2e3b5d208d29d156ff94f112b5bc95acee351 Mon Sep 17 00:00:00 2001 From: Valerii Lashmanov Date: Tue, 15 Sep 2020 18:22:24 -0500 Subject: [PATCH 0564/1052] Better handling for exponential-sized types in misc places Mostly to fix ui/issues/issue-37311-type-length-limit/issue-37311.rs. Most parts of the compiler can handle deeply nested types with a lot of duplicates just fine, but some parts still attempt to naively traverse type tree. Before such problems were caught by type length limit check, but now these places will have to be changed to handle duplicated types gracefully. --- compiler/rustc_infer/src/infer/combine.rs | 15 +++++- compiler/rustc_middle/src/ty/print/mod.rs | 30 +++++++++--- compiler/rustc_middle/src/ty/print/pretty.rs | 12 ++++- .../rustc_mir/src/monomorphize/collector.rs | 47 +++++++++++-------- .../ui/infinite/infinite-instantiation.stderr | 2 +- .../issue-37311.rs | 4 +- .../issue-37311.stderr | 10 ++-- src/test/ui/issues/issue-67552.stderr | 2 +- src/test/ui/issues/issue-8727.stderr | 2 +- ...-38591-non-regular-dropck-recursion.stderr | 2 +- src/test/ui/recursion/recursion.stderr | 2 +- src/test/ui/type_length_limit.stderr | 2 +- 12 files changed, 89 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index ae4612a89f277..bff8ed4ad05a5 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -31,6 +31,7 @@ use super::unify_key::replace_if_possible; use super::unify_key::{ConstVarValue, ConstVariableValue}; use super::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use super::{InferCtxt, MiscVariable, TypeTrace}; +use rustc_data_structures::fx::FxHashMap; use crate::traits::{Obligation, PredicateObligations}; @@ -379,6 +380,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { needs_wf: false, root_ty: ty, param_env: self.param_env, + cache: FxHashMap::default(), }; let ty = match generalize.relate(ty, ty) { @@ -438,6 +440,8 @@ struct Generalizer<'cx, 'tcx> { root_ty: Ty<'tcx>, param_env: ty::ParamEnv<'tcx>, + + cache: FxHashMap<(Ty<'tcx>, Ty<'tcx>), RelateResult<'tcx, Ty<'tcx>>>, } /// Result from a generalization operation. This includes @@ -535,13 +539,17 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { assert_eq!(t, t2); // we are abusing TypeRelation here; both LHS and RHS ought to be == + let cache_key = (t, t2); + if let Some(result) = self.cache.get(&cache_key) { + return result.clone(); + } debug!("generalize: t={:?}", t); // Check to see whether the type we are generalizing references // any other type variable related to `vid` via // subtyping. This is basically our "occurs check", preventing // us from creating infinitely sized types. - match *t.kind() { + let result = match *t.kind() { ty::Infer(ty::TyVar(vid)) => { let vid = self.infcx.inner.borrow_mut().type_variables().root_var(vid); let sub_vid = self.infcx.inner.borrow_mut().type_variables().sub_root_var(vid); @@ -598,7 +606,10 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { Ok(t) } _ => relate::super_relate_tys(self, t, t), - } + }; + + self.cache.insert(cache_key, result.clone()); + return result; } fn regions( diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 709a4018d809c..4e424156c4d41 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -4,6 +4,7 @@ use crate::ty::{self, DefIdTree, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; +use rustc_middle::ty::walk::MiniSet; // `pretty` is a separate module only for organization. mod pretty; @@ -263,21 +264,33 @@ pub trait Printer<'tcx>: Sized { /// function tries to find a "characteristic `DefId`" for a /// type. It's just a heuristic so it makes some questionable /// decisions and we may want to adjust it later. -pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option { +/// +/// Visited set is needed in to avoid full iteration over +/// deeply nested tuples that have no DefId. +fn characteristic_def_id_of_type_cached<'a>( + ty: Ty<'a>, + visited: &mut MiniSet>, +) -> Option { match *ty.kind() { ty::Adt(adt_def, _) => Some(adt_def.did), ty::Dynamic(data, ..) => data.principal_def_id(), - ty::Array(subty, _) | ty::Slice(subty) => characteristic_def_id_of_type(subty), + ty::Array(subty, _) | ty::Slice(subty) => { + characteristic_def_id_of_type_cached(subty, visited) + } - ty::RawPtr(mt) => characteristic_def_id_of_type(mt.ty), + ty::RawPtr(mt) => characteristic_def_id_of_type_cached(mt.ty, visited), - ty::Ref(_, ty, _) => characteristic_def_id_of_type(ty), + ty::Ref(_, ty, _) => characteristic_def_id_of_type_cached(ty, visited), - ty::Tuple(ref tys) => { - tys.iter().find_map(|ty| characteristic_def_id_of_type(ty.expect_ty())) - } + ty::Tuple(ref tys) => tys.iter().find_map(|ty| { + let ty = ty.expect_ty(); + if visited.insert(ty) { + return characteristic_def_id_of_type_cached(ty, visited); + } + return None; + }), ty::FnDef(def_id, _) | ty::Closure(def_id, _) @@ -302,6 +315,9 @@ pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option { | ty::Float(_) => None, } } +pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option { + characteristic_def_id_of_type_cached(ty, &mut MiniSet::new()) +} impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::RegionKind { type Output = P::Region; diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 9562d43791493..1ed98d1f2cafd 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1264,6 +1264,7 @@ pub struct FmtPrinterData<'a, 'tcx, F> { used_region_names: FxHashSet, region_index: usize, binder_depth: usize, + printed_type_count: usize, pub region_highlight_mode: RegionHighlightMode, @@ -1294,6 +1295,7 @@ impl FmtPrinter<'a, 'tcx, F> { used_region_names: Default::default(), region_index: 0, binder_depth: 0, + printed_type_count: 0, region_highlight_mode: RegionHighlightMode::default(), name_resolver: None, })) @@ -1411,8 +1413,14 @@ impl Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { self.pretty_print_region(region) } - fn print_type(self, ty: Ty<'tcx>) -> Result { - self.pretty_print_type(ty) + fn print_type(mut self, ty: Ty<'tcx>) -> Result { + if self.tcx.sess.type_length_limit().value_within_limit(self.printed_type_count) { + self.printed_type_count += 1; + self.pretty_print_type(ty) + } else { + write!(self, "...")?; + Ok(self) + } } fn print_dyn_existential( diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs index 9ea103463d5eb..0dbb4b1015e79 100644 --- a/compiler/rustc_mir/src/monomorphize/collector.rs +++ b/compiler/rustc_mir/src/monomorphize/collector.rs @@ -418,6 +418,29 @@ fn record_accesses<'a, 'tcx: 'a>( inlining_map.lock_mut().record_accesses(caller, &accesses); } +// Shrinks string by keeping prefix and suffix of given sizes. +fn shrink(s: String, before: usize, after: usize) -> String { + // An iterator of all byte positions including the end of the string. + let positions = || s.char_indices().map(|(i, _)| i).chain(iter::once(s.len())); + + let shrunk = format!( + "{before}...{after}", + before = &s[..positions().nth(before).unwrap_or(s.len())], + after = &s[positions().rev().nth(after).unwrap_or(0)..], + ); + + // Only use the shrunk version if it's really shorter. + // This also avoids the case where before and after slices overlap. + if shrunk.len() < s.len() { shrunk } else { s } +} + +// Format instance name that is already known to be too long for rustc. +// Show only the first and last 32 characters to avoid blasting +// the user's terminal with thousands of lines of type-name. +fn shrunk_instance_name(instance: &Instance<'tcx>) -> String { + shrink(instance.to_string(), 32, 32) +} + fn check_recursion_limit<'tcx>( tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, @@ -440,7 +463,10 @@ fn check_recursion_limit<'tcx>( // more than the recursion limit is assumed to be causing an // infinite expansion. if !tcx.sess.recursion_limit().value_within_limit(adjusted_recursion_depth) { - let error = format!("reached the recursion limit while instantiating `{}`", instance); + let error = format!( + "reached the recursion limit while instantiating `{}`", + shrunk_instance_name(&instance), + ); let mut err = tcx.sess.struct_span_fatal(span, &error); err.span_note( tcx.def_span(def_id), @@ -474,26 +500,9 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { // // Bail out in these cases to avoid that bad user experience. if !tcx.sess.type_length_limit().value_within_limit(type_length) { - // The instance name is already known to be too long for rustc. - // Show only the first and last 32 characters to avoid blasting - // the user's terminal with thousands of lines of type-name. - let shrink = |s: String, before: usize, after: usize| { - // An iterator of all byte positions including the end of the string. - let positions = || s.char_indices().map(|(i, _)| i).chain(iter::once(s.len())); - - let shrunk = format!( - "{before}...{after}", - before = &s[..positions().nth(before).unwrap_or(s.len())], - after = &s[positions().rev().nth(after).unwrap_or(0)..], - ); - - // Only use the shrunk version if it's really shorter. - // This also avoids the case where before and after slices overlap. - if shrunk.len() < s.len() { shrunk } else { s } - }; let msg = format!( "reached the type-length limit while instantiating `{}`", - shrink(instance.to_string(), 32, 32) + shrunk_instance_name(&instance), ); let mut diag = tcx.sess.struct_span_fatal(tcx.def_span(instance.def_id()), &msg); diag.note(&format!( diff --git a/src/test/ui/infinite/infinite-instantiation.stderr b/src/test/ui/infinite/infinite-instantiation.stderr index 1aaefea9f042c..d27d14842ce99 100644 --- a/src/test/ui/infinite/infinite-instantiation.stderr +++ b/src/test/ui/infinite/infinite-instantiation.stderr @@ -1,4 +1,4 @@ -error: reached the recursion limit while instantiating `function::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` +error: reached the recursion limit while instantiating `function::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/infinite-instantiation.rs:21:9 | LL | function(counter - 1, t.to_option()); diff --git a/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.rs b/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.rs index fec4b17153609..d3d5863ddb3c9 100644 --- a/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.rs +++ b/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.rs @@ -12,8 +12,8 @@ trait Foo { impl Foo for T { #[allow(unconditional_recursion)] - fn recurse(&self) { //~ ERROR reached the type-length limit - (self, self).recurse(); + fn recurse(&self) { + (self, self).recurse(); //~ ERROR reached the recursion limit } } diff --git a/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr b/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr index 6229d90d4b477..a94f190d6b25d 100644 --- a/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr +++ b/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr @@ -1,10 +1,14 @@ -error: reached the type-length limit while instantiating `<(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(...))))))))))))))) as Foo>::recurse` +error: reached the recursion limit while instantiating `<(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(.....), ...), ...) as Foo>::recurse` + --> $DIR/issue-37311.rs:16:9 + | +LL | (self, self).recurse(); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: `::recurse` defined here --> $DIR/issue-37311.rs:15:5 | LL | fn recurse(&self) { | ^^^^^^^^^^^^^^^^^ - | - = note: consider adding a `#![type_length_limit="2097149"]` attribute to your crate error: aborting due to previous error diff --git a/src/test/ui/issues/issue-67552.stderr b/src/test/ui/issues/issue-67552.stderr index 8243e52039d48..f3e73399b57ce 100644 --- a/src/test/ui/issues/issue-67552.stderr +++ b/src/test/ui/issues/issue-67552.stderr @@ -1,4 +1,4 @@ -error: reached the recursion limit while instantiating `rec::<&mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut Empty>` +error: reached the recursion limit while instantiating `rec::<&mut &mut &mut &mut &mut &... &mut &mut &mut &mut &mut Empty>` --> $DIR/issue-67552.rs:27:9 | LL | rec(identity(&mut it)) diff --git a/src/test/ui/issues/issue-8727.stderr b/src/test/ui/issues/issue-8727.stderr index dd57e69f2cff0..279e3ffbb4a41 100644 --- a/src/test/ui/issues/issue-8727.stderr +++ b/src/test/ui/issues/issue-8727.stderr @@ -9,7 +9,7 @@ LL | generic::>(); = note: `#[warn(unconditional_recursion)]` on by default = help: a `loop` may express intention better if this is on purpose -error: reached the recursion limit while instantiating `generic::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` +error: reached the recursion limit while instantiating `generic::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/issue-8727.rs:7:5 | LL | generic::>(); diff --git a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr index 536e26d295569..4d77b3d295c00 100644 --- a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr +++ b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr @@ -1,4 +1,4 @@ -error: reached the recursion limit while instantiating `drop_in_place::> - shim(Some(S))` +error: reached the recursion limit while instantiating `drop_in_place::))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL | LL | / pub unsafe fn drop_in_place(to_drop: *mut T) { diff --git a/src/test/ui/recursion/recursion.stderr b/src/test/ui/recursion/recursion.stderr index db4c99eeb8b16..085bf82ef8b93 100644 --- a/src/test/ui/recursion/recursion.stderr +++ b/src/test/ui/recursion/recursion.stderr @@ -1,4 +1,4 @@ -error: reached the recursion limit while instantiating `test::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` +error: reached the recursion limit while instantiating `test::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/recursion.rs:17:11 | LL | _ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})} diff --git a/src/test/ui/type_length_limit.stderr b/src/test/ui/type_length_limit.stderr index e8fddfd4ece15..cf3d64d734ba0 100644 --- a/src/test/ui/type_length_limit.stderr +++ b/src/test/ui/type_length_limit.stderr @@ -1,4 +1,4 @@ -error: reached the type-length limit while instantiating `std::mem::drop::>` +error: reached the type-length limit while instantiating `std::mem::drop::>` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL | LL | pub fn drop(_x: T) {} From f583513dc2ad48076665505a1418db6053657f0b Mon Sep 17 00:00:00 2001 From: Valerii Lashmanov Date: Thu, 17 Sep 2020 20:43:29 -0500 Subject: [PATCH 0565/1052] Intorduced MiniMap - a tiny small storage optimized map implementation This makes everything about 1% faster in rustc-perf, mostly negating performance hit of previous commit. --- Cargo.lock | 1 + compiler/rustc_infer/Cargo.toml | 1 + compiler/rustc_infer/src/infer/combine.rs | 63 ++++++++++++++++++++++- 3 files changed, 63 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 05d3a9c56219c..23878f7ade7a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3594,6 +3594,7 @@ dependencies = [ name = "rustc_infer" version = "0.0.0" dependencies = [ + "arrayvec", "rustc_ast", "rustc_data_structures", "rustc_errors", diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml index 5dba4106c9423..a8c1a370cef82 100644 --- a/compiler/rustc_infer/Cargo.toml +++ b/compiler/rustc_infer/Cargo.toml @@ -21,4 +21,5 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } +arrayvec = { version = "0.5.1", default-features = false } rustc_ast = { path = "../rustc_ast" } diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index bff8ed4ad05a5..68197f75b9f7b 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -31,7 +31,9 @@ use super::unify_key::replace_if_possible; use super::unify_key::{ConstVarValue, ConstVariableValue}; use super::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use super::{InferCtxt, MiscVariable, TypeTrace}; +use arrayvec::ArrayVec; use rustc_data_structures::fx::FxHashMap; +use std::hash::Hash; use crate::traits::{Obligation, PredicateObligations}; @@ -45,6 +47,63 @@ use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{IntType, UintType}; use rustc_span::DUMMY_SP; +/// Small-storage-optimized implementation of a map +/// made specifically for caching results. +/// +/// Stores elements in a small array up to a certain length +/// and switches to `HashMap` when that length is exceeded. +enum MiniMap { + Array(ArrayVec<[(K, V); 8]>), + Map(FxHashMap), +} + +impl MiniMap { + /// Creates an empty `MiniMap`. + pub fn new() -> Self { + MiniMap::Array(ArrayVec::new()) + } + + /// Inserts or updates value in the map. + pub fn insert(&mut self, key: K, value: V) { + match self { + MiniMap::Array(array) => { + for pair in array.iter_mut() { + if pair.0 == key { + pair.1 = value; + return; + } + } + if let Err(error) = array.try_push((key, value)) { + let mut map: FxHashMap = array.drain(..).collect(); + let (key, value) = error.element(); + map.insert(key, value); + *self = MiniMap::Map(map); + } + } + MiniMap::Map(map) => { + map.insert(key, value); + } + } + } + + /// Return value by key if any. + pub fn get(&self, key: &K) -> Option<&V> { + match self { + MiniMap::Array(array) => { + for pair in array { + if pair.0 == *key { + return Some(&pair.1); + } + } + return None; + } + MiniMap::Map(map) => { + return map.get(key); + } + } + } +} + #[derive(Clone)] pub struct CombineFields<'infcx, 'tcx> { pub infcx: &'infcx InferCtxt<'infcx, 'tcx>, @@ -380,7 +439,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { needs_wf: false, root_ty: ty, param_env: self.param_env, - cache: FxHashMap::default(), + cache: MiniMap::new(), }; let ty = match generalize.relate(ty, ty) { @@ -441,7 +500,7 @@ struct Generalizer<'cx, 'tcx> { param_env: ty::ParamEnv<'tcx>, - cache: FxHashMap<(Ty<'tcx>, Ty<'tcx>), RelateResult<'tcx, Ty<'tcx>>>, + cache: MiniMap<(Ty<'tcx>, Ty<'tcx>), RelateResult<'tcx, Ty<'tcx>>>, } /// Result from a generalization operation. This includes From 2818032a2dee83b0b58318828e666e404838c8d9 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 18 Sep 2020 01:55:40 +0000 Subject: [PATCH 0566/1052] Calculate more correct capacity in merge_attrs Co-authored-by: jyn514 --- src/librustdoc/clean/inline.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index f8987c6beca33..a12181be67dd3 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -306,15 +306,17 @@ fn merge_attrs( attrs: Attrs<'_>, other_attrs: Option>, ) -> clean::Attributes { - let mut merged_attrs: Vec = Vec::with_capacity(attrs.len()); - // If we have additional attributes (from a re-export), + // NOTE: If we have additional attributes (from a re-export), // always insert them first. This ensure that re-export // doc comments show up before the original doc comments // when we render them. - if let Some(a) = other_attrs { - merged_attrs.extend(a.iter().cloned()); - } - merged_attrs.extend(attrs.to_vec()); + let merged_attrs = if let Some(inner) = other_attrs { + let mut both = inner.to_vec(); + both.extend_from_slice(attrs); + both + } else { + attrs.to_vec() + }; merged_attrs.clean(cx) } From 5acfcceb47609862bba7035cf1cbfd807918dd36 Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 17 Sep 2020 16:40:02 +0200 Subject: [PATCH 0567/1052] Dogfood new_uninit and maybe_uninit_slice in rustc_arena --- compiler/rustc_arena/src/lib.rs | 35 +++++++++++++++------------------ 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 5e6a0340d12a0..2edf822cdb198 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -13,12 +13,11 @@ )] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] -#![feature(raw_vec_internals)] +#![feature(new_uninit)] +#![feature(maybe_uninit_slice)] #![cfg_attr(test, feature(test))] #![allow(deprecated)] -extern crate alloc; - use rustc_data_structures::cold_path; use smallvec::SmallVec; @@ -27,12 +26,10 @@ use std::cell::{Cell, RefCell}; use std::cmp; use std::intrinsics; use std::marker::{PhantomData, Send}; -use std::mem; +use std::mem::{self, MaybeUninit}; use std::ptr; use std::slice; -use alloc::raw_vec::RawVec; - /// An arena that can hold objects of only one type. pub struct TypedArena { /// A pointer to the next object to be allocated. @@ -52,7 +49,7 @@ pub struct TypedArena { struct TypedArenaChunk { /// The raw storage for the arena chunk. - storage: RawVec, + storage: Box<[MaybeUninit]>, /// The number of valid entries in the chunk. entries: usize, } @@ -60,7 +57,7 @@ struct TypedArenaChunk { impl TypedArenaChunk { #[inline] unsafe fn new(capacity: usize) -> TypedArenaChunk { - TypedArenaChunk { storage: RawVec::with_capacity(capacity), entries: 0 } + TypedArenaChunk { storage: Box::new_uninit_slice(capacity), entries: 0 } } /// Destroys this arena chunk. @@ -80,19 +77,19 @@ impl TypedArenaChunk { // Returns a pointer to the first allocated object. #[inline] - fn start(&self) -> *mut T { - self.storage.ptr() + fn start(&mut self) -> *mut T { + MaybeUninit::slice_as_mut_ptr(&mut self.storage) } // Returns a pointer to the end of the allocated space. #[inline] - fn end(&self) -> *mut T { + fn end(&mut self) -> *mut T { unsafe { if mem::size_of::() == 0 { // A pointer as large as possible for zero-sized elements. !0 as *mut T } else { - self.start().add(self.storage.capacity()) + self.start().add(self.storage.len()) } } } @@ -226,10 +223,10 @@ impl TypedArena { let used_bytes = self.ptr.get() as usize - last_chunk.start() as usize; last_chunk.entries = used_bytes / mem::size_of::(); - // If the previous chunk's capacity is less than HUGE_PAGE + // If the previous chunk's len is less than HUGE_PAGE // bytes, then this chunk will be least double the previous // chunk's size. - new_cap = last_chunk.storage.capacity(); + new_cap = last_chunk.storage.len(); if new_cap < HUGE_PAGE / elem_size { new_cap = new_cap.checked_mul(2).unwrap(); } @@ -239,7 +236,7 @@ impl TypedArena { // Also ensure that this chunk can fit `additional`. new_cap = cmp::max(additional, new_cap); - let chunk = TypedArenaChunk::::new(new_cap); + let mut chunk = TypedArenaChunk::::new(new_cap); self.ptr.set(chunk.start()); self.end.set(chunk.end()); chunks.push(chunk); @@ -301,7 +298,7 @@ unsafe impl<#[may_dangle] T> Drop for TypedArena { chunk.destroy(chunk.entries); } } - // RawVec handles deallocation of `last_chunk` and `self.chunks`. + // Box handles deallocation of `last_chunk` and `self.chunks`. } } } @@ -344,10 +341,10 @@ impl DroplessArena { // There is no need to update `last_chunk.entries` because that // field isn't used by `DroplessArena`. - // If the previous chunk's capacity is less than HUGE_PAGE + // If the previous chunk's len is less than HUGE_PAGE // bytes, then this chunk will be least double the previous // chunk's size. - new_cap = last_chunk.storage.capacity(); + new_cap = last_chunk.storage.len(); if new_cap < HUGE_PAGE { new_cap = new_cap.checked_mul(2).unwrap(); } @@ -357,7 +354,7 @@ impl DroplessArena { // Also ensure that this chunk can fit `additional`. new_cap = cmp::max(additional, new_cap); - let chunk = TypedArenaChunk::::new(new_cap); + let mut chunk = TypedArenaChunk::::new(new_cap); self.ptr.set(chunk.start()); self.end.set(chunk.end()); chunks.push(chunk); From daccd1709ef1913e23d1b2f15dfeb16ac6e70ed8 Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 17 Sep 2020 17:20:22 +0200 Subject: [PATCH 0568/1052] Replace loop with drop_in_place call --- compiler/rustc_arena/src/lib.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 2edf822cdb198..0d0b1efd2de18 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -66,12 +66,7 @@ impl TypedArenaChunk { // The branch on needs_drop() is an -O1 performance optimization. // Without the branch, dropping TypedArena takes linear time. if mem::needs_drop::() { - let mut start = self.start(); - // Destroy all allocated objects. - for _ in 0..len { - ptr::drop_in_place(start); - start = start.offset(1); - } + ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(&mut self.storage[..len])); } } From 6928041c0a992093a7752ae3c04090caebcd4515 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 17 Sep 2020 20:21:09 -0700 Subject: [PATCH 0569/1052] Update src/doc/rustdoc/src/linking-to-items-by-name.md Co-authored-by: Joshua Nelson --- src/doc/rustdoc/src/linking-to-items-by-name.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustdoc/src/linking-to-items-by-name.md b/src/doc/rustdoc/src/linking-to-items-by-name.md index d48ba5f9d2bcc..5e46ef583f60c 100644 --- a/src/doc/rustdoc/src/linking-to-items-by-name.md +++ b/src/doc/rustdoc/src/linking-to-items-by-name.md @@ -50,7 +50,7 @@ You can also link to sections using URL fragment specifiers: struct MySpecialFormatter; ``` -Paths in Rust have three namespaces: type, value, and macro. Items from these namespaces are allowed to overlap. In case of ambiguity, rustdoc will warn about the ambiguity and ask you to disambiguate, which can be done by using a prefix like `struct@`, `enum@`, `type@`, `trait@`, `union@`, `const@`, `static@`, `value@`, `function@`, `mod@`, `fn@`, `module@`, `method@`, `prim@`, `primitive@`, `macro@`, or `derive@`:: +Paths in Rust have three namespaces: type, value, and macro. Items from these namespaces are allowed to overlap. In case of ambiguity, rustdoc will warn about the ambiguity and ask you to disambiguate, which can be done by using a prefix like `struct@`, `enum@`, `type@`, `trait@`, `union@`, `const@`, `static@`, `value@`, `function@`, `mod@`, `fn@`, `module@`, `method@`, `prim@`, `primitive@`, `macro@`, or `derive@`: ```rust /// See also: [`Foo`](struct@Foo) From 2805a0515461d6f70f7d4a6c1f5491dbed5d61b8 Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 18 Sep 2020 05:52:45 +0200 Subject: [PATCH 0570/1052] Add bench_typed_arena_clear_100 bench --- compiler/rustc_arena/src/tests.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/compiler/rustc_arena/src/tests.rs b/compiler/rustc_arena/src/tests.rs index 8e63bdf545841..e8a1f2db1a16b 100644 --- a/compiler/rustc_arena/src/tests.rs +++ b/compiler/rustc_arena/src/tests.rs @@ -121,6 +121,17 @@ pub fn bench_typed_arena_clear(b: &mut Bencher) { }) } +#[bench] +pub fn bench_typed_arena_clear_100(b: &mut Bencher) { + let mut arena = TypedArena::default(); + b.iter(|| { + for _ in 0..100 { + arena.alloc(Point { x: 1, y: 2, z: 3 }); + } + arena.clear(); + }) +} + // Drop tests struct DropCounter<'a> { From f05b47ccdfa63f8b4b9fb47a9aa92381801d3ff1 Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 18 Sep 2020 06:21:06 +0200 Subject: [PATCH 0571/1052] Don't download/sync llvm-project submodule if download-ci-llvm is set llvm-project takes > 1GB storage space and a long time to download. It's better to not download it unless needed. --- src/bootstrap/bootstrap.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 5f78031e1c7cb..613f364b753d4 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -881,8 +881,9 @@ def update_submodules(self): submodules_names = [] for module in submodules: if module.endswith("llvm-project"): - if self.get_toml('llvm-config') and self.get_toml('lld') != 'true': - continue + if self.get_toml('llvm-config') or self.get_toml('download-ci-llvm') == 'true': + if self.get_toml('lld') != 'true': + continue check = self.check_submodule(module, slow_submodules) filtered_submodules.append((module, check)) submodules_names.append(module) From 28cfa9730eec41314dee99323f7d20aaadde9e0e Mon Sep 17 00:00:00 2001 From: Juan Aguilar Santillana Date: Fri, 18 Sep 2020 05:57:01 +0000 Subject: [PATCH 0572/1052] Simplify panic_if_treat_err_as_bug avoiding allocations --- compiler/rustc_errors/src/lib.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 2abd20869aecf..b16fe5603c100 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -973,16 +973,14 @@ impl HandlerInner { fn panic_if_treat_err_as_bug(&self) { if self.treat_err_as_bug() { - let s = match (self.err_count(), self.flags.treat_err_as_bug.unwrap_or(0)) { - (0, _) => return, - (1, 1) => "aborting due to `-Z treat-err-as-bug=1`".to_string(), - (1, _) => return, - (count, as_bug) => format!( + match (self.err_count(), self.flags.treat_err_as_bug.unwrap_or(0)) { + (1, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"), + (0, _) | (1, _) => {} + (count, as_bug) => panic!( "aborting after {} errors due to `-Z treat-err-as-bug={}`", count, as_bug, ), - }; - panic!(s); + } } } } From baafc71f1fc04ec1d042dc8de9d29d1e24316c4b Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 18 Sep 2020 08:59:43 +0200 Subject: [PATCH 0573/1052] Remove unused libc feature gate Libc isn't used by alloc. And std and panic_* use libc from crates.io now, which isn't feature gated. --- library/alloc/src/lib.rs | 1 - library/panic_abort/src/lib.rs | 1 - library/panic_unwind/src/lib.rs | 1 - library/std/src/lib.rs | 1 - 4 files changed, 4 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 7881c101f9f60..3061ab8ee5369 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -103,7 +103,6 @@ #![feature(inplace_iteration)] #![feature(lang_items)] #![feature(layout_for_ptr)] -#![feature(libc)] #![feature(map_first_last)] #![feature(map_into_keys_values)] #![feature(maybe_uninit_ref)] diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index 3b08a64b22d85..7a5c613688d42 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -12,7 +12,6 @@ #![panic_runtime] #![allow(unused_features)] #![feature(core_intrinsics)] -#![feature(libc)] #![feature(nll)] #![feature(panic_runtime)] #![feature(staged_api)] diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index 6f31e6dcae70d..0a193f7bf4149 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -19,7 +19,6 @@ )] #![feature(core_intrinsics)] #![feature(lang_items)] -#![feature(libc)] #![feature(nll)] #![feature(panic_unwind)] #![feature(staged_api)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index b834361b750eb..34230629fb0be 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -268,7 +268,6 @@ #![feature(integer_atomics)] #![feature(into_future)] #![feature(lang_items)] -#![feature(libc)] #![feature(link_args)] #![feature(linkage)] #![feature(llvm_asm)] From 4675a3104b3ace025560337c5d164e330f6b9d68 Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Fri, 18 Sep 2020 09:51:26 +0200 Subject: [PATCH 0574/1052] Use intra-doc links in core/src/iter when possible --- library/core/src/iter/sources.rs | 76 +++++++------------- library/core/src/iter/traits/accum.rs | 46 ++++++------ library/core/src/iter/traits/collect.rs | 20 ++---- library/core/src/iter/traits/double_ended.rs | 39 +++++----- library/core/src/iter/traits/exact_size.rs | 23 +++--- library/core/src/iter/traits/iterator.rs | 1 - library/core/src/iter/traits/marker.rs | 18 ++--- 7 files changed, 91 insertions(+), 132 deletions(-) diff --git a/library/core/src/iter/sources.rs b/library/core/src/iter/sources.rs index d76fa89bd012c..0348d5a10d984 100644 --- a/library/core/src/iter/sources.rs +++ b/library/core/src/iter/sources.rs @@ -5,9 +5,7 @@ use super::{FusedIterator, TrustedLen}; /// An iterator that repeats an element endlessly. /// -/// This `struct` is created by the [`repeat`] function. See its documentation for more. -/// -/// [`repeat`]: fn.repeat.html +/// This `struct` is created by the [`repeat()`] function. See its documentation for more. #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Repeat { @@ -47,15 +45,11 @@ unsafe impl TrustedLen for Repeat {} /// The `repeat()` function repeats a single value over and over again. /// /// Infinite iterators like `repeat()` are often used with adapters like -/// [`take`], in order to make them finite. -/// -/// [`take`]: trait.Iterator.html#method.take +/// [`Iterator::take()`], in order to make them finite. /// /// If the element type of the iterator you need does not implement `Clone`, /// or if you do not want to keep the repeated element in memory, you can -/// instead use the [`repeat_with`] function. -/// -/// [`repeat_with`]: fn.repeat_with.html +/// instead use the [`repeat_with()`] function. /// /// # Examples /// @@ -77,7 +71,7 @@ unsafe impl TrustedLen for Repeat {} /// assert_eq!(Some(4), fours.next()); /// ``` /// -/// Going finite with [`take`]: +/// Going finite with [`Iterator::take()`]: /// /// ``` /// use std::iter; @@ -102,10 +96,8 @@ pub fn repeat(elt: T) -> Repeat { /// An iterator that repeats elements of type `A` endlessly by /// applying the provided closure `F: FnMut() -> A`. /// -/// This `struct` is created by the [`repeat_with`] function. +/// This `struct` is created by the [`repeat_with()`] function. /// See its documentation for more. -/// -/// [`repeat_with`]: fn.repeat_with.html #[derive(Copy, Clone, Debug)] #[stable(feature = "iterator_repeat_with", since = "1.28.0")] pub struct RepeatWith { @@ -139,20 +131,18 @@ unsafe impl A> TrustedLen for RepeatWith {} /// The `repeat_with()` function calls the repeater over and over again. /// /// Infinite iterators like `repeat_with()` are often used with adapters like -/// [`take`], in order to make them finite. +/// [`Iterator::take()`], in order to make them finite. /// -/// [`take`]: trait.Iterator.html#method.take -/// -/// If the element type of the iterator you need implements `Clone`, and +/// If the element type of the iterator you need implements [`Clone`], and /// it is OK to keep the source element in memory, you should instead use -/// the [`repeat`] function. -/// -/// [`repeat`]: fn.repeat.html +/// the [`repeat()`] function. /// -/// An iterator produced by `repeat_with()` is not a `DoubleEndedIterator`. -/// If you need `repeat_with()` to return a `DoubleEndedIterator`, +/// An iterator produced by `repeat_with()` is not a [`DoubleEndedIterator`]. +/// If you need `repeat_with()` to return a [`DoubleEndedIterator`], /// please open a GitHub issue explaining your use case. /// +/// [`DoubleEndedIterator`]: crate::iter::DoubleEndedIterator +/// /// # Examples /// /// Basic usage: @@ -201,9 +191,7 @@ pub fn repeat_with A>(repeater: F) -> RepeatWith { /// An iterator that yields nothing. /// -/// This `struct` is created by the [`empty`] function. See its documentation for more. -/// -/// [`empty`]: fn.empty.html +/// This `struct` is created by the [`empty()`] function. See its documentation for more. #[stable(feature = "iter_empty", since = "1.2.0")] pub struct Empty(marker::PhantomData); @@ -292,9 +280,7 @@ pub const fn empty() -> Empty { /// An iterator that yields an element exactly once. /// -/// This `struct` is created by the [`once`] function. See its documentation for more. -/// -/// [`once`]: fn.once.html +/// This `struct` is created by the [`once()`] function. See its documentation for more. #[derive(Clone, Debug)] #[stable(feature = "iter_once", since = "1.2.0")] pub struct Once { @@ -336,12 +322,12 @@ impl FusedIterator for Once {} /// Creates an iterator that yields an element exactly once. /// -/// This is commonly used to adapt a single value into a [`chain`] of other +/// This is commonly used to adapt a single value into a [`chain()`] of other /// kinds of iteration. Maybe you have an iterator that covers almost /// everything, but you need an extra special case. Maybe you have a function /// which works on iterators, but you only need to process one value. /// -/// [`chain`]: trait.Iterator.html#method.chain +/// [`chain()`]: Iterator::chain /// /// # Examples /// @@ -393,10 +379,8 @@ pub fn once(value: T) -> Once { /// An iterator that yields a single element of type `A` by /// applying the provided closure `F: FnOnce() -> A`. /// -/// This `struct` is created by the [`once_with`] function. +/// This `struct` is created by the [`once_with()`] function. /// See its documentation for more. -/// -/// [`once_with`]: fn.once_with.html #[derive(Clone, Debug)] #[stable(feature = "iter_once_with", since = "1.43.0")] pub struct OnceWith { @@ -442,15 +426,14 @@ unsafe impl A> TrustedLen for OnceWith {} /// Creates an iterator that lazily generates a value exactly once by invoking /// the provided closure. /// -/// This is commonly used to adapt a single value generator into a [`chain`] of +/// This is commonly used to adapt a single value generator into a [`chain()`] of /// other kinds of iteration. Maybe you have an iterator that covers almost /// everything, but you need an extra special case. Maybe you have a function /// which works on iterators, but you only need to process one value. /// -/// Unlike [`once`], this function will lazily generate the value on request. +/// Unlike [`once()`], this function will lazily generate the value on request. /// -/// [`once`]: fn.once.html -/// [`chain`]: trait.Iterator.html#method.chain +/// [`chain()`]: Iterator::chain /// /// # Examples /// @@ -505,17 +488,16 @@ pub fn once_with A>(gen: F) -> OnceWith { /// /// This allows creating a custom iterator with any behavior /// without using the more verbose syntax of creating a dedicated type -/// and implementing the `Iterator` trait for it. +/// and implementing the [`Iterator`] trait for it. /// /// Note that the `FromFn` iterator doesn’t make assumptions about the behavior of the closure, /// and therefore conservatively does not implement [`FusedIterator`], -/// or override [`Iterator::size_hint`] from its default `(0, None)`. -/// -/// [`FusedIterator`]: trait.FusedIterator.html -/// [`Iterator::size_hint`]: trait.Iterator.html#method.size_hint +/// or override [`Iterator::size_hint()`] from its default `(0, None)`. /// /// The closure can use captures and its environment to track state across iterations. Depending on -/// how the iterator is used, this may require specifying the `move` keyword on the closure. +/// how the iterator is used, this may require specifying the [`move`] keyword on the closure. +/// +/// [`move`]: ../../../std/keyword.move.html /// /// # Examples /// @@ -549,10 +531,8 @@ where /// An iterator where each iteration calls the provided closure `F: FnMut() -> Option`. /// -/// This `struct` is created by the [`iter::from_fn`] function. +/// This `struct` is created by the [`from_fn()`] function. /// See its documentation for more. -/// -/// [`iter::from_fn`]: fn.from_fn.html #[derive(Clone)] #[stable(feature = "iter_from_fn", since = "1.34.0")] pub struct FromFn(F); @@ -601,10 +581,8 @@ where /// An new iterator where each successive item is computed based on the preceding one. /// -/// This `struct` is created by the [`successors`] function. +/// This `struct` is created by the [`successors()`] function. /// See its documentation for more. -/// -/// [`successors`]: fn.successors.html #[derive(Clone)] #[stable(feature = "iter_successors", since = "1.34.0")] pub struct Successors { diff --git a/library/core/src/iter/traits/accum.rs b/library/core/src/iter/traits/accum.rs index 494c75174ff83..dc0d8087ffbff 100644 --- a/library/core/src/iter/traits/accum.rs +++ b/library/core/src/iter/traits/accum.rs @@ -4,14 +4,13 @@ use crate::ops::{Add, Mul}; /// Trait to represent types that can be created by summing up an iterator. /// -/// This trait is used to implement the [`sum`] method on iterators. Types which -/// implement the trait can be generated by the [`sum`] method. Like +/// This trait is used to implement the [`sum()`] method on iterators. Types which +/// implement the trait can be generated by the [`sum()`] method. Like /// [`FromIterator`] this trait should rarely be called directly and instead -/// interacted with through [`Iterator::sum`]. +/// interacted with through [`Iterator::sum()`]. /// -/// [`sum`]: #tymethod.sum -/// [`FromIterator`]: crate::iter::FromIterator -/// [`Iterator::sum`]: crate::iter::Iterator::sum +/// [`sum()`]: Sum::sum +/// [`FromIterator`]: iter::FromIterator #[stable(feature = "iter_arith_traits", since = "1.12.0")] pub trait Sum: Sized { /// Method which takes an iterator and generates `Self` from the elements by @@ -23,14 +22,13 @@ pub trait Sum: Sized { /// Trait to represent types that can be created by multiplying elements of an /// iterator. /// -/// This trait is used to implement the [`product`] method on iterators. Types -/// which implement the trait can be generated by the [`product`] method. Like +/// This trait is used to implement the [`product()`] method on iterators. Types +/// which implement the trait can be generated by the [`product()`] method. Like /// [`FromIterator`] this trait should rarely be called directly and instead -/// interacted with through [`Iterator::product`]. +/// interacted with through [`Iterator::product()`]. /// -/// [`product`]: #tymethod.product -/// [`FromIterator`]: crate::iter::FromIterator -/// [`Iterator::product`]: crate::iter::Iterator::product +/// [`product()`]: Product::product +/// [`FromIterator`]: iter::FromIterator #[stable(feature = "iter_arith_traits", since = "1.12.0")] pub trait Product: Sized { /// Method which takes an iterator and generates `Self` from the elements by @@ -120,9 +118,9 @@ impl Sum> for Result where T: Sum, { - /// Takes each element in the `Iterator`: if it is an `Err`, no further - /// elements are taken, and the `Err` is returned. Should no `Err` occur, - /// the sum of all elements is returned. + /// Takes each element in the [`Iterator`]: if it is an [`Err`], no further + /// elements are taken, and the [`Err`] is returned. Should no [`Err`] + /// occur, the sum of all elements is returned. /// /// # Examples /// @@ -150,9 +148,9 @@ impl Product> for Result where T: Product, { - /// Takes each element in the `Iterator`: if it is an `Err`, no further - /// elements are taken, and the `Err` is returned. Should no `Err` occur, - /// the product of all elements is returned. + /// Takes each element in the [`Iterator`]: if it is an [`Err`], no further + /// elements are taken, and the [`Err`] is returned. Should no [`Err`] + /// occur, the product of all elements is returned. fn product(iter: I) -> Result where I: Iterator>, @@ -166,9 +164,9 @@ impl Sum> for Option where T: Sum, { - /// Takes each element in the `Iterator`: if it is a `None`, no further - /// elements are taken, and the `None` is returned. Should no `None` occur, - /// the sum of all elements is returned. + /// Takes each element in the [`Iterator`]: if it is a [`None`], no further + /// elements are taken, and the [`None`] is returned. Should no [`None`] + /// occur, the sum of all elements is returned. /// /// # Examples /// @@ -193,9 +191,9 @@ impl Product> for Option where T: Product, { - /// Takes each element in the `Iterator`: if it is a `None`, no further - /// elements are taken, and the `None` is returned. Should no `None` occur, - /// the product of all elements is returned. + /// Takes each element in the [`Iterator`]: if it is a [`None`], no further + /// elements are taken, and the [`None`] is returned. Should no [`None`] + /// occur, the product of all elements is returned. fn product(iter: I) -> Option where I: Iterator>, diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index 75827d785e10e..41a503c4abb4f 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -1,21 +1,15 @@ -/// Conversion from an `Iterator`. +/// Conversion from an [`Iterator`]. /// /// By implementing `FromIterator` for a type, you define how it will be /// created from an iterator. This is common for types which describe a /// collection of some kind. /// -/// `FromIterator`'s [`from_iter`] is rarely called explicitly, and is instead -/// used through [`Iterator`]'s [`collect`] method. See [`collect`]'s +/// [`FromIterator::from_iter()`] is rarely called explicitly, and is instead +/// used through [`Iterator::collect()`] method. See [`Iterator::collect()`]'s /// documentation for more examples. /// -/// [`from_iter`]: #tymethod.from_iter -/// [`Iterator`]: trait.Iterator.html -/// [`collect`]: trait.Iterator.html#method.collect -/// /// See also: [`IntoIterator`]. /// -/// [`IntoIterator`]: trait.IntoIterator.html -/// /// # Examples /// /// Basic usage: @@ -30,7 +24,7 @@ /// assert_eq!(v, vec![5, 5, 5, 5, 5]); /// ``` /// -/// Using [`collect`] to implicitly use `FromIterator`: +/// Using [`Iterator::collect()`] to implicitly use `FromIterator`: /// /// ``` /// let five_fives = std::iter::repeat(5).take(5); @@ -119,7 +113,7 @@ pub trait FromIterator: Sized { fn from_iter>(iter: T) -> Self; } -/// Conversion into an `Iterator`. +/// Conversion into an [`Iterator`]. /// /// By implementing `IntoIterator` for a type, you define how it will be /// converted to an iterator. This is common for types which describe a @@ -130,8 +124,6 @@ pub trait FromIterator: Sized { /// /// See also: [`FromIterator`]. /// -/// [`FromIterator`]: trait.FromIterator.html -/// /// # Examples /// /// Basic usage: @@ -326,7 +318,7 @@ pub trait Extend { /// As this is the only required method for this trait, the [trait-level] docs /// contain more details. /// - /// [trait-level]: trait.Extend.html + /// [trait-level]: Extend /// /// # Examples /// diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index a025bc8b56049..bc03c143d6afb 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -10,11 +10,12 @@ use crate::ops::{ControlFlow, Try}; /// and do not cross: iteration is over when they meet in the middle. /// /// In a similar fashion to the [`Iterator`] protocol, once a -/// `DoubleEndedIterator` returns `None` from a `next_back()`, calling it again -/// may or may not ever return `Some` again. `next()` and `next_back()` are -/// interchangeable for this purpose. +/// `DoubleEndedIterator` returns [`None`] from a [`next_back()`], calling it +/// again may or may not ever return [`Some`] again. [`next()`] and +/// [`next_back()`] are interchangeable for this purpose. /// -/// [`Iterator`]: trait.Iterator.html +/// [`next_back()`]: DoubleEndedIterator::next_back +/// [`next()`]: Iterator::next /// /// # Examples /// @@ -42,7 +43,7 @@ pub trait DoubleEndedIterator: Iterator { /// /// The [trait-level] docs contain more details. /// - /// [trait-level]: trait.DoubleEndedIterator.html + /// [trait-level]: DoubleEndedIterator /// /// # Examples /// @@ -66,7 +67,7 @@ pub trait DoubleEndedIterator: Iterator { /// # Remarks /// /// The elements yielded by `DoubleEndedIterator`'s methods may differ from - /// the ones yielded by `Iterator`'s methods: + /// the ones yielded by [`Iterator`]'s methods: /// /// ``` /// let vec = vec![(1, 'a'), (1, 'b'), (1, 'c'), (2, 'a'), (2, 'b')]; @@ -87,25 +88,23 @@ pub trait DoubleEndedIterator: Iterator { /// vec![(2, 'b'), (1, 'c')] /// ); /// ``` - /// #[stable(feature = "rust1", since = "1.0.0")] fn next_back(&mut self) -> Option; /// Returns the `n`th element from the end of the iterator. /// - /// This is essentially the reversed version of [`nth`]. Although like most indexing - /// operations, the count starts from zero, so `nth_back(0)` returns the first value from - /// the end, `nth_back(1)` the second, and so on. + /// This is essentially the reversed version of [`Iterator::nth()`]. + /// Although like most indexing operations, the count starts from zero, so + /// `nth_back(0)` returns the first value from the end, `nth_back(1)` the + /// second, and so on. /// /// Note that all elements between the end and the returned element will be /// consumed, including the returned element. This also means that calling /// `nth_back(0)` multiple times on the same iterator will return different /// elements. /// - /// `nth_back()` will return [`None`] if `n` is greater than or equal to the length of the - /// iterator. - /// - /// [`nth`]: crate::iter::Iterator::nth + /// `nth_back()` will return [`None`] if `n` is greater than or equal to the + /// length of the iterator. /// /// # Examples /// @@ -145,10 +144,8 @@ pub trait DoubleEndedIterator: Iterator { None } - /// This is the reverse version of [`try_fold()`]: it takes elements - /// starting from the back of the iterator. - /// - /// [`try_fold()`]: Iterator::try_fold + /// This is the reverse version of [`Iterator::try_fold()`]: it takes + /// elements starting from the back of the iterator. /// /// # Examples /// @@ -195,8 +192,8 @@ pub trait DoubleEndedIterator: Iterator { /// An iterator method that reduces the iterator's elements to a single, /// final value, starting from the back. /// - /// This is the reverse version of [`fold()`]: it takes elements starting from - /// the back of the iterator. + /// This is the reverse version of [`Iterator::fold()`]: it takes elements + /// starting from the back of the iterator. /// /// `rfold()` takes two arguments: an initial value, and a closure with two /// arguments: an 'accumulator', and an element. The closure returns the value that @@ -213,8 +210,6 @@ pub trait DoubleEndedIterator: Iterator { /// Folding is useful whenever you have a collection of something, and want /// to produce a single value from it. /// - /// [`fold()`]: Iterator::fold - /// /// # Examples /// /// Basic usage: diff --git a/library/core/src/iter/traits/exact_size.rs b/library/core/src/iter/traits/exact_size.rs index ad87d09588e3a..33ace60a27419 100644 --- a/library/core/src/iter/traits/exact_size.rs +++ b/library/core/src/iter/traits/exact_size.rs @@ -6,17 +6,14 @@ /// backwards, a good start is to know where the end is. /// /// When implementing an `ExactSizeIterator`, you must also implement -/// [`Iterator`]. When doing so, the implementation of [`size_hint`] *must* -/// return the exact size of the iterator. -/// -/// [`Iterator`]: trait.Iterator.html -/// [`size_hint`]: trait.Iterator.html#method.size_hint +/// [`Iterator`]. When doing so, the implementation of [`Iterator::size_hint`] +/// *must* return the exact size of the iterator. /// /// The [`len`] method has a default implementation, so you usually shouldn't /// implement it. However, you may be able to provide a more performant /// implementation than the default, so overriding it in this case makes sense. /// -/// [`len`]: #method.len +/// [`len`]: ExactSizeIterator::len /// /// # Examples /// @@ -72,17 +69,17 @@ pub trait ExactSizeIterator: Iterator { /// Returns the exact length of the iterator. /// /// The implementation ensures that the iterator will return exactly `len()` - /// more times a `Some(T)` value, before returning `None`. + /// more times a [`Some(T)`] value, before returning [`None`]. /// This method has a default implementation, so you usually should not /// implement it directly. However, if you can provide a more efficient /// implementation, you can do so. See the [trait-level] docs for an /// example. /// - /// This function has the same safety guarantees as the [`size_hint`] - /// function. + /// This function has the same safety guarantees as the + /// [`Iterator::size_hint`] function. /// - /// [trait-level]: trait.ExactSizeIterator.html - /// [`size_hint`]: trait.Iterator.html#method.size_hint + /// [trait-level]: ExactSizeIterator + /// [`Some(T)`]: Some /// /// # Examples /// @@ -108,8 +105,8 @@ pub trait ExactSizeIterator: Iterator { /// Returns `true` if the iterator is empty. /// - /// This method has a default implementation using `self.len()`, so you - /// don't need to implement it yourself. + /// This method has a default implementation using + /// [`ExactSizeIterator::len()`], so you don't need to implement it yourself. /// /// # Examples /// diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index b8a09f822b6da..f70e92f0ffafe 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -2203,7 +2203,6 @@ pub trait Iterator { /// /// `iter.find_map(f)` is equivalent to `iter.filter_map(f).next()`. /// - /// /// # Examples /// /// ``` diff --git a/library/core/src/iter/traits/marker.rs b/library/core/src/iter/traits/marker.rs index f287196da03ef..0900676146c0d 100644 --- a/library/core/src/iter/traits/marker.rs +++ b/library/core/src/iter/traits/marker.rs @@ -2,14 +2,13 @@ /// /// Calling next on a fused iterator that has returned `None` once is guaranteed /// to return [`None`] again. This trait should be implemented by all iterators -/// that behave this way because it allows optimizing [`Iterator::fuse`]. +/// that behave this way because it allows optimizing [`Iterator::fuse()`]. /// /// Note: In general, you should not use `FusedIterator` in generic bounds if -/// you need a fused iterator. Instead, you should just call [`Iterator::fuse`] +/// you need a fused iterator. Instead, you should just call [`Iterator::fuse()`] /// on the iterator. If the iterator is already fused, the additional [`Fuse`] /// wrapper will be a no-op with no performance penalty. /// -/// [`Iterator::fuse`]: crate::iter::Iterator::fuse /// [`Fuse`]: crate::iter::Fuse #[stable(feature = "fused", since = "1.26.0")] #[rustc_unsafe_specialization_marker] @@ -24,18 +23,18 @@ impl FusedIterator for &mut I {} /// (lower bound is equal to upper bound), or the upper bound is [`None`]. /// The upper bound must only be [`None`] if the actual iterator length is /// larger than [`usize::MAX`]. In that case, the lower bound must be -/// [`usize::MAX`], resulting in a [`.size_hint`] of `(usize::MAX, None)`. +/// [`usize::MAX`], resulting in a [`Iterator::size_hint()`] of +/// `(usize::MAX, None)`. /// /// The iterator must produce exactly the number of elements it reported /// or diverge before reaching the end. /// /// # Safety /// -/// This trait must only be implemented when the contract is upheld. -/// Consumers of this trait must inspect [`.size_hint`]’s upper bound. +/// This trait must only be implemented when the contract is upheld. Consumers +/// of this trait must inspect [`Iterator::size_hint()`]’s upper bound. /// /// [`usize::MAX`]: crate::usize::MAX -/// [`.size_hint`]: crate::iter::Iterator::size_hint #[unstable(feature = "trusted_len", issue = "37572")] #[rustc_unsafe_specialization_marker] pub unsafe trait TrustedLen: Iterator {} @@ -46,11 +45,12 @@ unsafe impl TrustedLen for &mut I {} /// An iterator that when yielding an item will have taken at least one element /// from its underlying [`SourceIter`]. /// -/// Calling next() guarantees that at least one value of the iterator's underlying source +/// Calling [`next()`] guarantees that at least one value of the iterator's underlying source /// has been moved out and the result of the iterator chain could be inserted in its place, /// assuming structural constraints of the source allow such an insertion. /// In other words this trait indicates that an iterator pipeline can be collected in place. /// -/// [`SourceIter`]: ../../std/iter/trait.SourceIter.html +/// [`SourceIter`]: crate::iter::SourceIter +/// [`next()`]: Iterator::next #[unstable(issue = "none", feature = "inplace_iteration")] pub unsafe trait InPlaceIterable: Iterator {} From 4c92b3dc7d189bdff8f7e78be293d03e43466621 Mon Sep 17 00:00:00 2001 From: Poliorcetics Date: Fri, 18 Sep 2020 09:52:35 +0200 Subject: [PATCH 0575/1052] Apply suggestions from code review Co-authored-by: Joshua Nelson --- library/core/src/future/pending.rs | 2 +- library/core/src/future/poll_fn.rs | 2 +- library/core/src/future/ready.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/core/src/future/pending.rs b/library/core/src/future/pending.rs index 388b9e7bdb0e7..ab162638a1cfe 100644 --- a/library/core/src/future/pending.rs +++ b/library/core/src/future/pending.rs @@ -7,7 +7,7 @@ use crate::task::{Context, Poll}; /// Creates a future which never resolves, representing a computation that never /// finishes. /// -/// This `struct` is created by the [`pending`] function. See its +/// This `struct` is created by [`pending()`]. See its /// documentation for more. #[stable(feature = "future_readiness_fns", since = "1.48.0")] #[must_use = "futures do nothing unless you `.await` or poll them"] diff --git a/library/core/src/future/poll_fn.rs b/library/core/src/future/poll_fn.rs index 3fe7eb88d0ff3..f302cda09e721 100644 --- a/library/core/src/future/poll_fn.rs +++ b/library/core/src/future/poll_fn.rs @@ -33,7 +33,7 @@ where /// A Future that wraps a function returning `Poll`. /// -/// This `struct` is created by the [`poll_fn`] function. See its +/// This `struct` is created by [`poll_fn()`]. See its /// documentation for more. #[must_use = "futures do nothing unless you `.await` or poll them"] #[unstable(feature = "future_poll_fn", issue = "72302")] diff --git a/library/core/src/future/ready.rs b/library/core/src/future/ready.rs index ad93157c3454d..e98f5c570bf3c 100644 --- a/library/core/src/future/ready.rs +++ b/library/core/src/future/ready.rs @@ -4,7 +4,7 @@ use crate::task::{Context, Poll}; /// Creates a future that is immediately ready with a value. /// -/// This `struct` is created by the [`ready`] function. See its +/// This `struct` is created by [`ready()`]. See its /// documentation for more. #[stable(feature = "future_readiness_fns", since = "1.48.0")] #[derive(Debug, Clone)] From 53d5261c696bac17cecfb029f8578ce41d66ef13 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Thu, 17 Sep 2020 09:14:28 +0000 Subject: [PATCH 0576/1052] Move unsafe code of slice `new` function of their Iterator structs Init false state in Split* constructors --- library/core/src/slice/iter.rs | 148 +++++++++++++++++++++++---------- library/core/src/slice/mod.rs | 115 ++++--------------------- 2 files changed, 122 insertions(+), 141 deletions(-) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 1c004f2d3fafc..8c322c202783d 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -82,8 +82,20 @@ unsafe impl Sync for Iter<'_, T> {} unsafe impl Send for Iter<'_, T> {} impl<'a, T> Iter<'a, T> { - pub(super) fn new(ptr: NonNull, end: *const T) -> Self { - Self { ptr, end, _marker: PhantomData } + pub(super) fn new(slice: &'a [T]) -> Self { + let ptr = slice.as_ptr(); + // SAFETY: Similar to `IterMut::new`. + unsafe { + assume(!ptr.is_null()); + + let end = if mem::size_of::() == 0 { + (ptr as *const u8).wrapping_add(slice.len()) as *const T + } else { + ptr.add(slice.len()) + }; + + Self { ptr: NonNull::new_unchecked(ptr as *mut T), end, _marker: PhantomData } + } } /// Views the underlying data as a subslice of the original data. @@ -188,8 +200,35 @@ unsafe impl Sync for IterMut<'_, T> {} unsafe impl Send for IterMut<'_, T> {} impl<'a, T> IterMut<'a, T> { - pub(super) fn new(ptr: NonNull, end: *mut T) -> Self { - Self { ptr, end, _marker: PhantomData } + pub(super) fn new(slice: &'a mut [T]) -> Self { + let ptr = slice.as_mut_ptr(); + // SAFETY: There are several things here: + // + // `ptr` has been obtained by `slice.as_ptr()` where `slice` is a valid + // reference thus it is non-NUL and safe to use and pass to + // `NonNull::new_unchecked` . + // + // Adding `slice.len()` to the starting pointer gives a pointer + // at the end of `slice`. `end` will never be dereferenced, only checked + // for direct pointer equality with `ptr` to check if the iterator is + // done. + // + // In the case of a ZST, the end pointer is just the start pointer plus + // the length, to also allows for the fast `ptr == end` check. + // + // See the `next_unchecked!` and `is_empty!` macros as well as the + // `post_inc_start` method for more informations. + unsafe { + assume(!ptr.is_null()); + + let end = if mem::size_of::() == 0 { + (ptr as *mut u8).wrapping_add(slice.len()) as *mut T + } else { + ptr.add(slice.len()) + }; + + Self { ptr: NonNull::new_unchecked(ptr), end, _marker: PhantomData } + } } /// Views the underlying data as a subslice of the original data. @@ -291,8 +330,8 @@ where } impl<'a, T: 'a, P: FnMut(&T) -> bool> Split<'a, T, P> { - pub(super) fn new(slice: &'a [T], pred: P, finished: bool) -> Self { - Self { v: slice, pred, finished } + pub(super) fn new(slice: &'a [T], pred: P) -> Self { + Self { v: slice, pred, finished: false } } } @@ -405,8 +444,9 @@ where } impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitInclusive<'a, T, P> { - pub(super) fn new(slice: &'a [T], pred: P, finished: bool) -> Self { - Self { v: slice, pred, finished } + #[inline] + pub(super) fn new(slice: &'a [T], pred: P) -> Self { + Self { v: slice, pred, finished: false } } } @@ -509,8 +549,9 @@ where } impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitMut<'a, T, P> { - pub(super) fn new(slice: &'a mut [T], pred: P, finished: bool) -> Self { - Self { v: slice, pred, finished } + #[inline] + pub(super) fn new(slice: &'a mut [T], pred: P) -> Self { + Self { v: slice, pred, finished: false } } } @@ -630,8 +671,9 @@ where } impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitInclusiveMut<'a, T, P> { - pub(super) fn new(slice: &'a mut [T], pred: P, finished: bool) -> Self { - Self { v: slice, pred, finished } + #[inline] + pub(super) fn new(slice: &'a mut [T], pred: P) -> Self { + Self { v: slice, pred, finished: false } } } @@ -742,8 +784,9 @@ where } impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplit<'a, T, P> { - pub(super) fn new(slice: &'a [T], pred: P, finished: bool) -> Self { - Self { inner: Split::new(slice, pred, finished) } + #[inline] + pub(super) fn new(slice: &'a [T], pred: P) -> Self { + Self { inner: Split::new(slice, pred) } } } @@ -819,8 +862,9 @@ where } impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplitMut<'a, T, P> { - pub(super) fn new(slice: &'a mut [T], pred: P, finished: bool) -> Self { - Self { inner: SplitMut::new(slice, pred, finished) } + #[inline] + pub(super) fn new(slice: &'a mut [T], pred: P) -> Self { + Self { inner: SplitMut::new(slice, pred) } } } @@ -1516,13 +1560,15 @@ pub struct ChunksExact<'a, T: 'a> { chunk_size: usize, } -impl<'a, T: 'a> ChunksExact<'a, T> { - pub(super) fn new(slice: &'a [T], rem: &'a [T], size: usize) -> Self { - Self { v: slice, rem, chunk_size: size } +impl<'a, T> ChunksExact<'a, T> { + pub(super) fn new(slice: &'a [T], chunk_size: usize) -> Self { + let rem = slice.len() % chunk_size; + let fst_len = slice.len() - rem; + // SAFETY: 0 <= fst_len <= slice.len() by construction above + let (fst, snd) = unsafe { slice.split_at_unchecked(fst_len) }; + Self { v: fst, rem: snd, chunk_size } } -} -impl<'a, T> ChunksExact<'a, T> { /// Returns the remainder of the original slice that is not going to be /// returned by the iterator. The returned slice has at most `chunk_size-1` /// elements. @@ -1662,13 +1708,15 @@ pub struct ChunksExactMut<'a, T: 'a> { chunk_size: usize, } -impl<'a, T: 'a> ChunksExactMut<'a, T> { - pub(super) fn new(slice: &'a mut [T], rem: &'a mut [T], size: usize) -> Self { - Self { v: slice, rem, chunk_size: size } +impl<'a, T> ChunksExactMut<'a, T> { + pub(super) fn new(slice: &'a mut [T], chunk_size: usize) -> Self { + let rem = slice.len() % chunk_size; + let fst_len = slice.len() - rem; + // SAFETY: 0 <= fst_len <= slice.len() by construction above + let (fst, snd) = unsafe { slice.split_at_mut_unchecked(fst_len) }; + Self { v: fst, rem: snd, chunk_size } } -} -impl<'a, T> ChunksExactMut<'a, T> { /// Returns the remainder of the original slice that is not going to be /// returned by the iterator. The returned slice has at most `chunk_size-1` /// elements. @@ -1801,8 +1849,9 @@ pub struct ArrayWindows<'a, T: 'a, const N: usize> { } impl<'a, T: 'a, const N: usize> ArrayWindows<'a, T, N> { - pub(super) fn new(head: *const T, num: usize) -> Self { - Self { slice_head: head, num, marker: PhantomData } + pub(super) fn new(slice: &'a [T]) -> Self { + let num_windows = slice.len().saturating_sub(N - 1); + Self { slice_head: slice.as_ptr(), num: num_windows, marker: PhantomData } } } @@ -1910,13 +1959,17 @@ pub struct ArrayChunks<'a, T: 'a, const N: usize> { rem: &'a [T], } -impl<'a, T: 'a, const N: usize> ArrayChunks<'a, T, N> { - pub(super) fn new(iter: Iter<'a, [T; N]>, rem: &'a [T]) -> Self { - Self { iter, rem } +impl<'a, T, const N: usize> ArrayChunks<'a, T, N> { + pub(super) fn new(slice: &'a [T]) -> Self { + let len = slice.len() / N; + let (fst, snd) = slice.split_at(len * N); + // SAFETY: We cast a slice of `len * N` elements into + // a slice of `len` many `N` elements chunks. + let array_slice: &[[T; N]] = unsafe { from_raw_parts(fst.as_ptr().cast(), len) }; + + Self { iter: array_slice.iter(), rem: snd } } -} -impl<'a, T, const N: usize> ArrayChunks<'a, T, N> { /// Returns the remainder of the original slice that is not going to be /// returned by the iterator. The returned slice has at most `N-1` /// elements. @@ -2023,13 +2076,18 @@ pub struct ArrayChunksMut<'a, T: 'a, const N: usize> { rem: &'a mut [T], } -impl<'a, T: 'a, const N: usize> ArrayChunksMut<'a, T, N> { - pub(super) fn new(iter: IterMut<'a, [T; N]>, rem: &'a mut [T]) -> Self { - Self { iter, rem } +impl<'a, T, const N: usize> ArrayChunksMut<'a, T, N> { + pub(super) fn new(slice: &'a mut [T]) -> Self { + let len = slice.len() / N; + let (fst, snd) = slice.split_at_mut(len * N); + // SAFETY: We cast a slice of `len * N` elements into + // a slice of `len` many `N` elements chunks. + unsafe { + let array_slice: &mut [[T; N]] = from_raw_parts_mut(fst.as_mut_ptr().cast(), len); + Self { iter: array_slice.iter_mut(), rem: snd } + } } -} -impl<'a, T, const N: usize> ArrayChunksMut<'a, T, N> { /// Returns the remainder of the original slice that is not going to be /// returned by the iterator. The returned slice has at most `N-1` /// elements. @@ -2440,8 +2498,11 @@ pub struct RChunksExact<'a, T: 'a> { } impl<'a, T> RChunksExact<'a, T> { - pub(super) fn new(slice: &'a [T], rem: &'a [T], size: usize) -> Self { - Self { v: slice, rem, chunk_size: size } + pub(super) fn new(slice: &'a [T], chunk_size: usize) -> Self { + let rem = slice.len() % chunk_size; + // SAFETY: 0 <= rem <= slice.len() by construction above + let (fst, snd) = unsafe { slice.split_at_unchecked(rem) }; + Self { v: snd, rem: fst, chunk_size } } /// Returns the remainder of the original slice that is not going to be @@ -2589,8 +2650,11 @@ pub struct RChunksExactMut<'a, T: 'a> { } impl<'a, T> RChunksExactMut<'a, T> { - pub(super) fn new(slice: &'a mut [T], rem: &'a mut [T], size: usize) -> Self { - Self { v: slice, rem, chunk_size: size } + pub(super) fn new(slice: &'a mut [T], chunk_size: usize) -> Self { + let rem = slice.len() % chunk_size; + // SAFETY: 0 <= rem <= slice.len() by construction above + let (fst, snd) = unsafe { slice.split_at_mut_unchecked(rem) }; + Self { v: snd, rem: fst, chunk_size } } /// Returns the remainder of the original slice that is not going to be diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 238e5c209d392..fd98f60c3ddc6 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -9,13 +9,12 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::cmp::Ordering::{self, Equal, Greater, Less}; -use crate::intrinsics::assume; use crate::marker::Copy; use crate::mem; use crate::ops::{FnMut, Range, RangeBounds}; use crate::option::Option; use crate::option::Option::{None, Some}; -use crate::ptr::{self, NonNull}; +use crate::ptr; use crate::result::Result; use crate::result::Result::{Err, Ok}; @@ -679,34 +678,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn iter(&self) -> Iter<'_, T> { - let ptr = self.as_ptr(); - // SAFETY: There are several things here: - // - // `ptr` has been obtained by `self.as_ptr()` where `self` is a valid - // reference thus it is non-NUL and safe to use and pass to - // `NonNull::new_unchecked` . - // - // Adding `self.len()` to the starting pointer gives a pointer - // at the end of `self`. `end` will never be dereferenced, only checked - // for direct pointer equality with `ptr` to check if the iterator is - // done. - // - // In the case of a ZST, the end pointer is just the start pointer plus - // the length, to also allows for the fast `ptr == end` check. - // - // See the `next_unchecked!` and `is_empty!` macros as well as the - // `post_inc_start` method for more informations. - unsafe { - assume(!ptr.is_null()); - - let end = if mem::size_of::() == 0 { - (ptr as *const u8).wrapping_add(self.len()) as *const T - } else { - ptr.add(self.len()) - }; - - Iter::new(NonNull::new_unchecked(ptr as *mut T), end) - } + Iter::new(self) } /// Returns an iterator that allows modifying each value. @@ -723,34 +695,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn iter_mut(&mut self) -> IterMut<'_, T> { - let ptr = self.as_mut_ptr(); - // SAFETY: There are several things here: - // - // `ptr` has been obtained by `self.as_ptr()` where `self` is a valid - // reference thus it is non-NUL and safe to use and pass to - // `NonNull::new_unchecked` . - // - // Adding `self.len()` to the starting pointer gives a pointer - // at the end of `self`. `end` will never be dereferenced, only checked - // for direct pointer equality with `ptr` to check if the iterator is - // done. - // - // In the case of a ZST, the end pointer is just the start pointer plus - // the length, to also allows for the fast `ptr == end` check. - // - // See the `next_unchecked!` and `is_empty!` macros as well as the - // `post_inc_start` method for more informations. - unsafe { - assume(!ptr.is_null()); - - let end = if mem::size_of::() == 0 { - (ptr as *mut u8).wrapping_add(self.len()) as *mut T - } else { - ptr.add(self.len()) - }; - - IterMut::new(NonNull::new_unchecked(ptr), end) - } + IterMut::new(self) } /// Returns an iterator over all contiguous windows of length @@ -892,11 +837,7 @@ impl [T] { #[inline] pub fn chunks_exact(&self, chunk_size: usize) -> ChunksExact<'_, T> { assert_ne!(chunk_size, 0); - let rem = self.len() % chunk_size; - let fst_len = self.len() - rem; - // SAFETY: 0 <= fst_len <= self.len() by construction above - let (fst, snd) = unsafe { self.split_at_unchecked(fst_len) }; - ChunksExact::new(fst, snd, chunk_size) + ChunksExact::new(self, chunk_size) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the @@ -938,11 +879,7 @@ impl [T] { #[inline] pub fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_, T> { assert_ne!(chunk_size, 0); - let rem = self.len() % chunk_size; - let fst_len = self.len() - rem; - // SAFETY: 0 <= fst_len <= self.len() by construction above - let (fst, snd) = unsafe { self.split_at_mut_unchecked(fst_len) }; - ChunksExactMut::new(fst, snd, chunk_size) + ChunksExactMut::new(self, chunk_size) } /// Returns an iterator over `N` elements of the slice at a time, starting at the @@ -976,12 +913,7 @@ impl [T] { #[inline] pub fn array_chunks(&self) -> ArrayChunks<'_, T, N> { assert_ne!(N, 0); - let len = self.len() / N; - let (fst, snd) = self.split_at(len * N); - // SAFETY: We cast a slice of `len * N` elements into - // a slice of `len` many `N` elements chunks. - let array_slice: &[[T; N]] = unsafe { from_raw_parts(fst.as_ptr().cast(), len) }; - ArrayChunks::new(array_slice.iter(), snd) + ArrayChunks::new(self) } /// Returns an iterator over `N` elements of the slice at a time, starting at the @@ -1017,14 +949,7 @@ impl [T] { #[inline] pub fn array_chunks_mut(&mut self) -> ArrayChunksMut<'_, T, N> { assert_ne!(N, 0); - let len = self.len() / N; - let (fst, snd) = self.split_at_mut(len * N); - // SAFETY: We cast a slice of `len * N` elements into - // a slice of `len` many `N` elements chunks. - unsafe { - let array_slice: &mut [[T; N]] = from_raw_parts_mut(fst.as_mut_ptr().cast(), len); - ArrayChunksMut::new(array_slice.iter_mut(), snd) - } + ArrayChunksMut::new(self) } /// Returns an iterator over overlapping windows of `N` elements of a slice, @@ -1056,9 +981,7 @@ impl [T] { #[inline] pub fn array_windows(&self) -> ArrayWindows<'_, T, N> { assert_ne!(N, 0); - - let num_windows = self.len().saturating_sub(N - 1); - ArrayWindows::new(self.as_ptr(), num_windows) + ArrayWindows::new(self) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end @@ -1169,10 +1092,7 @@ impl [T] { #[inline] pub fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact<'_, T> { assert!(chunk_size != 0); - let rem = self.len() % chunk_size; - // SAFETY: 0 <= rem <= self.len() by construction above - let (fst, snd) = unsafe { self.split_at_unchecked(rem) }; - RChunksExact::new(snd, fst, chunk_size) + RChunksExact::new(self, chunk_size) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end @@ -1215,10 +1135,7 @@ impl [T] { #[inline] pub fn rchunks_exact_mut(&mut self, chunk_size: usize) -> RChunksExactMut<'_, T> { assert!(chunk_size != 0); - let rem = self.len() % chunk_size; - // SAFETY: 0 <= rem <= self.len() by construction above - let (fst, snd) = unsafe { self.split_at_mut_unchecked(rem) }; - RChunksExactMut::new(snd, fst, chunk_size) + RChunksExactMut::new(self, chunk_size) } /// Divides one slice into two at an index. @@ -1437,7 +1354,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - Split::new(self, pred, false) + Split::new(self, pred) } /// Returns an iterator over mutable subslices separated by elements that @@ -1459,7 +1376,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - SplitMut::new(self, pred, false) + SplitMut::new(self, pred) } /// Returns an iterator over subslices separated by elements that match @@ -1497,7 +1414,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - SplitInclusive::new(self, pred, false) + SplitInclusive::new(self, pred) } /// Returns an iterator over mutable subslices separated by elements that @@ -1522,7 +1439,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - SplitInclusiveMut::new(self, pred, false) + SplitInclusiveMut::new(self, pred) } /// Returns an iterator over subslices separated by elements that match @@ -1558,7 +1475,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - RSplit::new(self, pred, false) + RSplit::new(self, pred) } /// Returns an iterator over mutable subslices separated by elements that @@ -1584,7 +1501,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - RSplitMut::new(self, pred, false) + RSplitMut::new(self, pred) } /// Returns an iterator over subslices separated by elements that match From b65937031d7c5a1ad45c847e9d3d97c822c1ac81 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Thu, 17 Sep 2020 09:23:14 +0000 Subject: [PATCH 0577/1052] inline inner function of inlining methods --- library/core/src/slice/iter.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 8c322c202783d..546edef7f5753 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -82,6 +82,7 @@ unsafe impl Sync for Iter<'_, T> {} unsafe impl Send for Iter<'_, T> {} impl<'a, T> Iter<'a, T> { + #[inline] pub(super) fn new(slice: &'a [T]) -> Self { let ptr = slice.as_ptr(); // SAFETY: Similar to `IterMut::new`. @@ -200,6 +201,7 @@ unsafe impl Sync for IterMut<'_, T> {} unsafe impl Send for IterMut<'_, T> {} impl<'a, T> IterMut<'a, T> { + #[inline] pub(super) fn new(slice: &'a mut [T]) -> Self { let ptr = slice.as_mut_ptr(); // SAFETY: There are several things here: @@ -330,6 +332,7 @@ where } impl<'a, T: 'a, P: FnMut(&T) -> bool> Split<'a, T, P> { + #[inline] pub(super) fn new(slice: &'a [T], pred: P) -> Self { Self { v: slice, pred, finished: false } } @@ -974,6 +977,7 @@ where } impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitN<'a, T, P> { + #[inline] pub(super) fn new(s: Split<'a, T, P>, n: usize) -> Self { Self { inner: GenericSplitN { iter: s, count: n } } } @@ -1006,6 +1010,7 @@ where } impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplitN<'a, T, P> { + #[inline] pub(super) fn new(s: RSplit<'a, T, P>, n: usize) -> Self { Self { inner: GenericSplitN { iter: s, count: n } } } @@ -1037,6 +1042,7 @@ where } impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitNMut<'a, T, P> { + #[inline] pub(super) fn new(s: SplitMut<'a, T, P>, n: usize) -> Self { Self { inner: GenericSplitN { iter: s, count: n } } } @@ -1069,6 +1075,7 @@ where } impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplitNMut<'a, T, P> { + #[inline] pub(super) fn new(s: RSplitMut<'a, T, P>, n: usize) -> Self { Self { inner: GenericSplitN { iter: s, count: n } } } @@ -1103,6 +1110,7 @@ pub struct Windows<'a, T: 'a> { } impl<'a, T: 'a> Windows<'a, T> { + #[inline] pub(super) fn new(slice: &'a [T], size: usize) -> Self { Self { v: slice, size } } @@ -1241,6 +1249,7 @@ pub struct Chunks<'a, T: 'a> { } impl<'a, T: 'a> Chunks<'a, T> { + #[inline] pub(super) fn new(slice: &'a [T], size: usize) -> Self { Self { v: slice, chunk_size: size } } @@ -1401,6 +1410,7 @@ pub struct ChunksMut<'a, T: 'a> { } impl<'a, T: 'a> ChunksMut<'a, T> { + #[inline] pub(super) fn new(slice: &'a mut [T], size: usize) -> Self { Self { v: slice, chunk_size: size } } @@ -1561,6 +1571,7 @@ pub struct ChunksExact<'a, T: 'a> { } impl<'a, T> ChunksExact<'a, T> { + #[inline] pub(super) fn new(slice: &'a [T], chunk_size: usize) -> Self { let rem = slice.len() % chunk_size; let fst_len = slice.len() - rem; @@ -1709,6 +1720,7 @@ pub struct ChunksExactMut<'a, T: 'a> { } impl<'a, T> ChunksExactMut<'a, T> { + #[inline] pub(super) fn new(slice: &'a mut [T], chunk_size: usize) -> Self { let rem = slice.len() % chunk_size; let fst_len = slice.len() - rem; @@ -1849,6 +1861,7 @@ pub struct ArrayWindows<'a, T: 'a, const N: usize> { } impl<'a, T: 'a, const N: usize> ArrayWindows<'a, T, N> { + #[inline] pub(super) fn new(slice: &'a [T]) -> Self { let num_windows = slice.len().saturating_sub(N - 1); Self { slice_head: slice.as_ptr(), num: num_windows, marker: PhantomData } @@ -1960,6 +1973,7 @@ pub struct ArrayChunks<'a, T: 'a, const N: usize> { } impl<'a, T, const N: usize> ArrayChunks<'a, T, N> { + #[inline] pub(super) fn new(slice: &'a [T]) -> Self { let len = slice.len() / N; let (fst, snd) = slice.split_at(len * N); @@ -2077,6 +2091,7 @@ pub struct ArrayChunksMut<'a, T: 'a, const N: usize> { } impl<'a, T, const N: usize> ArrayChunksMut<'a, T, N> { + #[inline] pub(super) fn new(slice: &'a mut [T]) -> Self { let len = slice.len() / N; let (fst, snd) = slice.split_at_mut(len * N); @@ -2185,6 +2200,7 @@ pub struct RChunks<'a, T: 'a> { } impl<'a, T: 'a> RChunks<'a, T> { + #[inline] pub(super) fn new(slice: &'a [T], size: usize) -> Self { Self { v: slice, chunk_size: size } } @@ -2341,6 +2357,7 @@ pub struct RChunksMut<'a, T: 'a> { } impl<'a, T: 'a> RChunksMut<'a, T> { + #[inline] pub(super) fn new(slice: &'a mut [T], size: usize) -> Self { Self { v: slice, chunk_size: size } } @@ -2498,6 +2515,7 @@ pub struct RChunksExact<'a, T: 'a> { } impl<'a, T> RChunksExact<'a, T> { + #[inline] pub(super) fn new(slice: &'a [T], chunk_size: usize) -> Self { let rem = slice.len() % chunk_size; // SAFETY: 0 <= rem <= slice.len() by construction above @@ -2650,6 +2668,7 @@ pub struct RChunksExactMut<'a, T: 'a> { } impl<'a, T> RChunksExactMut<'a, T> { + #[inline] pub(super) fn new(slice: &'a mut [T], chunk_size: usize) -> Self { let rem = slice.len() % chunk_size; // SAFETY: 0 <= rem <= slice.len() by construction above From bdb039d10b2fdbbdf3b906e8a3f941ebbdbb71fd Mon Sep 17 00:00:00 2001 From: Denis Vasilik Date: Fri, 18 Sep 2020 10:50:04 +0200 Subject: [PATCH 0578/1052] Use intra-doc links --- library/alloc/src/collections/binary_heap.rs | 26 ++++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index 24d17fdd880ba..8181e413d893a 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -15,7 +15,6 @@ //! [dijkstra]: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm //! [sssp]: https://en.wikipedia.org/wiki/Shortest_path_problem //! [dir_graph]: https://en.wikipedia.org/wiki/Directed_graph -//! [`BinaryHeap`]: struct.BinaryHeap.html //! //! ``` //! use std::cmp::Ordering; @@ -240,10 +239,10 @@ use super::SpecExtend; /// The value for `push` is an expected cost; the method documentation gives a /// more detailed analysis. /// -/// [push]: #method.push -/// [pop]: #method.pop -/// [peek]: #method.peek -/// [peek\_mut]: #method.peek_mut +/// [push]: BinaryHeap::push +/// [pop]: BinaryHeap::pop +/// [peek]: BinaryHeap::peek +/// [peek\_mut]: BinaryHeap::peek_mut #[stable(feature = "rust1", since = "1.0.0")] pub struct BinaryHeap { data: Vec, @@ -255,8 +254,7 @@ pub struct BinaryHeap { /// This `struct` is created by the [`peek_mut`] method on [`BinaryHeap`]. See /// its documentation for more. /// -/// [`peek_mut`]: struct.BinaryHeap.html#method.peek_mut -/// [`BinaryHeap`]: struct.BinaryHeap.html +/// [`peek_mut`]: BinaryHeap::peek_mut #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] pub struct PeekMut<'a, T: 'a + Ord> { heap: &'a mut BinaryHeap, @@ -802,7 +800,7 @@ impl BinaryHeap { /// heap.push(4); /// ``` /// - /// [`reserve`]: #method.reserve + /// [`reserve`]: BinaryHeap::reserve #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve_exact(&mut self, additional: usize) { self.data.reserve_exact(additional); @@ -1060,8 +1058,7 @@ impl Drop for Hole<'_, T> { /// This `struct` is created by the [`iter`] method on [`BinaryHeap`]. See its /// documentation for more. /// -/// [`iter`]: struct.BinaryHeap.html#method.iter -/// [`BinaryHeap`]: struct.BinaryHeap.html +/// [`iter`]: BinaryHeap::iter #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, T: 'a> { iter: slice::Iter<'a, T>, @@ -1125,8 +1122,7 @@ impl FusedIterator for Iter<'_, T> {} /// This `struct` is created by the [`into_iter`] method on [`BinaryHeap`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// -/// [`into_iter`]: struct.BinaryHeap.html#method.into_iter -/// [`BinaryHeap`]: struct.BinaryHeap.html +/// [`into_iter`]: BinaryHeap::into_iter #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] pub struct IntoIter { @@ -1230,8 +1226,7 @@ unsafe impl TrustedLen for IntoIterSorted {} /// This `struct` is created by the [`drain`] method on [`BinaryHeap`]. See its /// documentation for more. /// -/// [`drain`]: struct.BinaryHeap.html#method.drain -/// [`BinaryHeap`]: struct.BinaryHeap.html +/// [`drain`]: BinaryHeap::drain #[stable(feature = "drain", since = "1.6.0")] #[derive(Debug)] pub struct Drain<'a, T: 'a> { @@ -1276,8 +1271,7 @@ impl FusedIterator for Drain<'_, T> {} /// This `struct` is created by the [`drain_sorted`] method on [`BinaryHeap`]. See its /// documentation for more. /// -/// [`drain_sorted`]: struct.BinaryHeap.html#method.drain_sorted -/// [`BinaryHeap`]: struct.BinaryHeap.html +/// [`drain_sorted`]: BinaryHeap::drain_sorted #[unstable(feature = "binary_heap_drain_sorted", issue = "59278")] #[derive(Debug)] pub struct DrainSorted<'a, T: Ord> { From 3ccb1c37e6f37070b090b63acb3751438c152ed4 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Fri, 18 Sep 2020 06:07:19 +0000 Subject: [PATCH 0579/1052] Remove redundancy in cache key --- compiler/rustc_infer/src/infer/combine.rs | 7 +++---- compiler/rustc_middle/src/ty/print/mod.rs | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 68197f75b9f7b..5bd6c667fd7f6 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -500,7 +500,7 @@ struct Generalizer<'cx, 'tcx> { param_env: ty::ParamEnv<'tcx>, - cache: MiniMap<(Ty<'tcx>, Ty<'tcx>), RelateResult<'tcx, Ty<'tcx>>>, + cache: MiniMap, RelateResult<'tcx, Ty<'tcx>>>, } /// Result from a generalization operation. This includes @@ -598,8 +598,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { assert_eq!(t, t2); // we are abusing TypeRelation here; both LHS and RHS ought to be == - let cache_key = (t, t2); - if let Some(result) = self.cache.get(&cache_key) { + if let Some(result) = self.cache.get(&t) { return result.clone(); } debug!("generalize: t={:?}", t); @@ -667,7 +666,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { _ => relate::super_relate_tys(self, t, t), }; - self.cache.insert(cache_key, result.clone()); + self.cache.insert(t, result.clone()); return result; } diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 4e424156c4d41..f315292dab546 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -265,7 +265,7 @@ pub trait Printer<'tcx>: Sized { /// type. It's just a heuristic so it makes some questionable /// decisions and we may want to adjust it later. /// -/// Visited set is needed in to avoid full iteration over +/// Visited set is needed to avoid full iteration over /// deeply nested tuples that have no DefId. fn characteristic_def_id_of_type_cached<'a>( ty: Ty<'a>, From bffd2111f7b033902e60889da5d3fa7a033a7d5e Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Fri, 18 Sep 2020 11:09:36 +0200 Subject: [PATCH 0580/1052] Finish moving to intra doc links for std::sync --- library/std/src/sync/barrier.rs | 23 +++++------- library/std/src/sync/once.rs | 62 ++++++++++++++------------------- 2 files changed, 34 insertions(+), 51 deletions(-) diff --git a/library/std/src/sync/barrier.rs b/library/std/src/sync/barrier.rs index 204d7f3084f03..b8b4baf14b4c1 100644 --- a/library/std/src/sync/barrier.rs +++ b/library/std/src/sync/barrier.rs @@ -43,11 +43,8 @@ struct BarrierState { generation_id: usize, } -/// A `BarrierWaitResult` is returned by [`wait`] when all threads in the [`Barrier`] -/// have rendezvoused. -/// -/// [`wait`]: struct.Barrier.html#method.wait -/// [`Barrier`]: struct.Barrier.html +/// A `BarrierWaitResult` is returned by [`Barrier::wait()`] when all threads +/// in the [`Barrier`] have rendezvoused. /// /// # Examples /// @@ -70,10 +67,10 @@ impl fmt::Debug for Barrier { impl Barrier { /// Creates a new barrier that can block a given number of threads. /// - /// A barrier will block `n`-1 threads which call [`wait`] and then wake up - /// all threads at once when the `n`th thread calls [`wait`]. + /// A barrier will block `n`-1 threads which call [`wait()`] and then wake + /// up all threads at once when the `n`th thread calls [`wait()`]. /// - /// [`wait`]: #method.wait + /// [`wait()`]: Barrier::wait /// /// # Examples /// @@ -99,10 +96,7 @@ impl Barrier { /// A single (arbitrary) thread will receive a [`BarrierWaitResult`] that /// returns `true` from [`is_leader`] when returning from this function, and /// all other threads will receive a result that will return `false` from - /// [`is_leader`]. - /// - /// [`BarrierWaitResult`]: struct.BarrierWaitResult.html - /// [`is_leader`]: struct.BarrierWaitResult.html#method.is_leader + /// [`BarrierWaitResult::is_leader`]. /// /// # Examples /// @@ -156,13 +150,12 @@ impl fmt::Debug for BarrierWaitResult { } impl BarrierWaitResult { - /// Returns `true` if this thread from [`wait`] is the "leader thread". + /// Returns `true` if this thread from [`Barrier::wait()`] is the + /// "leader thread". /// /// Only one thread will have `true` returned from their result, all other /// threads will have `false` returned. /// - /// [`wait`]: struct.Barrier.html#method.wait - /// /// # Examples /// /// ``` diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs index 29ae338cb2ec7..ee8902bf764bf 100644 --- a/library/std/src/sync/once.rs +++ b/library/std/src/sync/once.rs @@ -95,11 +95,9 @@ use crate::thread::{self, Thread}; /// A synchronization primitive which can be used to run a one-time global /// initialization. Useful for one-time initialization for FFI or related -/// functionality. This type can only be constructed with the [`Once::new`] +/// functionality. This type can only be constructed with the [`Once::new()`] /// constructor. /// -/// [`Once::new`]: struct.Once.html#method.new -/// /// # Examples /// /// ``` @@ -126,11 +124,8 @@ unsafe impl Sync for Once {} #[stable(feature = "rust1", since = "1.0.0")] unsafe impl Send for Once {} -/// State yielded to [`call_once_force`]’s closure parameter. The state can be -/// used to query the poison status of the [`Once`]. -/// -/// [`call_once_force`]: struct.Once.html#method.call_once_force -/// [`Once`]: struct.Once.html +/// State yielded to [`Once::call_once_force()`]’s closure parameter. The state +/// can be used to query the poison status of the [`Once`]. #[unstable(feature = "once_poison", issue = "33577")] #[derive(Debug)] pub struct OnceState { @@ -140,8 +135,6 @@ pub struct OnceState { /// Initialization value for static [`Once`] values. /// -/// [`Once`]: struct.Once.html -/// /// # Examples /// /// ``` @@ -212,7 +205,7 @@ impl Once { /// happens-before relation between the closure and code executing after the /// return). /// - /// If the given closure recursively invokes `call_once` on the same `Once` + /// If the given closure recursively invokes `call_once` on the same [`Once`] /// instance the exact behavior is not specified, allowed outcomes are /// a panic or a deadlock. /// @@ -249,7 +242,7 @@ impl Once { /// /// The closure `f` will only be executed once if this is called /// concurrently amongst many threads. If that closure panics, however, then - /// it will *poison* this `Once` instance, causing all future invocations of + /// it will *poison* this [`Once`] instance, causing all future invocations of /// `call_once` to also panic. /// /// This is similar to [poisoning with mutexes][poison]. @@ -269,21 +262,21 @@ impl Once { self.call_inner(false, &mut |_| f.take().unwrap()()); } - /// Performs the same function as [`call_once`] except ignores poisoning. + /// Performs the same function as [`call_once()`] except ignores poisoning. /// - /// Unlike [`call_once`], if this `Once` has been poisoned (i.e., a previous - /// call to `call_once` or `call_once_force` caused a panic), calling - /// `call_once_force` will still invoke the closure `f` and will _not_ - /// result in an immediate panic. If `f` panics, the `Once` will remain - /// in a poison state. If `f` does _not_ panic, the `Once` will no - /// longer be in a poison state and all future calls to `call_once` or - /// `call_once_force` will be no-ops. + /// Unlike [`call_once()`], if this [`Once`] has been poisoned (i.e., a previous + /// call to [`call_once()`] or [`call_once_force()`] caused a panic), calling + /// [`call_once_force()`] will still invoke the closure `f` and will _not_ + /// result in an immediate panic. If `f` panics, the [`Once`] will remain + /// in a poison state. If `f` does _not_ panic, the [`Once`] will no + /// longer be in a poison state and all future calls to [`call_once()`] or + /// [`call_once_force()`] will be no-ops. /// /// The closure `f` is yielded a [`OnceState`] structure which can be used - /// to query the poison status of the `Once`. + /// to query the poison status of the [`Once`]. /// - /// [`call_once`]: struct.Once.html#method.call_once - /// [`OnceState`]: struct.OnceState.html + /// [`call_once()`]: Once::call_once + /// [`call_once_force()`]: Once::call_once_force /// /// # Examples /// @@ -329,18 +322,20 @@ impl Once { self.call_inner(true, &mut |p| f.take().unwrap()(p)); } - /// Returns `true` if some `call_once` call has completed + /// Returns `true` if some [`call_once()`] call has completed /// successfully. Specifically, `is_completed` will return false in /// the following situations: - /// * `call_once` was not called at all, - /// * `call_once` was called, but has not yet completed, - /// * the `Once` instance is poisoned + /// * [`call_once()`] was not called at all, + /// * [`call_once()`] was called, but has not yet completed, + /// * the [`Once`] instance is poisoned /// - /// This function returning `false` does not mean that `Once` has not been + /// This function returning `false` does not mean that [`Once`] has not been /// executed. For example, it may have been executed in the time between /// when `is_completed` starts executing and when it returns, in which case /// the `false` return value would be stale (but still permissible). /// + /// [`call_once()`]: Once::call_once + /// /// # Examples /// /// ``` @@ -519,14 +514,11 @@ impl Drop for WaiterQueue<'_> { impl OnceState { /// Returns `true` if the associated [`Once`] was poisoned prior to the - /// invocation of the closure passed to [`call_once_force`]. - /// - /// [`call_once_force`]: struct.Once.html#method.call_once_force - /// [`Once`]: struct.Once.html + /// invocation of the closure passed to [`Once::call_once_force()`]. /// /// # Examples /// - /// A poisoned `Once`: + /// A poisoned [`Once`]: /// /// ``` /// #![feature(once_poison)] @@ -547,7 +539,7 @@ impl OnceState { /// }); /// ``` /// - /// An unpoisoned `Once`: + /// An unpoisoned [`Once`]: /// /// ``` /// #![feature(once_poison)] @@ -565,8 +557,6 @@ impl OnceState { } /// Poison the associated [`Once`] without explicitly panicking. - /// - /// [`Once`]: struct.Once.html // NOTE: This is currently only exposed for the `lazy` module pub(crate) fn poison(&self) { self.set_state_on_drop_to.set(POISONED); From 982ec0d0c9ed93d806340502d48de190e1558a64 Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Fri, 18 Sep 2020 11:14:36 +0200 Subject: [PATCH 0581/1052] Fix broken link --- library/core/src/iter/sources.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/iter/sources.rs b/library/core/src/iter/sources.rs index 0348d5a10d984..c28538ef027c0 100644 --- a/library/core/src/iter/sources.rs +++ b/library/core/src/iter/sources.rs @@ -497,7 +497,7 @@ pub fn once_with A>(gen: F) -> OnceWith { /// 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 +/// [`move`]: ../../std/keyword.move.html /// /// # Examples /// From b534d9f6e1e2b3e77842c5ededa62f6bcfb2ea58 Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Fri, 18 Sep 2020 12:04:49 +0200 Subject: [PATCH 0582/1052] Fix broken link --- library/std/src/sync/barrier.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/sync/barrier.rs b/library/std/src/sync/barrier.rs index b8b4baf14b4c1..8d3e30dbd4545 100644 --- a/library/std/src/sync/barrier.rs +++ b/library/std/src/sync/barrier.rs @@ -94,9 +94,9 @@ impl Barrier { /// be used continuously. /// /// A single (arbitrary) thread will receive a [`BarrierWaitResult`] that - /// returns `true` from [`is_leader`] when returning from this function, and - /// all other threads will receive a result that will return `false` from - /// [`BarrierWaitResult::is_leader`]. + /// returns `true` from [`BarrierWaitResult::is_leader()`] when returning + /// from this function, and all other threads will receive a result that + /// will return `false` from [`BarrierWaitResult::is_leader()`]. /// /// # Examples /// From 4af1b90b41ba19cb2ab6c84291123822ac6ed26e Mon Sep 17 00:00:00 2001 From: Denis Vasilik Date: Fri, 18 Sep 2020 12:38:25 +0200 Subject: [PATCH 0583/1052] Move to intra-doc links --- library/alloc/src/collections/vec_deque.rs | 48 ++++++++++++---------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/library/alloc/src/collections/vec_deque.rs b/library/alloc/src/collections/vec_deque.rs index 65cfe9a9b4996..8e9acc42d9aba 100644 --- a/library/alloc/src/collections/vec_deque.rs +++ b/library/alloc/src/collections/vec_deque.rs @@ -48,11 +48,11 @@ const MAXIMUM_ZST_CAPACITY: usize = 1 << (core::mem::size_of::() * 8 - 1) /// so that its elements do not wrap, and returns a mutable slice to the /// now-contiguous element sequence. /// -/// [`push_back`]: #method.push_back -/// [`pop_front`]: #method.pop_front -/// [`extend`]: #method.extend -/// [`append`]: #method.append -/// [`make_contiguous`]: #method.make_contiguous +/// [`push_back`]: VecDeque::push_back +/// [`pop_front`]: VecDeque::pop_front +/// [`extend`]: VecDeque::extend +/// [`append`]: VecDeque::append +/// [`make_contiguous`]: VecDeque::make_contiguous #[cfg_attr(not(test), rustc_diagnostic_item = "vecdeque_type")] #[stable(feature = "rust1", since = "1.0.0")] pub struct VecDeque { @@ -640,7 +640,7 @@ impl VecDeque { /// assert!(buf.capacity() >= 11); /// ``` /// - /// [`reserve`]: #method.reserve + /// [`reserve`]: VecDeque::reserve #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve_exact(&mut self, additional: usize) { self.reserve(additional); @@ -987,8 +987,10 @@ impl VecDeque { /// Returns a pair of slices which contain, in order, the contents of the /// `VecDeque`. /// - /// If [`make_contiguous`](#method.make_contiguous) was previously called, all elements - /// of the `VecDeque` will be in the first slice and the second slice will be empty. + /// If [`make_contiguous`] was previously called, all elements of the + /// `VecDeque` will be in the first slice and the second slice will be empty. + /// + /// [`make_contiguous`]: VecDeque::make_contiguous /// /// # Examples /// @@ -1020,8 +1022,10 @@ impl VecDeque { /// Returns a pair of slices which contain, in order, the contents of the /// `VecDeque`. /// - /// If [`make_contiguous`](#method.make_contiguous) was previously called, all elements - /// of the `VecDeque` will be in the first slice and the second slice will be empty. + /// If [`make_contiguous`] was previously called, all elements of the + /// `VecDeque` will be in the first slice and the second slice will be empty. + /// + /// [`make_contiguous`]: VecDeque::make_contiguous /// /// # Examples /// @@ -2160,15 +2164,20 @@ impl VecDeque { } } - /// Rearranges the internal storage of this deque so it is one contiguous slice, which is then returned. + /// Rearranges the internal storage of this deque so it is one contiguous + /// slice, which is then returned. /// - /// This method does not allocate and does not change the order of the inserted elements. - /// As it returns a mutable slice, this can be used to sort or binary search a deque. + /// This method does not allocate and does not change the order of the + /// inserted elements. As it returns a mutable slice, this can be used to + /// sort or binary search a deque. /// - /// Once the internal storage is contiguous, the [`as_slices`](#method.as_slices) and - /// [`as_mut_slices`](#method.as_mut_slices) methods will return the entire contents of the + /// Once the internal storage is contiguous, the [`as_slices`] and + /// [`as_mut_slices`] methods will return the entire contents of the /// `VecDeque` in a single slice. /// + /// [`as_slices`]: VecDeque::as_slices + /// [`as_mut_slices`]: VecDeque::as_mut_slices + /// /// # Examples /// /// Sorting the content of a deque. @@ -2495,8 +2504,7 @@ fn count(tail: usize, head: usize, size: usize) -> usize { /// This `struct` is created by the [`iter`] method on [`VecDeque`]. See its /// documentation for more. /// -/// [`iter`]: struct.VecDeque.html#method.iter -/// [`VecDeque`]: struct.VecDeque.html +/// [`iter`]: VecDeque::iter #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, T: 'a> { ring: &'a [T], @@ -2650,8 +2658,7 @@ impl FusedIterator for Iter<'_, T> {} /// This `struct` is created by the [`iter_mut`] method on [`VecDeque`]. See its /// documentation for more. /// -/// [`iter_mut`]: struct.VecDeque.html#method.iter_mut -/// [`VecDeque`]: struct.VecDeque.html +/// [`iter_mut`]: VecDeque::iter_mut #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, T: 'a> { ring: &'a mut [T], @@ -2756,8 +2763,7 @@ impl FusedIterator for IterMut<'_, T> {} /// This `struct` is created by the [`into_iter`] method on [`VecDeque`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// -/// [`into_iter`]: struct.VecDeque.html#method.into_iter -/// [`VecDeque`]: struct.VecDeque.html +/// [`into_iter`]: VecDeque::into_iter #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { From 49c8fcb47e8476cc8b95b547e97329c143d9c5f1 Mon Sep 17 00:00:00 2001 From: Denis Vasilik Date: Fri, 18 Sep 2020 12:38:37 +0200 Subject: [PATCH 0584/1052] Use intra-doc links --- library/alloc/src/collections/vec_deque/drain.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/drain.rs b/library/alloc/src/collections/vec_deque/drain.rs index 1ae94de75adb7..4ffb435d1e366 100644 --- a/library/alloc/src/collections/vec_deque/drain.rs +++ b/library/alloc/src/collections/vec_deque/drain.rs @@ -9,8 +9,7 @@ use super::{count, Iter, VecDeque}; /// This `struct` is created by the [`drain`] method on [`VecDeque`]. See its /// documentation for more. /// -/// [`drain`]: struct.VecDeque.html#method.drain -/// [`VecDeque`]: struct.VecDeque.html +/// [`drain`]: VecDeque::drain #[stable(feature = "drain", since = "1.6.0")] pub struct Drain<'a, T: 'a> { pub(crate) after_tail: usize, From 0bc405e3521d84cfaef7d94f1ae40c6c16796c8b Mon Sep 17 00:00:00 2001 From: khyperia Date: Fri, 18 Sep 2020 13:06:53 +0200 Subject: [PATCH 0585/1052] Remove DeclareMethods --- compiler/rustc_codegen_llvm/src/context.rs | 11 +++++ compiler/rustc_codegen_llvm/src/declare.rs | 43 +++++++++++++---- compiler/rustc_codegen_ssa/src/base.rs | 22 +++++---- .../rustc_codegen_ssa/src/traits/declare.rs | 46 +------------------ compiler/rustc_codegen_ssa/src/traits/misc.rs | 2 + compiler/rustc_codegen_ssa/src/traits/mod.rs | 4 +- 6 files changed, 62 insertions(+), 66 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 1c51a9df5d884..1696f35563d91 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -433,6 +433,17 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { llvm::LLVMSetSection(g, section.as_ptr()); } } + + fn declare_c_main(&self, fn_type: Self::Type) -> Option { + if self.get_declared_value("main").is_none() { + Some(self.declare_cfn("main", fn_type)) + } else { + // If the symbol already exists, it is an error: for example, the user wrote + // #[no_mangle] extern "C" fn main(..) {..} + // instead of #[start] + None + } + } } impl CodegenCx<'b, 'tcx> { diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index ec42bd4a039e6..a3d6882940a09 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -51,17 +51,32 @@ fn declare_raw_fn( llfn } -impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> { - fn declare_global(&self, name: &str, ty: &'ll Type) -> &'ll Value { +impl CodegenCx<'ll, 'tcx> { + /// Declare a global value. + /// + /// If there’s a value with the same name already declared, the function will + /// return its Value instead. + pub fn declare_global(&self, name: &str, ty: &'ll Type) -> &'ll Value { debug!("declare_global(name={:?})", name); unsafe { llvm::LLVMRustGetOrInsertGlobal(self.llmod, name.as_ptr().cast(), name.len(), ty) } } - fn declare_cfn(&self, name: &str, fn_type: &'ll Type) -> &'ll Value { + /// Declare a C ABI function. + /// + /// Only use this for foreign function ABIs and glue. For Rust functions use + /// `declare_fn` instead. + /// + /// If there’s a value with the same name already declared, the function will + /// update the declaration and return existing Value instead. + pub fn declare_cfn(&self, name: &str, fn_type: &'ll Type) -> &'ll Value { declare_raw_fn(self, name, llvm::CCallConv, fn_type) } - fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> &'ll Value { + /// Declare a Rust function. + /// + /// If there’s a value with the same name already declared, the function will + /// update the declaration and return existing Value instead. + pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> &'ll Value { debug!("declare_rust_fn(name={:?}, fn_abi={:?})", name, fn_abi); let llfn = declare_raw_fn(self, name, fn_abi.llvm_cconv(), fn_abi.llvm_type(self)); @@ -69,7 +84,13 @@ impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> { llfn } - fn define_global(&self, name: &str, ty: &'ll Type) -> Option<&'ll Value> { + /// Declare a global with an intention to define it. + /// + /// Use this function when you intend to define a global. This function will + /// return `None` if the name already has a definition associated with it. In that + /// case an error should be reported to the user, because it usually happens due + /// to user’s fault (e.g., misuse of `#[no_mangle]` or `#[export_name]` attributes). + pub fn define_global(&self, name: &str, ty: &'ll Type) -> Option<&'ll Value> { if self.get_defined_value(name).is_some() { None } else { @@ -77,16 +98,22 @@ impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - fn define_private_global(&self, ty: &'ll Type) -> &'ll Value { + /// Declare a private global + /// + /// Use this function when you intend to define a global without a name. + pub fn define_private_global(&self, ty: &'ll Type) -> &'ll Value { unsafe { llvm::LLVMRustInsertPrivateGlobal(self.llmod, ty) } } - fn get_declared_value(&self, name: &str) -> Option<&'ll Value> { + /// Gets declared value by name. + pub fn get_declared_value(&self, name: &str) -> Option<&'ll Value> { debug!("get_declared_value(name={:?})", name); unsafe { llvm::LLVMRustGetNamedValue(self.llmod, name.as_ptr().cast(), name.len()) } } - fn get_defined_value(&self, name: &str) -> Option<&'ll Value> { + /// Gets defined or externally defined (AvailableExternally linkage) value by + /// name. + pub fn get_defined_value(&self, name: &str) -> Option<&'ll Value> { self.get_declared_value(name).and_then(|val| { let declaration = unsafe { llvm::LLVMIsDeclaration(val) != 0 }; if !declaration { Some(val) } else { None } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 6fc849969a4d6..d82fc2c9f63d9 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -407,16 +407,18 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // listing. let main_ret_ty = cx.tcx().erase_regions(&main_ret_ty.no_bound_vars().unwrap()); - if cx.get_declared_value("main").is_some() { - // FIXME: We should be smart and show a better diagnostic here. - cx.sess() - .struct_span_err(sp, "entry symbol `main` declared multiple times") - .help("did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead") - .emit(); - cx.sess().abort_if_errors(); - bug!(); - } - let llfn = cx.declare_cfn("main", llfty); + let llfn = match cx.declare_c_main(llfty) { + Some(llfn) => llfn, + None => { + // FIXME: We should be smart and show a better diagnostic here. + cx.sess() + .struct_span_err(sp, "entry symbol `main` declared multiple times") + .help("did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead") + .emit(); + cx.sess().abort_if_errors(); + bug!(); + } + }; // `main` should respect same config for frame pointer elimination as rest of code cx.set_frame_pointer_elimination(llfn); diff --git a/compiler/rustc_codegen_ssa/src/traits/declare.rs b/compiler/rustc_codegen_ssa/src/traits/declare.rs index 690aacd20566b..655afcd17f0da 100644 --- a/compiler/rustc_codegen_ssa/src/traits/declare.rs +++ b/compiler/rustc_codegen_ssa/src/traits/declare.rs @@ -1,51 +1,7 @@ use super::BackendTypes; use rustc_hir::def_id::DefId; use rustc_middle::mir::mono::{Linkage, Visibility}; -use rustc_middle::ty::{Instance, Ty}; -use rustc_target::abi::call::FnAbi; - -pub trait DeclareMethods<'tcx>: BackendTypes { - /// Declare a global value. - /// - /// If there’s a value with the same name already declared, the function will - /// return its Value instead. - fn declare_global(&self, name: &str, ty: Self::Type) -> Self::Value; - - /// Declare a C ABI function. - /// - /// Only use this for foreign function ABIs and glue. For Rust functions use - /// `declare_fn` instead. - /// - /// If there’s a value with the same name already declared, the function will - /// update the declaration and return existing Value instead. - fn declare_cfn(&self, name: &str, fn_type: Self::Type) -> Self::Function; - - /// Declare a Rust function. - /// - /// If there’s a value with the same name already declared, the function will - /// update the declaration and return existing Value instead. - fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Function; - - /// Declare a global with an intention to define it. - /// - /// Use this function when you intend to define a global. This function will - /// return `None` if the name already has a definition associated with it. In that - /// case an error should be reported to the user, because it usually happens due - /// to user’s fault (e.g., misuse of `#[no_mangle]` or `#[export_name]` attributes). - fn define_global(&self, name: &str, ty: Self::Type) -> Option; - - /// Declare a private global - /// - /// Use this function when you intend to define a global without a name. - fn define_private_global(&self, ty: Self::Type) -> Self::Value; - - /// Gets declared value by name. - fn get_declared_value(&self, name: &str) -> Option; - - /// Gets defined or externally defined (AvailableExternally linkage) value by - /// name. - fn get_defined_value(&self, name: &str) -> Option; -} +use rustc_middle::ty::Instance; pub trait PreDefineMethods<'tcx>: BackendTypes { fn predefine_static( diff --git a/compiler/rustc_codegen_ssa/src/traits/misc.rs b/compiler/rustc_codegen_ssa/src/traits/misc.rs index fc57a9a80b261..6fff64bfcb6c5 100644 --- a/compiler/rustc_codegen_ssa/src/traits/misc.rs +++ b/compiler/rustc_codegen_ssa/src/traits/misc.rs @@ -19,4 +19,6 @@ pub trait MiscMethods<'tcx>: BackendTypes { fn set_frame_pointer_elimination(&self, llfn: Self::Function); fn apply_target_cpu_attr(&self, llfn: Self::Function); fn create_used_variable(&self); + /// Declares the extern "C" main function for the entry point. Returns None if the symbol already exists. + fn declare_c_main(&self, fn_type: Self::Type) -> Option; } diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs index 0ac519dd0b17c..698ef6083e674 100644 --- a/compiler/rustc_codegen_ssa/src/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -35,7 +35,7 @@ pub use self::builder::{BuilderMethods, OverflowOp}; pub use self::consts::ConstMethods; pub use self::coverageinfo::{CoverageInfoBuilderMethods, CoverageInfoMethods}; pub use self::debuginfo::{DebugInfoBuilderMethods, DebugInfoMethods}; -pub use self::declare::{DeclareMethods, PreDefineMethods}; +pub use self::declare::PreDefineMethods; pub use self::intrinsic::IntrinsicCallMethods; pub use self::misc::MiscMethods; pub use self::statics::{StaticBuilderMethods, StaticMethods}; @@ -60,7 +60,6 @@ pub trait CodegenMethods<'tcx>: + StaticMethods + CoverageInfoMethods + DebugInfoMethods<'tcx> - + DeclareMethods<'tcx> + AsmMethods + PreDefineMethods<'tcx> + HasParamEnv<'tcx> @@ -77,7 +76,6 @@ impl<'tcx, T> CodegenMethods<'tcx> for T where + StaticMethods + CoverageInfoMethods + DebugInfoMethods<'tcx> - + DeclareMethods<'tcx> + AsmMethods + PreDefineMethods<'tcx> + HasParamEnv<'tcx> From 0810c3ef1971b87f05561b8da9947f52a5270f29 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 18 Sep 2020 13:15:54 +0200 Subject: [PATCH 0586/1052] support panic=abort in Miri --- library/panic_abort/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index 3b08a64b22d85..e5800fbceb27a 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -47,7 +47,7 @@ pub unsafe extern "C" fn __rust_start_panic(_payload: usize) -> u32 { } __rust_abort(); } - } else if #[cfg(windows)] { + } else if #[cfg(all(windows, not(miri)))] { // On Windows, use the processor-specific __fastfail mechanism. In Windows 8 // and later, this will terminate the process immediately without running any // in-process exception handlers. In earlier versions of Windows, this From b9af3e30a9e34e4fe353e7e5c42103851f9c8f79 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 18 Sep 2020 14:58:22 +0200 Subject: [PATCH 0587/1052] bootstrap: move the version number to a plaintext file The Rust version number is currently embedded in bootstrap's source code, which makes it hard to update it automatically or access it outside of ./x.py (as you'd have to parse the source code). This commit moves the version number to a standalone plaintext file, which makes accessing or updating it trivial. --- src/bootstrap/channel.rs | 3 --- src/bootstrap/dist.rs | 7 +++---- src/bootstrap/doc.rs | 4 ++-- src/bootstrap/lib.rs | 21 ++++++++++++++------- src/bootstrap/native.rs | 3 +-- src/bootstrap/test.rs | 2 +- src/bootstrap/tool.rs | 3 +-- src/version | 1 + 8 files changed, 23 insertions(+), 21 deletions(-) create mode 100644 src/version diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index 2a461170b5cce..2b82f6c30b273 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -12,9 +12,6 @@ use build_helper::output; use crate::Build; -// The version number -pub const CFG_RELEASE_NUM: &str = "1.48.0"; - pub struct GitInfo { inner: Option, } diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index cf73e570fa56f..f25ad50c9b774 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -18,7 +18,6 @@ use build_helper::{output, t}; use crate::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::cache::{Interned, INTERNER}; -use crate::channel; use crate::compile; use crate::config::TargetSelection; use crate::tool::{self, Tool}; @@ -569,7 +568,7 @@ impl Step for Rustc { &page_dst, &[ ("", &month_year), - ("", channel::CFG_RELEASE_NUM), + ("", &builder.version), ], ); } @@ -2289,9 +2288,9 @@ impl Step for Extended { } fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: TargetSelection) { - let mut parts = channel::CFG_RELEASE_NUM.split('.'); + let mut parts = builder.version.split('.'); cmd.env("CFG_RELEASE_INFO", builder.rust_version()) - .env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM) + .env("CFG_RELEASE_NUM", &builder.version) .env("CFG_RELEASE", builder.rust_release()) .env("CFG_VER_MAJOR", parts.next().unwrap()) .env("CFG_VER_MINOR", parts.next().unwrap()) diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index f90e76a4f4ea6..97f32b61fb9c9 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -433,7 +433,7 @@ impl Step for Std { .arg("-Z") .arg("unstable-options") .arg("--resource-suffix") - .arg(crate::channel::CFG_RELEASE_NUM) + .arg(&builder.version) .arg("--index-page") .arg(&builder.src.join("src/doc/index.md")); @@ -659,7 +659,7 @@ impl Step for ErrorIndex { let mut index = tool::ErrorIndex::command(builder, self.compiler); index.arg("html"); index.arg(out.join("error-index.html")); - index.arg(crate::channel::CFG_RELEASE_NUM); + index.arg(&builder.version); builder.run(&mut index); } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 91b85f5af1d4b..3f7aeae0ed495 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -218,6 +218,9 @@ pub struct Build { /// User-specified configuration from `config.toml`. config: Config, + // Version information + version: String, + // Properties derived from the above configuration src: PathBuf, out: PathBuf, @@ -380,6 +383,10 @@ impl Build { .unwrap() .to_path_buf(); + let version = std::fs::read_to_string(src.join("src").join("version")) + .expect("failed to read src/version"); + let version = version.trim(); + let mut build = Build { initial_rustc: config.initial_rustc.clone(), initial_cargo: config.initial_cargo.clone(), @@ -395,6 +402,7 @@ impl Build { targets: config.targets.clone(), config, + version: version.to_string(), src, out, @@ -433,8 +441,7 @@ impl Build { .next() .unwrap() .trim(); - let my_version = channel::CFG_RELEASE_NUM; - if local_release.split('.').take(2).eq(my_version.split('.').take(2)) { + if local_release.split('.').take(2).eq(version.split('.').take(2)) { build.verbose(&format!("auto-detected local-rebuild {}", local_release)); build.local_rebuild = true; } @@ -785,7 +792,7 @@ impl Build { match which { GitRepo::Rustc => { - let sha = self.rust_sha().unwrap_or(channel::CFG_RELEASE_NUM); + let sha = self.rust_sha().unwrap_or(&self.version); Some(format!("/rustc/{}", sha)) } GitRepo::Llvm => Some(String::from("/rustc/llvm")), @@ -1016,7 +1023,7 @@ impl Build { /// Returns the value of `release` above for Rust itself. fn rust_release(&self) -> String { - self.release(channel::CFG_RELEASE_NUM) + self.release(&self.version) } /// Returns the "package version" for a component given the `num` release @@ -1036,7 +1043,7 @@ impl Build { /// Returns the value of `package_vers` above for Rust itself. fn rust_package_vers(&self) -> String { - self.package_vers(channel::CFG_RELEASE_NUM) + self.package_vers(&self.version) } /// Returns the value of `package_vers` above for Cargo @@ -1070,7 +1077,7 @@ impl Build { } fn llvm_tools_package_vers(&self) -> String { - self.package_vers(channel::CFG_RELEASE_NUM) + self.package_vers(&self.version) } fn llvm_tools_vers(&self) -> String { @@ -1087,7 +1094,7 @@ impl Build { /// 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, channel::CFG_RELEASE_NUM) + self.rust_info.version(self, &self.version) } /// Returns the full commit hash. diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 3829d47da335f..9e4d6d0023dc9 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -19,7 +19,6 @@ use std::process::Command; use build_helper::{output, t}; use crate::builder::{Builder, RunConfig, ShouldRun, Step}; -use crate::channel; use crate::config::TargetSelection; use crate::util::{self, exe}; use crate::GitRepo; @@ -296,7 +295,7 @@ impl Step for Llvm { // release number on the dev channel. cfg.define("LLVM_VERSION_SUFFIX", "-rust-dev"); } else { - let suffix = format!("-rust-{}-{}", channel::CFG_RELEASE_NUM, builder.config.channel); + let suffix = format!("-rust-{}-{}", builder.version, builder.config.channel); cfg.define("LLVM_VERSION_SUFFIX", suffix); } diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index ba5f75c49ac77..dc28b8ece2452 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -636,7 +636,7 @@ impl Step for RustdocJSStd { .arg("--crate-name") .arg("std") .arg("--resource-suffix") - .arg(crate::channel::CFG_RELEASE_NUM) + .arg(&builder.version) .arg("--doc-folder") .arg(builder.doc_out(self.target)) .arg("--test-folder") diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 99e33e3b006fe..5d66632d92ceb 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -7,7 +7,6 @@ use std::process::{exit, Command}; use build_helper::t; use crate::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step}; -use crate::channel; use crate::channel::GitInfo; use crate::compile; use crate::config::TargetSelection; @@ -255,7 +254,7 @@ pub fn prepare_tool_cargo( cargo.env("CFG_RELEASE", builder.rust_release()); cargo.env("CFG_RELEASE_CHANNEL", &builder.config.channel); cargo.env("CFG_VERSION", builder.rust_version()); - cargo.env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM); + cargo.env("CFG_RELEASE_NUM", &builder.version); let info = GitInfo::new(builder.config.ignore_git, &dir); if let Some(sha) = info.sha() { diff --git a/src/version b/src/version new file mode 100644 index 0000000000000..9db5ea12f5227 --- /dev/null +++ b/src/version @@ -0,0 +1 @@ +1.48.0 From 15bd2365fc32556d3d1ab6fa76e8363214343e6e Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Thu, 17 Sep 2020 20:14:09 -0400 Subject: [PATCH 0588/1052] Upgrade libz-sys to 1.1.2 --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d3f777bc663dd..429f73d578688 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1657,9 +1657,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.0.27" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ca8894883d250240341478bf987467332fbdd5da5c42426c69a8f93dbc302f2" +checksum = "602113192b08db8f38796c4e85c39e960c145965140e918018bcde1952429655" dependencies = [ "cc", "libc", From 9803c9b2529a465582320f4d1d3f4de3151f7e94 Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Wed, 16 Sep 2020 13:09:25 -0400 Subject: [PATCH 0589/1052] Update cc crate to understand aarch64-apple-darwin with clang --- Cargo.lock | 4 ++-- compiler/rustc_llvm/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d3f777bc663dd..4895d18ddcc95 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -408,9 +408,9 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.58" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518" +checksum = "ef611cc68ff783f18535d77ddd080185275713d852c4f5cbb6122c462a7a825c" dependencies = [ "jobserver", ] diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml index ee83689f0a469..e29af0532891f 100644 --- a/compiler/rustc_llvm/Cargo.toml +++ b/compiler/rustc_llvm/Cargo.toml @@ -13,4 +13,4 @@ libc = "0.2.73" [build-dependencies] build_helper = { path = "../../src/build_helper" } -cc = "1.0.58" +cc = "1.0.60" From d327fa112b8ca56e8c310a8ec9bf458909beacfe Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 10 Sep 2020 09:06:30 +0200 Subject: [PATCH 0590/1052] initial working state --- .../rustc_middle/src/mir/abstract_const.rs | 15 + compiler/rustc_middle/src/mir/mod.rs | 1 + compiler/rustc_middle/src/query/mod.rs | 19 ++ compiler/rustc_mir/src/transform/mod.rs | 6 +- compiler/rustc_trait_selection/src/lib.rs | 1 + .../src/traits/const_evaluatable.rs | 256 +++++++++++++++++- .../rustc_trait_selection/src/traits/mod.rs | 14 + .../const_evaluatable_checked/less_than.rs | 14 + 8 files changed, 313 insertions(+), 13 deletions(-) create mode 100644 compiler/rustc_middle/src/mir/abstract_const.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/less_than.rs diff --git a/compiler/rustc_middle/src/mir/abstract_const.rs b/compiler/rustc_middle/src/mir/abstract_const.rs new file mode 100644 index 0000000000000..48fe8dafd5343 --- /dev/null +++ b/compiler/rustc_middle/src/mir/abstract_const.rs @@ -0,0 +1,15 @@ +//! A subset of a mir body used for const evaluatability checking. +use crate::mir; +use crate::ty; + +/// An index into an `AbstractConst`. +pub type NodeId = usize; + +/// A node of an `AbstractConst`. +#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable)] +pub enum Node<'tcx> { + Leaf(&'tcx ty::Const<'tcx>), + Binop(mir::BinOp, NodeId, NodeId), + UnaryOp(mir::UnOp, NodeId), + FunctionCall(NodeId, &'tcx [NodeId]), +} diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 29daf7e9309aa..be61b67680750 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -40,6 +40,7 @@ use std::{iter, mem, option}; use self::predecessors::{PredecessorCache, Predecessors}; pub use self::query::*; +pub mod abstract_const; pub mod coverage; pub mod interpret; pub mod mono; diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 15e3110bc851e..41b8bb60ef5ea 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -244,6 +244,25 @@ rustc_queries! { no_hash } + /// Try to build an abstract representation of the given constant. + query mir_abstract_const( + key: DefId + ) -> Option<&'tcx [mir::abstract_const::Node<'tcx>]> { + desc { + |tcx| "building an abstract representation for {}", tcx.def_path_str(key), + } + } + /// Try to build an abstract representation of the given constant. + query mir_abstract_const_of_const_arg( + key: (LocalDefId, DefId) + ) -> Option<&'tcx [mir::abstract_const::Node<'tcx>]> { + desc { + |tcx| + "building an abstract representation for the const argument {}", + tcx.def_path_str(key.0.to_def_id()), + } + } + query mir_drops_elaborated_and_const_checked( key: ty::WithOptConstParam ) -> &'tcx Steal> { diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index 8025b7c02043d..226282fe4263c 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -329,7 +329,11 @@ fn mir_promoted( // this point, before we steal the mir-const result. // Also this means promotion can rely on all const checks having been done. let _ = tcx.mir_const_qualif_opt_const_arg(def); - + let _ = if let Some(param_did) = def.const_param_did { + tcx.mir_abstract_const_of_const_arg((def.did, param_did)) + } else { + tcx.mir_abstract_const(def.did.to_def_id()) + }; let mut body = tcx.mir_const(def).steal(); let mut required_consts = Vec::new(); diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index b5882df47294e..da1996b92a60b 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -12,6 +12,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(bool_to_option)] +#![feature(box_patterns)] #![feature(drain_filter)] #![feature(in_band_lifetimes)] #![feature(crate_visibility_modifier)] diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index fdb87c085b54e..9d74de44d171c 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -1,10 +1,17 @@ +#![allow(warnings)] use rustc_hir::def::DefKind; +use rustc_index::bit_set::BitSet; +use rustc_index::vec::IndexVec; use rustc_infer::infer::InferCtxt; +use rustc_middle::mir::abstract_const::{Node, NodeId}; use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::{self, Rvalue, StatementKind, TerminatorKind}; +use rustc_middle::ty::subst::Subst; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, TypeFoldable}; +use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; use rustc_session::lint; -use rustc_span::def_id::DefId; +use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::Span; pub fn is_const_evaluatable<'cx, 'tcx>( @@ -16,18 +23,23 @@ pub fn is_const_evaluatable<'cx, 'tcx>( ) -> Result<(), ErrorHandled> { debug!("is_const_evaluatable({:?}, {:?})", def, substs); if infcx.tcx.features().const_evaluatable_checked { - // FIXME(const_evaluatable_checked): Actually look into generic constants to - // implement const equality. - for pred in param_env.caller_bounds() { - match pred.skip_binders() { - ty::PredicateAtom::ConstEvaluatable(b_def, b_substs) => { - debug!("is_const_evaluatable: caller_bound={:?}, {:?}", b_def, b_substs); - if b_def == def && b_substs == substs { - debug!("is_const_evaluatable: caller_bound ~~> ok"); - return Ok(()); + if let Some(ct) = AbstractConst::new(infcx.tcx, def, substs) { + for pred in param_env.caller_bounds() { + match pred.skip_binders() { + ty::PredicateAtom::ConstEvaluatable(b_def, b_substs) => { + debug!("is_const_evaluatable: caller_bound={:?}, {:?}", b_def, b_substs); + if b_def == def && b_substs == substs { + debug!("is_const_evaluatable: caller_bound ~~> ok"); + return Ok(()); + } else if AbstractConst::new(infcx.tcx, b_def, b_substs) + .map_or(false, |b_ct| try_unify(infcx.tcx, ct, b_ct)) + { + debug!("is_const_evaluatable: abstract_const ~~> ok"); + return Ok(()); + } } + _ => {} // don't care } - _ => {} // don't care } } } @@ -76,3 +88,223 @@ pub fn is_const_evaluatable<'cx, 'tcx>( debug!(?concrete, "is_const_evaluatable"); concrete.map(drop) } + +/// A tree representing an anonymous constant. +/// +/// This is only able to represent a subset of `MIR`, +/// and should not leak any information about desugarings. +#[derive(Clone, Copy)] +pub struct AbstractConst<'tcx> { + pub inner: &'tcx [Node<'tcx>], + pub substs: SubstsRef<'tcx>, +} + +impl AbstractConst<'tcx> { + pub fn new( + tcx: TyCtxt<'tcx>, + def: ty::WithOptConstParam, + substs: SubstsRef<'tcx>, + ) -> Option> { + let inner = match (def.did.as_local(), def.const_param_did) { + (Some(did), Some(param_did)) => { + tcx.mir_abstract_const_of_const_arg((did, param_did))? + } + _ => tcx.mir_abstract_const(def.did)?, + }; + + Some(AbstractConst { inner, substs }) + } + + #[inline] + pub fn subtree(self, node: NodeId) -> AbstractConst<'tcx> { + AbstractConst { inner: &self.inner[..=node], substs: self.substs } + } + + #[inline] + pub fn root(self) -> Node<'tcx> { + self.inner.last().copied().unwrap() + } +} + +struct AbstractConstBuilder<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a mir::Body<'tcx>, + nodes: Vec>, + locals: IndexVec, + checked_op_locals: BitSet, +} + +impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { + fn new(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>) -> Option> { + if body.is_cfg_cyclic() { + return None; + } + + Some(AbstractConstBuilder { + tcx, + body, + nodes: vec![], + locals: IndexVec::from_elem(NodeId::MAX, &body.local_decls), + checked_op_locals: BitSet::new_empty(body.local_decls.len()), + }) + } + + fn add_node(&mut self, n: Node<'tcx>) -> NodeId { + let len = self.nodes.len(); + self.nodes.push(n); + len + } + + fn operand_to_node(&mut self, op: &mir::Operand<'tcx>) -> Option { + debug!("operand_to_node: op={:?}", op); + const ZERO_FIELD: mir::Field = mir::Field::from_usize(0); + match op { + mir::Operand::Copy(p) | mir::Operand::Move(p) => { + if let Some(p) = p.as_local() { + debug_assert!(!self.checked_op_locals.contains(p)); + Some(self.locals[p]) + } else if let &[mir::ProjectionElem::Field(ZERO_FIELD, _)] = p.projection.as_ref() { + // Only allow field accesses on the result of checked operations. + if self.checked_op_locals.contains(p.local) { + Some(self.locals[p.local]) + } else { + None + } + } else { + None + } + } + mir::Operand::Constant(ct) => Some(self.add_node(Node::Leaf(ct.literal))), + } + } + + fn check_binop(op: mir::BinOp) -> bool { + use mir::BinOp::*; + match op { + Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Shl | Shr | Eq | Lt | Le + | Ne | Ge | Gt => true, + Offset => false, + } + } + + fn build(mut self) -> Option<&'tcx [Node<'tcx>]> { + let mut block = &self.body.basic_blocks()[mir::START_BLOCK]; + loop { + debug!("AbstractConstBuilder: block={:?}", block); + for stmt in block.statements.iter() { + debug!("AbstractConstBuilder: stmt={:?}", stmt); + match stmt.kind { + StatementKind::Assign(box (ref place, ref rvalue)) => { + let local = place.as_local()?; + match *rvalue { + Rvalue::Use(ref operand) => { + self.locals[local] = self.operand_to_node(operand)?; + } + Rvalue::BinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => { + let lhs = self.operand_to_node(lhs)?; + let rhs = self.operand_to_node(rhs)?; + self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs)); + if op.is_checkable() { + bug!("unexpected unchecked checkable binary operation"); + } + } + Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) + if Self::check_binop(op) => + { + let lhs = self.operand_to_node(lhs)?; + let rhs = self.operand_to_node(rhs)?; + self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs)); + self.checked_op_locals.insert(local); + } + _ => return None, + } + } + _ => return None, + } + } + + debug!("AbstractConstBuilder: terminator={:?}", block.terminator()); + match block.terminator().kind { + TerminatorKind::Goto { target } => { + block = &self.body.basic_blocks()[target]; + } + TerminatorKind::Return => { + warn!(?self.nodes); + return { Some(self.tcx.arena.alloc_from_iter(self.nodes)) }; + } + TerminatorKind::Assert { ref cond, expected: false, target, .. } => { + let p = match cond { + mir::Operand::Copy(p) | mir::Operand::Move(p) => p, + mir::Operand::Constant(_) => bug!("Unexpected assert"), + }; + + const ONE_FIELD: mir::Field = mir::Field::from_usize(1); + debug!("proj: {:?}", p.projection); + if let &[mir::ProjectionElem::Field(ONE_FIELD, _)] = p.projection.as_ref() { + // Only allow asserts checking the result of a checked operation. + if self.checked_op_locals.contains(p.local) { + block = &self.body.basic_blocks()[target]; + continue; + } + } + + return None; + } + _ => return None, + } + } + } +} + +/// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead. +pub(super) fn mir_abstract_const<'tcx>( + tcx: TyCtxt<'tcx>, + def: ty::WithOptConstParam, +) -> Option<&'tcx [Node<'tcx>]> { + if !tcx.features().const_evaluatable_checked { + None + } else { + let body = tcx.mir_const(def).borrow(); + AbstractConstBuilder::new(tcx, &body)?.build() + } +} + +pub fn try_unify<'tcx>(tcx: TyCtxt<'tcx>, a: AbstractConst<'tcx>, b: AbstractConst<'tcx>) -> bool { + match (a.root(), b.root()) { + (Node::Leaf(a_ct), Node::Leaf(b_ct)) => { + let a_ct = a_ct.subst(tcx, a.substs); + let b_ct = b_ct.subst(tcx, b.substs); + match (a_ct.val, b_ct.val) { + (ty::ConstKind::Param(a_param), ty::ConstKind::Param(b_param)) => { + a_param == b_param + } + (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val, + // If we have `fn a() -> [u8; N + 1]` and `fn b() -> [u8; 1 + M]` + // we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This + // means that we can't do anything with inference variables here. + (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => false, + // FIXME(const_evaluatable_checked): We may want to either actually try + // to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like + // this, for now we just return false here. + _ => false, + } + } + (Node::Binop(a_op, al, ar), Node::Binop(b_op, bl, br)) if a_op == b_op => { + try_unify(tcx, a.subtree(al), b.subtree(bl)) + && try_unify(tcx, a.subtree(ar), b.subtree(br)) + } + (Node::UnaryOp(a_op, av), Node::UnaryOp(b_op, bv)) if a_op == b_op => { + try_unify(tcx, a.subtree(av), b.subtree(bv)) + } + (Node::FunctionCall(a_f, a_args), Node::FunctionCall(b_f, b_args)) + if a_args.len() == b_args.len() => + { + try_unify(tcx, a.subtree(a_f), b.subtree(b_f)) + && a_args + .iter() + .zip(b_args) + .all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn))) + } + _ => false, + } +} diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index b72e86a4cbde6..2f0b66ec8c941 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -552,6 +552,20 @@ pub fn provide(providers: &mut ty::query::Providers) { vtable_methods, type_implements_trait, subst_and_check_impossible_predicates, + mir_abstract_const: |tcx, def_id| { + let def_id = def_id.as_local()?; // We do not store failed AbstractConst's. + if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { + tcx.mir_abstract_const_of_const_arg(def) + } else { + const_evaluatable::mir_abstract_const(tcx, ty::WithOptConstParam::unknown(def_id)) + } + }, + mir_abstract_const_of_const_arg: |tcx, (did, param_did)| { + const_evaluatable::mir_abstract_const( + tcx, + ty::WithOptConstParam { did, const_param_did: Some(param_did) }, + ) + }, ..*providers }; } diff --git a/src/test/ui/const-generics/const_evaluatable_checked/less_than.rs b/src/test/ui/const-generics/const_evaluatable_checked/less_than.rs new file mode 100644 index 0000000000000..907ea255abb08 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/less_than.rs @@ -0,0 +1,14 @@ +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +struct Foo; + +fn test() -> Foo<{ N > 10 }> where Foo<{ N > 10 }>: Sized { + Foo +} + +fn main() { + let _: Foo = test::<12>(); + let _: Foo = test::<9>(); +} From 2230d8d14c0275798f799d099b05b47e34c8d573 Mon Sep 17 00:00:00 2001 From: Denis Vasilik Date: Fri, 18 Sep 2020 16:45:13 +0200 Subject: [PATCH 0591/1052] Update library/alloc/src/collections/binary_heap.rs Co-authored-by: Joshua Nelson --- library/alloc/src/collections/binary_heap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index 8181e413d893a..67a67cb66f1df 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -1119,7 +1119,7 @@ impl FusedIterator for Iter<'_, T> {} /// An owning iterator over the elements of a `BinaryHeap`. /// -/// This `struct` is created by the [`into_iter`] method on [`BinaryHeap`] +/// This `struct` is created by [`BinaryHeap::into_iter()`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: BinaryHeap::into_iter From ec7225feac1f64ca16f2d866fda02bcfcc577a9c Mon Sep 17 00:00:00 2001 From: Denis Vasilik Date: Fri, 18 Sep 2020 16:45:23 +0200 Subject: [PATCH 0592/1052] Update library/alloc/src/collections/binary_heap.rs Co-authored-by: Joshua Nelson --- library/alloc/src/collections/binary_heap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index 67a67cb66f1df..1f0abc6b1f1f4 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -1055,7 +1055,7 @@ impl Drop for Hole<'_, T> { /// An iterator over the elements of a `BinaryHeap`. /// -/// This `struct` is created by the [`iter`] method on [`BinaryHeap`]. See its +/// This `struct` is created by [`BinaryHeap::iter()`]. See its /// documentation for more. /// /// [`iter`]: BinaryHeap::iter From 62e0ee1ba0e120ffc4738e4c606869df7bc61c2c Mon Sep 17 00:00:00 2001 From: Denis Vasilik Date: Fri, 18 Sep 2020 16:45:35 +0200 Subject: [PATCH 0593/1052] Update library/alloc/src/collections/binary_heap.rs Co-authored-by: Joshua Nelson --- library/alloc/src/collections/binary_heap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index 1f0abc6b1f1f4..92c0dc92c5fe5 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -1223,7 +1223,7 @@ unsafe impl TrustedLen for IntoIterSorted {} /// A draining iterator over the elements of a `BinaryHeap`. /// -/// This `struct` is created by the [`drain`] method on [`BinaryHeap`]. See its +/// This `struct` is created by [`BinaryHeap::drain()`]. See its /// documentation for more. /// /// [`drain`]: BinaryHeap::drain From 719c40cb5aa580e0f51cff5e021ec51c52814621 Mon Sep 17 00:00:00 2001 From: Denis Vasilik Date: Fri, 18 Sep 2020 16:45:44 +0200 Subject: [PATCH 0594/1052] Update library/alloc/src/collections/binary_heap.rs Co-authored-by: Joshua Nelson --- library/alloc/src/collections/binary_heap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index 92c0dc92c5fe5..53815c38beff8 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -1268,7 +1268,7 @@ impl FusedIterator for Drain<'_, T> {} /// A draining iterator over the elements of a `BinaryHeap`. /// -/// This `struct` is created by the [`drain_sorted`] method on [`BinaryHeap`]. See its +/// This `struct` is created by [`BinaryHeap::drain_sorted()`]. See its /// documentation for more. /// /// [`drain_sorted`]: BinaryHeap::drain_sorted From 18ce4c1cfc24f797c8aac3ada99787f85868dae6 Mon Sep 17 00:00:00 2001 From: qlcom Date: Fri, 18 Sep 2020 21:08:48 +0600 Subject: [PATCH 0595/1052] README.md: Remove prompts from code blocks --- README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index cb5d71477d810..d445bbdf6e842 100644 --- a/README.md +++ b/README.md @@ -44,8 +44,8 @@ by running `./x.py --help` or reading the [rustc dev guide][rustcguidebuild]. 2. Clone the [source] with `git`: ```sh - $ git clone https://github.com/rust-lang/rust.git - $ cd rust + git clone https://github.com/rust-lang/rust.git + cd rust ``` [source]: https://github.com/rust-lang/rust @@ -57,7 +57,7 @@ by running `./x.py --help` or reading the [rustc dev guide][rustcguidebuild]. Copy the default `config.toml.example` to `config.toml` to get started. ```sh - $ cp config.toml.example config.toml + cp config.toml.example config.toml ``` If you plan to use `x.py install` to create an installation, it is recommended @@ -68,7 +68,7 @@ by running `./x.py --help` or reading the [rustc dev guide][rustcguidebuild]. 4. Build and install: ```sh - $ ./x.py build && ./x.py install + ./x.py build && ./x.py install ``` When complete, `./x.py install` will place several programs into @@ -106,7 +106,7 @@ build. ```sh # Update package mirrors (may be needed if you have a fresh install of MSYS2) - $ pacman -Sy pacman-mirrors + pacman -Sy pacman-mirrors # Install build tools needed for Rust. If you're building a 32-bit compiler, # then replace "x86_64" below with "i686". If you've already got git, python, @@ -114,7 +114,7 @@ build. # that it is important that you do **not** use the 'python2', 'cmake' and 'ninja' # packages from the 'msys2' subsystem. The build has historically been known # to fail with these packages. - $ pacman -S git \ + pacman -S git \ make \ diffutils \ tar \ @@ -127,7 +127,7 @@ build. 4. Navigate to Rust's source code (or clone it), then build it: ```sh - $ ./x.py build && ./x.py install + ./x.py build && ./x.py install ``` #### MSVC @@ -145,7 +145,7 @@ With these dependencies installed, you can build the compiler in a `cmd.exe` shell with: ```sh -> python x.py build +python x.py build ``` Currently, building Rust only works with some known versions of Visual Studio. If @@ -154,8 +154,8 @@ you may need to force rustbuild to use an older version. This can be done by manually calling the appropriate vcvars file before running the bootstrap. ```batch -> CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" -> python x.py build +CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" +python x.py build ``` #### Specifying an ABI @@ -181,8 +181,8 @@ While it's not the recommended build system, this project also provides a configure script and makefile (the latter of which just invokes `x.py`). ```sh -$ ./configure -$ make && sudo make install +./configure +make && sudo make install ``` When using the configure script, the generated `config.mk` file may override the @@ -194,7 +194,7 @@ When using the configure script, the generated `config.mk` file may override the If you’d like to build the documentation, it’s almost the same: ```sh -$ ./x.py doc +./x.py doc ``` The generated documentation will appear under `doc` in the `build` directory for From c3a772f55f2263cd2f2709f2bb187f59a8b4a673 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 10 Sep 2020 18:48:18 +0200 Subject: [PATCH 0596/1052] use abstract consts when unifying ConstKind::Unevaluated --- compiler/rustc_middle/src/query/mod.rs | 10 +++++++++ compiler/rustc_middle/src/ty/query/keys.rs | 16 ++++++++++++++ compiler/rustc_middle/src/ty/relate.rs | 15 ++++++++++++- .../src/traits/const_evaluatable.rs | 22 ++++++++++++++++++- .../src/traits/fulfill.rs | 19 ++++++++++++++++ .../rustc_trait_selection/src/traits/mod.rs | 1 + .../simple.min.stderr | 16 ++++++++++---- .../const_evaluatable_checked/simple.rs | 7 +++--- 8 files changed, 96 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 41b8bb60ef5ea..44d906dada5f0 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -263,6 +263,16 @@ rustc_queries! { } } + query try_unify_abstract_consts(key: ( + (ty::WithOptConstParam, SubstsRef<'tcx>), + (ty::WithOptConstParam, SubstsRef<'tcx>) + )) -> bool { + desc { + |tcx| "trying to unify the generic constants {} and {}", + tcx.def_path_str(key.0.0.did), tcx.def_path_str(key.1.0.did) + } + } + query mir_drops_elaborated_and_const_checked( key: ty::WithOptConstParam ) -> &'tcx Steal> { diff --git a/compiler/rustc_middle/src/ty/query/keys.rs b/compiler/rustc_middle/src/ty/query/keys.rs index 3f7a20bba2b9a..a005990264cf1 100644 --- a/compiler/rustc_middle/src/ty/query/keys.rs +++ b/compiler/rustc_middle/src/ty/query/keys.rs @@ -193,6 +193,22 @@ impl<'tcx> Key for (DefId, SubstsRef<'tcx>) { } } +impl<'tcx> Key + for ( + (ty::WithOptConstParam, SubstsRef<'tcx>), + (ty::WithOptConstParam, SubstsRef<'tcx>), + ) +{ + type CacheSelector = DefaultCacheSelector; + + fn query_crate(&self) -> CrateNum { + (self.0).0.did.krate + } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + (self.0).0.did.default_span(tcx) + } +} + impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) { type CacheSelector = DefaultCacheSelector; diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 7d3634a75b0a7..c4df0bba726cb 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -576,7 +576,20 @@ pub fn super_relate_consts>( new_val.map(ty::ConstKind::Value) } - // FIXME(const_generics): this is wrong, as it is a projection + ( + ty::ConstKind::Unevaluated(a_def, a_substs, None), + ty::ConstKind::Unevaluated(b_def, b_substs, None), + ) if tcx.features().const_evaluatable_checked => { + if tcx.try_unify_abstract_consts(((a_def, a_substs), (b_def, b_substs))) { + Ok(a.val) + } else { + Err(TypeError::ConstMismatch(expected_found(relation, a, b))) + } + } + + // While this is slightly incorrect, it shouldn't matter for `min_const_generics` + // and is the better alternative to waiting until `const_evaluatable_checked` can + // be stabilized. ( ty::ConstKind::Unevaluated(a_def, a_substs, a_promoted), ty::ConstKind::Unevaluated(b_def, b_substs, b_promoted), diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 9d74de44d171c..e14af1a27ef44 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -269,7 +269,27 @@ pub(super) fn mir_abstract_const<'tcx>( } } -pub fn try_unify<'tcx>(tcx: TyCtxt<'tcx>, a: AbstractConst<'tcx>, b: AbstractConst<'tcx>) -> bool { +pub(super) fn try_unify_abstract_consts<'tcx>( + tcx: TyCtxt<'tcx>, + ((a, a_substs), (b, b_substs)): ( + (ty::WithOptConstParam, SubstsRef<'tcx>), + (ty::WithOptConstParam, SubstsRef<'tcx>), + ), +) -> bool { + if let Some(a) = AbstractConst::new(tcx, a, a_substs) { + if let Some(b) = AbstractConst::new(tcx, b, b_substs) { + return try_unify(tcx, a, b); + } + } + + false +} + +pub(super) fn try_unify<'tcx>( + tcx: TyCtxt<'tcx>, + a: AbstractConst<'tcx>, + b: AbstractConst<'tcx>, +) -> bool { match (a.root(), b.root()) { (Node::Leaf(a_ct), Node::Leaf(b_ct)) => { let a_ct = a_ct.subst(tcx, a.substs); diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 1dd50d69a2195..5b4314598deb5 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -476,6 +476,25 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { ty::PredicateAtom::ConstEquate(c1, c2) => { debug!("equating consts: c1={:?} c2={:?}", c1, c2); + if self.selcx.tcx().features().const_evaluatable_checked { + // FIXME: we probably should only try to unify abstract constants + // if the constants depend on generic parameters. + // + // Let's just see where this breaks :shrug: + if let ( + ty::ConstKind::Unevaluated(a_def, a_substs, None), + ty::ConstKind::Unevaluated(b_def, b_substs, None), + ) = (c1.val, c2.val) + { + if self + .selcx + .tcx() + .try_unify_abstract_consts(((a_def, a_substs), (b_def, b_substs))) + { + return ProcessResult::Changed(vec![]); + } + } + } let stalled_on = &mut pending_obligation.stalled_on; diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 2f0b66ec8c941..098336453bc69 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -566,6 +566,7 @@ pub fn provide(providers: &mut ty::query::Providers) { ty::WithOptConstParam { did, const_param_did: Some(param_did) }, ) }, + try_unify_abstract_consts: const_evaluatable::try_unify_abstract_consts, ..*providers }; } diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr index da8ccdaee4146..3cac604a7b33a 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr @@ -1,10 +1,18 @@ error: generic parameters must not be used inside of non trivial constant values - --> $DIR/simple.rs:8:33 + --> $DIR/simple.rs:8:53 | -LL | type Arr = [u8; N - 1]; - | ^ non-trivial anonymous constants must not depend on the parameter `N` +LL | fn test() -> [u8; N - 1] where [u8; N - 1]: Default { + | ^ non-trivial anonymous constants must not depend on the parameter `N` | = help: it is currently only allowed to use either `N` or `{ N }` as generic constants -error: aborting due to previous error +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/simple.rs:8:35 + | +LL | fn test() -> [u8; N - 1] where [u8; N - 1]: Default { + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple.rs index 27dc6b103200d..dcf0071cb29b6 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/simple.rs +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple.rs @@ -5,10 +5,9 @@ #![feature(const_evaluatable_checked)] #![allow(incomplete_features)] -type Arr = [u8; N - 1]; -//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values - -fn test() -> Arr where Arr: Default { +fn test() -> [u8; N - 1] where [u8; N - 1]: Default { + //[min]~^ ERROR generic parameters + //[min]~| ERROR generic parameters Default::default() } From f24d532749674c41940120866937860c8d4abcc8 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Fri, 11 Sep 2020 09:00:21 +0200 Subject: [PATCH 0597/1052] refactor AbstractConstBuilder --- .../src/traits/const_evaluatable.rs | 125 ++++++++++-------- 1 file changed, 67 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index e14af1a27ef44..337276fd811e7 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -187,70 +187,79 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { } } - fn build(mut self) -> Option<&'tcx [Node<'tcx>]> { - let mut block = &self.body.basic_blocks()[mir::START_BLOCK]; - loop { - debug!("AbstractConstBuilder: block={:?}", block); - for stmt in block.statements.iter() { - debug!("AbstractConstBuilder: stmt={:?}", stmt); - match stmt.kind { - StatementKind::Assign(box (ref place, ref rvalue)) => { - let local = place.as_local()?; - match *rvalue { - Rvalue::Use(ref operand) => { - self.locals[local] = self.operand_to_node(operand)?; - } - Rvalue::BinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => { - let lhs = self.operand_to_node(lhs)?; - let rhs = self.operand_to_node(rhs)?; - self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs)); - if op.is_checkable() { - bug!("unexpected unchecked checkable binary operation"); - } - } - Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) - if Self::check_binop(op) => - { - let lhs = self.operand_to_node(lhs)?; - let rhs = self.operand_to_node(rhs)?; - self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs)); - self.checked_op_locals.insert(local); - } - _ => return None, + fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Option<()> { + debug!("AbstractConstBuilder: stmt={:?}", stmt); + match stmt.kind { + StatementKind::Assign(box (ref place, ref rvalue)) => { + let local = place.as_local()?; + match *rvalue { + Rvalue::Use(ref operand) => { + self.locals[local] = self.operand_to_node(operand)?; + } + Rvalue::BinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => { + let lhs = self.operand_to_node(lhs)?; + let rhs = self.operand_to_node(rhs)?; + self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs)); + if op.is_checkable() { + bug!("unexpected unchecked checkable binary operation"); } } + Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => { + let lhs = self.operand_to_node(lhs)?; + let rhs = self.operand_to_node(rhs)?; + self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs)); + self.checked_op_locals.insert(local); + } _ => return None, } } + _ => return None, + } - debug!("AbstractConstBuilder: terminator={:?}", block.terminator()); - match block.terminator().kind { - TerminatorKind::Goto { target } => { - block = &self.body.basic_blocks()[target]; - } - TerminatorKind::Return => { - warn!(?self.nodes); - return { Some(self.tcx.arena.alloc_from_iter(self.nodes)) }; - } - TerminatorKind::Assert { ref cond, expected: false, target, .. } => { - let p = match cond { - mir::Operand::Copy(p) | mir::Operand::Move(p) => p, - mir::Operand::Constant(_) => bug!("Unexpected assert"), - }; + Some(()) + } - const ONE_FIELD: mir::Field = mir::Field::from_usize(1); - debug!("proj: {:?}", p.projection); - if let &[mir::ProjectionElem::Field(ONE_FIELD, _)] = p.projection.as_ref() { - // Only allow asserts checking the result of a checked operation. - if self.checked_op_locals.contains(p.local) { - block = &self.body.basic_blocks()[target]; - continue; - } - } + fn build_terminator( + &mut self, + terminator: &mir::Terminator<'tcx>, + ) -> Option> { + debug!("AbstractConstBuilder: terminator={:?}", terminator); + match terminator.kind { + TerminatorKind::Goto { target } => Some(Some(target)), + TerminatorKind::Return => Some(None), + TerminatorKind::Assert { ref cond, expected: false, target, .. } => { + let p = match cond { + mir::Operand::Copy(p) | mir::Operand::Move(p) => p, + mir::Operand::Constant(_) => bug!("Unexpected assert"), + }; - return None; + const ONE_FIELD: mir::Field = mir::Field::from_usize(1); + debug!("proj: {:?}", p.projection); + if let &[mir::ProjectionElem::Field(ONE_FIELD, _)] = p.projection.as_ref() { + // Only allow asserts checking the result of a checked operation. + if self.checked_op_locals.contains(p.local) { + return Some(Some(target)); + } } - _ => return None, + + None + } + _ => None, + } + } + + fn build(mut self) -> Option<&'tcx [Node<'tcx>]> { + let mut block = &self.body.basic_blocks()[mir::START_BLOCK]; + loop { + debug!("AbstractConstBuilder: block={:?}", block); + for stmt in block.statements.iter() { + self.build_statement(stmt)?; + } + + if let Some(next) = self.build_terminator(block.terminator())? { + block = &self.body.basic_blocks()[next]; + } else { + return Some(self.tcx.arena.alloc_from_iter(self.nodes)); } } } @@ -261,11 +270,11 @@ pub(super) fn mir_abstract_const<'tcx>( tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam, ) -> Option<&'tcx [Node<'tcx>]> { - if !tcx.features().const_evaluatable_checked { - None - } else { + if tcx.features().const_evaluatable_checked { let body = tcx.mir_const(def).borrow(); AbstractConstBuilder::new(tcx, &body)?.build() + } else { + None } } From 5a277822a536eff72d562e75fb6046add63d4926 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Fri, 11 Sep 2020 09:18:54 +0200 Subject: [PATCH 0598/1052] use newtype_index for abstract_const::NodeId --- .../rustc_middle/src/mir/abstract_const.rs | 9 +++++-- .../src/traits/const_evaluatable.rs | 24 ++++++++----------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_middle/src/mir/abstract_const.rs b/compiler/rustc_middle/src/mir/abstract_const.rs index 48fe8dafd5343..8d215c5a5215a 100644 --- a/compiler/rustc_middle/src/mir/abstract_const.rs +++ b/compiler/rustc_middle/src/mir/abstract_const.rs @@ -2,8 +2,13 @@ use crate::mir; use crate::ty; -/// An index into an `AbstractConst`. -pub type NodeId = usize; +rustc_index::newtype_index! { + /// An index into an `AbstractConst`. + pub struct NodeId { + derive [HashStable] + DEBUG_FORMAT = "n{}", + } +} /// A node of an `AbstractConst`. #[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable)] diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 337276fd811e7..56886aae06669 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -95,8 +95,10 @@ pub fn is_const_evaluatable<'cx, 'tcx>( /// and should not leak any information about desugarings. #[derive(Clone, Copy)] pub struct AbstractConst<'tcx> { - pub inner: &'tcx [Node<'tcx>], - pub substs: SubstsRef<'tcx>, + // FIXME: Consider adding something like `IndexSlice` + // and use this here. + inner: &'tcx [Node<'tcx>], + substs: SubstsRef<'tcx>, } impl AbstractConst<'tcx> { @@ -117,7 +119,7 @@ impl AbstractConst<'tcx> { #[inline] pub fn subtree(self, node: NodeId) -> AbstractConst<'tcx> { - AbstractConst { inner: &self.inner[..=node], substs: self.substs } + AbstractConst { inner: &self.inner[..=node.index()], substs: self.substs } } #[inline] @@ -129,7 +131,7 @@ impl AbstractConst<'tcx> { struct AbstractConstBuilder<'a, 'tcx> { tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, - nodes: Vec>, + nodes: IndexVec>, locals: IndexVec, checked_op_locals: BitSet, } @@ -143,18 +145,12 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { Some(AbstractConstBuilder { tcx, body, - nodes: vec![], + nodes: IndexVec::new(), locals: IndexVec::from_elem(NodeId::MAX, &body.local_decls), checked_op_locals: BitSet::new_empty(body.local_decls.len()), }) } - fn add_node(&mut self, n: Node<'tcx>) -> NodeId { - let len = self.nodes.len(); - self.nodes.push(n); - len - } - fn operand_to_node(&mut self, op: &mir::Operand<'tcx>) -> Option { debug!("operand_to_node: op={:?}", op); const ZERO_FIELD: mir::Field = mir::Field::from_usize(0); @@ -174,7 +170,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { None } } - mir::Operand::Constant(ct) => Some(self.add_node(Node::Leaf(ct.literal))), + mir::Operand::Constant(ct) => Some(self.nodes.push(Node::Leaf(ct.literal))), } } @@ -199,7 +195,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { Rvalue::BinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => { let lhs = self.operand_to_node(lhs)?; let rhs = self.operand_to_node(rhs)?; - self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs)); + self.locals[local] = self.nodes.push(Node::Binop(op, lhs, rhs)); if op.is_checkable() { bug!("unexpected unchecked checkable binary operation"); } @@ -207,7 +203,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => { let lhs = self.operand_to_node(lhs)?; let rhs = self.operand_to_node(rhs)?; - self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs)); + self.locals[local] = self.nodes.push(Node::Binop(op, lhs, rhs)); self.checked_op_locals.insert(local); } _ => return None, From d1294e0ce2ce78e4a634fbfa68cb2bc4d50afc6e Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Fri, 11 Sep 2020 10:00:06 +0200 Subject: [PATCH 0599/1052] allow unary operations and ignore StorageLive/Dead stmts --- .../src/traits/const_evaluatable.rs | 27 ++++++++++++++++--- .../const_evaluatable_checked/unop.rs | 14 ++++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/unop.rs diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 56886aae06669..f0e5151173276 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -174,6 +174,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { } } + /// We do not allow all binary operations in abstract consts, so filter disallowed ones. fn check_binop(op: mir::BinOp) -> bool { use mir::BinOp::*; match op { @@ -183,6 +184,15 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { } } + /// While we currently allow all unary operations, we still want to explicitly guard against + /// future changes here. + fn check_unop(op: mir::UnOp) -> bool { + use mir::UnOp::*; + match op { + Not | Neg => true, + } + } + fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Option<()> { debug!("AbstractConstBuilder: stmt={:?}", stmt); match stmt.kind { @@ -191,6 +201,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { match *rvalue { Rvalue::Use(ref operand) => { self.locals[local] = self.operand_to_node(operand)?; + Some(()) } Rvalue::BinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => { let lhs = self.operand_to_node(lhs)?; @@ -198,6 +209,8 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { self.locals[local] = self.nodes.push(Node::Binop(op, lhs, rhs)); if op.is_checkable() { bug!("unexpected unchecked checkable binary operation"); + } else { + Some(()) } } Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => { @@ -205,14 +218,20 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { let rhs = self.operand_to_node(rhs)?; self.locals[local] = self.nodes.push(Node::Binop(op, lhs, rhs)); self.checked_op_locals.insert(local); + Some(()) } - _ => return None, + Rvalue::UnaryOp(op, ref operand) if Self::check_unop(op) => { + let operand = self.operand_to_node(operand)?; + self.locals[local] = self.nodes.push(Node::UnaryOp(op, operand)); + Some(()) + } + _ => None, } } - _ => return None, + // These are not actually relevant for us here, so we can ignore them. + StatementKind::StorageLive(_) | StatementKind::StorageDead(_) => Some(()), + _ => None, } - - Some(()) } fn build_terminator( diff --git a/src/test/ui/const-generics/const_evaluatable_checked/unop.rs b/src/test/ui/const-generics/const_evaluatable_checked/unop.rs new file mode 100644 index 0000000000000..8e0768b1c9595 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/unop.rs @@ -0,0 +1,14 @@ +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +struct Foo; + +fn test() -> Foo<{ !(N > 10) }> where Foo<{ !(N > 10) }>: Sized { + Foo +} + +fn main() { + let _: Foo = test::<12>(); + let _: Foo = test::<9>(); +} From c7d16df1d81934ff33d9d421ac2dc34c893ad68f Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Fri, 11 Sep 2020 10:35:28 +0200 Subject: [PATCH 0600/1052] add function calls --- .../src/traits/const_evaluatable.rs | 18 +++++++++++ .../const_evaluatable_checked/fn_call.rs | 30 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/fn_call.rs diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index f0e5151173276..50cc2afb89c80 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -242,6 +242,24 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { match terminator.kind { TerminatorKind::Goto { target } => Some(Some(target)), TerminatorKind::Return => Some(None), + TerminatorKind::Call { + ref func, + ref args, + destination: Some((ref place, target)), + cleanup: _, + from_hir_call: true, + fn_span: _, + } => { + let local = place.as_local()?; + let func = self.operand_to_node(func)?; + let args = self.tcx.arena.alloc_from_iter( + args.iter() + .map(|arg| self.operand_to_node(arg)) + .collect::>>()?, + ); + self.locals[local] = self.nodes.push(Node::FunctionCall(func, args)); + Some(Some(target)) + } TerminatorKind::Assert { ref cond, expected: false, target, .. } => { let p = match cond { mir::Operand::Copy(p) | mir::Operand::Move(p) => p, diff --git a/src/test/ui/const-generics/const_evaluatable_checked/fn_call.rs b/src/test/ui/const-generics/const_evaluatable_checked/fn_call.rs new file mode 100644 index 0000000000000..1b9ec0108b1e7 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/fn_call.rs @@ -0,0 +1,30 @@ +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +const fn test_me(a: usize, b: usize) -> usize { + if a < b { + std::mem::size_of::() + } else { + std::usize::MAX + } +} + +fn test_simple() -> [u8; std::mem::size_of::()] +where + [u8; std::mem::size_of::()]: Sized, +{ + [0; std::mem::size_of::()] +} + +fn test_with_args() -> [u8; test_me::(N, N + 1) + N] +where + [u8; test_me::(N, N + 1) + N]: Sized, +{ + [0; test_me::(N, N + 1) + N] +} + +fn main() { + assert_eq!([0; 8], test_simple::()); + assert_eq!([0; 12], test_with_args::()); +} From 82ebbd7d6b6d3f0ec1560c823320aab696463770 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Fri, 11 Sep 2020 10:46:35 +0200 Subject: [PATCH 0601/1052] add test for let-bindings --- compiler/rustc_typeck/src/collect.rs | 12 +++++++----- .../const_evaluatable_checked/let-bindings.rs | 15 +++++++++++++++ .../let-bindings.stderr | 18 ++++++++++++++++++ 3 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/let-bindings.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 9b8427a46955c..731ccfad2b44f 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1693,25 +1693,27 @@ pub fn const_evaluatable_predicates_of<'tcx>( ) -> impl Iterator, Span)> { #[derive(Default)] struct ConstCollector<'tcx> { - ct: SmallVec<[(ty::WithOptConstParam, SubstsRef<'tcx>); 4]>, + ct: SmallVec<[(ty::WithOptConstParam, SubstsRef<'tcx>, Span); 4]>, + curr_span: Span, } impl<'tcx> TypeVisitor<'tcx> for ConstCollector<'tcx> { fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> bool { if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val { - self.ct.push((def, substs)); + self.ct.push((def, substs, self.curr_span)); } false } } let mut collector = ConstCollector::default(); - for (pred, _span) in predicates.predicates.iter() { + for &(pred, span) in predicates.predicates.iter() { + collector.curr_span = span; pred.visit_with(&mut collector); } warn!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.ct); - collector.ct.into_iter().map(move |(def_id, subst)| { - (ty::PredicateAtom::ConstEvaluatable(def_id, subst).to_predicate(tcx), DUMMY_SP) + collector.ct.into_iter().map(move |(def_id, subst, span)| { + (ty::PredicateAtom::ConstEvaluatable(def_id, subst).to_predicate(tcx), span) }) } diff --git a/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.rs b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.rs new file mode 100644 index 0000000000000..d96788f8cd100 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.rs @@ -0,0 +1,15 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +// We do not yet want to support let-bindings in abstract consts, +// so this test should keep failing for now. +fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { + //~^ ERROR constant expression depends + //~| ERROR constant expression depends + Default::default() +} + +fn main() { + let x = test::<31>(); + assert_eq!(x, [0; 32]); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr new file mode 100644 index 0000000000000..95fb48bd43402 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr @@ -0,0 +1,18 @@ +error: constant expression depends on a generic parameter + --> $DIR/let-bindings.rs:6:91 + | +LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { + | ^^^^^^^ required by this bound in `test::{{constant}}#0` + | + = note: this may fail depending on what value the parameter takes + +error: constant expression depends on a generic parameter + --> $DIR/let-bindings.rs:6:30 + | +LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 2 previous errors + From 30ff1ef3d000c7f76a1906522b0efff4c8b27201 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Fri, 11 Sep 2020 21:16:16 +0200 Subject: [PATCH 0602/1052] support const_evaluatable_checked across crate boundaries --- compiler/rustc_metadata/src/rmeta/decoder.rs | 19 ++++++++++ .../src/rmeta/decoder/cstore_impl.rs | 1 + compiler/rustc_metadata/src/rmeta/encoder.rs | 11 ++++++ compiler/rustc_metadata/src/rmeta/mod.rs | 1 + .../rustc_middle/src/mir/abstract_const.rs | 2 +- compiler/rustc_middle/src/ty/codec.rs | 20 +++++++++++ .../src/ty/query/on_disk_cache.rs | 6 ++++ compiler/rustc_privacy/src/lib.rs | 9 +++++ .../src/traits/const_evaluatable.rs | 15 ++++++++ .../rustc_trait_selection/src/traits/mod.rs | 2 +- .../auxiliary/const_evaluatable_lib.rs | 9 +++++ .../const_evaluatable_checked/cross_crate.rs | 15 ++++++++ .../cross_crate_predicate.rs | 13 +++++++ .../cross_crate_predicate.stderr | 36 +++++++++++++++++++ 14 files changed, 157 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/auxiliary/const_evaluatable_lib.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/cross_crate.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 43d76e9fdb4c3..a2e2cf1ca0219 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -562,6 +562,12 @@ impl<'a, 'tcx> Decodable> for Span { } } +impl<'a, 'tcx> Decodable> for &'tcx [mir::abstract_const::Node<'tcx>] { + fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result { + ty::codec::RefDecodable::decode(d) + } +} + impl<'a, 'tcx> Decodable> for &'tcx [(ty::Predicate<'tcx>, Span)] { fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result { ty::codec::RefDecodable::decode(d) @@ -1191,6 +1197,19 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .decode((self, tcx)) } + fn get_mir_abstract_const( + &self, + tcx: TyCtxt<'tcx>, + id: DefIndex, + ) -> Option<&'tcx [mir::abstract_const::Node<'tcx>]> { + self.root + .tables + .mir_abstract_consts + .get(self, id) + .filter(|_| !self.is_proc_macro(id)) + .map_or(None, |v| Some(v.decode((self, tcx)))) + } + fn get_unused_generic_params(&self, id: DefIndex) -> FiniteBitSet { self.root .tables diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 94abfac19c665..d4f577a7d1b49 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -112,6 +112,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, } optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) } promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) } + mir_abstract_const => { cdata.get_mir_abstract_const(tcx, def_id.index) } unused_generic_params => { cdata.get_unused_generic_params(def_id.index) } mir_const_qualif => { cdata.mir_const_qualif(def_id.index) } fn_sig => { cdata.fn_sig(def_id.index, tcx) } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 1e313b7edfc27..eb091d86b82c6 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -321,6 +321,12 @@ impl<'a, 'tcx> TyEncoder<'tcx> for EncodeContext<'a, 'tcx> { } } +impl<'a, 'tcx> Encodable> for &'tcx [mir::abstract_const::Node<'tcx>] { + fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { + (**self).encode(s) + } +} + impl<'a, 'tcx> Encodable> for &'tcx [(ty::Predicate<'tcx>, Span)] { fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { (**self).encode(s) @@ -1109,6 +1115,11 @@ impl EncodeContext<'a, 'tcx> { if !unused.is_empty() { record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused); } + + let abstract_const = self.tcx.mir_abstract_const(def_id); + if let Some(abstract_const) = abstract_const { + record!(self.tables.mir_abstract_consts[def_id.to_def_id()] <- abstract_const); + } } } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 1ba5962d119e8..ba540c944117d 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -284,6 +284,7 @@ define_tables! { super_predicates: Table)>, mir: Table)>, promoted_mir: Table>)>, + mir_abstract_consts: Table])>, unused_generic_params: Table>>, // `def_keys` and `def_path_hashes` represent a lazy version of a // `DefPathTable`. This allows us to avoid deserializing an entire diff --git a/compiler/rustc_middle/src/mir/abstract_const.rs b/compiler/rustc_middle/src/mir/abstract_const.rs index 8d215c5a5215a..b85f1e6e5ded0 100644 --- a/compiler/rustc_middle/src/mir/abstract_const.rs +++ b/compiler/rustc_middle/src/mir/abstract_const.rs @@ -11,7 +11,7 @@ rustc_index::newtype_index! { } /// A node of an `AbstractConst`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] pub enum Node<'tcx> { Leaf(&'tcx ty::Const<'tcx>), Binop(mir::BinOp, NodeId, NodeId), diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index e2e5f08462f72..8ea34f9161abc 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -357,6 +357,26 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [(ty::Predicate<'tcx>, } } +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::Node<'tcx>] { + fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { + Ok(decoder.tcx().arena.alloc_from_iter( + (0..decoder.read_usize()?) + .map(|_| Decodable::decode(decoder)) + .collect::, _>>()?, + )) + } +} + +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::NodeId] { + fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { + Ok(decoder.tcx().arena.alloc_from_iter( + (0..decoder.read_usize()?) + .map(|_| Decodable::decode(decoder)) + .collect::, _>>()?, + )) + } +} + impl_decodable_via_ref! { &'tcx ty::TypeckResults<'tcx>, &'tcx ty::List>, diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs index dcfb8d314300f..b0c48a860ebaf 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -760,6 +760,12 @@ impl<'a, 'tcx> Decodable> } } +impl<'a, 'tcx> Decodable> for &'tcx [mir::abstract_const::Node<'tcx>] { + fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result { + RefDecodable::decode(d) + } +} + impl<'a, 'tcx> Decodable> for &'tcx [(ty::Predicate<'tcx>, Span)] { fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result { RefDecodable::decode(d) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 03cc718b8995d..1a95992ed8318 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -97,6 +97,15 @@ where ty.visit_with(self) } ty::PredicateAtom::RegionOutlives(..) => false, + ty::PredicateAtom::ConstEvaluatable(..) + if self.def_id_visitor.tcx().features().const_evaluatable_checked => + { + // FIXME(const_evaluatable_checked): If the constant used here depends on a + // private function we may have to do something here... + // + // For now, let's just pretend that everything is fine. + false + } _ => bug!("unexpected predicate: {:?}", predicate), } } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 50cc2afb89c80..1a5139d34d3cc 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -142,6 +142,12 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { return None; } + // We don't have to look at concrete constants, as we + // can just evaluate them. + if !body.is_polymorphic { + return None; + } + Some(AbstractConstBuilder { tcx, body, @@ -304,6 +310,15 @@ pub(super) fn mir_abstract_const<'tcx>( def: ty::WithOptConstParam, ) -> Option<&'tcx [Node<'tcx>]> { if tcx.features().const_evaluatable_checked { + match tcx.def_kind(def.did) { + // FIXME(const_evaluatable_checked): We currently only do this for anonymous constants, + // meaning that we do not look into associated constants. I(@lcnr) am not yet sure whether + // we want to look into them or treat them as opaque projections. + // + // Right now we do neither of that and simply always fail to unify them. + DefKind::AnonConst => (), + _ => return None, + } let body = tcx.mir_const(def).borrow(); AbstractConstBuilder::new(tcx, &body)?.build() } else { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 098336453bc69..79495ba7f9b30 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -553,7 +553,7 @@ pub fn provide(providers: &mut ty::query::Providers) { type_implements_trait, subst_and_check_impossible_predicates, mir_abstract_const: |tcx, def_id| { - let def_id = def_id.as_local()?; // We do not store failed AbstractConst's. + let def_id = def_id.expect_local(); if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { tcx.mir_abstract_const_of_const_arg(def) } else { diff --git a/src/test/ui/const-generics/const_evaluatable_checked/auxiliary/const_evaluatable_lib.rs b/src/test/ui/const-generics/const_evaluatable_checked/auxiliary/const_evaluatable_lib.rs new file mode 100644 index 0000000000000..9745dfed46087 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/auxiliary/const_evaluatable_lib.rs @@ -0,0 +1,9 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +pub fn test1() -> [u8; std::mem::size_of::() - 1] +where + [u8; std::mem::size_of::() - 1]: Sized, +{ + [0; std::mem::size_of::() - 1] +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate.rs b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate.rs new file mode 100644 index 0000000000000..53b237843871f --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate.rs @@ -0,0 +1,15 @@ +// aux-build:const_evaluatable_lib.rs +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] +extern crate const_evaluatable_lib; + +fn user() where [u8; std::mem::size_of::() - 1]: Sized { + assert_eq!(const_evaluatable_lib::test1::(), [0; std::mem::size_of::() - 1]); +} + +fn main() { + assert_eq!(const_evaluatable_lib::test1::(), [0; 3]); + user::(); + user::(); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs new file mode 100644 index 0000000000000..223699233298d --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs @@ -0,0 +1,13 @@ +// aux-build:const_evaluatable_lib.rs +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] +extern crate const_evaluatable_lib; + +fn user() { + let _ = const_evaluatable_lib::test1::(); + //~^ ERROR constant expression depends + //~| ERROR constant expression depends + //~| ERROR constant expression depends +} + +fn main() {} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr new file mode 100644 index 0000000000000..63abb782b93a3 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr @@ -0,0 +1,36 @@ +error: constant expression depends on a generic parameter + --> $DIR/cross_crate_predicate.rs:7:13 + | +LL | let _ = const_evaluatable_lib::test1::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:41 + | +LL | [u8; std::mem::size_of::() - 1]: Sized, + | ----- required by this bound in `test1` + | + = note: this may fail depending on what value the parameter takes + +error: constant expression depends on a generic parameter + --> $DIR/cross_crate_predicate.rs:7:13 + | +LL | let _ = const_evaluatable_lib::test1::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:41 + | +LL | [u8; std::mem::size_of::() - 1]: Sized, + | ----- required by this bound in `test1::{{constant}}#1` + | + = note: this may fail depending on what value the parameter takes + +error: constant expression depends on a generic parameter + --> $DIR/cross_crate_predicate.rs:7:13 + | +LL | let _ = const_evaluatable_lib::test1::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 3 previous errors + From 7fff155d2a2b10958454e4958197dda103644ad4 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Fri, 11 Sep 2020 21:19:15 +0200 Subject: [PATCH 0603/1052] remove allow(warnings) --- compiler/rustc_trait_selection/src/traits/const_evaluatable.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 1a5139d34d3cc..b2e5ad52b0126 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -1,11 +1,9 @@ -#![allow(warnings)] use rustc_hir::def::DefKind; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; use rustc_infer::infer::InferCtxt; use rustc_middle::mir::abstract_const::{Node, NodeId}; use rustc_middle::mir::interpret::ErrorHandled; -use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::{self, Rvalue, StatementKind, TerminatorKind}; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::subst::SubstsRef; From 1b275d08ad6299a1f9b31650ba906a18846d5461 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Fri, 11 Sep 2020 21:50:17 +0200 Subject: [PATCH 0604/1052] document `const_evaluatable` --- .../src/traits/const_evaluatable.rs | 50 +++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index b2e5ad52b0126..db79de06d5e4c 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -1,3 +1,13 @@ +//! Checking that constant values used in types can be successfully evaluated. +//! +//! For concrete constants, this is fairly simple as we can just try and evaluate it. +//! +//! When dealing with polymorphic constants, for example `std::mem::size_of::() - 1`, +//! this is not as easy. +//! +//! In this case we try to build an abstract representation of this constant using +//! `mir_abstract_const` which can then be checked for structural equality with other +//! generic constants mentioned in the `caller_bounds` of the current environment. use rustc_hir::def::DefKind; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; @@ -129,13 +139,19 @@ impl AbstractConst<'tcx> { struct AbstractConstBuilder<'a, 'tcx> { tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, + /// The current WIP node tree. nodes: IndexVec>, locals: IndexVec, + /// We only allow field accesses if they access + /// the result of a checked operation. checked_op_locals: BitSet, } impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { fn new(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>) -> Option> { + // We only allow consts without control flow, so + // we check for cycles here which simplifies the + // rest of this implementation. if body.is_cfg_cyclic() { return None; } @@ -154,17 +170,21 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { checked_op_locals: BitSet::new_empty(body.local_decls.len()), }) } - fn operand_to_node(&mut self, op: &mir::Operand<'tcx>) -> Option { debug!("operand_to_node: op={:?}", op); const ZERO_FIELD: mir::Field = mir::Field::from_usize(0); match op { mir::Operand::Copy(p) | mir::Operand::Move(p) => { + // Do not allow any projections. + // + // One exception are field accesses on the result of checked operations, + // which are required to support things like `1 + 2`. if let Some(p) = p.as_local() { debug_assert!(!self.checked_op_locals.contains(p)); Some(self.locals[p]) } else if let &[mir::ProjectionElem::Field(ZERO_FIELD, _)] = p.projection.as_ref() { - // Only allow field accesses on the result of checked operations. + // Only allow field accesses if the given local + // contains the result of a checked operation. if self.checked_op_locals.contains(p.local) { Some(self.locals[p.local]) } else { @@ -238,6 +258,11 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { } } + /// Possible return values: + /// + /// - `None`: unsupported terminator, stop building + /// - `Some(None)`: supported terminator, finish building + /// - `Some(Some(block))`: support terminator, build `block` next fn build_terminator( &mut self, terminator: &mir::Terminator<'tcx>, @@ -250,7 +275,18 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { ref func, ref args, destination: Some((ref place, target)), + // We do not care about `cleanup` here. Any branch which + // uses `cleanup` will fail const-eval and they therefore + // do not matter when checking for const evaluatability. + // + // Do note that even if `panic::catch_unwind` is made const, + // we still do not have to care about this, as we do not look + // into functions. cleanup: _, + // Do not allow overloaded operators for now, + // we probably do want to allow this in the future. + // + // This is currently fairly irrelevant as it requires `const Trait`s. from_hir_call: true, fn_span: _, } => { @@ -264,10 +300,14 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { self.locals[local] = self.nodes.push(Node::FunctionCall(func, args)); Some(Some(target)) } + // We only allow asserts for checked operations. + // + // These asserts seem to all have the form `!_local.0` so + // we only allow exactly that. TerminatorKind::Assert { ref cond, expected: false, target, .. } => { let p = match cond { mir::Operand::Copy(p) | mir::Operand::Move(p) => p, - mir::Operand::Constant(_) => bug!("Unexpected assert"), + mir::Operand::Constant(_) => bug!("unexpected assert"), }; const ONE_FIELD: mir::Field = mir::Field::from_usize(1); @@ -285,8 +325,11 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { } } + /// Builds the abstract const by walking the mir from start to finish + /// and bailing out when encountering an unsupported operation. fn build(mut self) -> Option<&'tcx [Node<'tcx>]> { let mut block = &self.body.basic_blocks()[mir::START_BLOCK]; + // We checked for a cyclic cfg above, so this should terminate. loop { debug!("AbstractConstBuilder: block={:?}", block); for stmt in block.statements.iter() { @@ -340,6 +383,7 @@ pub(super) fn try_unify_abstract_consts<'tcx>( false } +/// Tries to unify two abstract constants using structural equality. pub(super) fn try_unify<'tcx>( tcx: TyCtxt<'tcx>, a: AbstractConst<'tcx>, From 09e6254496e1b46a474757b8fcc66cc5981584c5 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Fri, 18 Sep 2020 17:11:17 +0200 Subject: [PATCH 0605/1052] review, small cleanup --- .../src/traits/const_evaluatable.rs | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index db79de06d5e4c..6abe62759b6b8 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -30,24 +30,24 @@ pub fn is_const_evaluatable<'cx, 'tcx>( span: Span, ) -> Result<(), ErrorHandled> { debug!("is_const_evaluatable({:?}, {:?})", def, substs); - if infcx.tcx.features().const_evaluatable_checked { - if let Some(ct) = AbstractConst::new(infcx.tcx, def, substs) { - for pred in param_env.caller_bounds() { - match pred.skip_binders() { - ty::PredicateAtom::ConstEvaluatable(b_def, b_substs) => { - debug!("is_const_evaluatable: caller_bound={:?}, {:?}", b_def, b_substs); - if b_def == def && b_substs == substs { - debug!("is_const_evaluatable: caller_bound ~~> ok"); - return Ok(()); - } else if AbstractConst::new(infcx.tcx, b_def, b_substs) - .map_or(false, |b_ct| try_unify(infcx.tcx, ct, b_ct)) - { - debug!("is_const_evaluatable: abstract_const ~~> ok"); - return Ok(()); - } + // `AbstractConst::new` already returns `None` if `const_evaluatable_checked` + // is not active, so we don't have to explicitly check for this here. + if let Some(ct) = AbstractConst::new(infcx.tcx, def, substs) { + for pred in param_env.caller_bounds() { + match pred.skip_binders() { + ty::PredicateAtom::ConstEvaluatable(b_def, b_substs) => { + debug!("is_const_evaluatable: caller_bound={:?}, {:?}", b_def, b_substs); + if b_def == def && b_substs == substs { + debug!("is_const_evaluatable: caller_bound ~~> ok"); + return Ok(()); + } else if AbstractConst::new(infcx.tcx, b_def, b_substs) + .map_or(false, |b_ct| try_unify(infcx.tcx, ct, b_ct)) + { + debug!("is_const_evaluatable: abstract_const ~~> ok"); + return Ok(()); } - _ => {} // don't care } + _ => {} // don't care } } } @@ -394,14 +394,17 @@ pub(super) fn try_unify<'tcx>( let a_ct = a_ct.subst(tcx, a.substs); let b_ct = b_ct.subst(tcx, b.substs); match (a_ct.val, b_ct.val) { + // We can just unify errors with everything to reduce the amount of + // emitted errors here. + (ty::ConstKind::Error(_), _) | (_, ty::ConstKind::Error(_)) => true, (ty::ConstKind::Param(a_param), ty::ConstKind::Param(b_param)) => { a_param == b_param } (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val, // If we have `fn a() -> [u8; N + 1]` and `fn b() -> [u8; 1 + M]` // we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This - // means that we can't do anything with inference variables here. - (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => false, + // means that we only allow inference variables if they are equal. + (ty::ConstKind::Infer(a_val), ty::ConstKind::Infer(b_val)) => a_val == b_val, // FIXME(const_evaluatable_checked): We may want to either actually try // to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like // this, for now we just return false here. From b7641209d79860172c5bf605d3ebf1377d46db55 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Fri, 18 Sep 2020 17:36:11 +0200 Subject: [PATCH 0606/1052] add `const-evaluatable_checked` check back in --- .../src/traits/const_evaluatable.rs | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 6abe62759b6b8..2642358dbc54c 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -30,24 +30,24 @@ pub fn is_const_evaluatable<'cx, 'tcx>( span: Span, ) -> Result<(), ErrorHandled> { debug!("is_const_evaluatable({:?}, {:?})", def, substs); - // `AbstractConst::new` already returns `None` if `const_evaluatable_checked` - // is not active, so we don't have to explicitly check for this here. - if let Some(ct) = AbstractConst::new(infcx.tcx, def, substs) { - for pred in param_env.caller_bounds() { - match pred.skip_binders() { - ty::PredicateAtom::ConstEvaluatable(b_def, b_substs) => { - debug!("is_const_evaluatable: caller_bound={:?}, {:?}", b_def, b_substs); - if b_def == def && b_substs == substs { - debug!("is_const_evaluatable: caller_bound ~~> ok"); - return Ok(()); - } else if AbstractConst::new(infcx.tcx, b_def, b_substs) - .map_or(false, |b_ct| try_unify(infcx.tcx, ct, b_ct)) - { - debug!("is_const_evaluatable: abstract_const ~~> ok"); - return Ok(()); + if infcx.tcx.features().const_evaluatable_checked { + if let Some(ct) = AbstractConst::new(infcx.tcx, def, substs) { + for pred in param_env.caller_bounds() { + match pred.skip_binders() { + ty::PredicateAtom::ConstEvaluatable(b_def, b_substs) => { + debug!("is_const_evaluatable: caller_bound={:?}, {:?}", b_def, b_substs); + if b_def == def && b_substs == substs { + debug!("is_const_evaluatable: caller_bound ~~> ok"); + return Ok(()); + } else if AbstractConst::new(infcx.tcx, b_def, b_substs) + .map_or(false, |b_ct| try_unify(infcx.tcx, ct, b_ct)) + { + debug!("is_const_evaluatable: abstract_const ~~> ok"); + return Ok(()); + } } + _ => {} // don't care } - _ => {} // don't care } } } From 15adc2ee830385293c3f826869033003130d904e Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 18 Sep 2020 11:54:00 -0400 Subject: [PATCH 0607/1052] Remove duplicate macOS builders --- .github/workflows/ci.yml | 29 ----------------------------- src/ci/github-actions/ci.yml | 36 ------------------------------------ 2 files changed, 65 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 50ae8c313d6fc..521d4aa25937d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -404,35 +404,6 @@ jobs: NO_LLVM_ASSERTIONS: 1 NO_DEBUG_ASSERTIONS: 1 os: macos-latest - - name: dist-x86_64-apple - env: - SCRIPT: "./x.py dist" - RUST_CONFIGURE_ARGS: "--host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false" - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - os: macos-latest - - name: dist-x86_64-apple-alt - env: - SCRIPT: "./x.py dist" - RUST_CONFIGURE_ARGS: "--enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false" - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - os: macos-latest - - name: x86_64-apple - env: - SCRIPT: "./x.py --stage 2 test" - RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false" - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.8 - MACOSX_STD_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - os: macos-latest - name: x86_64-msvc-1 env: RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler" diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index f8d3bc8e8e588..1b04213fcc900 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -436,42 +436,6 @@ jobs: # macOS Builders # #################### - - name: dist-x86_64-apple - env: - SCRIPT: ./x.py dist - RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - <<: *job-macos-xl - - - name: dist-x86_64-apple-alt - env: - SCRIPT: ./x.py dist - RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - <<: *job-macos-xl - - - name: x86_64-apple - env: - SCRIPT: ./x.py --stage 2 test - RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.8 - MACOSX_STD_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - <<: *job-macos-xl - - #################### - # macOS Builders # - #################### - - name: dist-x86_64-apple env: SCRIPT: ./x.py dist From d0dff8f873a80f4995e4e90bf865747eab8226db Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 18 Sep 2020 11:56:41 -0400 Subject: [PATCH 0608/1052] Make sure we build target-only things (e.g., docs) for host platforms too --- .github/workflows/ci.yml | 4 ++-- src/ci/azure-pipelines/auto.yml | 2 +- src/ci/github-actions/ci.yml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 521d4aa25937d..490258f9c09bb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -378,7 +378,7 @@ jobs: - name: dist-x86_64-apple env: SCRIPT: "./x.py dist" - RUST_CONFIGURE_ARGS: "--host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false" + RUST_CONFIGURE_ARGS: "--host=x86_64-apple-darwin --target=x86_64-apple-darwin,aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false" RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 MACOSX_DEPLOYMENT_TARGET: 10.7 NO_LLVM_ASSERTIONS: 1 @@ -479,7 +479,7 @@ jobs: os: windows-latest-xl - name: dist-i686-msvc env: - RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-msvc --host=i686-pc-windows-msvc --target=i586-pc-windows-msvc --enable-full-tools --enable-profiler" + RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-msvc --host=i686-pc-windows-msvc --target=i686-pc-windows-msvc,i586-pc-windows-msvc --enable-full-tools --enable-profiler" SCRIPT: python x.py dist DIST_REQUIRE_ALL_TOOLS: 1 os: windows-latest-xl diff --git a/src/ci/azure-pipelines/auto.yml b/src/ci/azure-pipelines/auto.yml index 2dcb55bb9731b..05177e517d03d 100644 --- a/src/ci/azure-pipelines/auto.yml +++ b/src/ci/azure-pipelines/auto.yml @@ -46,7 +46,7 @@ jobs: dist-x86_64-apple: SCRIPT: ./x.py dist - INITIAL_RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false + INITIAL_RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=x86_64-apple-darwin,aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 MACOSX_DEPLOYMENT_TARGET: 10.7 NO_LLVM_ASSERTIONS: 1 diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 1b04213fcc900..ea7e65a116836 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -439,7 +439,7 @@ jobs: - name: dist-x86_64-apple env: SCRIPT: ./x.py dist - RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false + RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=x86_64-apple-darwin,aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 MACOSX_DEPLOYMENT_TARGET: 10.7 NO_LLVM_ASSERTIONS: 1 @@ -588,7 +588,7 @@ jobs: RUST_CONFIGURE_ARGS: >- --build=i686-pc-windows-msvc --host=i686-pc-windows-msvc - --target=i586-pc-windows-msvc + --target=i686-pc-windows-msvc,i586-pc-windows-msvc --enable-full-tools --enable-profiler SCRIPT: python x.py dist From 6a96aea36ace13ad5b1be8cce0073ee8c2f2f32a Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 18 Sep 2020 11:09:00 -0400 Subject: [PATCH 0609/1052] Wrap recursive predicate evaluation with `ensure_sufficient_stack` I haven't been able to come up with a minimized test case for #76770, but this fixes a stack overflow in rustc as well. --- .../src/traits/select/mod.rs | 252 +++++++++--------- 1 file changed, 133 insertions(+), 119 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index ac98d840e98af..5e2f7d81d000a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -450,153 +450,167 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { None => self.check_recursion_limit(&obligation, &obligation)?, } - match obligation.predicate.skip_binders() { - ty::PredicateAtom::Trait(t, _) => { - let t = ty::Binder::bind(t); - debug_assert!(!t.has_escaping_bound_vars()); - let obligation = obligation.with(t); - self.evaluate_trait_predicate_recursively(previous_stack, obligation) - } + ensure_sufficient_stack(|| { + match obligation.predicate.skip_binders() { + ty::PredicateAtom::Trait(t, _) => { + let t = ty::Binder::bind(t); + debug_assert!(!t.has_escaping_bound_vars()); + let obligation = obligation.with(t); + self.evaluate_trait_predicate_recursively(previous_stack, obligation) + } + + ty::PredicateAtom::Subtype(p) => { + let p = ty::Binder::bind(p); + // Does this code ever run? + match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { + Some(Ok(InferOk { mut obligations, .. })) => { + self.add_depth(obligations.iter_mut(), obligation.recursion_depth); + self.evaluate_predicates_recursively( + previous_stack, + obligations.into_iter(), + ) + } + Some(Err(_)) => Ok(EvaluatedToErr), + None => Ok(EvaluatedToAmbig), + } + } - ty::PredicateAtom::Subtype(p) => { - let p = ty::Binder::bind(p); - // Does this code ever run? - match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { - Some(Ok(InferOk { mut obligations, .. })) => { + ty::PredicateAtom::WellFormed(arg) => match wf::obligations( + self.infcx, + obligation.param_env, + obligation.cause.body_id, + arg, + obligation.cause.span, + ) { + Some(mut obligations) => { self.add_depth(obligations.iter_mut(), obligation.recursion_depth); self.evaluate_predicates_recursively( previous_stack, obligations.into_iter(), ) } - Some(Err(_)) => Ok(EvaluatedToErr), None => Ok(EvaluatedToAmbig), - } - } + }, - ty::PredicateAtom::WellFormed(arg) => match wf::obligations( - self.infcx, - obligation.param_env, - obligation.cause.body_id, - arg, - obligation.cause.span, - ) { - Some(mut obligations) => { - self.add_depth(obligations.iter_mut(), obligation.recursion_depth); - self.evaluate_predicates_recursively(previous_stack, obligations.into_iter()) + ty::PredicateAtom::TypeOutlives(..) | ty::PredicateAtom::RegionOutlives(..) => { + // We do not consider region relationships when evaluating trait matches. + Ok(EvaluatedToOkModuloRegions) } - None => Ok(EvaluatedToAmbig), - }, - - ty::PredicateAtom::TypeOutlives(..) | ty::PredicateAtom::RegionOutlives(..) => { - // We do not consider region relationships when evaluating trait matches. - Ok(EvaluatedToOkModuloRegions) - } - ty::PredicateAtom::ObjectSafe(trait_def_id) => { - if self.tcx().is_object_safe(trait_def_id) { - Ok(EvaluatedToOk) - } else { - Ok(EvaluatedToErr) + ty::PredicateAtom::ObjectSafe(trait_def_id) => { + if self.tcx().is_object_safe(trait_def_id) { + Ok(EvaluatedToOk) + } else { + Ok(EvaluatedToErr) + } } - } - ty::PredicateAtom::Projection(data) => { - let data = ty::Binder::bind(data); - let project_obligation = obligation.with(data); - match project::poly_project_and_unify_type(self, &project_obligation) { - Ok(Ok(Some(mut subobligations))) => { - self.add_depth(subobligations.iter_mut(), obligation.recursion_depth); - let result = self.evaluate_predicates_recursively( - previous_stack, - subobligations.into_iter(), - ); - if let Some(key) = - ProjectionCacheKey::from_poly_projection_predicate(self, data) - { - self.infcx.inner.borrow_mut().projection_cache().complete(key); + ty::PredicateAtom::Projection(data) => { + let data = ty::Binder::bind(data); + let project_obligation = obligation.with(data); + match project::poly_project_and_unify_type(self, &project_obligation) { + Ok(Ok(Some(mut subobligations))) => { + self.add_depth(subobligations.iter_mut(), obligation.recursion_depth); + let result = self.evaluate_predicates_recursively( + previous_stack, + subobligations.into_iter(), + ); + if let Some(key) = + ProjectionCacheKey::from_poly_projection_predicate(self, data) + { + self.infcx.inner.borrow_mut().projection_cache().complete(key); + } + result } - result + Ok(Ok(None)) => Ok(EvaluatedToAmbig), + // EvaluatedToRecur might also be acceptable here, but use + // Unknown for now because it means that we won't dismiss a + // selection candidate solely because it has a projection + // cycle. This is closest to the previous behavior of + // immediately erroring. + Ok(Err(project::InProgress)) => Ok(EvaluatedToUnknown), + Err(_) => Ok(EvaluatedToErr), } - Ok(Ok(None)) => Ok(EvaluatedToAmbig), - // EvaluatedToRecur might also be acceptable here, but use - // Unknown for now because it means that we won't dismiss a - // selection candidate solely because it has a projection - // cycle. This is closest to the previous behavior of - // immediately erroring. - Ok(Err(project::InProgress)) => Ok(EvaluatedToUnknown), - Err(_) => Ok(EvaluatedToErr), } - } - ty::PredicateAtom::ClosureKind(_, closure_substs, kind) => { - match self.infcx.closure_kind(closure_substs) { - Some(closure_kind) => { - if closure_kind.extends(kind) { - Ok(EvaluatedToOk) - } else { - Ok(EvaluatedToErr) + ty::PredicateAtom::ClosureKind(_, closure_substs, kind) => { + match self.infcx.closure_kind(closure_substs) { + Some(closure_kind) => { + if closure_kind.extends(kind) { + Ok(EvaluatedToOk) + } else { + Ok(EvaluatedToErr) + } } + None => Ok(EvaluatedToAmbig), } - None => Ok(EvaluatedToAmbig), } - } - ty::PredicateAtom::ConstEvaluatable(def_id, substs) => { - match const_evaluatable::is_const_evaluatable( - self.infcx, - def_id, - substs, - obligation.param_env, - obligation.cause.span, - ) { - Ok(()) => Ok(EvaluatedToOk), - Err(ErrorHandled::TooGeneric) => Ok(EvaluatedToAmbig), - Err(_) => Ok(EvaluatedToErr), + ty::PredicateAtom::ConstEvaluatable(def_id, substs) => { + match const_evaluatable::is_const_evaluatable( + self.infcx, + def_id, + substs, + obligation.param_env, + obligation.cause.span, + ) { + Ok(()) => Ok(EvaluatedToOk), + Err(ErrorHandled::TooGeneric) => Ok(EvaluatedToAmbig), + Err(_) => Ok(EvaluatedToErr), + } } - } - ty::PredicateAtom::ConstEquate(c1, c2) => { - debug!("evaluate_predicate_recursively: equating consts c1={:?} c2={:?}", c1, c2); - - let evaluate = |c: &'tcx ty::Const<'tcx>| { - if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val { - self.infcx - .const_eval_resolve( - obligation.param_env, - def, - substs, - promoted, - Some(obligation.cause.span), - ) - .map(|val| ty::Const::from_value(self.tcx(), val, c.ty)) - } else { - Ok(c) - } - }; + ty::PredicateAtom::ConstEquate(c1, c2) => { + debug!( + "evaluate_predicate_recursively: equating consts c1={:?} c2={:?}", + c1, c2 + ); - match (evaluate(c1), evaluate(c2)) { - (Ok(c1), Ok(c2)) => { - match self.infcx().at(&obligation.cause, obligation.param_env).eq(c1, c2) { - Ok(_) => Ok(EvaluatedToOk), - Err(_) => Ok(EvaluatedToErr), + let evaluate = |c: &'tcx ty::Const<'tcx>| { + if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val { + self.infcx + .const_eval_resolve( + obligation.param_env, + def, + substs, + promoted, + Some(obligation.cause.span), + ) + .map(|val| ty::Const::from_value(self.tcx(), val, c.ty)) + } else { + Ok(c) + } + }; + + match (evaluate(c1), evaluate(c2)) { + (Ok(c1), Ok(c2)) => { + match self + .infcx() + .at(&obligation.cause, obligation.param_env) + .eq(c1, c2) + { + Ok(_) => Ok(EvaluatedToOk), + Err(_) => Ok(EvaluatedToErr), + } + } + (Err(ErrorHandled::Reported(ErrorReported)), _) + | (_, Err(ErrorHandled::Reported(ErrorReported))) => Ok(EvaluatedToErr), + (Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => { + span_bug!( + obligation.cause.span(self.tcx()), + "ConstEquate: const_eval_resolve returned an unexpected error" + ) + } + (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => { + Ok(EvaluatedToAmbig) } - } - (Err(ErrorHandled::Reported(ErrorReported)), _) - | (_, Err(ErrorHandled::Reported(ErrorReported))) => Ok(EvaluatedToErr), - (Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => span_bug!( - obligation.cause.span(self.tcx()), - "ConstEquate: const_eval_resolve returned an unexpected error" - ), - (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => { - Ok(EvaluatedToAmbig) } } + ty::PredicateAtom::TypeWellFormedFromEnv(..) => { + bug!("TypeWellFormedFromEnv is only used for chalk") + } } - ty::PredicateAtom::TypeWellFormedFromEnv(..) => { - bug!("TypeWellFormedFromEnv is only used for chalk") - } - } + }) } fn evaluate_trait_predicate_recursively<'o>( From e3c6e46168758642f0bab64da374f93ed21b1cd0 Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Fri, 18 Sep 2020 19:23:50 +0200 Subject: [PATCH 0610/1052] Make some methods of `Pin<&mut T>` unstable const Make the following methods unstable const under the `const_pin` feature: - `into_ref` - `get_mut` - `get_unchecked_mut` --- library/core/src/pin.rs | 13 ++++++++----- library/core/tests/lib.rs | 1 + library/core/tests/pin.rs | 12 +++++++++++- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index fa5b37edc36e6..9f0284d5d9542 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -708,8 +708,9 @@ impl<'a, T: ?Sized> Pin<&'a T> { impl<'a, T: ?Sized> Pin<&'a mut T> { /// Converts this `Pin<&mut T>` into a `Pin<&T>` with the same lifetime. #[inline(always)] + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] #[stable(feature = "pin", since = "1.33.0")] - pub fn into_ref(self) -> Pin<&'a T> { + pub const fn into_ref(self) -> Pin<&'a T> { Pin { pointer: self.pointer } } @@ -722,9 +723,10 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { /// that lives for as long as the borrow of the `Pin`, not the lifetime of /// the `Pin` itself. This method allows turning the `Pin` into a reference /// with the same lifetime as the original `Pin`. - #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn get_mut(self) -> &'a mut T + #[stable(feature = "pin", since = "1.33.0")] + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + pub const fn get_mut(self) -> &'a mut T where T: Unpin, { @@ -741,9 +743,10 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { /// /// If the underlying data is `Unpin`, `Pin::get_mut` should be used /// instead. - #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub unsafe fn get_unchecked_mut(self) -> &'a mut T { + #[stable(feature = "pin", since = "1.33.0")] + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + pub const unsafe fn get_unchecked_mut(self) -> &'a mut T { self.pointer } diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index b8d67d7266543..490f016ab8b2e 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -39,6 +39,7 @@ #![feature(iter_order_by)] #![feature(cmp_min_max_by)] #![feature(iter_map_while)] +#![feature(const_mut_refs)] #![feature(const_pin)] #![feature(const_slice_from_raw_parts)] #![feature(const_raw_ptr_deref)] diff --git a/library/core/tests/pin.rs b/library/core/tests/pin.rs index 1363353163829..6f617c8d0c297 100644 --- a/library/core/tests/pin.rs +++ b/library/core/tests/pin.rs @@ -17,5 +17,15 @@ fn pin_const() { assert_eq!(INNER_UNCHECKED, POINTER); const REF: &'static usize = PINNED.get_ref(); - assert_eq!(REF, POINTER) + assert_eq!(REF, POINTER); + + // Note: `pin_mut_const` tests that the methods of `Pin<&mut T>` are usable in a const context. + // A const fn is used because `&mut` is not (yet) usable in constants. + const fn pin_mut_const() { + let _ = Pin::new(&mut 2).into_ref(); + let _ = Pin::new(&mut 2).get_mut(); + let _ = unsafe { Pin::new(&mut 2).get_unchecked_mut() }; + } + + pin_mut_const(); } From 28588e5df1747572110f0fc247d2efd653f3b398 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 18 Sep 2020 18:30:08 +0200 Subject: [PATCH 0611/1052] Add missing examples on HashSet iter types --- library/std/src/collections/hash/set.rs | 86 +++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index 72f4798b65d66..a0c39852ad5d8 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -1173,6 +1173,16 @@ where /// See its documentation for more. /// /// [`iter`]: HashSet::iter +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let a: HashSet = vec![1, 2, 3].into_iter().collect(); +/// +/// let mut iter = a.iter(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, K: 'a> { base: base::Iter<'a, K>, @@ -1184,6 +1194,16 @@ pub struct Iter<'a, K: 'a> { /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: IntoIterator::into_iter +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let a: HashSet = vec![1, 2, 3].into_iter().collect(); +/// +/// let mut iter = a.into_iter(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { base: base::IntoIter, @@ -1195,6 +1215,16 @@ pub struct IntoIter { /// See its documentation for more. /// /// [`drain`]: HashSet::drain +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let mut a: HashSet = vec![1, 2, 3].into_iter().collect(); +/// +/// let mut drain = a.drain(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Drain<'a, K: 'a> { base: base::Drain<'a, K>, @@ -1205,6 +1235,18 @@ pub struct Drain<'a, K: 'a> { /// This `struct` is created by the [`drain_filter`] method on [`HashSet`]. /// /// [`drain_filter`]: HashSet::drain_filter +/// +/// # Examples +/// +/// ``` +/// #![feature(hash_drain_filter)] +/// +/// use std::collections::HashSet; +/// +/// let mut a: HashSet = vec![1, 2, 3].into_iter().collect(); +/// +/// let mut drain_filtered = a.drain_filter(|v| v % 2 == 0); +/// ``` #[unstable(feature = "hash_drain_filter", issue = "59618")] pub struct DrainFilter<'a, K, F> where @@ -1219,6 +1261,17 @@ where /// See its documentation for more. /// /// [`intersection`]: HashSet::intersection +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let a: HashSet = vec![1, 2, 3].into_iter().collect(); +/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); +/// +/// let mut intersection = a.intersection(&b); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Intersection<'a, T: 'a, S: 'a> { // iterator of the first set @@ -1233,6 +1286,17 @@ pub struct Intersection<'a, T: 'a, S: 'a> { /// See its documentation for more. /// /// [`difference`]: HashSet::difference +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let a: HashSet = vec![1, 2, 3].into_iter().collect(); +/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); +/// +/// let mut difference = a.difference(&b); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Difference<'a, T: 'a, S: 'a> { // iterator of the first set @@ -1247,6 +1311,17 @@ pub struct Difference<'a, T: 'a, S: 'a> { /// [`HashSet`]. See its documentation for more. /// /// [`symmetric_difference`]: HashSet::symmetric_difference +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let a: HashSet = vec![1, 2, 3].into_iter().collect(); +/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); +/// +/// let mut intersection = a.symmetric_difference(&b); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct SymmetricDifference<'a, T: 'a, S: 'a> { iter: Chain, Difference<'a, T, S>>, @@ -1258,6 +1333,17 @@ pub struct SymmetricDifference<'a, T: 'a, S: 'a> { /// See its documentation for more. /// /// [`union`]: HashSet::union +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let a: HashSet = vec![1, 2, 3].into_iter().collect(); +/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); +/// +/// let mut union_iter = a.union(&b); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Union<'a, T: 'a, S: 'a> { iter: Chain, Difference<'a, T, S>>, From 40dddd33059344b546a11f150c0ec63e797f021c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Fri, 18 Sep 2020 19:11:06 +0200 Subject: [PATCH 0612/1052] use matches!() macro for simple if let conditions --- compiler/rustc_ast/src/ast.rs | 6 +++--- compiler/rustc_ast_passes/src/ast_validation.rs | 5 +---- compiler/rustc_attr/src/builtin.rs | 4 ++-- .../src/deriving/generic/mod.rs | 2 +- compiler/rustc_errors/src/snippet.rs | 8 +++----- compiler/rustc_lint/src/builtin.rs | 13 +++++++------ compiler/rustc_middle/src/middle/cstore.rs | 2 +- .../borrow_check/diagnostics/outlives_suggestion.rs | 7 ++++--- compiler/rustc_mir/src/transform/promote_consts.rs | 2 +- compiler/rustc_mir/src/transform/simplify.rs | 3 +-- compiler/rustc_mir_build/src/build/block.rs | 3 +-- compiler/rustc_mir_build/src/build/matches/mod.rs | 2 +- compiler/rustc_resolve/src/build_reduced_graph.rs | 2 +- compiler/rustc_resolve/src/late.rs | 2 +- compiler/rustc_typeck/src/check/expr.rs | 8 +++++--- 15 files changed, 33 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index dee3a16f9b133..95abf55291506 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1931,7 +1931,7 @@ pub enum TyKind { impl TyKind { pub fn is_implicit_self(&self) -> bool { - if let TyKind::ImplicitSelf = *self { true } else { false } + matches!(self, TyKind::ImplicitSelf) } pub fn is_unit(&self) -> bool { @@ -2227,7 +2227,7 @@ pub enum Async { impl Async { pub fn is_async(self) -> bool { - if let Async::Yes { .. } = self { true } else { false } + matches!(self, Async::Yes { .. }) } /// In this case this is an `async` return, the `NodeId` for the generated `impl Trait` item. @@ -2508,7 +2508,7 @@ pub enum VisibilityKind { impl VisibilityKind { pub fn is_pub(&self) -> bool { - if let VisibilityKind::Public = *self { true } else { false } + matches!(self, VisibilityKind::Public) } } diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 31c05325d1d25..232ee35c4f7df 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -868,10 +868,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .emit(); } - if !bounds - .iter() - .any(|b| if let GenericBound::Trait(..) = *b { true } else { false }) - { + if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) { self.err_handler().span_err(ty.span, "at least one trait must be specified"); } diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index b8929fe088913..9951c25200129 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -160,10 +160,10 @@ pub enum StabilityLevel { impl StabilityLevel { pub fn is_unstable(&self) -> bool { - if let StabilityLevel::Unstable { .. } = *self { true } else { false } + matches!(self, StabilityLevel::Unstable { .. }) } pub fn is_stable(&self) -> bool { - if let StabilityLevel::Stable { .. } = *self { true } else { false } + matches!(self, StabilityLevel::Stable { .. }) } } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index d235caec1031f..f4924997d1af9 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -1529,7 +1529,7 @@ impl<'a> TraitDef<'a> { } } - let is_tuple = if let ast::VariantData::Tuple(..) = struct_def { true } else { false }; + let is_tuple = matches!(struct_def, ast::VariantData::Tuple(..)); match (just_spans.is_empty(), named_idents.is_empty()) { (false, false) => cx.span_bug( self.span, diff --git a/compiler/rustc_errors/src/snippet.rs b/compiler/rustc_errors/src/snippet.rs index 160bf57779970..fae5b94b3a81e 100644 --- a/compiler/rustc_errors/src/snippet.rs +++ b/compiler/rustc_errors/src/snippet.rs @@ -118,17 +118,15 @@ pub struct Annotation { impl Annotation { /// Whether this annotation is a vertical line placeholder. pub fn is_line(&self) -> bool { - if let AnnotationType::MultilineLine(_) = self.annotation_type { true } else { false } + matches!(self.annotation_type, AnnotationType::MultilineLine(_)) } pub fn is_multiline(&self) -> bool { - match self.annotation_type { + matches!(self.annotation_type, AnnotationType::Multiline(_) | AnnotationType::MultilineStart(_) | AnnotationType::MultilineLine(_) - | AnnotationType::MultilineEnd(_) => true, - _ => false, - } + | AnnotationType::MultilineEnd(_)) } pub fn len(&self) -> usize { diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 5b5dbcf192ca1..43424ce9b80e9 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1985,9 +1985,9 @@ impl ExplicitOutlivesRequirements { .filter_map(|(i, bound)| { if let hir::GenericBound::Outlives(lifetime) = bound { let is_inferred = match tcx.named_region(lifetime.hir_id) { - Some(Region::Static) if infer_static => inferred_outlives - .iter() - .any(|r| if let ty::ReStatic = r { true } else { false }), + Some(Region::Static) if infer_static => { + inferred_outlives.iter().any(|r| matches!(r, ty::ReStatic)) + } Some(Region::EarlyBound(index, ..)) => inferred_outlives.iter().any(|r| { if let ty::ReEarlyBound(ebr) = r { ebr.index == index } else { false } }), @@ -2079,9 +2079,10 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { let mut lint_spans = Vec::new(); for param in hir_generics.params { - let has_lifetime_bounds = param.bounds.iter().any(|bound| { - if let hir::GenericBound::Outlives(_) = bound { true } else { false } - }); + let has_lifetime_bounds = param + .bounds + .iter() + .any(|bound| matches!(bound, hir::GenericBound::Outlives(_))); if !has_lifetime_bounds { continue; } diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs index 1af1d58181760..f3d7c8506ab6f 100644 --- a/compiler/rustc_middle/src/middle/cstore.rs +++ b/compiler/rustc_middle/src/middle/cstore.rs @@ -69,7 +69,7 @@ pub enum LibSource { impl LibSource { pub fn is_some(&self) -> bool { - if let LibSource::Some(_) = *self { true } else { false } + matches!(self, LibSource::Some(_)) } pub fn option(&self) -> Option { diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/outlives_suggestion.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/outlives_suggestion.rs index a775fa59c1b9d..7505e6e2dd11e 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/outlives_suggestion.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/outlives_suggestion.rs @@ -115,9 +115,10 @@ impl OutlivesSuggestionBuilder { // should just replace 'a with 'static. // 3) Suggest unifying 'a with 'b if we have both 'a: 'b and 'b: 'a - if outlived.iter().any(|(_, outlived_name)| { - if let RegionNameSource::Static = outlived_name.source { true } else { false } - }) { + if outlived + .iter() + .any(|(_, outlived_name)| matches!(outlived_name.source, RegionNameSource::Static)) + { suggested.push(SuggestedConstraint::Static(fr_name)); } else { // We want to isolate out all lifetimes that should be unified and print out diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index 1d2295a37dddf..75efed043ce45 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -92,7 +92,7 @@ pub enum TempState { impl TempState { pub fn is_promotable(&self) -> bool { debug!("is_promotable: self={:?}", self); - if let TempState::Defined { .. } = *self { true } else { false } + matches!(self, TempState::Defined { .. } ) } } diff --git a/compiler/rustc_mir/src/transform/simplify.rs b/compiler/rustc_mir/src/transform/simplify.rs index d8995e92abfcc..3fc8e6d4b04b8 100644 --- a/compiler/rustc_mir/src/transform/simplify.rs +++ b/compiler/rustc_mir/src/transform/simplify.rs @@ -281,8 +281,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { fn strip_nops(&mut self) { for blk in self.basic_blocks.iter_mut() { - blk.statements - .retain(|stmt| if let StatementKind::Nop = stmt.kind { false } else { true }) + blk.statements.retain(|stmt| !matches!(stmt.kind, StatementKind::Nop)) } } } diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index d1cbf209b06ce..beaf12b1db042 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -96,8 +96,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); } StmtKind::Let { remainder_scope, init_scope, pattern, initializer, lint_level } => { - let ignores_expr_result = - if let PatKind::Wild = *pattern.kind { true } else { false }; + let ignores_expr_result = matches!(*pattern.kind, PatKind::Wild); this.block_context.push(BlockFrame::Statement { ignores_expr_result }); // Enter the remainder scope, i.e., the bindings' destruction scope. diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 3a525d10b0817..6e9d5eedf051f 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1793,7 +1793,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .flat_map(|(bindings, _)| bindings) .chain(&candidate.bindings) .filter(|binding| { - if let BindingMode::ByValue = binding.binding_mode { true } else { false } + matches!(binding.binding_mode, BindingMode::ByValue ) }); // Read all of the by reference bindings to ensure that the // place they refer to can't be modified by the guard. diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 565313902a42e..a48d002b2a35b 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -395,7 +395,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { // so prefixes are prepended with crate root segment if necessary. // The root is prepended lazily, when the first non-empty prefix or terminating glob // appears, so imports in braced groups can have roots prepended independently. - let is_glob = if let ast::UseTreeKind::Glob = use_tree.kind { true } else { false }; + let is_glob = matches!(use_tree.kind, ast::UseTreeKind::Glob); let crate_root = match prefix_iter.peek() { Some(seg) if !seg.ident.is_path_segment_keyword() && seg.ident.span.rust_2015() => { Some(seg.ident.span.ctxt()) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 6788df9be7820..2c01934b490dc 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1034,7 +1034,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let mut add_bindings_for_ns = |ns| { let parent_rib = self.ribs[ns] .iter() - .rfind(|r| if let ItemRibKind(_) = r.kind { true } else { false }) + .rfind(|r| matches!(r.kind, ItemRibKind(_))) .expect("associated item outside of an item"); seen_bindings .extend(parent_rib.bindings.iter().map(|(ident, _)| (*ident, ident.span))); diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index d5563cdac02de..af800eab67a5e 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -439,9 +439,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This is maybe too permissive, since it allows // `let u = &raw const Box::new((1,)).0`, which creates an // immediately dangling raw pointer. - self.typeck_results.borrow().adjustments().get(base.hir_id).map_or(false, |x| { - x.iter().any(|adj| if let Adjust::Deref(_) = adj.kind { true } else { false }) - }) + self.typeck_results + .borrow() + .adjustments() + .get(base.hir_id) + .map_or(false, |x| x.iter().any(|adj| matches!(adj.kind, Adjust::Deref(_)))) }); if !is_named { self.tcx.sess.emit_err(AddressOfTemporaryTaken { span: oprnd.span }) From 925cd2616238d4f93b80cc26f02b5f5b256978fc Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Fri, 18 Sep 2020 20:49:25 +0200 Subject: [PATCH 0613/1052] don't take `TyCtxt` by reference --- compiler/rustc_middle/src/middle/lang_items.rs | 6 +++--- compiler/rustc_middle/src/mir/interpret/mod.rs | 18 +++++++++--------- compiler/rustc_middle/src/ty/context.rs | 18 +++++++++--------- compiler/rustc_middle/src/ty/error.rs | 12 ++++++------ compiler/rustc_middle/src/ty/fold.rs | 8 ++++---- compiler/rustc_middle/src/ty/util.rs | 10 ++++------ 6 files changed, 35 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs index 7194a035e89f6..cc9706f2d867c 100644 --- a/compiler/rustc_middle/src/middle/lang_items.rs +++ b/compiler/rustc_middle/src/middle/lang_items.rs @@ -17,7 +17,7 @@ use rustc_target::spec::PanicStrategy; impl<'tcx> TyCtxt<'tcx> { /// Returns the `DefId` for a given `LangItem`. /// If not found, fatally aborts compilation. - pub fn require_lang_item(&self, lang_item: LangItem, span: Option) -> DefId { + pub fn require_lang_item(self, lang_item: LangItem, span: Option) -> DefId { self.lang_items().require(lang_item).unwrap_or_else(|msg| { if let Some(span) = span { self.sess.span_fatal(span, &msg) @@ -27,7 +27,7 @@ impl<'tcx> TyCtxt<'tcx> { }) } - pub fn fn_trait_kind_from_lang_item(&self, id: DefId) -> Option { + pub fn fn_trait_kind_from_lang_item(self, id: DefId) -> Option { let items = self.lang_items(); match Some(id) { x if x == items.fn_trait() => Some(ty::ClosureKind::Fn), @@ -37,7 +37,7 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub fn is_weak_lang_item(&self, item_def_id: DefId) -> bool { + pub fn is_weak_lang_item(self, item_def_id: DefId) -> bool { self.lang_items().is_weak_lang_item(item_def_id) } } diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index cbc362d934ff8..51642fceb1d93 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -447,14 +447,14 @@ impl<'tcx> TyCtxt<'tcx> { /// /// Make sure to call `set_alloc_id_memory` or `set_alloc_id_same_memory` before returning such /// an `AllocId` from a query. - pub fn reserve_alloc_id(&self) -> AllocId { + pub fn reserve_alloc_id(self) -> AllocId { self.alloc_map.lock().reserve() } /// Reserves a new ID *if* this allocation has not been dedup-reserved before. /// Should only be used for function pointers and statics, we don't want /// to dedup IDs for "real" memory! - fn reserve_and_set_dedup(&self, alloc: GlobalAlloc<'tcx>) -> AllocId { + fn reserve_and_set_dedup(self, alloc: GlobalAlloc<'tcx>) -> AllocId { let mut alloc_map = self.alloc_map.lock(); match alloc { GlobalAlloc::Function(..) | GlobalAlloc::Static(..) => {} @@ -472,13 +472,13 @@ impl<'tcx> TyCtxt<'tcx> { /// Generates an `AllocId` for a static or return a cached one in case this function has been /// called on the same static before. - pub fn create_static_alloc(&self, static_id: DefId) -> AllocId { + pub fn create_static_alloc(self, static_id: DefId) -> AllocId { self.reserve_and_set_dedup(GlobalAlloc::Static(static_id)) } /// Generates an `AllocId` for a function. Depending on the function type, /// this might get deduplicated or assigned a new ID each time. - pub fn create_fn_alloc(&self, instance: Instance<'tcx>) -> AllocId { + pub fn create_fn_alloc(self, instance: Instance<'tcx>) -> AllocId { // Functions cannot be identified by pointers, as asm-equal functions can get deduplicated // by the linker (we set the "unnamed_addr" attribute for LLVM) and functions can be // duplicated across crates. @@ -507,7 +507,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Statics with identical content will still point to the same `Allocation`, i.e., /// their data will be deduplicated through `Allocation` interning -- but they /// are different places in memory and as such need different IDs. - pub fn create_memory_alloc(&self, mem: &'tcx Allocation) -> AllocId { + pub fn create_memory_alloc(self, mem: &'tcx Allocation) -> AllocId { let id = self.reserve_alloc_id(); self.set_alloc_id_memory(id, mem); id @@ -519,7 +519,7 @@ impl<'tcx> TyCtxt<'tcx> { /// This function exists to allow const eval to detect the difference between evaluation- /// local dangling pointers and allocations in constants/statics. #[inline] - pub fn get_global_alloc(&self, id: AllocId) -> Option> { + pub fn get_global_alloc(self, id: AllocId) -> Option> { self.alloc_map.lock().alloc_map.get(&id).cloned() } @@ -529,7 +529,7 @@ impl<'tcx> TyCtxt<'tcx> { /// constants (as all constants must pass interning and validation that check for dangling /// ids), this function is frequently used throughout rustc, but should not be used within /// the miri engine. - pub fn global_alloc(&self, id: AllocId) -> GlobalAlloc<'tcx> { + pub fn global_alloc(self, id: AllocId) -> GlobalAlloc<'tcx> { match self.get_global_alloc(id) { Some(alloc) => alloc, None => bug!("could not find allocation for {}", id), @@ -538,7 +538,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. Trying to /// call this function twice, even with the same `Allocation` will ICE the compiler. - pub fn set_alloc_id_memory(&self, id: AllocId, mem: &'tcx Allocation) { + pub fn set_alloc_id_memory(self, id: AllocId, mem: &'tcx Allocation) { if let Some(old) = self.alloc_map.lock().alloc_map.insert(id, GlobalAlloc::Memory(mem)) { bug!("tried to set allocation ID {}, but it was already existing as {:#?}", id, old); } @@ -546,7 +546,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. May be called /// twice for the same `(AllocId, Allocation)` pair. - fn set_alloc_id_same_memory(&self, id: AllocId, mem: &'tcx Allocation) { + fn set_alloc_id_same_memory(self, id: AllocId, mem: &'tcx Allocation) { self.alloc_map.lock().alloc_map.insert_same(id, GlobalAlloc::Memory(mem)); } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 56746666e2f1f..39bf5472b76f8 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1403,7 +1403,7 @@ impl<'tcx> TyCtxt<'tcx> { } // Returns the `DefId` and the `BoundRegion` corresponding to the given region. - pub fn is_suitable_region(&self, region: Region<'tcx>) -> Option { + pub fn is_suitable_region(self, region: Region<'tcx>) -> Option { let (suitable_region_binding_scope, bound_region) = match *region { ty::ReFree(ref free_region) => { (free_region.scope.expect_local(), free_region.bound_region) @@ -1433,7 +1433,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Given a `DefId` for an `fn`, return all the `dyn` and `impl` traits in its return type. pub fn return_type_impl_or_dyn_traits( - &self, + self, scope_def_id: LocalDefId, ) -> Vec<&'tcx hir::Ty<'tcx>> { let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id); @@ -1479,7 +1479,7 @@ impl<'tcx> TyCtxt<'tcx> { v.0 } - pub fn return_type_impl_trait(&self, scope_def_id: LocalDefId) -> Option<(Ty<'tcx>, Span)> { + pub fn return_type_impl_trait(self, scope_def_id: LocalDefId) -> Option<(Ty<'tcx>, Span)> { // HACK: `type_of_def_id()` will fail on these (#55796), so return `None`. let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id); match self.hir().get(hir_id) { @@ -1497,7 +1497,7 @@ impl<'tcx> TyCtxt<'tcx> { let ret_ty = self.type_of(scope_def_id); match ret_ty.kind() { ty::FnDef(_, _) => { - let sig = ret_ty.fn_sig(*self); + let sig = ret_ty.fn_sig(self); let output = self.erase_late_bound_regions(&sig.output()); if output.is_impl_trait() { let fn_decl = self.hir().fn_decl_by_hir_id(hir_id).unwrap(); @@ -1511,7 +1511,7 @@ impl<'tcx> TyCtxt<'tcx> { } // Checks if the bound region is in Impl Item. - pub fn is_bound_region_in_impl_item(&self, suitable_region_binding_scope: LocalDefId) -> bool { + pub fn is_bound_region_in_impl_item(self, suitable_region_binding_scope: LocalDefId) -> bool { let container_id = self.associated_item(suitable_region_binding_scope.to_def_id()).container.id(); if self.impl_trait_ref(container_id).is_some() { @@ -1528,21 +1528,21 @@ impl<'tcx> TyCtxt<'tcx> { /// Determines whether identifiers in the assembly have strict naming rules. /// Currently, only NVPTX* targets need it. - pub fn has_strict_asm_symbol_naming(&self) -> bool { + pub fn has_strict_asm_symbol_naming(self) -> bool { self.sess.target.target.arch.contains("nvptx") } /// Returns `&'static core::panic::Location<'static>`. - pub fn caller_location_ty(&self) -> Ty<'tcx> { + pub fn caller_location_ty(self) -> Ty<'tcx> { self.mk_imm_ref( self.lifetimes.re_static, self.type_of(self.require_lang_item(LangItem::PanicLocation, None)) - .subst(*self, self.mk_substs([self.lifetimes.re_static.into()].iter())), + .subst(self, self.mk_substs([self.lifetimes.re_static.into()].iter())), ) } /// Returns a displayable description and article for the given `def_id` (e.g. `("a", "struct")`). - pub fn article_and_description(&self, def_id: DefId) -> (&'static str, &'static str) { + pub fn article_and_description(self, def_id: DefId) -> (&'static str, &'static str) { match self.def_kind(def_id) { DefKind::Generator => match self.generator_kind(def_id).unwrap() { rustc_hir::GeneratorKind::Async(..) => ("an", "async closure"), diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 7226a906e5c97..475c3101c1e98 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -546,7 +546,7 @@ impl Trait for X { } fn suggest_constraint( - &self, + self, db: &mut DiagnosticBuilder<'_>, msg: &str, body_owner_def_id: DefId, @@ -554,14 +554,14 @@ impl Trait for X { ty: Ty<'tcx>, ) -> bool { let assoc = self.associated_item(proj_ty.item_def_id); - let trait_ref = proj_ty.trait_ref(*self); + let trait_ref = proj_ty.trait_ref(self); if let Some(item) = self.hir().get_if_local(body_owner_def_id) { if let Some(hir_generics) = item.generics() { // Get the `DefId` for the type parameter corresponding to `A` in `::Foo`. // This will also work for `impl Trait`. let def_id = if let ty::Param(param_ty) = proj_ty.self_ty().kind() { let generics = self.generics_of(body_owner_def_id); - generics.type_param(¶m_ty, *self).def_id + generics.type_param(param_ty, self).def_id } else { return false; }; @@ -629,7 +629,7 @@ impl Trait for X { /// and the `impl`, we provide a generic `help` to constrain the assoc type or call an assoc /// fn that returns the type. fn expected_projection( - &self, + self, db: &mut DiagnosticBuilder<'_>, proj_ty: &ty::ProjectionTy<'tcx>, values: &ExpectedFound>, @@ -734,7 +734,7 @@ fn foo(&self) -> Self::T { String::new() } } fn point_at_methods_that_satisfy_associated_type( - &self, + self, db: &mut DiagnosticBuilder<'_>, assoc_container_id: DefId, current_method_ident: Option, @@ -789,7 +789,7 @@ fn foo(&self) -> Self::T { String::new() } } fn point_at_associated_type( - &self, + self, db: &mut DiagnosticBuilder<'_>, body_owner_def_id: DefId, found: Ty<'tcx>, diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 5e8fb95dc2985..84134bedef0bc 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -623,7 +623,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Replaces any late-bound regions bound in `value` with /// free variants attached to `all_outlive_scope`. pub fn liberate_late_bound_regions( - &self, + self, all_outlive_scope: DefId, value: &ty::Binder, ) -> T @@ -644,7 +644,7 @@ impl<'tcx> TyCtxt<'tcx> { /// variables and equate `value` with something else, those /// variables will also be equated. pub fn collect_constrained_late_bound_regions( - &self, + self, value: &Binder, ) -> FxHashSet where @@ -655,7 +655,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns a set of all late-bound regions that appear in `value` anywhere. pub fn collect_referenced_late_bound_regions( - &self, + self, value: &Binder, ) -> FxHashSet where @@ -665,7 +665,7 @@ impl<'tcx> TyCtxt<'tcx> { } fn collect_late_bound_regions( - &self, + self, value: &Binder, just_constraint: bool, ) -> FxHashSet diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index f3eb7c35f0494..4127b6535bca6 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -170,9 +170,7 @@ impl<'tcx> TyCtxt<'tcx> { }); hasher.finish() } -} -impl<'tcx> TyCtxt<'tcx> { pub fn has_error_field(self, ty: Ty<'tcx>) -> bool { if let ty::Adt(def, substs) = *ty.kind() { for field in def.all_fields() { @@ -526,22 +524,22 @@ impl<'tcx> TyCtxt<'tcx> { } /// Returns `true` if the node pointed to by `def_id` is a `static` item. - pub fn is_static(&self, def_id: DefId) -> bool { + pub fn is_static(self, def_id: DefId) -> bool { self.static_mutability(def_id).is_some() } /// Returns `true` if this is a `static` item with the `#[thread_local]` attribute. - pub fn is_thread_local_static(&self, def_id: DefId) -> bool { + pub fn is_thread_local_static(self, def_id: DefId) -> bool { self.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) } /// Returns `true` if the node pointed to by `def_id` is a mutable `static` item. - pub fn is_mutable_static(&self, def_id: DefId) -> bool { + pub fn is_mutable_static(self, def_id: DefId) -> bool { self.static_mutability(def_id) == Some(hir::Mutability::Mut) } /// Get the type of the pointer to the static that we use in MIR. - pub fn static_ptr_ty(&self, def_id: DefId) -> Ty<'tcx> { + pub fn static_ptr_ty(self, def_id: DefId) -> Ty<'tcx> { // Make sure that any constants in the static's type are evaluated. let static_ty = self.normalize_erasing_regions(ty::ParamEnv::empty(), self.type_of(def_id)); From 78ff69ba1086decb205b988f05aba7711dddb221 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 24 May 2020 18:22:04 +0200 Subject: [PATCH 0614/1052] Implement a destination propagation pass --- compiler/rustc_mir/src/dataflow/impls/mod.rs | 2 +- compiler/rustc_mir/src/lib.rs | 1 + compiler/rustc_mir/src/transform/dest_prop.rs | 732 ++++++++++++++++++ compiler/rustc_mir/src/transform/mod.rs | 2 + compiler/rustc_mir/src/transform/nrvo.rs | 6 + 5 files changed, 742 insertions(+), 1 deletion(-) create mode 100644 compiler/rustc_mir/src/transform/dest_prop.rs diff --git a/compiler/rustc_mir/src/dataflow/impls/mod.rs b/compiler/rustc_mir/src/dataflow/impls/mod.rs index c42d586785656..1769feaf7a514 100644 --- a/compiler/rustc_mir/src/dataflow/impls/mod.rs +++ b/compiler/rustc_mir/src/dataflow/impls/mod.rs @@ -204,7 +204,7 @@ impl<'a, 'tcx> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { /// `EverInitializedPlaces` tracks all places that might have ever been /// initialized upon reaching a particular point in the control flow -/// for a function, without an intervening `Storage Dead`. +/// for a function, without an intervening `StorageDead`. /// /// This dataflow is used to determine if an immutable local variable may /// be assigned to. diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index 42717f273843a..251037792c917 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -6,6 +6,7 @@ Rust MIR: a lowered representation of Rust. #![feature(nll)] #![feature(in_band_lifetimes)] +#![feature(bindings_after_at)] #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs new file mode 100644 index 0000000000000..19054f36171d9 --- /dev/null +++ b/compiler/rustc_mir/src/transform/dest_prop.rs @@ -0,0 +1,732 @@ +//! Propagates assignment destinations backwards in the CFG to eliminate redundant assignments. +//! +//! # Motivation +//! +//! MIR building can insert a lot of redundant copies, and Rust code in general often tends to move +//! values around a lot. The result is a lot of assignments of the form `dest = {move} src;` in MIR. +//! MIR building for constants in particular tends to create additional locals that are only used +//! inside a single block to shuffle a value around unnecessarily. +//! +//! LLVM by itself is not good enough at eliminating these redundant copies (eg. see +//! https://github.com/rust-lang/rust/issues/32966), so this leaves some performance on the table +//! that we can regain by implementing an optimization for removing these assign statements in rustc +//! itself. When this optimization runs fast enough, it can also speed up the constant evaluation +//! and code generation phases of rustc due to the reduced number of statements and locals. +//! +//! # The Optimization +//! +//! Conceptually, this optimization is "destination propagation". It is similar to the Named Return +//! Value Optimization, or NRVO, known from the C++ world, except that it isn't limited to return +//! values or the return place `_0`. On a very high level, independent of the actual implementation +//! details, it does the following: +//! +//! 1) Identify `dest = src;` statements that can be soundly eliminated. +//! 2) Replace all mentions of `src` with `dest` ("unifying" them and propagating the destination +//! backwards). +//! 3) Delete the `dest = src;` statement (by making it a `nop`). +//! +//! Step 1) is by far the hardest, so it is explained in more detail below. +//! +//! ## Soundness +//! +//! Given an `Assign` statement `dest = src;`, where `dest` is a `Place` and `src` is an `Rvalue`, +//! there are a few requirements that must hold for the optimization to be sound: +//! +//! * `dest` must not contain any *indirection* through a pointer. It must access part of the base +//! local. Otherwise it might point to arbitrary memory that is hard to track. +//! +//! It must also not contain any indexing projections, since those take an arbitrary `Local` as +//! the index, and that local might only be initialized shortly before `dest` is used. +//! +//! Subtle case: If `dest` is a, or projects through a union, then we have to make sure that there +//! remains an assignment to it, since that sets the "active field" of the union. But if `src` is +//! a ZST, it might not be initialized, so there might not be any use of it before the assignment, +//! and performing the optimization would simply delete the assignment, leaving `dest` +//! uninitialized. +//! +//! * `src` must be a bare `Local` without any indirections or field projections (FIXME: Why?). +//! It can be copied or moved by the assignment. +//! +//! * The `dest` and `src` locals must never be [*live*][liveness] at the same time. If they are, it +//! means that they both hold a (potentially different) value that is needed by a future use of +//! the locals. Unifying them would overwrite one of the values. +//! +//! Note that computing liveness of locals that have had their address taken is more difficult: +//! Short of doing full escape analysis on the address/pointer/reference, the pass would need to +//! assume that any operation that can potentially involve opaque user code (such as function +//! calls, destructors, and inline assembly) may access any local that had its address taken +//! before that point. +//! +//! Here, the first two conditions are simple structural requirements on the `Assign` statements +//! that can be trivially checked. The liveness requirement however is more difficult and costly to +//! check. +//! +//! ## Previous Work +//! +//! A [previous attempt] at implementing an optimization like this turned out to be a significant +//! regression in compiler performance. Fixing the regressions introduced a lot of undesirable +//! complexity to the implementation. +//! +//! A [subsequent approach] tried to avoid the costly computation by limiting itself to acyclic +//! CFGs, but still turned out to be far too costly to run due to suboptimal performance within +//! individual basic blocks, requiring a walk across the entire block for every assignment found +//! within the block. For the `tuple-stress` benchmark, which has 458745 statements in a single +//! block, this proved to be far too costly. +//! +//! Since the first attempt at this, the compiler has improved dramatically, and new analysis +//! frameworks have been added that should make this approach viable without requiring a limited +//! approach that only works for some classes of CFGs: +//! - rustc now has a powerful dataflow analysis framework that can handle forwards and backwards +//! analyses efficiently. +//! - Layout optimizations for generators have been added to improve code generation for +//! async/await, which are very similar in spirit to what this optimization does. Both walk the +//! MIR and record conflicting uses of locals in a `BitMatrix`. +//! +//! Also, rustc now has a simple NRVO pass (see `nrvo.rs`), which handles a subset of the cases that +//! this destination propagation pass handles, proving that similar optimizations can be performed +//! on MIR. +//! +//! ## Pre/Post Optimization +//! +//! It is recommended to run `SimplifyCfg` and then `SimplifyLocals` some time after this pass, as +//! it replaces the eliminated assign statements with `nop`s and leaves unused locals behind. +//! +//! [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis +//! [previous attempt]: https://github.com/rust-lang/rust/pull/47954 +//! [subsequent approach]: https://github.com/rust-lang/rust/pull/71003 + +use crate::dataflow::{self, Analysis}; +use crate::{ + transform::{MirPass, MirSource}, + util::{dump_mir, PassWhere}, +}; +use dataflow::{ + impls::{MaybeInitializedLocals, MaybeLiveLocals}, + ResultsCursor, +}; +use rustc_data_structures::unify::{InPlaceUnificationTable, UnifyKey}; +use rustc_index::{ + bit_set::{BitMatrix, BitSet}, + vec::IndexVec, +}; +use rustc_middle::mir::tcx::PlaceTy; +use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; +use rustc_middle::mir::{ + traversal, Body, Local, LocalKind, Location, Operand, Place, PlaceElem, Rvalue, Statement, + StatementKind, Terminator, TerminatorKind, +}; +use rustc_middle::ty::{self, Ty, TyCtxt}; + +pub struct DestinationPropagation; + +impl<'tcx> MirPass<'tcx> for DestinationPropagation { + fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { + // Only run at mir-opt-level=2 or higher for now (we don't fix up debuginfo and remove + // storage statements at the moment). + if tcx.sess.opts.debugging_opts.mir_opt_level <= 1 { + return; + } + + let mut conflicts = Conflicts::build(tcx, body, source); + let mut replacements = Replacements::new(body.local_decls.len()); + for candidate @ CandidateAssignment { dest, src, loc } in find_candidates(tcx, body) { + // Merge locals that don't conflict. + if conflicts.contains(dest.local, src) { + debug!("at assignment {:?}, conflict {:?} vs. {:?}", loc, dest.local, src); + continue; + } + + if !tcx.consider_optimizing(|| { + format!("DestinationPropagation {:?} {:?}", source.def_id(), candidate) + }) { + break; + } + + if replacements.push(candidate).is_ok() { + conflicts.unify(candidate.src, candidate.dest.local); + } + } + + replacements.flatten(tcx); + + debug!("replacements {:?}", replacements.map); + + Replacer { tcx, replacements, place_elem_cache: Vec::new() }.visit_body(body); + + // FIXME fix debug info + } +} + +#[derive(Debug, Eq, PartialEq, Copy, Clone)] +struct UnifyLocal(Local); + +impl From for UnifyLocal { + fn from(l: Local) -> Self { + Self(l) + } +} + +impl UnifyKey for UnifyLocal { + type Value = (); + fn index(&self) -> u32 { + self.0.as_u32() + } + fn from_index(u: u32) -> Self { + Self(Local::from_u32(u)) + } + fn tag() -> &'static str { + "UnifyLocal" + } +} + +struct Replacements<'tcx> { + /// Maps locals to their replacement. + map: IndexVec>>, + + /// Whose locals' live ranges to kill. + kill: BitSet, + + /// Tracks locals that have already been merged together to prevent cycles. + unified_locals: InPlaceUnificationTable, +} + +impl Replacements<'tcx> { + fn new(locals: usize) -> Self { + Self { + map: IndexVec::from_elem_n(None, locals), + kill: BitSet::new_empty(locals), + unified_locals: { + let mut table = InPlaceUnificationTable::new(); + for local in 0..locals { + assert_eq!(table.new_key(()), UnifyLocal(Local::from_usize(local))); + } + table + }, + } + } + + fn push(&mut self, candidate: CandidateAssignment<'tcx>) -> Result<(), ()> { + if self.unified_locals.unioned(candidate.src, candidate.dest.local) { + // Candidate conflicts with previous replacement (ie. could possibly form a cycle and + // hang). + + let replacement = self.map[candidate.src].as_mut().unwrap(); + + // If the current replacement is for the same `dest` local, there are 2 or more + // equivalent `src = dest;` assignments. This is fine, the replacer will `nop` out all + // of them. + if replacement.local == candidate.dest.local { + assert_eq!(replacement.projection, candidate.dest.projection); + } + + // We still return `Err` in any case, as `src` and `dest` do not need to be unified + // *again*. + return Err(()); + } + + let entry = &mut self.map[candidate.src]; + if entry.is_some() { + // We're already replacing `src` with something else, so this candidate is out. + return Err(()); + } + + self.unified_locals.union(candidate.src, candidate.dest.local); + + *entry = Some(candidate.dest); + self.kill.insert(candidate.src); + self.kill.insert(candidate.dest.local); + + Ok(()) + } + + /// Applies the stored replacements to all replacements, until no replacements would result in + /// locals that need further replacements when applied. + fn flatten(&mut self, tcx: TyCtxt<'tcx>) { + // Note: This assumes that there are no cycles in the replacements, which is enforced via + // `self.unified_locals`. Otherwise this can cause an infinite loop. + + for local in self.map.indices() { + if let Some(replacement) = self.map[local] { + // Substitute the base local of `replacement` until fixpoint. + let mut base = replacement.local; + let mut reversed_projection_slices = Vec::with_capacity(1); + while let Some(replacement_for_replacement) = self.map[base] { + base = replacement_for_replacement.local; + reversed_projection_slices.push(replacement_for_replacement.projection); + } + + let projection: Vec<_> = reversed_projection_slices + .iter() + .rev() + .flat_map(|projs| projs.iter()) + .chain(replacement.projection.iter()) + .collect(); + let projection = tcx.intern_place_elems(&projection); + + // Replace with the final `Place`. + self.map[local] = Some(Place { local: base, projection }); + } + } + } + + fn for_src(&self, src: Local) -> Option<&Place<'tcx>> { + self.map[src].as_ref() + } +} + +struct Replacer<'tcx> { + tcx: TyCtxt<'tcx>, + replacements: Replacements<'tcx>, + place_elem_cache: Vec>, +} + +impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> { + fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_local(&mut self, local: &mut Local, context: PlaceContext, location: Location) { + if context.is_use() && self.replacements.for_src(*local).is_some() { + bug!( + "use of local {:?} should have been replaced by visit_place; context={:?}, loc={:?}", + local, + context, + location, + ); + } + } + + fn process_projection_elem( + &mut self, + elem: PlaceElem<'tcx>, + _: Location, + ) -> Option> { + match elem { + PlaceElem::Index(local) => { + if let Some(replacement) = self.replacements.for_src(local) { + bug!( + "cannot replace {:?} with {:?} in index projection {:?}", + local, + replacement, + elem, + ); + } else { + None + } + } + _ => None, + } + } + + fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { + if let Some(replacement) = self.replacements.for_src(place.local) { + // Rebase `place`s projections onto `replacement`'s. + self.place_elem_cache.clear(); + self.place_elem_cache.extend(replacement.projection.iter().chain(place.projection)); + let projection = self.tcx.intern_place_elems(&self.place_elem_cache); + let new_place = Place { local: replacement.local, projection }; + + debug!("Replacer: {:?} -> {:?}", place, new_place); + *place = new_place; + } + + self.super_place(place, context, location); + } + + fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { + self.super_statement(statement, location); + + match &statement.kind { + // FIXME: Don't delete storage statements, merge the live ranges instead + StatementKind::StorageDead(local) | StatementKind::StorageLive(local) + if self.replacements.kill.contains(*local) => + { + statement.make_nop() + } + + StatementKind::Assign(box (dest, rvalue)) => { + match rvalue { + Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) => { + // These might've been turned into self-assignments by the replacement + // (this includes the original statement we wanted to eliminate). + if dest == place { + debug!("{:?} turned into self-assignment, deleting", location); + statement.make_nop(); + } + } + _ => {} + } + } + + _ => {} + } + } +} + +struct Conflicts { + /// The conflict matrix. It is always symmetric and the adjacency matrix of the corresponding + /// conflict graph. + matrix: BitMatrix, + + /// Preallocated `BitSet` used by `unify`. + unify_cache: BitSet, +} + +impl Conflicts { + fn build<'tcx>(tcx: TyCtxt<'tcx>, body: &'_ Body<'tcx>, source: MirSource<'tcx>) -> Self { + // We don't have to look out for locals that have their address taken, since `find_candidates` + // already takes care of that. + + let mut conflicts = BitMatrix::from_row_n( + &BitSet::new_empty(body.local_decls.len()), + body.local_decls.len(), + ); + + let mut record_conflicts = + |init: &ResultsCursor<'_, '_, MaybeInitializedLocals>, + live: &ResultsCursor<'_, '_, MaybeLiveLocals>| { + let mut requires_storage = init.get().clone(); + requires_storage.intersect(live.get()); + + for local in requires_storage.iter() { + conflicts.union_row_with(&requires_storage, local); + } + }; + + let def_id = source.def_id(); + let mut init = MaybeInitializedLocals + .into_engine(tcx, body, def_id) + .iterate_to_fixpoint() + .into_results_cursor(body); + let mut live = MaybeLiveLocals + .into_engine(tcx, body, def_id) + .iterate_to_fixpoint() + .into_results_cursor(body); + + dump_mir( + tcx, + None, + "DestinationPropagation-dataflow", + &"", + source, + body, + |pass_where, w| { + match pass_where { + PassWhere::BeforeLocation(loc) => { + init.seek_before_primary_effect(loc); + live.seek_after_primary_effect(loc); + + writeln!(w, " // init: {:?}", init.get())?; + writeln!(w, " // live: {:?}", live.get())?; + } + PassWhere::AfterTerminator(bb) => { + let loc = body.terminator_loc(bb); + init.seek_after_primary_effect(loc); + live.seek_before_primary_effect(loc); + + writeln!(w, " // init: {:?}", init.get())?; + writeln!(w, " // live: {:?}", live.get())?; + } + + PassWhere::BeforeBlock(bb) => { + init.seek_to_block_start(bb); + live.seek_to_block_start(bb); + + writeln!(w, " // init: {:?}", init.get())?; + writeln!(w, " // live: {:?}", live.get())?; + } + + PassWhere::BeforeCFG | PassWhere::AfterCFG | PassWhere::AfterLocation(_) => {} + } + + Ok(()) + }, + ); + + // Visit only reachable basic blocks. The exact order is not important. + for (block, data) in traversal::preorder(body) { + // Observe the dataflow state *before* all possible locations (statement or terminator) in + // each basic block... + for statement_index in 0..=data.statements.len() { + let loc = Location { block, statement_index }; + trace!("record conflicts at {:?}", loc); + init.seek_before_primary_effect(loc); + live.seek_after_primary_effect(loc); + // FIXME: liveness is backwards, so this is slow + + record_conflicts(&init, &live); + } + + // ...and then observe the state *after* the terminator effect is applied. As long as + // neither `init` nor `borrowed` has a "before" effect, we will observe all possible + // dataflow states here or in the loop above. + trace!("record conflicts at end of {:?}", block); + init.seek_to_block_end(block); + live.seek_to_block_end(block); + record_conflicts(&init, &live); + } + + Self { matrix: conflicts, unify_cache: BitSet::new_empty(body.local_decls.len()) } + } + + fn contains(&self, a: Local, b: Local) -> bool { + self.matrix.contains(a, b) + } + + /// Merges the conflicts of `a` and `b`, so that each one inherits all conflicts of the other. + /// + /// This is called when the pass makes the decision to unify `a` and `b` (or parts of `a` and + /// `b`) and is needed to ensure that future unification decisions take potentially newly + /// introduced conflicts into account. + /// + /// For an example, assume we have locals `_0`, `_1`, `_2`, and `_3`. There are these conflicts: + /// + /// * `_0` <-> `_1` + /// * `_1` <-> `_2` + /// * `_3` <-> `_0` + /// + /// We then decide to merge `_2` with `_3` since they don't conflict. Then we decide to merge + /// `_2` with `_0`, which also doesn't have a conflict in the above list. However `_2` is now + /// `_3`, which does conflict with `_0`. + fn unify(&mut self, a: Local, b: Local) { + // FIXME: This might be somewhat slow. Conflict graphs are undirected, maybe we can use + // something with union-find to speed this up? + + // Make all locals that conflict with `a` also conflict with `b`, and vice versa. + self.unify_cache.clear(); + for conflicts_with_a in self.matrix.iter(a) { + self.unify_cache.insert(conflicts_with_a); + } + for conflicts_with_b in self.matrix.iter(b) { + self.unify_cache.insert(conflicts_with_b); + } + for conflicts_with_a_or_b in self.unify_cache.iter() { + // Set both `a` and `b` for this local's row. + self.matrix.insert(conflicts_with_a_or_b, a); + self.matrix.insert(conflicts_with_a_or_b, b); + } + + // Write the locals `a` conflicts with to `b`'s row. + self.matrix.union_rows(a, b); + // Write the locals `b` conflicts with to `a`'s row. + self.matrix.union_rows(b, a); + } +} + +/// A `dest = {move} src;` statement at `loc`. +/// +/// We want to consider merging `dest` and `src` due to this assignment. +#[derive(Debug, Copy, Clone)] +struct CandidateAssignment<'tcx> { + /// Does not contain indirection or indexing (so the only local it contains is the place base). + dest: Place<'tcx>, + src: Local, + loc: Location, +} + +/// Scans the MIR for assignments between locals that we might want to consider merging. +/// +/// This will filter out assignments that do not match the right form (as described in the top-level +/// comment) and also throw out assignments that involve a local that has its address taken or is +/// otherwise ineligible (eg. locals used as array indices are ignored because we cannot propagate +/// arbitrary places into array indices). +fn find_candidates<'a, 'tcx>( + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, +) -> Vec> { + struct FindAssignments<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + candidates: Vec>, + ever_borrowed_locals: BitSet, + locals_used_as_array_index: BitSet, + } + + impl<'a, 'tcx> Visitor<'tcx> for FindAssignments<'a, 'tcx> { + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + if let StatementKind::Assign(box ( + dest, + Rvalue::Use(Operand::Copy(src) | Operand::Move(src)), + )) = &statement.kind + { + // `dest` must not have pointer indirection. + if dest.is_indirect() { + return; + } + + // `src` must be a plain local. + if !src.projection.is_empty() { + return; + } + + // Since we want to replace `src` with `dest`, `src` must not be required. + if is_local_required(src.local, self.body) { + return; + } + + // Can't optimize if both locals ever have their address taken (can introduce + // aliasing). + // FIXME: This can be smarter and take `StorageDead` into account (which + // invalidates borrows). + if self.ever_borrowed_locals.contains(dest.local) + && self.ever_borrowed_locals.contains(src.local) + { + return; + } + + assert_ne!(dest.local, src.local, "self-assignments are UB"); + + // We can't replace locals occurring in `PlaceElem::Index` for now. + if self.locals_used_as_array_index.contains(src.local) { + return; + } + + // Handle the "subtle case" described above by rejecting any `dest` that is or + // projects through a union. + let is_union = |ty: Ty<'_>| { + if let ty::Adt(def, _) = ty.kind() { + if def.is_union() { + return true; + } + } + + false + }; + let mut place_ty = PlaceTy::from_ty(self.body.local_decls[dest.local].ty); + if is_union(place_ty.ty) { + return; + } + for elem in dest.projection { + if let PlaceElem::Index(_) = elem { + // `dest` contains an indexing projection. + return; + } + + place_ty = place_ty.projection_ty(self.tcx, elem); + if is_union(place_ty.ty) { + return; + } + } + + self.candidates.push(CandidateAssignment { + dest: *dest, + src: src.local, + loc: location, + }); + } + } + } + + let mut visitor = FindAssignments { + tcx, + body, + candidates: Vec::new(), + ever_borrowed_locals: ever_borrowed_locals(body), + locals_used_as_array_index: locals_used_as_array_index(body), + }; + visitor.visit_body(body); + visitor.candidates +} + +/// Some locals are part of the function's interface and can not be removed. +/// +/// Note that these locals *can* still be merged with non-required locals by removing that other +/// local. +fn is_local_required(local: Local, body: &Body<'_>) -> bool { + match body.local_kind(local) { + LocalKind::Arg | LocalKind::ReturnPointer => true, + LocalKind::Var | LocalKind::Temp => false, + } +} + +/// Walks MIR to find all locals that have their address taken anywhere. +fn ever_borrowed_locals(body: &Body<'_>) -> BitSet { + struct BorrowCollector { + locals: BitSet, + } + + impl<'tcx> Visitor<'tcx> for BorrowCollector { + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + self.super_rvalue(rvalue, location); + + match rvalue { + Rvalue::AddressOf(_, borrowed_place) | Rvalue::Ref(_, _, borrowed_place) => { + if !borrowed_place.is_indirect() { + self.locals.insert(borrowed_place.local); + } + } + + Rvalue::Cast(..) + | Rvalue::Use(..) + | Rvalue::Repeat(..) + | Rvalue::Len(..) + | Rvalue::BinaryOp(..) + | Rvalue::CheckedBinaryOp(..) + | Rvalue::NullaryOp(..) + | Rvalue::UnaryOp(..) + | Rvalue::Discriminant(..) + | Rvalue::Aggregate(..) + | Rvalue::ThreadLocalRef(..) => {} + } + } + + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + self.super_terminator(terminator, location); + + match terminator.kind { + TerminatorKind::Drop { place: dropped_place, .. } + | TerminatorKind::DropAndReplace { place: dropped_place, .. } => { + self.locals.insert(dropped_place.local); + } + + TerminatorKind::Abort + | TerminatorKind::Assert { .. } + | TerminatorKind::Call { .. } + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::Return + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::Unreachable + | TerminatorKind::Yield { .. } + | TerminatorKind::InlineAsm { .. } => {} + } + } + } + + let mut visitor = BorrowCollector { locals: BitSet::new_empty(body.local_decls.len()) }; + visitor.visit_body(body); + visitor.locals +} + +/// `PlaceElem::Index` only stores a `Local`, so we can't replace that with a full `Place`. +/// +/// Collect locals used as indices so we don't generate candidates that are impossible to apply +/// later. +fn locals_used_as_array_index(body: &Body<'_>) -> BitSet { + struct IndexCollector { + locals: BitSet, + } + + impl<'tcx> Visitor<'tcx> for IndexCollector { + fn visit_projection_elem( + &mut self, + local: Local, + proj_base: &[PlaceElem<'tcx>], + elem: PlaceElem<'tcx>, + context: PlaceContext, + location: Location, + ) { + if let PlaceElem::Index(i) = elem { + self.locals.insert(i); + } + self.super_projection_elem(local, proj_base, elem, context, location); + } + } + + let mut visitor = IndexCollector { locals: BitSet::new_empty(body.local_decls.len()) }; + visitor.visit_body(body); + visitor.locals +} diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index 226282fe4263c..fc9854ba499f8 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -24,6 +24,7 @@ pub mod cleanup_post_borrowck; pub mod const_prop; pub mod copy_prop; pub mod deaggregator; +pub mod dest_prop; pub mod dump_mir; pub mod elaborate_drops; pub mod generator; @@ -467,6 +468,7 @@ fn run_optimization_passes<'tcx>( &simplify_comparison_integral::SimplifyComparisonIntegral, &simplify_try::SimplifyArmIdentity, &simplify_try::SimplifyBranchSame, + &dest_prop::DestinationPropagation, ©_prop::CopyPropagation, &simplify_branches::SimplifyBranches::new("after-copy-prop"), &remove_noop_landing_pads::RemoveNoopLandingPads, diff --git a/compiler/rustc_mir/src/transform/nrvo.rs b/compiler/rustc_mir/src/transform/nrvo.rs index 3673b6a4aa223..1ffb5a87c4762 100644 --- a/compiler/rustc_mir/src/transform/nrvo.rs +++ b/compiler/rustc_mir/src/transform/nrvo.rs @@ -36,6 +36,12 @@ impl<'tcx> MirPass<'tcx> for RenameReturnPlace { return; } + if tcx.sess.opts.debugging_opts.mir_opt_level >= 2 { + // The `DestinationPropagation` pass runs at level 2, so this pass is redundant (and + // fails some asserts). + return; + } + let returned_local = match local_eligible_for_nrvo(body) { Some(l) => l, None => { From 43ad8e4260bec289c522a2fd3597c275e9e3c39c Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 25 May 2020 23:22:19 +0200 Subject: [PATCH 0615/1052] simplify_try: print dest_prop diff and bless The new diff is to convince me that this is correct and nothing funky is going on. --- ...c.try_identity.DestinationPropagation.diff | 72 +++++++++++++++++++ src/test/mir-opt/simplify_try.rs | 2 + ...y.try_identity.DestinationPropagation.diff | 72 +++++++++++++++++++ ..._try.try_identity.SimplifyLocals.after.mir | 4 +- 4 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 src/test/mir-opt/rustc.try_identity.DestinationPropagation.diff create mode 100644 src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff diff --git a/src/test/mir-opt/rustc.try_identity.DestinationPropagation.diff b/src/test/mir-opt/rustc.try_identity.DestinationPropagation.diff new file mode 100644 index 0000000000000..ff84af7491dbf --- /dev/null +++ b/src/test/mir-opt/rustc.try_identity.DestinationPropagation.diff @@ -0,0 +1,72 @@ +- // MIR for `try_identity` before DestinationPropagation ++ // MIR for `try_identity` after DestinationPropagation + + fn try_identity(_1: std::result::Result) -> std::result::Result { + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:5:17: 5:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:5:41: 5:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:6:9: 6:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:14 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:7:8: 7:9 + scope 1 { + debug y => _2; // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10 + } + scope 2 { + debug err => _6; // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15 + scope 3 { + scope 7 { + debug t => _9; // in scope 7 at $SRC_DIR/libcore/convert/mod.rs:LL:COL + } + scope 8 { + debug v => _8; // in scope 8 at $SRC_DIR/libcore/result.rs:LL:COL + let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:6:14: 6:15 + } + } + } + scope 4 { + debug val => _10; // in scope 4 at $DIR/simplify_try.rs:6:13: 6:15 + scope 5 { + } + } + scope 6 { +- debug self => _4; // in scope 6 at $SRC_DIR/libcore/result.rs:LL:COL ++ debug self => _0; // in scope 6 at $SRC_DIR/libcore/result.rs:LL:COL + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:6:9: 6:10 +- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:6:13: 6:15 +- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:6:13: 6:14 +- _4 = _1; // scope 0 at $DIR/simplify_try.rs:6:13: 6:14 +- _3 = move _4; // scope 6 at $SRC_DIR/libcore/result.rs:LL:COL +- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 +- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:6:13: 6:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:6:13: 6:14 ++ _0 = _1; // scope 0 at $DIR/simplify_try.rs:6:13: 6:14 ++ nop; // scope 6 at $SRC_DIR/libcore/result.rs:LL:COL ++ nop; // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 ++ _5 = discriminant(_0); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 + goto -> bb1; // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 + } + + bb1: { +- _0 = move _3; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10 +- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:6:15: 6:16 ++ nop; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10 ++ nop; // scope 0 at $DIR/simplify_try.rs:6:15: 6:16 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:8:1: 8:2 + goto -> bb2; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2 + } + + bb2: { + return; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2 + } + } + diff --git a/src/test/mir-opt/simplify_try.rs b/src/test/mir-opt/simplify_try.rs index fa127de13dfd9..d77e17c1c62fb 100644 --- a/src/test/mir-opt/simplify_try.rs +++ b/src/test/mir-opt/simplify_try.rs @@ -10,3 +10,5 @@ fn try_identity(x: Result) -> Result { fn main() { let _ = try_identity(Ok(0)); } + +// EMIT_MIR simplify_try.try_identity.DestinationPropagation.diff diff --git a/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff b/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff new file mode 100644 index 0000000000000..78b0b24bf1109 --- /dev/null +++ b/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff @@ -0,0 +1,72 @@ +- // MIR for `try_identity` before DestinationPropagation ++ // MIR for `try_identity` after DestinationPropagation + + fn try_identity(_1: std::result::Result) -> std::result::Result { + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:5:17: 5:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:5:41: 5:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:6:9: 6:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:14 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:7:8: 7:9 + scope 1 { + debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10 + } + scope 2 { + debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15 + scope 3 { + scope 7 { + debug t => ((_0 as Err).0: i32); // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL + } + scope 8 { + debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL + let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:6:14: 6:15 + } + } + } + scope 4 { + debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:6:13: 6:15 + scope 5 { + } + } + scope 6 { +- debug self => _4; // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL ++ debug self => _0; // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:6:9: 6:10 +- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:6:13: 6:15 +- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:6:13: 6:14 +- _4 = _1; // scope 0 at $DIR/simplify_try.rs:6:13: 6:14 +- _3 = move _4; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL +- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 +- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:6:13: 6:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:6:13: 6:14 ++ _0 = _1; // scope 0 at $DIR/simplify_try.rs:6:13: 6:14 ++ nop; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL ++ nop; // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 ++ _5 = discriminant(_0); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 + goto -> bb1; // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 + } + + bb1: { +- _0 = move _3; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10 +- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:6:15: 6:16 ++ nop; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10 ++ nop; // scope 0 at $DIR/simplify_try.rs:6:15: 6:16 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:8:1: 8:2 + goto -> bb2; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2 + } + + bb2: { + return; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2 + } + } + diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir b/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir index d65a2b12c0fd3..d11e4454d2538 100644 --- a/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir +++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir @@ -23,11 +23,11 @@ fn try_identity(_1: std::result::Result) -> std::result::Result _1; // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL + debug self => _0; // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL } bb0: { - _0 = move _1; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10 + _0 = _1; // scope 0 at $DIR/simplify_try.rs:6:13: 6:14 return; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2 } } From 16498953856a41e781da65709f1d111cef66af91 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 25 May 2020 23:22:47 +0200 Subject: [PATCH 0616/1052] simplify_try: clean up test --- ...c.try_identity.DestinationPropagation.diff | 70 ++++++------ src/test/mir-opt/simplify_try.rs | 3 +- ...y.try_identity.DestinationPropagation.diff | 70 ++++++------ ..._try.try_identity.SimplifyArmIdentity.diff | 102 +++++++++--------- ....try_identity.SimplifyBranchSame.after.mir | 56 +++++----- ..._try.try_identity.SimplifyLocals.after.mir | 14 +-- 6 files changed, 157 insertions(+), 158 deletions(-) diff --git a/src/test/mir-opt/rustc.try_identity.DestinationPropagation.diff b/src/test/mir-opt/rustc.try_identity.DestinationPropagation.diff index ff84af7491dbf..c3e503bf2c686 100644 --- a/src/test/mir-opt/rustc.try_identity.DestinationPropagation.diff +++ b/src/test/mir-opt/rustc.try_identity.DestinationPropagation.diff @@ -2,35 +2,35 @@ + // MIR for `try_identity` after DestinationPropagation fn try_identity(_1: std::result::Result) -> std::result::Result { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:5:17: 5:18 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:5:41: 5:57 - let _2: u32; // in scope 0 at $DIR/simplify_try.rs:6:9: 6:10 - let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15 - let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:14 - let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let _6: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let _10: u32; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15 - let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:7:8: 7:9 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:6:17: 6:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:6:41: 6:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:7:9: 7:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:14 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:8:8: 8:9 scope 1 { - debug y => _2; // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10 + debug y => _2; // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10 } scope 2 { - debug err => _6; // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15 + debug err => _6; // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15 scope 3 { scope 7 { debug t => _9; // in scope 7 at $SRC_DIR/libcore/convert/mod.rs:LL:COL } scope 8 { debug v => _8; // in scope 8 at $SRC_DIR/libcore/result.rs:LL:COL - let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:6:14: 6:15 + let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:7:14: 7:15 } } } scope 4 { - debug val => _10; // in scope 4 at $DIR/simplify_try.rs:6:13: 6:15 + debug val => _10; // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15 scope 5 { } } @@ -40,33 +40,33 @@ } bb0: { - StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:6:9: 6:10 -- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:6:13: 6:15 -- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:6:13: 6:14 -- _4 = _1; // scope 0 at $DIR/simplify_try.rs:6:13: 6:14 + StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:7:9: 7:10 +- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:7:13: 7:15 +- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 +- _4 = _1; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 - _3 = move _4; // scope 6 at $SRC_DIR/libcore/result.rs:LL:COL -- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 -- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 -+ nop; // scope 0 at $DIR/simplify_try.rs:6:13: 6:15 -+ nop; // scope 0 at $DIR/simplify_try.rs:6:13: 6:14 -+ _0 = _1; // scope 0 at $DIR/simplify_try.rs:6:13: 6:14 +- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 +- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:7:13: 7:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 ++ _0 = _1; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 + nop; // scope 6 at $SRC_DIR/libcore/result.rs:LL:COL -+ nop; // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 -+ _5 = discriminant(_0); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - goto -> bb1; // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 ++ _5 = discriminant(_0); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + goto -> bb1; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 } bb1: { -- _0 = move _3; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10 -- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:6:15: 6:16 -+ nop; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10 -+ nop; // scope 0 at $DIR/simplify_try.rs:6:15: 6:16 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:8:1: 8:2 - goto -> bb2; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2 +- _0 = move _3; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10 +- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:7:15: 7:16 ++ nop; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10 ++ nop; // scope 0 at $DIR/simplify_try.rs:7:15: 7:16 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:9:1: 9:2 + goto -> bb2; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2 } bb2: { - return; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2 + return; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/simplify_try.rs b/src/test/mir-opt/simplify_try.rs index d77e17c1c62fb..fca80bee89679 100644 --- a/src/test/mir-opt/simplify_try.rs +++ b/src/test/mir-opt/simplify_try.rs @@ -1,6 +1,7 @@ // EMIT_MIR simplify_try.try_identity.SimplifyArmIdentity.diff // EMIT_MIR simplify_try.try_identity.SimplifyBranchSame.after.mir // EMIT_MIR simplify_try.try_identity.SimplifyLocals.after.mir +// EMIT_MIR simplify_try.try_identity.DestinationPropagation.diff fn try_identity(x: Result) -> Result { let y = x?; @@ -10,5 +11,3 @@ fn try_identity(x: Result) -> Result { fn main() { let _ = try_identity(Ok(0)); } - -// EMIT_MIR simplify_try.try_identity.DestinationPropagation.diff diff --git a/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff b/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff index 78b0b24bf1109..187a3cfbb896d 100644 --- a/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff +++ b/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff @@ -2,35 +2,35 @@ + // MIR for `try_identity` after DestinationPropagation fn try_identity(_1: std::result::Result) -> std::result::Result { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:5:17: 5:18 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:5:41: 5:57 - let _2: u32; // in scope 0 at $DIR/simplify_try.rs:6:9: 6:10 - let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15 - let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:14 - let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let _6: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let _10: u32; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15 - let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:7:8: 7:9 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:6:17: 6:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:6:41: 6:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:7:9: 7:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:14 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:8:8: 8:9 scope 1 { - debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10 + debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10 } scope 2 { - debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15 + debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15 scope 3 { scope 7 { debug t => ((_0 as Err).0: i32); // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL } scope 8 { debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:6:14: 6:15 + let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:7:14: 7:15 } } } scope 4 { - debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:6:13: 6:15 + debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15 scope 5 { } } @@ -40,33 +40,33 @@ } bb0: { - StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:6:9: 6:10 -- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:6:13: 6:15 -- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:6:13: 6:14 -- _4 = _1; // scope 0 at $DIR/simplify_try.rs:6:13: 6:14 + StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:7:9: 7:10 +- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:7:13: 7:15 +- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 +- _4 = _1; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 - _3 = move _4; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL -- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 -- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 -+ nop; // scope 0 at $DIR/simplify_try.rs:6:13: 6:15 -+ nop; // scope 0 at $DIR/simplify_try.rs:6:13: 6:14 -+ _0 = _1; // scope 0 at $DIR/simplify_try.rs:6:13: 6:14 +- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 +- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:7:13: 7:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 ++ _0 = _1; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 + nop; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL -+ nop; // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 -+ _5 = discriminant(_0); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - goto -> bb1; // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 ++ _5 = discriminant(_0); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + goto -> bb1; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 } bb1: { -- _0 = move _3; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10 -- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:6:15: 6:16 -+ nop; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10 -+ nop; // scope 0 at $DIR/simplify_try.rs:6:15: 6:16 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:8:1: 8:2 - goto -> bb2; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2 +- _0 = move _3; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10 +- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:7:15: 7:16 ++ nop; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10 ++ nop; // scope 0 at $DIR/simplify_try.rs:7:15: 7:16 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:9:1: 9:2 + goto -> bb2; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2 } bb2: { - return; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2 + return; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff index 26ce290b5496a..0c687684c508e 100644 --- a/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff @@ -2,25 +2,25 @@ + // MIR for `try_identity` after SimplifyArmIdentity fn try_identity(_1: std::result::Result) -> std::result::Result { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:5:17: 5:18 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:5:41: 5:57 - let _2: u32; // in scope 0 at $DIR/simplify_try.rs:6:9: 6:10 - let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15 - let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:14 - let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let _6: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let _10: u32; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15 - let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:7:8: 7:9 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:6:17: 6:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:6:41: 6:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:7:9: 7:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:14 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:8:8: 8:9 scope 1 { -- debug y => _2; // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10 -+ debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10 +- debug y => _2; // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10 ++ debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10 } scope 2 { -- debug err => _6; // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15 -+ debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15 +- debug err => _6; // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15 ++ debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15 scope 3 { scope 7 { - debug t => _9; // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL @@ -29,13 +29,13 @@ scope 8 { - debug v => _8; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL + debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:6:14: 6:15 + let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:7:14: 7:15 } } } scope 4 { -- debug val => _10; // in scope 4 at $DIR/simplify_try.rs:6:13: 6:15 -+ debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:6:13: 6:15 +- debug val => _10; // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15 ++ debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15 scope 5 { } } @@ -44,55 +44,55 @@ } bb0: { - StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:6:9: 6:10 - StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:6:13: 6:15 - StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:6:13: 6:14 - _4 = _1; // scope 0 at $DIR/simplify_try.rs:6:13: 6:14 + StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:7:9: 7:10 + StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:7:13: 7:15 + StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 + _4 = _1; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 _3 = move _4; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 + StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 } bb1: { -- StorageLive(_10); // scope 0 at $DIR/simplify_try.rs:6:13: 6:15 -- _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:6:13: 6:15 -- _2 = _10; // scope 5 at $DIR/simplify_try.rs:6:13: 6:15 -- StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 -+ _0 = move _3; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10 - StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:6:15: 6:16 -- StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:7:8: 7:9 -- _11 = _2; // scope 1 at $DIR/simplify_try.rs:7:8: 7:9 -- ((_0 as Ok).0: u32) = move _11; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10 -- discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10 -- StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:7:9: 7:10 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:8:1: 8:2 - goto -> bb3; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2 +- StorageLive(_10); // scope 0 at $DIR/simplify_try.rs:7:13: 7:15 +- _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:7:13: 7:15 +- _2 = _10; // scope 5 at $DIR/simplify_try.rs:7:13: 7:15 +- StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 ++ _0 = move _3; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:7:15: 7:16 +- StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:8:8: 8:9 +- _11 = _2; // scope 1 at $DIR/simplify_try.rs:8:8: 8:9 +- ((_0 as Ok).0: u32) = move _11; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10 +- discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10 +- StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:8:9: 8:10 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:9:1: 9:2 + goto -> bb3; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2 } bb2: { -- StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 -- _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 -- StorageLive(_8); // scope 3 at $DIR/simplify_try.rs:6:14: 6:15 -- StorageLive(_9); // scope 3 at $DIR/simplify_try.rs:6:14: 6:15 -- _9 = _6; // scope 3 at $DIR/simplify_try.rs:6:14: 6:15 +- StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 +- _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 +- StorageLive(_8); // scope 3 at $DIR/simplify_try.rs:7:14: 7:15 +- StorageLive(_9); // scope 3 at $DIR/simplify_try.rs:7:14: 7:15 +- _9 = _6; // scope 3 at $DIR/simplify_try.rs:7:14: 7:15 - _8 = move _9; // scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL -- StorageDead(_9); // scope 3 at $DIR/simplify_try.rs:6:14: 6:15 +- StorageDead(_9); // scope 3 at $DIR/simplify_try.rs:7:14: 7:15 - StorageLive(_12); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - _12 = move _8; // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - ((_0 as Err).0: i32) = move _12; // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - discriminant(_0) = 1; // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_12); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL -- StorageDead(_8); // scope 3 at $DIR/simplify_try.rs:6:14: 6:15 -- StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 +- StorageDead(_8); // scope 3 at $DIR/simplify_try.rs:7:14: 7:15 +- StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + _0 = move _3; // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:6:15: 6:16 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:8:1: 8:2 - goto -> bb3; // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:7:15: 7:16 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:9:1: 9:2 + goto -> bb3; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 } bb3: { - return; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2 + return; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir b/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir index dc4aae176f2c4..9428d305c8731 100644 --- a/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir +++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir @@ -1,35 +1,35 @@ // MIR for `try_identity` after SimplifyBranchSame fn try_identity(_1: std::result::Result) -> std::result::Result { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:5:17: 5:18 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:5:41: 5:57 - let _2: u32; // in scope 0 at $DIR/simplify_try.rs:6:9: 6:10 - let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15 - let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:14 - let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let _6: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let _10: u32; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15 - let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:7:8: 7:9 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:6:17: 6:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:6:41: 6:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:7:9: 7:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:14 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:8:8: 8:9 scope 1 { - debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10 + debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10 } scope 2 { - debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15 + debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15 scope 3 { scope 7 { debug t => ((_0 as Err).0: i32); // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL } scope 8 { debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:6:14: 6:15 + let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:7:14: 7:15 } } } scope 4 { - debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:6:13: 6:15 + debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15 scope 5 { } } @@ -38,24 +38,24 @@ fn try_identity(_1: std::result::Result) -> std::result::Result bb1; // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 + StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + goto -> bb1; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 } bb1: { - _0 = move _3; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10 - StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:6:15: 6:16 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:8:1: 8:2 - goto -> bb2; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2 + _0 = move _3; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:7:15: 7:16 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:9:1: 9:2 + goto -> bb2; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2 } bb2: { - return; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2 + return; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir b/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir index d11e4454d2538..a25472f6a5e05 100644 --- a/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir +++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir @@ -1,13 +1,13 @@ // MIR for `try_identity` after SimplifyLocals fn try_identity(_1: std::result::Result) -> std::result::Result { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:5:17: 5:18 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:5:41: 5:57 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:6:17: 6:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:6:41: 6:57 scope 1 { - debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10 + debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10 } scope 2 { - debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15 + debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15 scope 3 { scope 7 { debug t => ((_0 as Err).0: i32); // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL @@ -18,7 +18,7 @@ fn try_identity(_1: std::result::Result) -> std::result::Result ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:6:13: 6:15 + debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15 scope 5 { } } @@ -27,7 +27,7 @@ fn try_identity(_1: std::result::Result) -> std::result::Result Date: Mon, 25 May 2020 23:37:10 +0200 Subject: [PATCH 0617/1052] Make nrvo-simple set mir-opt-level=1 The additional copies are due to the lack of copy propagation --- src/test/mir-opt/nrvo-simple.rs | 2 + .../nrvo_simple.nrvo.RenameReturnPlace.diff | 55 ++++++++++--------- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/src/test/mir-opt/nrvo-simple.rs b/src/test/mir-opt/nrvo-simple.rs index f0eb711b3f0a7..ab46d7b94c72c 100644 --- a/src/test/mir-opt/nrvo-simple.rs +++ b/src/test/mir-opt/nrvo-simple.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmir-opt-level=1 + // EMIT_MIR nrvo_simple.nrvo.RenameReturnPlace.diff fn nrvo(init: fn(&mut [u8; 1024])) -> [u8; 1024] { let mut buf = [0; 1024]; diff --git a/src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff b/src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff index 924e87ea8c0ad..f438eaa002780 100644 --- a/src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff +++ b/src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff @@ -2,39 +2,42 @@ + // MIR for `nrvo` after RenameReturnPlace fn nrvo(_1: for<'r> fn(&'r mut [u8; 1024])) -> [u8; 1024] { - debug init => _1; // in scope 0 at $DIR/nrvo-simple.rs:2:9: 2:13 -- let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/nrvo-simple.rs:2:39: 2:49 -+ let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/nrvo-simple.rs:3:9: 3:16 - let mut _2: [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:3:9: 3:16 - let _3: (); // in scope 0 at $DIR/nrvo-simple.rs:4:5: 4:19 - let mut _4: for<'r> fn(&'r mut [u8; 1024]); // in scope 0 at $DIR/nrvo-simple.rs:4:5: 4:9 - let mut _5: &mut [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:4:10: 4:18 - let mut _6: &mut [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:4:10: 4:18 + debug init => _1; // in scope 0 at $DIR/nrvo-simple.rs:4:9: 4:13 +- let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/nrvo-simple.rs:4:39: 4:49 ++ let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/nrvo-simple.rs:5:9: 5:16 + let mut _2: [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:5:9: 5:16 + let _3: (); // in scope 0 at $DIR/nrvo-simple.rs:6:5: 6:19 + let mut _4: for<'r> fn(&'r mut [u8; 1024]); // in scope 0 at $DIR/nrvo-simple.rs:6:5: 6:9 + let mut _5: &mut [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:6:10: 6:18 + let mut _6: &mut [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:6:10: 6:18 scope 1 { -- debug buf => _2; // in scope 1 at $DIR/nrvo-simple.rs:3:9: 3:16 -+ debug buf => _0; // in scope 1 at $DIR/nrvo-simple.rs:3:9: 3:16 +- debug buf => _2; // in scope 1 at $DIR/nrvo-simple.rs:5:9: 5:16 ++ debug buf => _0; // in scope 1 at $DIR/nrvo-simple.rs:5:9: 5:16 } bb0: { -- StorageLive(_2); // scope 0 at $DIR/nrvo-simple.rs:3:9: 3:16 -- _2 = [const 0_u8; 1024]; // scope 0 at $DIR/nrvo-simple.rs:3:19: 3:28 -+ _0 = [const 0_u8; 1024]; // scope 0 at $DIR/nrvo-simple.rs:3:19: 3:28 - StorageLive(_3); // scope 1 at $DIR/nrvo-simple.rs:4:5: 4:19 - StorageLive(_5); // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18 - StorageLive(_6); // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18 -- _6 = &mut _2; // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18 -+ _6 = &mut _0; // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18 - _5 = &mut (*_6); // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18 - _3 = move _1(move _5) -> bb1; // scope 1 at $DIR/nrvo-simple.rs:4:5: 4:19 +- StorageLive(_2); // scope 0 at $DIR/nrvo-simple.rs:5:9: 5:16 +- _2 = [const 0_u8; 1024]; // scope 0 at $DIR/nrvo-simple.rs:5:19: 5:28 ++ _0 = [const 0_u8; 1024]; // scope 0 at $DIR/nrvo-simple.rs:5:19: 5:28 + StorageLive(_3); // scope 1 at $DIR/nrvo-simple.rs:6:5: 6:19 + StorageLive(_4); // scope 1 at $DIR/nrvo-simple.rs:6:5: 6:9 + _4 = _1; // scope 1 at $DIR/nrvo-simple.rs:6:5: 6:9 + StorageLive(_5); // scope 1 at $DIR/nrvo-simple.rs:6:10: 6:18 + StorageLive(_6); // scope 1 at $DIR/nrvo-simple.rs:6:10: 6:18 +- _6 = &mut _2; // scope 1 at $DIR/nrvo-simple.rs:6:10: 6:18 ++ _6 = &mut _0; // scope 1 at $DIR/nrvo-simple.rs:6:10: 6:18 + _5 = &mut (*_6); // scope 1 at $DIR/nrvo-simple.rs:6:10: 6:18 + _3 = move _4(move _5) -> bb1; // scope 1 at $DIR/nrvo-simple.rs:6:5: 6:19 } bb1: { - StorageDead(_5); // scope 1 at $DIR/nrvo-simple.rs:4:18: 4:19 - StorageDead(_6); // scope 1 at $DIR/nrvo-simple.rs:4:19: 4:20 - StorageDead(_3); // scope 1 at $DIR/nrvo-simple.rs:4:19: 4:20 -- _0 = _2; // scope 1 at $DIR/nrvo-simple.rs:5:5: 5:8 -- StorageDead(_2); // scope 0 at $DIR/nrvo-simple.rs:6:1: 6:2 - return; // scope 0 at $DIR/nrvo-simple.rs:6:2: 6:2 + StorageDead(_5); // scope 1 at $DIR/nrvo-simple.rs:6:18: 6:19 + StorageDead(_4); // scope 1 at $DIR/nrvo-simple.rs:6:18: 6:19 + StorageDead(_6); // scope 1 at $DIR/nrvo-simple.rs:6:19: 6:20 + StorageDead(_3); // scope 1 at $DIR/nrvo-simple.rs:6:19: 6:20 +- _0 = _2; // scope 1 at $DIR/nrvo-simple.rs:7:5: 7:8 +- StorageDead(_2); // scope 0 at $DIR/nrvo-simple.rs:8:1: 8:2 + return; // scope 0 at $DIR/nrvo-simple.rs:8:2: 8:2 } } From 8a3e2b78bb0595bc9205b29898eb128836b5c57f Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 12 Sep 2020 14:58:46 +0200 Subject: [PATCH 0618/1052] Bless mir-opt tests --- ..._allocation.main.ConstProp.after.32bit.mir | 28 +-- ..._allocation.main.ConstProp.after.64bit.mir | 32 +-- ...allocation2.main.ConstProp.after.32bit.mir | 26 +-- ...allocation2.main.ConstProp.after.64bit.mir | 28 +-- ...allocation3.main.ConstProp.after.32bit.mir | 4 +- ...allocation3.main.ConstProp.after.64bit.mir | 4 +- ...copy_propagation.test.CopyPropagation.diff | 15 +- ...opagation_arg.arg_src.CopyPropagation.diff | 10 +- ...y_propagation_arg.baz.CopyPropagation.diff | 8 +- ...y_propagation_arg.foo.CopyPropagation.diff | 8 +- ...line_closure_captures.foo.Inline.after.mir | 24 +- .../issue_73223.main.PreCodegen.32bit.diff | 207 +++++++----------- .../issue_73223.main.PreCodegen.64bit.diff | 207 +++++++----------- 13 files changed, 259 insertions(+), 342 deletions(-) diff --git a/src/test/mir-opt/const_allocation.main.ConstProp.after.32bit.mir b/src/test/mir-opt/const_allocation.main.ConstProp.after.32bit.mir index a137d7fadba10..8b09eade06704 100644 --- a/src/test/mir-opt/const_allocation.main.ConstProp.after.32bit.mir +++ b/src/test/mir-opt/const_allocation.main.ConstProp.after.32bit.mir @@ -24,42 +24,42 @@ fn main() -> () { } alloc0 (static: FOO, size: 8, align: 4) { - ╾─alloc17─╼ 03 00 00 00 │ ╾──╼.... + ╾─alloc14─╼ 03 00 00 00 │ ╾──╼.... } -alloc17 (size: 48, align: 4) { +alloc14 (size: 48, align: 4) { 0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc4──╼ 00 00 00 00 │ ....░░░░╾──╼.... - 0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc8──╼ 02 00 00 00 │ ....░░░░╾──╼.... - 0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc13─╼ 03 00 00 00 │ ....*...╾──╼.... + 0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc7──╼ 02 00 00 00 │ ....░░░░╾──╼.... + 0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc11─╼ 03 00 00 00 │ ....*...╾──╼.... } alloc4 (size: 0, align: 4) {} -alloc8 (size: 16, align: 4) { - ╾─alloc7──╼ 03 00 00 00 ╾─alloc9──╼ 03 00 00 00 │ ╾──╼....╾──╼.... +alloc7 (size: 16, align: 4) { + ╾─alloc6──╼ 03 00 00 00 ╾─alloc8──╼ 03 00 00 00 │ ╾──╼....╾──╼.... } -alloc7 (size: 3, align: 1) { +alloc6 (size: 3, align: 1) { 66 6f 6f │ foo } -alloc9 (size: 3, align: 1) { +alloc8 (size: 3, align: 1) { 62 61 72 │ bar } -alloc13 (size: 24, align: 4) { - 0x00 │ ╾─alloc12─╼ 03 00 00 00 ╾─alloc14─╼ 03 00 00 00 │ ╾──╼....╾──╼.... - 0x10 │ ╾─alloc15─╼ 04 00 00 00 │ ╾──╼.... +alloc11 (size: 24, align: 4) { + 0x00 │ ╾─alloc10─╼ 03 00 00 00 ╾─alloc12─╼ 03 00 00 00 │ ╾──╼....╾──╼.... + 0x10 │ ╾─alloc13─╼ 04 00 00 00 │ ╾──╼.... } -alloc12 (size: 3, align: 1) { +alloc10 (size: 3, align: 1) { 6d 65 68 │ meh } -alloc14 (size: 3, align: 1) { +alloc12 (size: 3, align: 1) { 6d 6f 70 │ mop } -alloc15 (size: 4, align: 1) { +alloc13 (size: 4, align: 1) { 6d c3 b6 70 │ m..p } diff --git a/src/test/mir-opt/const_allocation.main.ConstProp.after.64bit.mir b/src/test/mir-opt/const_allocation.main.ConstProp.after.64bit.mir index ef98cf9c09148..2853a0ac18b0d 100644 --- a/src/test/mir-opt/const_allocation.main.ConstProp.after.64bit.mir +++ b/src/test/mir-opt/const_allocation.main.ConstProp.after.64bit.mir @@ -24,46 +24,46 @@ fn main() -> () { } alloc0 (static: FOO, size: 16, align: 8) { - ╾───────alloc17───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ + ╾───────alloc14───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ } -alloc17 (size: 72, align: 8) { +alloc14 (size: 72, align: 8) { 0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc4────────╼ │ ....░░░░╾──────╼ 0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░ - 0x20 │ ╾───────alloc8────────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc13───────╼ │ ....*...╾──────╼ + 0x20 │ ╾───────alloc7────────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc11───────╼ │ ....*...╾──────╼ 0x40 │ 03 00 00 00 00 00 00 00 │ ........ } alloc4 (size: 0, align: 8) {} -alloc8 (size: 32, align: 8) { - 0x00 │ ╾───────alloc7────────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x10 │ ╾───────alloc9────────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ +alloc7 (size: 32, align: 8) { + 0x00 │ ╾───────alloc6────────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x10 │ ╾───────alloc8────────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ } -alloc7 (size: 3, align: 1) { +alloc6 (size: 3, align: 1) { 66 6f 6f │ foo } -alloc9 (size: 3, align: 1) { +alloc8 (size: 3, align: 1) { 62 61 72 │ bar } -alloc13 (size: 48, align: 8) { - 0x00 │ ╾───────alloc12───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x10 │ ╾───────alloc14───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x20 │ ╾───────alloc15───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ +alloc11 (size: 48, align: 8) { + 0x00 │ ╾───────alloc10───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x10 │ ╾───────alloc12───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x20 │ ╾───────alloc13───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ } -alloc12 (size: 3, align: 1) { +alloc10 (size: 3, align: 1) { 6d 65 68 │ meh } -alloc14 (size: 3, align: 1) { +alloc12 (size: 3, align: 1) { 6d 6f 70 │ mop } -alloc15 (size: 4, align: 1) { +alloc13 (size: 4, align: 1) { 6d c3 b6 70 │ m..p } diff --git a/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir b/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir index c4f10064890a7..710ffeeda075a 100644 --- a/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir +++ b/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir @@ -24,41 +24,41 @@ fn main() -> () { } alloc0 (static: FOO, size: 8, align: 4) { - ╾─alloc23─╼ 03 00 00 00 │ ╾──╼.... + ╾─alloc20─╼ 03 00 00 00 │ ╾──╼.... } -alloc23 (size: 48, align: 4) { +alloc20 (size: 48, align: 4) { 0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc8──╼ 00 00 00 00 │ ....░░░░╾──╼.... - 0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc13─╼ 02 00 00 00 │ ....░░░░╾──╼.... - 0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc21─╼ 03 00 00 00 │ ....*...╾──╼.... + 0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc12─╼ 02 00 00 00 │ ....░░░░╾──╼.... + 0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc19─╼ 03 00 00 00 │ ....*...╾──╼.... } alloc8 (size: 0, align: 4) {} -alloc13 (size: 8, align: 4) { - ╾─alloc11─╼ ╾─alloc12─╼ │ ╾──╼╾──╼ +alloc12 (size: 8, align: 4) { + ╾─alloc10─╼ ╾─alloc11─╼ │ ╾──╼╾──╼ } -alloc11 (size: 1, align: 1) { +alloc10 (size: 1, align: 1) { 05 │ . } -alloc12 (size: 1, align: 1) { +alloc11 (size: 1, align: 1) { 06 │ . } -alloc21 (size: 12, align: 4) { - ╾─a17+0x3─╼ ╾─alloc18─╼ ╾─a20+0x2─╼ │ ╾──╼╾──╼╾──╼ +alloc19 (size: 12, align: 4) { + ╾─a15+0x3─╼ ╾─alloc16─╼ ╾─a18+0x2─╼ │ ╾──╼╾──╼╾──╼ } -alloc17 (size: 4, align: 1) { +alloc15 (size: 4, align: 1) { 2a 45 15 6f │ *E.o } -alloc18 (size: 1, align: 1) { +alloc16 (size: 1, align: 1) { 2a │ * } -alloc20 (size: 4, align: 1) { +alloc18 (size: 4, align: 1) { 2a 45 15 6f │ *E.o } diff --git a/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir b/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir index b16b85c4e95ac..97a7f76f6bb5d 100644 --- a/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir +++ b/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir @@ -24,44 +24,44 @@ fn main() -> () { } alloc0 (static: FOO, size: 16, align: 8) { - ╾───────alloc23───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ + ╾───────alloc20───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ } -alloc23 (size: 72, align: 8) { +alloc20 (size: 72, align: 8) { 0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc8────────╼ │ ....░░░░╾──────╼ 0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░ - 0x20 │ ╾───────alloc13───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc21───────╼ │ ....*...╾──────╼ + 0x20 │ ╾───────alloc12───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc19───────╼ │ ....*...╾──────╼ 0x40 │ 03 00 00 00 00 00 00 00 │ ........ } alloc8 (size: 0, align: 8) {} -alloc13 (size: 16, align: 8) { - ╾───────alloc11───────╼ ╾───────alloc12───────╼ │ ╾──────╼╾──────╼ +alloc12 (size: 16, align: 8) { + ╾───────alloc10───────╼ ╾───────alloc11───────╼ │ ╾──────╼╾──────╼ } -alloc11 (size: 1, align: 1) { +alloc10 (size: 1, align: 1) { 05 │ . } -alloc12 (size: 1, align: 1) { +alloc11 (size: 1, align: 1) { 06 │ . } -alloc21 (size: 24, align: 8) { - 0x00 │ ╾─────alloc17+0x3─────╼ ╾───────alloc18───────╼ │ ╾──────╼╾──────╼ - 0x10 │ ╾─────alloc20+0x2─────╼ │ ╾──────╼ +alloc19 (size: 24, align: 8) { + 0x00 │ ╾─────alloc15+0x3─────╼ ╾───────alloc16───────╼ │ ╾──────╼╾──────╼ + 0x10 │ ╾─────alloc18+0x2─────╼ │ ╾──────╼ } -alloc17 (size: 4, align: 1) { +alloc15 (size: 4, align: 1) { 2a 45 15 6f │ *E.o } -alloc18 (size: 1, align: 1) { +alloc16 (size: 1, align: 1) { 2a │ * } -alloc20 (size: 4, align: 1) { +alloc18 (size: 4, align: 1) { 2a 45 15 6f │ *E.o } diff --git a/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir b/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir index 99d3a278d6922..19d6c51bc75f3 100644 --- a/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir +++ b/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir @@ -24,10 +24,10 @@ fn main() -> () { } alloc0 (static: FOO, size: 4, align: 4) { - ╾─alloc9──╼ │ ╾──╼ + ╾─alloc3──╼ │ ╾──╼ } -alloc9 (size: 168, align: 1) { +alloc3 (size: 168, align: 1) { 0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................ 0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾─alloc4──╼ │ ............╾──╼ 0x20 │ 01 ef cd ab 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ diff --git a/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir b/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir index d6e49892d4c6a..94388b08c0ec0 100644 --- a/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir +++ b/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir @@ -24,10 +24,10 @@ fn main() -> () { } alloc0 (static: FOO, size: 8, align: 8) { - ╾───────alloc9────────╼ │ ╾──────╼ + ╾───────alloc3────────╼ │ ╾──────╼ } -alloc9 (size: 180, align: 1) { +alloc3 (size: 180, align: 1) { 0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................ 0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾──alloc4── │ ............╾─── 0x20 │ ──────────╼ 01 ef cd ab 00 00 00 00 00 00 00 00 │ ───╼............ diff --git a/src/test/mir-opt/copy_propagation.test.CopyPropagation.diff b/src/test/mir-opt/copy_propagation.test.CopyPropagation.diff index f2838638aca0e..1f3e559c1b7f4 100644 --- a/src/test/mir-opt/copy_propagation.test.CopyPropagation.diff +++ b/src/test/mir-opt/copy_propagation.test.CopyPropagation.diff @@ -6,19 +6,14 @@ let mut _0: u32; // return place in scope 0 at $DIR/copy_propagation.rs:3:20: 3:23 let _2: u32; // in scope 0 at $DIR/copy_propagation.rs:4:9: 4:10 scope 1 { -- debug y => _2; // in scope 1 at $DIR/copy_propagation.rs:4:9: 4:10 -+ debug y => _1; // in scope 1 at $DIR/copy_propagation.rs:4:9: 4:10 + debug y => _0; // in scope 1 at $DIR/copy_propagation.rs:4:9: 4:10 } bb0: { -- StorageLive(_2); // scope 0 at $DIR/copy_propagation.rs:4:9: 4:10 -- _2 = _1; // scope 0 at $DIR/copy_propagation.rs:4:13: 4:14 -- _0 = _2; // scope 1 at $DIR/copy_propagation.rs:5:5: 5:6 -- StorageDead(_2); // scope 0 at $DIR/copy_propagation.rs:6:1: 6:2 -+ nop; // scope 0 at $DIR/copy_propagation.rs:4:9: 4:10 -+ nop; // scope 0 at $DIR/copy_propagation.rs:4:13: 4:14 -+ _0 = _1; // scope 1 at $DIR/copy_propagation.rs:5:5: 5:6 -+ nop; // scope 0 at $DIR/copy_propagation.rs:6:1: 6:2 + nop; // scope 0 at $DIR/copy_propagation.rs:4:9: 4:10 + _0 = _1; // scope 0 at $DIR/copy_propagation.rs:4:13: 4:14 + nop; // scope 1 at $DIR/copy_propagation.rs:5:5: 5:6 + nop; // scope 0 at $DIR/copy_propagation.rs:6:1: 6:2 return; // scope 0 at $DIR/copy_propagation.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/copy_propagation_arg.arg_src.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg.arg_src.CopyPropagation.diff index a4d60ae25d0c4..8aab2299d2651 100644 --- a/src/test/mir-opt/copy_propagation_arg.arg_src.CopyPropagation.diff +++ b/src/test/mir-opt/copy_propagation_arg.arg_src.CopyPropagation.diff @@ -6,15 +6,15 @@ let mut _0: i32; // return place in scope 0 at $DIR/copy_propagation_arg.rs:27:27: 27:30 let _2: i32; // in scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10 scope 1 { - debug y => _2; // in scope 1 at $DIR/copy_propagation_arg.rs:28:9: 28:10 + debug y => _0; // in scope 1 at $DIR/copy_propagation_arg.rs:28:9: 28:10 } bb0: { - StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10 - _2 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:28:13: 28:14 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10 + _0 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:28:13: 28:14 _1 = const 123_i32; // scope 1 at $DIR/copy_propagation_arg.rs:29:5: 29:12 - _0 = _2; // scope 1 at $DIR/copy_propagation_arg.rs:30:5: 30:6 - StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:31:1: 31:2 + nop; // scope 1 at $DIR/copy_propagation_arg.rs:30:5: 30:6 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:31:1: 31:2 return; // scope 0 at $DIR/copy_propagation_arg.rs:31:2: 31:2 } } diff --git a/src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff index b20003bd7c67e..1ea51fec71069 100644 --- a/src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff +++ b/src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff @@ -7,10 +7,10 @@ let mut _2: i32; // in scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 bb0: { - StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 - _2 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 - _1 = move _2; // scope 0 at $DIR/copy_propagation_arg.rs:23:5: 23:10 - StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:23:5: 23:10 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 _0 = const (); // scope 0 at $DIR/copy_propagation_arg.rs:21:20: 24:2 return; // scope 0 at $DIR/copy_propagation_arg.rs:24:2: 24:2 } diff --git a/src/test/mir-opt/copy_propagation_arg.foo.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg.foo.CopyPropagation.diff index d07a4c0541e1b..48ab37a239c62 100644 --- a/src/test/mir-opt/copy_propagation_arg.foo.CopyPropagation.diff +++ b/src/test/mir-opt/copy_propagation_arg.foo.CopyPropagation.diff @@ -8,10 +8,10 @@ let mut _3: u8; // in scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16 bb0: { - StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17 StorageLive(_3); // scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16 _3 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16 - _2 = dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17 + _1 = dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17 // mir::Constant // + span: $DIR/copy_propagation_arg.rs:11:9: 11:14 // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(Scalar()) } @@ -19,8 +19,8 @@ bb1: { StorageDead(_3); // scope 0 at $DIR/copy_propagation_arg.rs:11:16: 11:17 - _1 = move _2; // scope 0 at $DIR/copy_propagation_arg.rs:11:5: 11:17 - StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:11:16: 11:17 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:11:5: 11:17 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:11:16: 11:17 _0 = const (); // scope 0 at $DIR/copy_propagation_arg.rs:9:19: 12:2 return; // scope 0 at $DIR/copy_propagation_arg.rs:12:2: 12:2 } diff --git a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir index 0258e3c2e4b38..ab194cf532ff3 100644 --- a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir @@ -10,15 +10,14 @@ fn foo(_1: T, _2: i32) -> (i32, T) { let mut _6: &[closure@foo::{{closure}}#0 q:&i32, t:&T]; // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:6 let mut _7: (i32,); // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:9 let mut _8: i32; // in scope 0 at $DIR/inline-closure-captures.rs:12:7: 12:8 - let mut _11: i32; // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:9 + let mut _10: i32; // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:9 scope 1 { debug x => _3; // in scope 1 at $DIR/inline-closure-captures.rs:11:9: 11:10 scope 2 { - debug _q => _11; // in scope 2 at $DIR/inline-closure-captures.rs:11:14: 11:16 + debug _q => _10; // in scope 2 at $DIR/inline-closure-captures.rs:11:14: 11:16 debug q => (*((*_6).0: &i32)); // in scope 2 at $DIR/inline-closure-captures.rs:10:23: 10:24 debug t => (*((*_6).1: &T)); // in scope 2 at $DIR/inline-closure-captures.rs:10:17: 10:18 - let mut _9: i32; // in scope 2 at $DIR/inline-closure-captures.rs:12:5: 12:9 - let mut _10: T; // in scope 2 at $DIR/inline-closure-captures.rs:12:5: 12:9 + let mut _9: T; // in scope 2 at $DIR/inline-closure-captures.rs:12:5: 12:9 } } @@ -38,17 +37,14 @@ fn foo(_1: T, _2: i32) -> (i32, T) { StorageLive(_8); // scope 1 at $DIR/inline-closure-captures.rs:12:7: 12:8 _8 = _2; // scope 1 at $DIR/inline-closure-captures.rs:12:7: 12:8 (_7.0: i32) = move _8; // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 - StorageLive(_11); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 - _11 = move (_7.0: i32); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 - StorageLive(_9); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 - _9 = (*((*_6).0: &i32)); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 - StorageLive(_10); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 - _10 = (*((*_6).1: &T)); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 - (_0.0: i32) = move _9; // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24 - (_0.1: T) = move _10; // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24 - StorageDead(_10); // scope 2 at $DIR/inline-closure-captures.rs:11:23: 11:24 + StorageLive(_10); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 + _10 = move (_7.0: i32); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 + (_0.0: i32) = (*((*_6).0: &i32)); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 + StorageLive(_9); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 + _9 = (*((*_6).1: &T)); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 + (_0.1: T) = move _9; // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24 StorageDead(_9); // scope 2 at $DIR/inline-closure-captures.rs:11:23: 11:24 - StorageDead(_11); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 + StorageDead(_10); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 StorageDead(_8); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9 StorageDead(_7); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9 StorageDead(_6); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9 diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff index f86755cfa7f70..a8662b96566cc 100644 --- a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff +++ b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff @@ -3,66 +3,59 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:1:11: 1:11 - let mut _1: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - let _2: i32; // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15 - let mut _4: i32; // in scope 0 at $DIR/issue-73223.rs:7:22: 7:27 - let mut _5: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _6: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - 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 _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]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _15: &[std::fmt::ArgumentV1]; // 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 _17: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _18: (&&i32, &&i32); // in scope 0 at $SRC_DIR/std/src/macros.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: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _24: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _25: 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 _26: std::fmt::ArgumentV1; // in scope 0 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 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let _1: i32; // in scope 0 at $DIR/issue-73223.rs:2:9: 2:14 + let mut _2: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + let mut _4: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _5: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _6: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _7: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _8: &std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let _9: std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _10: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let _11: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _12: (&&i32, &&i32); // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let _13: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _14: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let _15: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _16: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _17: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL scope 1 { - debug split => _2; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14 + debug split => _1; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14 let _3: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14 scope 3 { debug _prev => _3; // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14 - let _7: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _8: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 4 { - 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 - let _22: &&i32; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _23: &&i32; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + debug left_val => _13; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + debug right_val => _15; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 5 { - debug arg0 => _22; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + debug arg0 => _20; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL debug arg1 => _23; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 6 { - debug x => _22; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - debug f => _25; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _28: 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 _29: &core::fmt::Opaque; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL + debug x => _20; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug f => _19; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + let mut _18: 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 _19: 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 _20: &&i32; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL } scope 8 { debug x => _23; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - debug f => _27; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _30: 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 _31: &core::fmt::Opaque; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL + debug f => _22; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + let mut _21: 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 _22: 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 _23: &&i32; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL } } scope 10 { - debug pieces => _14; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - debug args => _15; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _32: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL + debug pieces => (_9.0: &[&str]); // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug args => _25; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + let mut _24: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _25: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL } } } } scope 2 { - debug v => _2; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15 + debug v => _1; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15 } scope 7 { } @@ -70,138 +63,108 @@ } bb0: { - StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - ((_1 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - discriminant(_1) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - _2 = ((_1 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 - StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 - StorageLive(_3); // scope 1 at $DIR/issue-73223.rs:7:9: 7:14 - StorageLive(_4); // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 - _4 = _2; // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 - ((_3 as Some).0: i32) = move _4; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 + StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + _1 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 + ((_3 as Some).0: i32) = _1; // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 discriminant(_3) = 1; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 - StorageDead(_4); // scope 1 at $DIR/issue-73223.rs:7:27: 7:28 - StorageLive(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_6); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _6 = &_2; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_5.0: &i32) = move _6; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_5.1: &i32) = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_4.0: &i32) = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_4.1: &i32) = 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[0]), 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[0]), const_param_did: None }, [], Some(promoted[1])) } - StorageDead(_6); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _7 = (_5.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _8 = (_5.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _11 = (*_7); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _10 = Eq(move _11, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _9 = Not(move _10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - switchInt(_9) -> [false: bb1, otherwise: bb2]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _13 = (_4.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _15 = (_4.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_5); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_6); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_7); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _7 = (*_13); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _6 = Eq(move _7, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_7); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _5 = Not(move _6); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_6); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + switchInt(_5) -> [false: bb1, otherwise: bb2]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL } bb1: { - StorageDead(_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_5); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _0 = const (); // scope 0 at $DIR/issue-73223.rs:1:11: 9:2 - StorageDead(_3); // scope 1 at $DIR/issue-73223.rs:9:1: 9:2 return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 } bb2: { - StorageLive(_13); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _14 = const main::promoted[0] as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_9.0: &[&str]) = const main::promoted[0] as &[&str] (Pointer(Unsize)); // 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[0]), 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[0]), const_param_did: None }, [], Some(promoted[0])) } - StorageLive(_17); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageLive(_18); // 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 - _20 = _7; // 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 - StorageLive(_21); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _21 = &_8; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_18.0: &&i32) = move _19; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - (_18.1: &&i32) = move _21; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageDead(_21); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageDead(_19); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _22 = (_18.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _23 = (_18.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_24); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - _25 = <&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 + StorageLive(_11); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + (_12.0: &&i32) = &_13; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_14); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _14 = &_15; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_12.1: &&i32) = move _14; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + StorageDead(_14); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + _20 = (_12.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _23 = (_12.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _19 = <&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()) } - StorageLive(_28); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _28 = transmute:: 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 _25) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageLive(_18); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _18 = transmute:: 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 _19) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/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:: 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()) } } bb3: { - StorageLive(_29); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _29 = transmute::<&&i32, &core::fmt::Opaque>(move _22) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_16.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _20) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/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()) } } bb4: { - (_24.0: &core::fmt::Opaque) = move _29; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_24.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _28; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_29); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_28); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageLive(_26); // scope 5 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 + (_16.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _18; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_18); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _22 = <&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()) } - StorageLive(_30); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _30 = transmute:: 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/core/src/fmt/mod.rs:LL:COL + StorageLive(_21); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _21 = transmute:: 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 _22) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/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:: 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()) } } bb5: { - StorageLive(_31); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _31 = transmute::<&&i32, &core::fmt::Opaque>(move _23) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_17.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _23) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/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()) } } bb6: { - (_26.0: &core::fmt::Opaque) = move _31; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_26.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _30; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_31); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_30); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _17 = [move _24, move _26]; // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageDead(_26); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageDead(_24); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - _16 = &_17; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _15 = move _16 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageLive(_32); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - discriminant(_32) = 0; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_13.0: &[&str]) = move _14; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_13.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _32; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_13.2: &[std::fmt::ArgumentV1]) = move _15; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_32); // scope 10 at $SRC_DIR/core/src/fmt/mod.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 + (_17.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _21; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_21); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _11 = [move _16, move _17]; // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL + _10 = &_11; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + _25 = move _10 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + StorageLive(_24); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + discriminant(_24) = 0; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_9.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _24; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_9.2: &[std::fmt::ArgumentV1]) = move _25; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_24); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _8 = &_9; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + begin_panic_fmt(move _8); // scope 4 at $SRC_DIR/std/src/macros.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()) } diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff index f86755cfa7f70..a8662b96566cc 100644 --- a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff +++ b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff @@ -3,66 +3,59 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:1:11: 1:11 - let mut _1: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - let _2: i32; // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15 - let mut _4: i32; // in scope 0 at $DIR/issue-73223.rs:7:22: 7:27 - let mut _5: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _6: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - 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 _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]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _15: &[std::fmt::ArgumentV1]; // 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 _17: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _18: (&&i32, &&i32); // in scope 0 at $SRC_DIR/std/src/macros.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: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _24: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _25: 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 _26: std::fmt::ArgumentV1; // in scope 0 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 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let _1: i32; // in scope 0 at $DIR/issue-73223.rs:2:9: 2:14 + let mut _2: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + let mut _4: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _5: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _6: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _7: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _8: &std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let _9: std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _10: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let _11: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _12: (&&i32, &&i32); // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let _13: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _14: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let _15: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _16: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _17: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL scope 1 { - debug split => _2; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14 + debug split => _1; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14 let _3: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14 scope 3 { debug _prev => _3; // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14 - let _7: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _8: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 4 { - 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 - let _22: &&i32; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _23: &&i32; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + debug left_val => _13; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + debug right_val => _15; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 5 { - debug arg0 => _22; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + debug arg0 => _20; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL debug arg1 => _23; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 6 { - debug x => _22; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - debug f => _25; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _28: 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 _29: &core::fmt::Opaque; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL + debug x => _20; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug f => _19; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + let mut _18: 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 _19: 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 _20: &&i32; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL } scope 8 { debug x => _23; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - debug f => _27; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _30: 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 _31: &core::fmt::Opaque; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL + debug f => _22; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + let mut _21: 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 _22: 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 _23: &&i32; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL } } scope 10 { - debug pieces => _14; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - debug args => _15; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _32: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL + debug pieces => (_9.0: &[&str]); // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug args => _25; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + let mut _24: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _25: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL } } } } scope 2 { - debug v => _2; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15 + debug v => _1; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15 } scope 7 { } @@ -70,138 +63,108 @@ } bb0: { - StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - ((_1 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - discriminant(_1) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - _2 = ((_1 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 - StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 - StorageLive(_3); // scope 1 at $DIR/issue-73223.rs:7:9: 7:14 - StorageLive(_4); // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 - _4 = _2; // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 - ((_3 as Some).0: i32) = move _4; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 + StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + _1 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 + ((_3 as Some).0: i32) = _1; // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 discriminant(_3) = 1; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 - StorageDead(_4); // scope 1 at $DIR/issue-73223.rs:7:27: 7:28 - StorageLive(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_6); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _6 = &_2; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_5.0: &i32) = move _6; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_5.1: &i32) = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_4.0: &i32) = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_4.1: &i32) = 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[0]), 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[0]), const_param_did: None }, [], Some(promoted[1])) } - StorageDead(_6); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _7 = (_5.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _8 = (_5.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _11 = (*_7); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _10 = Eq(move _11, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _9 = Not(move _10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - switchInt(_9) -> [false: bb1, otherwise: bb2]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _13 = (_4.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _15 = (_4.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_5); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_6); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_7); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _7 = (*_13); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _6 = Eq(move _7, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_7); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _5 = Not(move _6); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_6); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + switchInt(_5) -> [false: bb1, otherwise: bb2]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL } bb1: { - StorageDead(_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_5); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _0 = const (); // scope 0 at $DIR/issue-73223.rs:1:11: 9:2 - StorageDead(_3); // scope 1 at $DIR/issue-73223.rs:9:1: 9:2 return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 } bb2: { - StorageLive(_13); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _14 = const main::promoted[0] as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_9.0: &[&str]) = const main::promoted[0] as &[&str] (Pointer(Unsize)); // 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[0]), 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[0]), const_param_did: None }, [], Some(promoted[0])) } - StorageLive(_17); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageLive(_18); // 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 - _20 = _7; // 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 - StorageLive(_21); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _21 = &_8; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_18.0: &&i32) = move _19; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - (_18.1: &&i32) = move _21; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageDead(_21); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageDead(_19); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _22 = (_18.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _23 = (_18.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_24); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - _25 = <&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 + StorageLive(_11); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + (_12.0: &&i32) = &_13; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_14); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _14 = &_15; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_12.1: &&i32) = move _14; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + StorageDead(_14); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + _20 = (_12.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _23 = (_12.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _19 = <&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()) } - StorageLive(_28); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _28 = transmute:: 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 _25) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageLive(_18); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _18 = transmute:: 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 _19) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/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:: 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()) } } bb3: { - StorageLive(_29); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _29 = transmute::<&&i32, &core::fmt::Opaque>(move _22) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_16.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _20) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/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()) } } bb4: { - (_24.0: &core::fmt::Opaque) = move _29; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_24.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _28; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_29); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_28); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageLive(_26); // scope 5 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 + (_16.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _18; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_18); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _22 = <&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()) } - StorageLive(_30); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _30 = transmute:: 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/core/src/fmt/mod.rs:LL:COL + StorageLive(_21); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _21 = transmute:: 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 _22) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/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:: 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()) } } bb5: { - StorageLive(_31); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _31 = transmute::<&&i32, &core::fmt::Opaque>(move _23) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_17.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _23) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/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()) } } bb6: { - (_26.0: &core::fmt::Opaque) = move _31; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_26.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _30; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_31); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_30); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _17 = [move _24, move _26]; // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageDead(_26); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageDead(_24); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - _16 = &_17; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _15 = move _16 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageLive(_32); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - discriminant(_32) = 0; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_13.0: &[&str]) = move _14; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_13.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _32; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_13.2: &[std::fmt::ArgumentV1]) = move _15; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_32); // scope 10 at $SRC_DIR/core/src/fmt/mod.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 + (_17.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _21; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_21); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _11 = [move _16, move _17]; // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL + _10 = &_11; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + _25 = move _10 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + StorageLive(_24); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + discriminant(_24) = 0; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_9.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _24; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_9.2: &[std::fmt::ArgumentV1]) = move _25; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_24); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _8 = &_9; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + begin_panic_fmt(move _8); // scope 4 at $SRC_DIR/std/src/macros.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()) } From 812d4bbc8d1a240ecc900ffafacb5ce34f69e9f3 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 12 Sep 2020 14:58:52 +0200 Subject: [PATCH 0619/1052] Fix dataflow assert errors --- compiler/rustc_mir/src/transform/dest_prop.rs | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs index 19054f36171d9..3c46e8fc36b8d 100644 --- a/compiler/rustc_mir/src/transform/dest_prop.rs +++ b/compiler/rustc_mir/src/transform/dest_prop.rs @@ -403,6 +403,7 @@ impl Conflicts { .iterate_to_fixpoint() .into_results_cursor(body); + let mut reachable = None; dump_mir( tcx, None, @@ -411,15 +412,18 @@ impl Conflicts { source, body, |pass_where, w| { + let reachable = + reachable.get_or_insert_with(|| traversal::reachable_as_bitset(body)); + match pass_where { - PassWhere::BeforeLocation(loc) => { + PassWhere::BeforeLocation(loc) if reachable.contains(loc.block) => { init.seek_before_primary_effect(loc); live.seek_after_primary_effect(loc); writeln!(w, " // init: {:?}", init.get())?; writeln!(w, " // live: {:?}", live.get())?; } - PassWhere::AfterTerminator(bb) => { + PassWhere::AfterTerminator(bb) if reachable.contains(bb) => { let loc = body.terminator_loc(bb); init.seek_after_primary_effect(loc); live.seek_before_primary_effect(loc); @@ -428,7 +432,7 @@ impl Conflicts { writeln!(w, " // live: {:?}", live.get())?; } - PassWhere::BeforeBlock(bb) => { + PassWhere::BeforeBlock(bb) if reachable.contains(bb) => { init.seek_to_block_start(bb); live.seek_to_block_start(bb); @@ -437,6 +441,16 @@ impl Conflicts { } PassWhere::BeforeCFG | PassWhere::AfterCFG | PassWhere::AfterLocation(_) => {} + + PassWhere::BeforeLocation(_) | PassWhere::AfterTerminator(_) => { + writeln!(w, " // init: ")?; + writeln!(w, " // live: ")?; + } + + PassWhere::BeforeBlock(_) => { + writeln!(w, " // init: ")?; + writeln!(w, " // live: ")?; + } } Ok(()) From 7dbc7f76e1a0f1d054655f6fa5786b700745b66e Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 24 May 2020 21:37:09 +0200 Subject: [PATCH 0620/1052] Add a few dest-prop MIR tests --- src/test/mir-opt/dest-prop/branch.rs | 21 +++++ .../rustc.main.DestinationPropagation.diff | 88 ++++++++++++++++++ src/test/mir-opt/dest-prop/cycle.rs | 15 +++ .../rustc.main.DestinationPropagation.diff | 91 +++++++++++++++++++ src/test/mir-opt/dest-prop/simple.rs | 14 +++ .../rustc.nrvo.DestinationPropagation.diff | 56 ++++++++++++ src/test/mir-opt/dest-prop/union.rs | 16 ++++ .../rustc.main.DestinationPropagation.diff | 61 +++++++++++++ 8 files changed, 362 insertions(+) create mode 100644 src/test/mir-opt/dest-prop/branch.rs create mode 100644 src/test/mir-opt/dest-prop/branch/rustc.main.DestinationPropagation.diff create mode 100644 src/test/mir-opt/dest-prop/cycle.rs create mode 100644 src/test/mir-opt/dest-prop/cycle/rustc.main.DestinationPropagation.diff create mode 100644 src/test/mir-opt/dest-prop/simple.rs create mode 100644 src/test/mir-opt/dest-prop/simple/rustc.nrvo.DestinationPropagation.diff create mode 100644 src/test/mir-opt/dest-prop/union.rs create mode 100644 src/test/mir-opt/dest-prop/union/rustc.main.DestinationPropagation.diff diff --git a/src/test/mir-opt/dest-prop/branch.rs b/src/test/mir-opt/dest-prop/branch.rs new file mode 100644 index 0000000000000..b49ecf07daa39 --- /dev/null +++ b/src/test/mir-opt/dest-prop/branch.rs @@ -0,0 +1,21 @@ +//! Tests that assignment in both branches of an `if` are eliminated. + +fn val() -> i32 { + 1 +} + +fn cond() -> bool { + true +} + +// EMIT_MIR rustc.main.DestinationPropagation.diff +fn main() { + let x = val(); + + let y = if cond() { + x + } else { + val(); + x + }; +} diff --git a/src/test/mir-opt/dest-prop/branch/rustc.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/branch/rustc.main.DestinationPropagation.diff new file mode 100644 index 0000000000000..b8387ae449387 --- /dev/null +++ b/src/test/mir-opt/dest-prop/branch/rustc.main.DestinationPropagation.diff @@ -0,0 +1,88 @@ +- // MIR for `main` before DestinationPropagation ++ // MIR for `main` after DestinationPropagation + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/branch.rs:12:11: 12:11 + let _1: i32; // in scope 0 at $DIR/branch.rs:13:9: 13:10 + let mut _3: bool; // in scope 0 at $DIR/branch.rs:15:16: 15:22 + let _4: i32; // in scope 0 at $DIR/branch.rs:18:9: 18:14 + scope 1 { +- debug x => _1; // in scope 1 at $DIR/branch.rs:13:9: 13:10 ++ debug x => _2; // in scope 1 at $DIR/branch.rs:13:9: 13:10 + let _2: i32; // in scope 1 at $DIR/branch.rs:15:9: 15:10 + scope 2 { + debug y => _2; // in scope 2 at $DIR/branch.rs:15:9: 15:10 + } + } + + bb0: { +- StorageLive(_1); // scope 0 at $DIR/branch.rs:13:9: 13:10 +- _1 = const val() -> bb1; // scope 0 at $DIR/branch.rs:13:13: 13:18 ++ nop; // scope 0 at $DIR/branch.rs:13:9: 13:10 ++ _2 = const val() -> bb1; // scope 0 at $DIR/branch.rs:13:13: 13:18 + // ty::Const + // + ty: fn() -> i32 {val} + // + val: Value(Scalar()) + // mir::Constant + // + span: $DIR/branch.rs:13:13: 13:16 + // + literal: Const { ty: fn() -> i32 {val}, val: Value(Scalar()) } + } + + bb1: { +- StorageLive(_2); // scope 1 at $DIR/branch.rs:15:9: 15:10 ++ nop; // scope 1 at $DIR/branch.rs:15:9: 15:10 + StorageLive(_3); // scope 1 at $DIR/branch.rs:15:16: 15:22 + _3 = const cond() -> bb2; // scope 1 at $DIR/branch.rs:15:16: 15:22 + // ty::Const + // + ty: fn() -> bool {cond} + // + val: Value(Scalar()) + // mir::Constant + // + span: $DIR/branch.rs:15:16: 15:20 + // + literal: Const { ty: fn() -> bool {cond}, val: Value(Scalar()) } + } + + bb2: { + switchInt(_3) -> [false: bb3, otherwise: bb4]; // scope 1 at $DIR/branch.rs:15:13: 20:6 + } + + bb3: { + StorageLive(_4); // scope 1 at $DIR/branch.rs:18:9: 18:14 + _4 = const val() -> bb5; // scope 1 at $DIR/branch.rs:18:9: 18:14 + // ty::Const + // + ty: fn() -> i32 {val} + // + val: Value(Scalar()) + // mir::Constant + // + span: $DIR/branch.rs:18:9: 18:12 + // + literal: Const { ty: fn() -> i32 {val}, val: Value(Scalar()) } + } + + bb4: { +- _2 = _1; // scope 1 at $DIR/branch.rs:16:9: 16:10 ++ nop; // scope 1 at $DIR/branch.rs:16:9: 16:10 + goto -> bb6; // scope 1 at $DIR/branch.rs:15:13: 20:6 + } + + bb5: { + StorageDead(_4); // scope 1 at $DIR/branch.rs:18:14: 18:15 +- _2 = _1; // scope 1 at $DIR/branch.rs:19:9: 19:10 ++ nop; // scope 1 at $DIR/branch.rs:19:9: 19:10 + goto -> bb6; // scope 1 at $DIR/branch.rs:15:13: 20:6 + } + + bb6: { + StorageDead(_3); // scope 1 at $DIR/branch.rs:20:6: 20:7 + _0 = const (); // scope 0 at $DIR/branch.rs:12:11: 21:2 + // ty::Const + // + ty: () + // + val: Value(Scalar()) + // mir::Constant + // + span: $DIR/branch.rs:12:11: 21:2 + // + literal: Const { ty: (), val: Value(Scalar()) } +- StorageDead(_2); // scope 1 at $DIR/branch.rs:21:1: 21:2 +- StorageDead(_1); // scope 0 at $DIR/branch.rs:21:1: 21:2 ++ nop; // scope 1 at $DIR/branch.rs:21:1: 21:2 ++ nop; // scope 0 at $DIR/branch.rs:21:1: 21:2 + return; // scope 0 at $DIR/branch.rs:21:2: 21:2 + } + } + diff --git a/src/test/mir-opt/dest-prop/cycle.rs b/src/test/mir-opt/dest-prop/cycle.rs new file mode 100644 index 0000000000000..d55d527bc65f6 --- /dev/null +++ b/src/test/mir-opt/dest-prop/cycle.rs @@ -0,0 +1,15 @@ +//! Tests that cyclic assignments don't hang DestinationPropagation, and result in reasonable code. + +fn val() -> i32 { + 1 +} + +// EMIT_MIR rustc.main.DestinationPropagation.diff +fn main() { + let mut x = val(); + let y = x; + let z = y; + x = z; + + drop(x); +} diff --git a/src/test/mir-opt/dest-prop/cycle/rustc.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/cycle/rustc.main.DestinationPropagation.diff new file mode 100644 index 0000000000000..5189b665acff1 --- /dev/null +++ b/src/test/mir-opt/dest-prop/cycle/rustc.main.DestinationPropagation.diff @@ -0,0 +1,91 @@ +- // MIR for `main` before DestinationPropagation ++ // MIR for `main` after DestinationPropagation + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/cycle.rs:8:11: 8:11 + let mut _1: i32; // in scope 0 at $DIR/cycle.rs:9:9: 9:14 + let mut _4: i32; // in scope 0 at $DIR/cycle.rs:12:9: 12:10 + let _5: (); // in scope 0 at $DIR/cycle.rs:14:5: 14:12 + let mut _6: i32; // in scope 0 at $DIR/cycle.rs:14:10: 14:11 + scope 1 { +- debug x => _1; // in scope 1 at $DIR/cycle.rs:9:9: 9:14 ++ debug x => _4; // in scope 1 at $DIR/cycle.rs:9:9: 9:14 + let _2: i32; // in scope 1 at $DIR/cycle.rs:10:9: 10:10 + scope 2 { +- debug y => _2; // in scope 2 at $DIR/cycle.rs:10:9: 10:10 ++ debug y => _4; // in scope 2 at $DIR/cycle.rs:10:9: 10:10 + let _3: i32; // in scope 2 at $DIR/cycle.rs:11:9: 11:10 + scope 3 { +- debug z => _3; // in scope 3 at $DIR/cycle.rs:11:9: 11:10 ++ debug z => _4; // in scope 3 at $DIR/cycle.rs:11:9: 11:10 + scope 4 { + debug _x => _6; // in scope 4 at $SRC_DIR/libcore/mem/mod.rs:LL:COL + } + } + } + } + + bb0: { +- StorageLive(_1); // scope 0 at $DIR/cycle.rs:9:9: 9:14 +- _1 = const val() -> bb1; // scope 0 at $DIR/cycle.rs:9:17: 9:22 ++ nop; // scope 0 at $DIR/cycle.rs:9:9: 9:14 ++ _4 = const val() -> bb1; // scope 0 at $DIR/cycle.rs:9:17: 9:22 + // ty::Const + // + ty: fn() -> i32 {val} + // + val: Value(Scalar()) + // mir::Constant + // + span: $DIR/cycle.rs:9:17: 9:20 + // + literal: Const { ty: fn() -> i32 {val}, val: Value(Scalar()) } + } + + bb1: { +- StorageLive(_2); // scope 1 at $DIR/cycle.rs:10:9: 10:10 +- _2 = _1; // scope 1 at $DIR/cycle.rs:10:13: 10:14 +- StorageLive(_3); // scope 2 at $DIR/cycle.rs:11:9: 11:10 +- _3 = _2; // scope 2 at $DIR/cycle.rs:11:13: 11:14 +- StorageLive(_4); // scope 3 at $DIR/cycle.rs:12:9: 12:10 +- _4 = _3; // scope 3 at $DIR/cycle.rs:12:9: 12:10 +- _1 = move _4; // scope 3 at $DIR/cycle.rs:12:5: 12:10 +- StorageDead(_4); // scope 3 at $DIR/cycle.rs:12:9: 12:10 ++ nop; // scope 1 at $DIR/cycle.rs:10:9: 10:10 ++ nop; // scope 1 at $DIR/cycle.rs:10:13: 10:14 ++ nop; // scope 2 at $DIR/cycle.rs:11:9: 11:10 ++ nop; // scope 2 at $DIR/cycle.rs:11:13: 11:14 ++ nop; // scope 3 at $DIR/cycle.rs:12:9: 12:10 ++ nop; // scope 3 at $DIR/cycle.rs:12:9: 12:10 ++ nop; // scope 3 at $DIR/cycle.rs:12:5: 12:10 ++ nop; // scope 3 at $DIR/cycle.rs:12:9: 12:10 + StorageLive(_5); // scope 3 at $DIR/cycle.rs:14:5: 14:12 + StorageLive(_6); // scope 3 at $DIR/cycle.rs:14:10: 14:11 +- _6 = _1; // scope 3 at $DIR/cycle.rs:14:10: 14:11 ++ _6 = _4; // scope 3 at $DIR/cycle.rs:14:10: 14:11 + _5 = const (); // scope 4 at $SRC_DIR/libcore/mem/mod.rs:LL:COL + // ty::Const + // + ty: () + // + val: Value(Scalar()) + // mir::Constant + // + span: $SRC_DIR/libcore/mem/mod.rs:LL:COL + // + literal: Const { ty: (), val: Value(Scalar()) } + drop(_6) -> bb2; // scope 4 at $SRC_DIR/libcore/mem/mod.rs:LL:COL + } + + bb2: { + StorageDead(_6); // scope 3 at $DIR/cycle.rs:14:11: 14:12 + StorageDead(_5); // scope 3 at $DIR/cycle.rs:14:12: 14:13 + _0 = const (); // scope 0 at $DIR/cycle.rs:8:11: 15:2 + // ty::Const + // + ty: () + // + val: Value(Scalar()) + // mir::Constant + // + span: $DIR/cycle.rs:8:11: 15:2 + // + literal: Const { ty: (), val: Value(Scalar()) } +- StorageDead(_3); // scope 2 at $DIR/cycle.rs:15:1: 15:2 +- StorageDead(_2); // scope 1 at $DIR/cycle.rs:15:1: 15:2 +- StorageDead(_1); // scope 0 at $DIR/cycle.rs:15:1: 15:2 ++ nop; // scope 2 at $DIR/cycle.rs:15:1: 15:2 ++ nop; // scope 1 at $DIR/cycle.rs:15:1: 15:2 ++ nop; // scope 0 at $DIR/cycle.rs:15:1: 15:2 + return; // scope 0 at $DIR/cycle.rs:15:2: 15:2 + } + } + diff --git a/src/test/mir-opt/dest-prop/simple.rs b/src/test/mir-opt/dest-prop/simple.rs new file mode 100644 index 0000000000000..add821eafe0b0 --- /dev/null +++ b/src/test/mir-opt/dest-prop/simple.rs @@ -0,0 +1,14 @@ +//! Copy of `nrvo-simple.rs`, to ensure that full dest-prop handles it too. + +// EMIT_MIR rustc.nrvo.DestinationPropagation.diff +fn nrvo(init: fn(&mut [u8; 1024])) -> [u8; 1024] { + let mut buf = [0; 1024]; + init(&mut buf); + buf +} + +fn main() { + let _ = nrvo(|buf| { + buf[4] = 4; + }); +} diff --git a/src/test/mir-opt/dest-prop/simple/rustc.nrvo.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/simple/rustc.nrvo.DestinationPropagation.diff new file mode 100644 index 0000000000000..d59e1f3c0c938 --- /dev/null +++ b/src/test/mir-opt/dest-prop/simple/rustc.nrvo.DestinationPropagation.diff @@ -0,0 +1,56 @@ +- // MIR for `nrvo` before DestinationPropagation ++ // MIR for `nrvo` after DestinationPropagation + + fn nrvo(_1: for<'r> fn(&'r mut [u8; 1024])) -> [u8; 1024] { + debug init => _1; // in scope 0 at $DIR/simple.rs:4:9: 4:13 + let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/simple.rs:4:39: 4:49 + let mut _2: [u8; 1024]; // in scope 0 at $DIR/simple.rs:5:9: 5:16 + let _3: (); // in scope 0 at $DIR/simple.rs:6:5: 6:19 + let mut _4: for<'r> fn(&'r mut [u8; 1024]); // in scope 0 at $DIR/simple.rs:6:5: 6:9 + let mut _5: &mut [u8; 1024]; // in scope 0 at $DIR/simple.rs:6:10: 6:18 + let mut _6: &mut [u8; 1024]; // in scope 0 at $DIR/simple.rs:6:10: 6:18 + scope 1 { +- debug buf => _2; // in scope 1 at $DIR/simple.rs:5:9: 5:16 ++ debug buf => _0; // in scope 1 at $DIR/simple.rs:5:9: 5:16 + } + + bb0: { +- StorageLive(_2); // scope 0 at $DIR/simple.rs:5:9: 5:16 +- _2 = [const 0u8; 1024]; // scope 0 at $DIR/simple.rs:5:19: 5:28 ++ nop; // scope 0 at $DIR/simple.rs:5:9: 5:16 ++ _0 = [const 0u8; 1024]; // scope 0 at $DIR/simple.rs:5:19: 5:28 + // ty::Const + // + ty: u8 + // + val: Value(Scalar(0x00)) + // mir::Constant + // + span: $DIR/simple.rs:5:20: 5:21 + // + literal: Const { ty: u8, val: Value(Scalar(0x00)) } + StorageLive(_3); // scope 1 at $DIR/simple.rs:6:5: 6:19 + StorageLive(_4); // scope 1 at $DIR/simple.rs:6:5: 6:9 + _4 = _1; // scope 1 at $DIR/simple.rs:6:5: 6:9 +- StorageLive(_5); // scope 1 at $DIR/simple.rs:6:10: 6:18 +- StorageLive(_6); // scope 1 at $DIR/simple.rs:6:10: 6:18 +- _6 = &mut _2; // scope 1 at $DIR/simple.rs:6:10: 6:18 +- _5 = move _6; // scope 1 at $DIR/simple.rs:6:10: 6:18 ++ nop; // scope 1 at $DIR/simple.rs:6:10: 6:18 ++ nop; // scope 1 at $DIR/simple.rs:6:10: 6:18 ++ _5 = &mut _0; // scope 1 at $DIR/simple.rs:6:10: 6:18 ++ nop; // scope 1 at $DIR/simple.rs:6:10: 6:18 + _3 = move _4(move _5) -> bb1; // scope 1 at $DIR/simple.rs:6:5: 6:19 + } + + bb1: { +- StorageDead(_5); // scope 1 at $DIR/simple.rs:6:18: 6:19 ++ nop; // scope 1 at $DIR/simple.rs:6:18: 6:19 + StorageDead(_4); // scope 1 at $DIR/simple.rs:6:18: 6:19 +- StorageDead(_6); // scope 1 at $DIR/simple.rs:6:19: 6:20 ++ nop; // scope 1 at $DIR/simple.rs:6:19: 6:20 + StorageDead(_3); // scope 1 at $DIR/simple.rs:6:19: 6:20 +- _0 = _2; // scope 1 at $DIR/simple.rs:7:5: 7:8 +- StorageDead(_2); // scope 0 at $DIR/simple.rs:8:1: 8:2 ++ nop; // scope 1 at $DIR/simple.rs:7:5: 7:8 ++ nop; // scope 0 at $DIR/simple.rs:8:1: 8:2 + return; // scope 0 at $DIR/simple.rs:8:2: 8:2 + } + } + diff --git a/src/test/mir-opt/dest-prop/union.rs b/src/test/mir-opt/dest-prop/union.rs new file mode 100644 index 0000000000000..ea8364124043e --- /dev/null +++ b/src/test/mir-opt/dest-prop/union.rs @@ -0,0 +1,16 @@ +//! Tests that projections through unions cancel `DestinationPropagation`. + +fn val() -> u32 { + 1 +} + +// EMIT_MIR rustc.main.DestinationPropagation.diff +fn main() { + union Un { + us: u32, + } + + let un = Un { us: val() }; + + drop(unsafe { un.us }); +} diff --git a/src/test/mir-opt/dest-prop/union/rustc.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/union/rustc.main.DestinationPropagation.diff new file mode 100644 index 0000000000000..f6ebb6cb9403d --- /dev/null +++ b/src/test/mir-opt/dest-prop/union/rustc.main.DestinationPropagation.diff @@ -0,0 +1,61 @@ +- // MIR for `main` before DestinationPropagation ++ // MIR for `main` after DestinationPropagation + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/union.rs:8:11: 8:11 + let _1: main::Un; // in scope 0 at $DIR/union.rs:13:9: 13:11 + let mut _2: u32; // in scope 0 at $DIR/union.rs:13:23: 13:28 + let _3: (); // in scope 0 at $DIR/union.rs:15:5: 15:27 + let mut _4: u32; // in scope 0 at $DIR/union.rs:15:10: 15:26 + scope 1 { + debug un => _1; // in scope 1 at $DIR/union.rs:13:9: 13:11 + scope 2 { + } + scope 3 { + debug _x => _4; // in scope 3 at $SRC_DIR/libcore/mem/mod.rs:LL:COL + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/union.rs:13:9: 13:11 + StorageLive(_2); // scope 0 at $DIR/union.rs:13:23: 13:28 + _2 = const val() -> bb1; // scope 0 at $DIR/union.rs:13:23: 13:28 + // ty::Const + // + ty: fn() -> u32 {val} + // + val: Value(Scalar()) + // mir::Constant + // + span: $DIR/union.rs:13:23: 13:26 + // + literal: Const { ty: fn() -> u32 {val}, val: Value(Scalar()) } + } + + bb1: { + (_1.0: u32) = move _2; // scope 0 at $DIR/union.rs:13:14: 13:30 + StorageDead(_2); // scope 0 at $DIR/union.rs:13:29: 13:30 + StorageLive(_3); // scope 1 at $DIR/union.rs:15:5: 15:27 + StorageLive(_4); // scope 1 at $DIR/union.rs:15:10: 15:26 + _4 = (_1.0: u32); // scope 2 at $DIR/union.rs:15:19: 15:24 + _3 = const (); // scope 3 at $SRC_DIR/libcore/mem/mod.rs:LL:COL + // ty::Const + // + ty: () + // + val: Value(Scalar()) + // mir::Constant + // + span: $SRC_DIR/libcore/mem/mod.rs:LL:COL + // + literal: Const { ty: (), val: Value(Scalar()) } + drop(_4) -> bb2; // scope 3 at $SRC_DIR/libcore/mem/mod.rs:LL:COL + } + + bb2: { + StorageDead(_4); // scope 1 at $DIR/union.rs:15:26: 15:27 + StorageDead(_3); // scope 1 at $DIR/union.rs:15:27: 15:28 + _0 = const (); // scope 0 at $DIR/union.rs:8:11: 16:2 + // ty::Const + // + ty: () + // + val: Value(Scalar()) + // mir::Constant + // + span: $DIR/union.rs:8:11: 16:2 + // + literal: Const { ty: (), val: Value(Scalar()) } + StorageDead(_1); // scope 0 at $DIR/union.rs:16:1: 16:2 + return; // scope 0 at $DIR/union.rs:16:2: 16:2 + } + } + From 402f863d8ac2e69abf415d9ed9c1b9984e037700 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 12 Sep 2020 15:10:38 +0200 Subject: [PATCH 0621/1052] perf: walk liveness backwards in Conflicts::build --- compiler/rustc_mir/src/transform/dest_prop.rs | 63 ++++++++++++------- 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs index 3c46e8fc36b8d..8e174ce277a9c 100644 --- a/compiler/rustc_mir/src/transform/dest_prop.rs +++ b/compiler/rustc_mir/src/transform/dest_prop.rs @@ -100,10 +100,7 @@ use crate::{ transform::{MirPass, MirSource}, util::{dump_mir, PassWhere}, }; -use dataflow::{ - impls::{MaybeInitializedLocals, MaybeLiveLocals}, - ResultsCursor, -}; +use dataflow::impls::{MaybeInitializedLocals, MaybeLiveLocals}; use rustc_data_structures::unify::{InPlaceUnificationTable, UnifyKey}; use rustc_index::{ bit_set::{BitMatrix, BitSet}, @@ -382,16 +379,11 @@ impl Conflicts { body.local_decls.len(), ); - let mut record_conflicts = - |init: &ResultsCursor<'_, '_, MaybeInitializedLocals>, - live: &ResultsCursor<'_, '_, MaybeLiveLocals>| { - let mut requires_storage = init.get().clone(); - requires_storage.intersect(live.get()); - - for local in requires_storage.iter() { - conflicts.union_row_with(&requires_storage, local); - } - }; + let mut record_conflicts = |new_conflicts: &BitSet<_>| { + for local in new_conflicts.iter() { + conflicts.union_row_with(&new_conflicts, local); + } + }; let def_id = source.def_id(); let mut init = MaybeInitializedLocals @@ -457,27 +449,50 @@ impl Conflicts { }, ); + let mut relevant_locals = Vec::new(); + // Visit only reachable basic blocks. The exact order is not important. for (block, data) in traversal::preorder(body) { - // Observe the dataflow state *before* all possible locations (statement or terminator) in - // each basic block... + // We need to observe the dataflow state *before* all possible locations (statement or + // terminator) in each basic block, and then observe the state *after* the terminator + // effect is applied. As long as neither `init` nor `borrowed` has a "before" effect, + // we will observe all possible dataflow states. + + // Since liveness is a backwards analysis, we need to walk the results backwards. To do + // that, we first collect in the `MaybeInitializedLocals` results in a forwards + // traversal. + + relevant_locals.resize_with(data.statements.len() + 1, || { + BitSet::new_empty(body.local_decls.len()) + }); + + // First, go forwards for `MaybeInitializedLocals`. for statement_index in 0..=data.statements.len() { let loc = Location { block, statement_index }; - trace!("record conflicts at {:?}", loc); init.seek_before_primary_effect(loc); + + relevant_locals[statement_index].clone_from(init.get()); + } + + // Now, go backwards and union with the liveness results. + for statement_index in (0..=data.statements.len()).rev() { + let loc = Location { block, statement_index }; live.seek_after_primary_effect(loc); - // FIXME: liveness is backwards, so this is slow - record_conflicts(&init, &live); + relevant_locals[statement_index].intersect(live.get()); + + trace!("record conflicts at {:?}", loc); + + record_conflicts(&relevant_locals[statement_index]); } - // ...and then observe the state *after* the terminator effect is applied. As long as - // neither `init` nor `borrowed` has a "before" effect, we will observe all possible - // dataflow states here or in the loop above. - trace!("record conflicts at end of {:?}", block); init.seek_to_block_end(block); live.seek_to_block_end(block); - record_conflicts(&init, &live); + let mut conflicts = init.get().clone(); + conflicts.intersect(live.get()); + trace!("record conflicts at end of {:?}", block); + + record_conflicts(&conflicts); } Self { matrix: conflicts, unify_cache: BitSet::new_empty(body.local_decls.len()) } From 665a98d21f926fbd8a89fe2af7c448ff34deadc3 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 12 Sep 2020 15:10:51 +0200 Subject: [PATCH 0622/1052] Fix dest-prop mir-opt tests --- ...> branch.main.DestinationPropagation.diff} | 23 +++------------- src/test/mir-opt/dest-prop/branch.rs | 2 +- ...=> cycle.main.DestinationPropagation.diff} | 25 ++++------------- src/test/mir-opt/dest-prop/cycle.rs | 2 +- ...> simple.nrvo.DestinationPropagation.diff} | 27 ++++++------------- src/test/mir-opt/dest-prop/simple.rs | 2 +- ...=> union.main.DestinationPropagation.diff} | 23 +++------------- src/test/mir-opt/dest-prop/union.rs | 2 +- 8 files changed, 25 insertions(+), 81 deletions(-) rename src/test/mir-opt/dest-prop/{branch/rustc.main.DestinationPropagation.diff => branch.main.DestinationPropagation.diff} (74%) rename src/test/mir-opt/dest-prop/{cycle/rustc.main.DestinationPropagation.diff => cycle.main.DestinationPropagation.diff} (78%) rename src/test/mir-opt/dest-prop/{simple/rustc.nrvo.DestinationPropagation.diff => simple.nrvo.DestinationPropagation.diff} (63%) rename src/test/mir-opt/dest-prop/{union/rustc.main.DestinationPropagation.diff => union.main.DestinationPropagation.diff} (65%) diff --git a/src/test/mir-opt/dest-prop/branch/rustc.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/branch.main.DestinationPropagation.diff similarity index 74% rename from src/test/mir-opt/dest-prop/branch/rustc.main.DestinationPropagation.diff rename to src/test/mir-opt/dest-prop/branch.main.DestinationPropagation.diff index b8387ae449387..9c213eaed3c04 100644 --- a/src/test/mir-opt/dest-prop/branch/rustc.main.DestinationPropagation.diff +++ b/src/test/mir-opt/dest-prop/branch.main.DestinationPropagation.diff @@ -17,12 +17,9 @@ bb0: { - StorageLive(_1); // scope 0 at $DIR/branch.rs:13:9: 13:10 -- _1 = const val() -> bb1; // scope 0 at $DIR/branch.rs:13:13: 13:18 +- _1 = val() -> bb1; // scope 0 at $DIR/branch.rs:13:13: 13:18 + nop; // scope 0 at $DIR/branch.rs:13:9: 13:10 -+ _2 = const val() -> bb1; // scope 0 at $DIR/branch.rs:13:13: 13:18 - // ty::Const - // + ty: fn() -> i32 {val} - // + val: Value(Scalar()) ++ _2 = val() -> bb1; // scope 0 at $DIR/branch.rs:13:13: 13:18 // mir::Constant // + span: $DIR/branch.rs:13:13: 13:16 // + literal: Const { ty: fn() -> i32 {val}, val: Value(Scalar()) } @@ -32,10 +29,7 @@ - StorageLive(_2); // scope 1 at $DIR/branch.rs:15:9: 15:10 + nop; // scope 1 at $DIR/branch.rs:15:9: 15:10 StorageLive(_3); // scope 1 at $DIR/branch.rs:15:16: 15:22 - _3 = const cond() -> bb2; // scope 1 at $DIR/branch.rs:15:16: 15:22 - // ty::Const - // + ty: fn() -> bool {cond} - // + val: Value(Scalar()) + _3 = cond() -> bb2; // scope 1 at $DIR/branch.rs:15:16: 15:22 // mir::Constant // + span: $DIR/branch.rs:15:16: 15:20 // + literal: Const { ty: fn() -> bool {cond}, val: Value(Scalar()) } @@ -47,10 +41,7 @@ bb3: { StorageLive(_4); // scope 1 at $DIR/branch.rs:18:9: 18:14 - _4 = const val() -> bb5; // scope 1 at $DIR/branch.rs:18:9: 18:14 - // ty::Const - // + ty: fn() -> i32 {val} - // + val: Value(Scalar()) + _4 = val() -> bb5; // scope 1 at $DIR/branch.rs:18:9: 18:14 // mir::Constant // + span: $DIR/branch.rs:18:9: 18:12 // + literal: Const { ty: fn() -> i32 {val}, val: Value(Scalar()) } @@ -72,12 +63,6 @@ bb6: { StorageDead(_3); // scope 1 at $DIR/branch.rs:20:6: 20:7 _0 = const (); // scope 0 at $DIR/branch.rs:12:11: 21:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/branch.rs:12:11: 21:2 - // + literal: Const { ty: (), val: Value(Scalar()) } - StorageDead(_2); // scope 1 at $DIR/branch.rs:21:1: 21:2 - StorageDead(_1); // scope 0 at $DIR/branch.rs:21:1: 21:2 + nop; // scope 1 at $DIR/branch.rs:21:1: 21:2 diff --git a/src/test/mir-opt/dest-prop/branch.rs b/src/test/mir-opt/dest-prop/branch.rs index b49ecf07daa39..7e0e40671ddb2 100644 --- a/src/test/mir-opt/dest-prop/branch.rs +++ b/src/test/mir-opt/dest-prop/branch.rs @@ -8,7 +8,7 @@ fn cond() -> bool { true } -// EMIT_MIR rustc.main.DestinationPropagation.diff +// EMIT_MIR branch.main.DestinationPropagation.diff fn main() { let x = val(); diff --git a/src/test/mir-opt/dest-prop/cycle/rustc.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff similarity index 78% rename from src/test/mir-opt/dest-prop/cycle/rustc.main.DestinationPropagation.diff rename to src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff index 5189b665acff1..dd717c1b9c324 100644 --- a/src/test/mir-opt/dest-prop/cycle/rustc.main.DestinationPropagation.diff +++ b/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff @@ -19,7 +19,7 @@ - debug z => _3; // in scope 3 at $DIR/cycle.rs:11:9: 11:10 + debug z => _4; // in scope 3 at $DIR/cycle.rs:11:9: 11:10 scope 4 { - debug _x => _6; // in scope 4 at $SRC_DIR/libcore/mem/mod.rs:LL:COL + debug _x => _6; // in scope 4 at $SRC_DIR/core/src/mem/mod.rs:LL:COL } } } @@ -27,12 +27,9 @@ bb0: { - StorageLive(_1); // scope 0 at $DIR/cycle.rs:9:9: 9:14 -- _1 = const val() -> bb1; // scope 0 at $DIR/cycle.rs:9:17: 9:22 +- _1 = val() -> bb1; // scope 0 at $DIR/cycle.rs:9:17: 9:22 + nop; // scope 0 at $DIR/cycle.rs:9:9: 9:14 -+ _4 = const val() -> bb1; // scope 0 at $DIR/cycle.rs:9:17: 9:22 - // ty::Const - // + ty: fn() -> i32 {val} - // + val: Value(Scalar()) ++ _4 = val() -> bb1; // scope 0 at $DIR/cycle.rs:9:17: 9:22 // mir::Constant // + span: $DIR/cycle.rs:9:17: 9:20 // + literal: Const { ty: fn() -> i32 {val}, val: Value(Scalar()) } @@ -59,26 +56,14 @@ StorageLive(_6); // scope 3 at $DIR/cycle.rs:14:10: 14:11 - _6 = _1; // scope 3 at $DIR/cycle.rs:14:10: 14:11 + _6 = _4; // scope 3 at $DIR/cycle.rs:14:10: 14:11 - _5 = const (); // scope 4 at $SRC_DIR/libcore/mem/mod.rs:LL:COL - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $SRC_DIR/libcore/mem/mod.rs:LL:COL - // + literal: Const { ty: (), val: Value(Scalar()) } - drop(_6) -> bb2; // scope 4 at $SRC_DIR/libcore/mem/mod.rs:LL:COL + _5 = const (); // scope 4 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + drop(_6) -> bb2; // scope 4 at $SRC_DIR/core/src/mem/mod.rs:LL:COL } bb2: { StorageDead(_6); // scope 3 at $DIR/cycle.rs:14:11: 14:12 StorageDead(_5); // scope 3 at $DIR/cycle.rs:14:12: 14:13 _0 = const (); // scope 0 at $DIR/cycle.rs:8:11: 15:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/cycle.rs:8:11: 15:2 - // + literal: Const { ty: (), val: Value(Scalar()) } - StorageDead(_3); // scope 2 at $DIR/cycle.rs:15:1: 15:2 - StorageDead(_2); // scope 1 at $DIR/cycle.rs:15:1: 15:2 - StorageDead(_1); // scope 0 at $DIR/cycle.rs:15:1: 15:2 diff --git a/src/test/mir-opt/dest-prop/cycle.rs b/src/test/mir-opt/dest-prop/cycle.rs index d55d527bc65f6..7fbffb1335946 100644 --- a/src/test/mir-opt/dest-prop/cycle.rs +++ b/src/test/mir-opt/dest-prop/cycle.rs @@ -4,7 +4,7 @@ fn val() -> i32 { 1 } -// EMIT_MIR rustc.main.DestinationPropagation.diff +// EMIT_MIR cycle.main.DestinationPropagation.diff fn main() { let mut x = val(); let y = x; diff --git a/src/test/mir-opt/dest-prop/simple/rustc.nrvo.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.diff similarity index 63% rename from src/test/mir-opt/dest-prop/simple/rustc.nrvo.DestinationPropagation.diff rename to src/test/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.diff index d59e1f3c0c938..1277c51f2a050 100644 --- a/src/test/mir-opt/dest-prop/simple/rustc.nrvo.DestinationPropagation.diff +++ b/src/test/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.diff @@ -16,35 +16,24 @@ bb0: { - StorageLive(_2); // scope 0 at $DIR/simple.rs:5:9: 5:16 -- _2 = [const 0u8; 1024]; // scope 0 at $DIR/simple.rs:5:19: 5:28 +- _2 = [const 0_u8; 1024]; // scope 0 at $DIR/simple.rs:5:19: 5:28 + nop; // scope 0 at $DIR/simple.rs:5:9: 5:16 -+ _0 = [const 0u8; 1024]; // scope 0 at $DIR/simple.rs:5:19: 5:28 - // ty::Const - // + ty: u8 - // + val: Value(Scalar(0x00)) - // mir::Constant - // + span: $DIR/simple.rs:5:20: 5:21 - // + literal: Const { ty: u8, val: Value(Scalar(0x00)) } ++ _0 = [const 0_u8; 1024]; // scope 0 at $DIR/simple.rs:5:19: 5:28 StorageLive(_3); // scope 1 at $DIR/simple.rs:6:5: 6:19 StorageLive(_4); // scope 1 at $DIR/simple.rs:6:5: 6:9 _4 = _1; // scope 1 at $DIR/simple.rs:6:5: 6:9 -- StorageLive(_5); // scope 1 at $DIR/simple.rs:6:10: 6:18 -- StorageLive(_6); // scope 1 at $DIR/simple.rs:6:10: 6:18 + StorageLive(_5); // scope 1 at $DIR/simple.rs:6:10: 6:18 + StorageLive(_6); // scope 1 at $DIR/simple.rs:6:10: 6:18 - _6 = &mut _2; // scope 1 at $DIR/simple.rs:6:10: 6:18 -- _5 = move _6; // scope 1 at $DIR/simple.rs:6:10: 6:18 -+ nop; // scope 1 at $DIR/simple.rs:6:10: 6:18 -+ nop; // scope 1 at $DIR/simple.rs:6:10: 6:18 -+ _5 = &mut _0; // scope 1 at $DIR/simple.rs:6:10: 6:18 -+ nop; // scope 1 at $DIR/simple.rs:6:10: 6:18 ++ _6 = &mut _0; // scope 1 at $DIR/simple.rs:6:10: 6:18 + _5 = &mut (*_6); // scope 1 at $DIR/simple.rs:6:10: 6:18 _3 = move _4(move _5) -> bb1; // scope 1 at $DIR/simple.rs:6:5: 6:19 } bb1: { -- StorageDead(_5); // scope 1 at $DIR/simple.rs:6:18: 6:19 -+ nop; // scope 1 at $DIR/simple.rs:6:18: 6:19 + StorageDead(_5); // scope 1 at $DIR/simple.rs:6:18: 6:19 StorageDead(_4); // scope 1 at $DIR/simple.rs:6:18: 6:19 -- StorageDead(_6); // scope 1 at $DIR/simple.rs:6:19: 6:20 -+ nop; // scope 1 at $DIR/simple.rs:6:19: 6:20 + StorageDead(_6); // scope 1 at $DIR/simple.rs:6:19: 6:20 StorageDead(_3); // scope 1 at $DIR/simple.rs:6:19: 6:20 - _0 = _2; // scope 1 at $DIR/simple.rs:7:5: 7:8 - StorageDead(_2); // scope 0 at $DIR/simple.rs:8:1: 8:2 diff --git a/src/test/mir-opt/dest-prop/simple.rs b/src/test/mir-opt/dest-prop/simple.rs index add821eafe0b0..4655f96699874 100644 --- a/src/test/mir-opt/dest-prop/simple.rs +++ b/src/test/mir-opt/dest-prop/simple.rs @@ -1,6 +1,6 @@ //! Copy of `nrvo-simple.rs`, to ensure that full dest-prop handles it too. -// EMIT_MIR rustc.nrvo.DestinationPropagation.diff +// EMIT_MIR simple.nrvo.DestinationPropagation.diff fn nrvo(init: fn(&mut [u8; 1024])) -> [u8; 1024] { let mut buf = [0; 1024]; init(&mut buf); diff --git a/src/test/mir-opt/dest-prop/union/rustc.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff similarity index 65% rename from src/test/mir-opt/dest-prop/union/rustc.main.DestinationPropagation.diff rename to src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff index f6ebb6cb9403d..871f6e35043ec 100644 --- a/src/test/mir-opt/dest-prop/union/rustc.main.DestinationPropagation.diff +++ b/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff @@ -12,17 +12,14 @@ scope 2 { } scope 3 { - debug _x => _4; // in scope 3 at $SRC_DIR/libcore/mem/mod.rs:LL:COL + debug _x => _4; // in scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL } } bb0: { StorageLive(_1); // scope 0 at $DIR/union.rs:13:9: 13:11 StorageLive(_2); // scope 0 at $DIR/union.rs:13:23: 13:28 - _2 = const val() -> bb1; // scope 0 at $DIR/union.rs:13:23: 13:28 - // ty::Const - // + ty: fn() -> u32 {val} - // + val: Value(Scalar()) + _2 = val() -> bb1; // scope 0 at $DIR/union.rs:13:23: 13:28 // mir::Constant // + span: $DIR/union.rs:13:23: 13:26 // + literal: Const { ty: fn() -> u32 {val}, val: Value(Scalar()) } @@ -34,26 +31,14 @@ StorageLive(_3); // scope 1 at $DIR/union.rs:15:5: 15:27 StorageLive(_4); // scope 1 at $DIR/union.rs:15:10: 15:26 _4 = (_1.0: u32); // scope 2 at $DIR/union.rs:15:19: 15:24 - _3 = const (); // scope 3 at $SRC_DIR/libcore/mem/mod.rs:LL:COL - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $SRC_DIR/libcore/mem/mod.rs:LL:COL - // + literal: Const { ty: (), val: Value(Scalar()) } - drop(_4) -> bb2; // scope 3 at $SRC_DIR/libcore/mem/mod.rs:LL:COL + _3 = const (); // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + drop(_4) -> bb2; // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL } bb2: { StorageDead(_4); // scope 1 at $DIR/union.rs:15:26: 15:27 StorageDead(_3); // scope 1 at $DIR/union.rs:15:27: 15:28 _0 = const (); // scope 0 at $DIR/union.rs:8:11: 16:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/union.rs:8:11: 16:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_1); // scope 0 at $DIR/union.rs:16:1: 16:2 return; // scope 0 at $DIR/union.rs:16:2: 16:2 } diff --git a/src/test/mir-opt/dest-prop/union.rs b/src/test/mir-opt/dest-prop/union.rs index ea8364124043e..b9d831389e8b3 100644 --- a/src/test/mir-opt/dest-prop/union.rs +++ b/src/test/mir-opt/dest-prop/union.rs @@ -4,7 +4,7 @@ fn val() -> u32 { 1 } -// EMIT_MIR rustc.main.DestinationPropagation.diff +// EMIT_MIR union.main.DestinationPropagation.diff fn main() { union Un { us: u32, From ab26fb140c9225c690a219c055a54eba57188d4a Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 26 May 2020 22:21:10 +0200 Subject: [PATCH 0623/1052] perf: only calculate conflicts for candidates --- compiler/rustc_mir/src/transform/dest_prop.rs | 51 ++++++++++++++----- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs index 8e174ce277a9c..d22c11f491b40 100644 --- a/compiler/rustc_mir/src/transform/dest_prop.rs +++ b/compiler/rustc_mir/src/transform/dest_prop.rs @@ -124,9 +124,22 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { return; } - let mut conflicts = Conflicts::build(tcx, body, source); + let candidates = find_candidates(tcx, body); + if candidates.is_empty() { + debug!("{:?}: no dest prop candidates, done", source.def_id()); + return; + } + + // Collect all locals we care about. We only compute conflicts for these to save time. + let mut relevant_locals = BitSet::new_empty(body.local_decls.len()); + for CandidateAssignment { dest, src, loc: _ } in &candidates { + relevant_locals.insert(dest.local); + relevant_locals.insert(*src); + } + + let mut conflicts = Conflicts::build(tcx, body, source, &relevant_locals); let mut replacements = Replacements::new(body.local_decls.len()); - for candidate @ CandidateAssignment { dest, src, loc } in find_candidates(tcx, body) { + for candidate @ CandidateAssignment { dest, src, loc } in candidates { // Merge locals that don't conflict. if conflicts.contains(dest.local, src) { debug!("at assignment {:?}, conflict {:?} vs. {:?}", loc, dest.local, src); @@ -370,16 +383,30 @@ struct Conflicts { } impl Conflicts { - fn build<'tcx>(tcx: TyCtxt<'tcx>, body: &'_ Body<'tcx>, source: MirSource<'tcx>) -> Self { - // We don't have to look out for locals that have their address taken, since `find_candidates` - // already takes care of that. + fn build<'tcx>( + tcx: TyCtxt<'tcx>, + body: &'_ Body<'tcx>, + source: MirSource<'tcx>, + relevant_locals: &BitSet, + ) -> Self { + // We don't have to look out for locals that have their address taken, since + // `find_candidates` already takes care of that. + + debug!( + "Conflicts::build: {}/{} locals relevant", + relevant_locals.count(), + body.local_decls.len() + ); let mut conflicts = BitMatrix::from_row_n( &BitSet::new_empty(body.local_decls.len()), body.local_decls.len(), ); - let mut record_conflicts = |new_conflicts: &BitSet<_>| { + let mut record_conflicts = |new_conflicts: &mut BitSet<_>| { + // Remove all locals that are not candidates. + new_conflicts.intersect(relevant_locals); + for local in new_conflicts.iter() { conflicts.union_row_with(&new_conflicts, local); } @@ -449,7 +476,7 @@ impl Conflicts { }, ); - let mut relevant_locals = Vec::new(); + let mut live_and_init_locals = Vec::new(); // Visit only reachable basic blocks. The exact order is not important. for (block, data) in traversal::preorder(body) { @@ -462,7 +489,7 @@ impl Conflicts { // that, we first collect in the `MaybeInitializedLocals` results in a forwards // traversal. - relevant_locals.resize_with(data.statements.len() + 1, || { + live_and_init_locals.resize_with(data.statements.len() + 1, || { BitSet::new_empty(body.local_decls.len()) }); @@ -471,7 +498,7 @@ impl Conflicts { let loc = Location { block, statement_index }; init.seek_before_primary_effect(loc); - relevant_locals[statement_index].clone_from(init.get()); + live_and_init_locals[statement_index].clone_from(init.get()); } // Now, go backwards and union with the liveness results. @@ -479,11 +506,11 @@ impl Conflicts { let loc = Location { block, statement_index }; live.seek_after_primary_effect(loc); - relevant_locals[statement_index].intersect(live.get()); + live_and_init_locals[statement_index].intersect(live.get()); trace!("record conflicts at {:?}", loc); - record_conflicts(&relevant_locals[statement_index]); + record_conflicts(&mut live_and_init_locals[statement_index]); } init.seek_to_block_end(block); @@ -492,7 +519,7 @@ impl Conflicts { conflicts.intersect(live.get()); trace!("record conflicts at end of {:?}", block); - record_conflicts(&conflicts); + record_conflicts(&mut conflicts); } Self { matrix: conflicts, unify_cache: BitSet::new_empty(body.local_decls.len()) } From ddd6930b549d069ac13de66b8676fed4feb95ec4 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 26 May 2020 21:39:24 +0200 Subject: [PATCH 0624/1052] perf: bail out when there's >500 candidate locals --- compiler/rustc_mir/src/transform/dest_prop.rs | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs index d22c11f491b40..cb4321ace7f9a 100644 --- a/compiler/rustc_mir/src/transform/dest_prop.rs +++ b/compiler/rustc_mir/src/transform/dest_prop.rs @@ -114,6 +114,8 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::{self, Ty, TyCtxt}; +const MAX_LOCALS: usize = 500; + pub struct DestinationPropagation; impl<'tcx> MirPass<'tcx> for DestinationPropagation { @@ -137,7 +139,29 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { relevant_locals.insert(*src); } + // This pass unfortunately has `O(l² * s)` performance, where `l` is the number of locals + // and `s` is the number of statements and terminators in the function. + // To prevent blowing up compile times too much, we bail out when there are too many locals. + let relevant = relevant_locals.count(); + debug!( + "{:?}: {} locals ({} relevant), {} blocks", + source.def_id(), + body.local_decls.len(), + relevant, + body.basic_blocks().len() + ); + if relevant > MAX_LOCALS { + warn!( + "too many candidate locals in {:?} ({}, max is {}), not optimizing", + source.def_id(), + relevant, + MAX_LOCALS + ); + return; + } + let mut conflicts = Conflicts::build(tcx, body, source, &relevant_locals); + let mut replacements = Replacements::new(body.local_decls.len()); for candidate @ CandidateAssignment { dest, src, loc } in candidates { // Merge locals that don't conflict. @@ -392,12 +416,6 @@ impl Conflicts { // We don't have to look out for locals that have their address taken, since // `find_candidates` already takes care of that. - debug!( - "Conflicts::build: {}/{} locals relevant", - relevant_locals.count(), - body.local_decls.len() - ); - let mut conflicts = BitMatrix::from_row_n( &BitSet::new_empty(body.local_decls.len()), body.local_decls.len(), From 88538adf9ae1886d9b5c1f45d55b2f76bd6435bd Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 12 Sep 2020 15:15:05 +0200 Subject: [PATCH 0625/1052] Record intra-statement/terminator conflicts Some MIR statements and terminators have an (undocumented...) invariant that some of their input and outputs must not overlap. This records conflicts between locals used in these positions. --- compiler/rustc_mir/src/transform/dest_prop.rs | 228 ++++++++++++++++-- 1 file changed, 206 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs index cb4321ace7f9a..20f8f820176ab 100644 --- a/compiler/rustc_mir/src/transform/dest_prop.rs +++ b/compiler/rustc_mir/src/transform/dest_prop.rs @@ -109,8 +109,8 @@ use rustc_index::{ use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::{ - traversal, Body, Local, LocalKind, Location, Operand, Place, PlaceElem, Rvalue, Statement, - StatementKind, Terminator, TerminatorKind, + traversal, Body, InlineAsmOperand, Local, LocalKind, Location, Operand, Place, PlaceElem, + Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -397,7 +397,9 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> { } } -struct Conflicts { +struct Conflicts<'a> { + relevant_locals: &'a BitSet, + /// The conflict matrix. It is always symmetric and the adjacency matrix of the corresponding /// conflict graph. matrix: BitMatrix, @@ -406,30 +408,21 @@ struct Conflicts { unify_cache: BitSet, } -impl Conflicts { +impl Conflicts<'a> { fn build<'tcx>( tcx: TyCtxt<'tcx>, body: &'_ Body<'tcx>, source: MirSource<'tcx>, - relevant_locals: &BitSet, + relevant_locals: &'a BitSet, ) -> Self { // We don't have to look out for locals that have their address taken, since // `find_candidates` already takes care of that. - let mut conflicts = BitMatrix::from_row_n( + let conflicts = BitMatrix::from_row_n( &BitSet::new_empty(body.local_decls.len()), body.local_decls.len(), ); - let mut record_conflicts = |new_conflicts: &mut BitSet<_>| { - // Remove all locals that are not candidates. - new_conflicts.intersect(relevant_locals); - - for local in new_conflicts.iter() { - conflicts.union_row_with(&new_conflicts, local); - } - }; - let def_id = source.def_id(); let mut init = MaybeInitializedLocals .into_engine(tcx, body, def_id) @@ -494,6 +487,12 @@ impl Conflicts { }, ); + let mut this = Self { + relevant_locals, + matrix: conflicts, + unify_cache: BitSet::new_empty(body.local_decls.len()), + }; + let mut live_and_init_locals = Vec::new(); // Visit only reachable basic blocks. The exact order is not important. @@ -511,14 +510,22 @@ impl Conflicts { BitSet::new_empty(body.local_decls.len()) }); - // First, go forwards for `MaybeInitializedLocals`. - for statement_index in 0..=data.statements.len() { - let loc = Location { block, statement_index }; + // First, go forwards for `MaybeInitializedLocals` and apply intra-statement/terminator + // conflicts. + for (i, statement) in data.statements.iter().enumerate() { + this.record_statement_conflicts(statement); + + let loc = Location { block, statement_index: i }; init.seek_before_primary_effect(loc); - live_and_init_locals[statement_index].clone_from(init.get()); + live_and_init_locals[i].clone_from(init.get()); } + this.record_terminator_conflicts(data.terminator()); + let term_loc = Location { block, statement_index: data.statements.len() }; + init.seek_before_primary_effect(term_loc); + live_and_init_locals[term_loc.statement_index].clone_from(init.get()); + // Now, go backwards and union with the liveness results. for statement_index in (0..=data.statements.len()).rev() { let loc = Location { block, statement_index }; @@ -528,7 +535,7 @@ impl Conflicts { trace!("record conflicts at {:?}", loc); - record_conflicts(&mut live_and_init_locals[statement_index]); + this.record_conflicts(&mut live_and_init_locals[statement_index]); } init.seek_to_block_end(block); @@ -537,10 +544,187 @@ impl Conflicts { conflicts.intersect(live.get()); trace!("record conflicts at end of {:?}", block); - record_conflicts(&mut conflicts); + this.record_conflicts(&mut conflicts); + } + + this + } + + fn record_conflicts(&mut self, new_conflicts: &mut BitSet) { + // Remove all locals that are not candidates. + new_conflicts.intersect(self.relevant_locals); + + for local in new_conflicts.iter() { + self.matrix.union_row_with(&new_conflicts, local); + } + } + + /// Records locals that must not overlap during the evaluation of `stmt`. These locals conflict + /// and must not be merged. + fn record_statement_conflicts(&mut self, stmt: &Statement<'_>) { + match &stmt.kind { + // While the left and right sides of an assignment must not overlap, we do not mark + // conflicts here as that would make this optimization useless. When we optimize, we + // eliminate the resulting self-assignments automatically. + StatementKind::Assign(_) => {} + + StatementKind::LlvmInlineAsm(asm) => { + // Inputs and outputs must not overlap. + for (_, input) in &*asm.inputs { + if let Some(in_place) = input.place() { + if !in_place.is_indirect() { + for out_place in &*asm.outputs { + if !out_place.is_indirect() && !in_place.is_indirect() { + self.matrix.insert(in_place.local, out_place.local); + self.matrix.insert(out_place.local, in_place.local); + } + } + } + } + } + } + + StatementKind::SetDiscriminant { .. } + | StatementKind::StorageLive(_) + | StatementKind::StorageDead(_) + | StatementKind::Retag(_, _) + | StatementKind::FakeRead(_, _) + | StatementKind::AscribeUserType(_, _) + | StatementKind::Nop => {} } + } - Self { matrix: conflicts, unify_cache: BitSet::new_empty(body.local_decls.len()) } + fn record_terminator_conflicts(&mut self, term: &Terminator<'_>) { + match &term.kind { + TerminatorKind::DropAndReplace { location, value, target: _, unwind: _ } => { + if let Some(place) = value.place() { + if !place.is_indirect() && !location.is_indirect() { + self.matrix.insert(place.local, location.local); + self.matrix.insert(location.local, place.local); + } + } + } + TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => { + if let Some(place) = value.place() { + if !place.is_indirect() && !resume_arg.is_indirect() { + self.matrix.insert(place.local, resume_arg.local); + self.matrix.insert(resume_arg.local, place.local); + } + } + } + TerminatorKind::Call { + func, + args, + destination: Some((dest_place, _)), + cleanup: _, + from_hir_call: _, + } => { + // No arguments may overlap with the destination. + for arg in args.iter().chain(Some(func)) { + if let Some(place) = arg.place() { + if !place.is_indirect() && !dest_place.is_indirect() { + self.matrix.insert(dest_place.local, place.local); + self.matrix.insert(place.local, dest_place.local); + } + } + } + } + TerminatorKind::InlineAsm { + template: _, + operands, + options: _, + line_spans: _, + destination: _, + } => { + // The intended semantics here aren't documented, we just assume that nothing that + // could be written to by the assembly may overlap with any other operands. + for op in operands { + match op { + InlineAsmOperand::Out { reg: _, late: _, place: Some(dest_place) } + | InlineAsmOperand::InOut { + reg: _, + late: _, + in_value: _, + out_place: Some(dest_place), + } => { + // For output place `place`, add all places accessed by the inline asm. + for op in operands { + match op { + InlineAsmOperand::In { reg: _, value } => { + if let Some(p) = value.place() { + if !p.is_indirect() && !dest_place.is_indirect() { + self.matrix.insert(p.local, dest_place.local); + self.matrix.insert(dest_place.local, p.local); + } + } + } + InlineAsmOperand::Out { + reg: _, + late: _, + place: Some(place), + } => { + if !place.is_indirect() && !dest_place.is_indirect() { + self.matrix.insert(place.local, dest_place.local); + self.matrix.insert(dest_place.local, place.local); + } + } + InlineAsmOperand::InOut { + reg: _, + late: _, + in_value, + out_place, + } => { + if let Some(place) = in_value.place() { + if !place.is_indirect() && !dest_place.is_indirect() { + self.matrix.insert(place.local, dest_place.local); + self.matrix.insert(dest_place.local, place.local); + } + } + + if let Some(place) = out_place { + if !place.is_indirect() && !dest_place.is_indirect() { + self.matrix.insert(place.local, dest_place.local); + self.matrix.insert(dest_place.local, place.local); + } + } + } + InlineAsmOperand::Out { reg: _, late: _, place: None } + | InlineAsmOperand::Const { value: _ } + | InlineAsmOperand::SymFn { value: _ } + | InlineAsmOperand::SymStatic { value: _ } => {} + } + } + } + InlineAsmOperand::Const { value } => { + assert!(value.place().is_none()); + } + InlineAsmOperand::InOut { + reg: _, + late: _, + in_value: _, + out_place: None, + } + | InlineAsmOperand::In { reg: _, value: _ } + | InlineAsmOperand::Out { reg: _, late: _, place: None } + | InlineAsmOperand::SymFn { value: _ } + | InlineAsmOperand::SymStatic { value: _ } => {} + } + } + } + + TerminatorKind::Goto { .. } + | TerminatorKind::Call { destination: None, .. } + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::Drop { .. } + | TerminatorKind::Assert { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::FalseEdges { .. } + | TerminatorKind::FalseUnwind { .. } => {} + } } fn contains(&self, a: Local, b: Local) -> bool { From 934634eacc2721e482672a99f91ed458580eb978 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 23 Jun 2020 01:25:52 +0200 Subject: [PATCH 0626/1052] More logging --- compiler/rustc_mir/src/transform/dest_prop.rs | 80 ++++++++++++++----- 1 file changed, 59 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs index 20f8f820176ab..d8f62e3506270 100644 --- a/compiler/rustc_mir/src/transform/dest_prop.rs +++ b/compiler/rustc_mir/src/transform/dest_prop.rs @@ -95,12 +95,13 @@ //! [previous attempt]: https://github.com/rust-lang/rust/pull/47954 //! [subsequent approach]: https://github.com/rust-lang/rust/pull/71003 -use crate::dataflow::{self, Analysis}; +use crate::dataflow::impls::{MaybeInitializedLocals, MaybeLiveLocals}; +use crate::dataflow::Analysis; use crate::{ transform::{MirPass, MirSource}, util::{dump_mir, PassWhere}, }; -use dataflow::impls::{MaybeInitializedLocals, MaybeLiveLocals}; +use itertools::Itertools; use rustc_data_structures::unify::{InPlaceUnificationTable, UnifyKey}; use rustc_index::{ bit_set::{BitMatrix, BitSet}, @@ -255,12 +256,14 @@ impl Replacements<'tcx> { // We still return `Err` in any case, as `src` and `dest` do not need to be unified // *again*. + trace!("push({:?}): already unified", candidate); return Err(()); } let entry = &mut self.map[candidate.src]; if entry.is_some() { // We're already replacing `src` with something else, so this candidate is out. + trace!("push({:?}): src already has replacement", candidate); return Err(()); } @@ -270,6 +273,7 @@ impl Replacements<'tcx> { self.kill.insert(candidate.src); self.kill.insert(candidate.dest.local); + trace!("push({:?}): accepted", candidate); Ok(()) } @@ -535,7 +539,7 @@ impl Conflicts<'a> { trace!("record conflicts at {:?}", loc); - this.record_conflicts(&mut live_and_init_locals[statement_index]); + this.record_dataflow_conflicts(&mut live_and_init_locals[statement_index]); } init.seek_to_block_end(block); @@ -544,13 +548,13 @@ impl Conflicts<'a> { conflicts.intersect(live.get()); trace!("record conflicts at end of {:?}", block); - this.record_conflicts(&mut conflicts); + this.record_dataflow_conflicts(&mut conflicts); } this } - fn record_conflicts(&mut self, new_conflicts: &mut BitSet) { + fn record_dataflow_conflicts(&mut self, new_conflicts: &mut BitSet) { // Remove all locals that are not candidates. new_conflicts.intersect(self.relevant_locals); @@ -559,6 +563,12 @@ impl Conflicts<'a> { } } + fn record_local_conflict(&mut self, a: Local, b: Local, why: &str) { + trace!("conflict {:?} <-> {:?} due to {}", a, b, why); + self.matrix.insert(a, b); + self.matrix.insert(b, a); + } + /// Records locals that must not overlap during the evaluation of `stmt`. These locals conflict /// and must not be merged. fn record_statement_conflicts(&mut self, stmt: &Statement<'_>) { @@ -575,8 +585,11 @@ impl Conflicts<'a> { if !in_place.is_indirect() { for out_place in &*asm.outputs { if !out_place.is_indirect() && !in_place.is_indirect() { - self.matrix.insert(in_place.local, out_place.local); - self.matrix.insert(out_place.local, in_place.local); + self.record_local_conflict( + in_place.local, + out_place.local, + "aliasing llvm_asm! operands", + ); } } } @@ -599,16 +612,22 @@ impl Conflicts<'a> { TerminatorKind::DropAndReplace { location, value, target: _, unwind: _ } => { if let Some(place) = value.place() { if !place.is_indirect() && !location.is_indirect() { - self.matrix.insert(place.local, location.local); - self.matrix.insert(location.local, place.local); + self.record_local_conflict( + place.local, + location.local, + "DropAndReplace operand overlap", + ); } } } TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => { if let Some(place) = value.place() { if !place.is_indirect() && !resume_arg.is_indirect() { - self.matrix.insert(place.local, resume_arg.local); - self.matrix.insert(resume_arg.local, place.local); + self.record_local_conflict( + place.local, + resume_arg.local, + "Yield operand overlap", + ); } } } @@ -623,8 +642,11 @@ impl Conflicts<'a> { for arg in args.iter().chain(Some(func)) { if let Some(place) = arg.place() { if !place.is_indirect() && !dest_place.is_indirect() { - self.matrix.insert(dest_place.local, place.local); - self.matrix.insert(place.local, dest_place.local); + self.record_local_conflict( + dest_place.local, + place.local, + "call dest/arg overlap", + ); } } } @@ -653,8 +675,11 @@ impl Conflicts<'a> { InlineAsmOperand::In { reg: _, value } => { if let Some(p) = value.place() { if !p.is_indirect() && !dest_place.is_indirect() { - self.matrix.insert(p.local, dest_place.local); - self.matrix.insert(dest_place.local, p.local); + self.record_local_conflict( + p.local, + dest_place.local, + "asm! operand overlap", + ); } } } @@ -664,8 +689,11 @@ impl Conflicts<'a> { place: Some(place), } => { if !place.is_indirect() && !dest_place.is_indirect() { - self.matrix.insert(place.local, dest_place.local); - self.matrix.insert(dest_place.local, place.local); + self.record_local_conflict( + place.local, + dest_place.local, + "asm! operand overlap", + ); } } InlineAsmOperand::InOut { @@ -676,15 +704,21 @@ impl Conflicts<'a> { } => { if let Some(place) = in_value.place() { if !place.is_indirect() && !dest_place.is_indirect() { - self.matrix.insert(place.local, dest_place.local); - self.matrix.insert(dest_place.local, place.local); + self.record_local_conflict( + place.local, + dest_place.local, + "asm! operand overlap", + ); } } if let Some(place) = out_place { if !place.is_indirect() && !dest_place.is_indirect() { - self.matrix.insert(place.local, dest_place.local); - self.matrix.insert(dest_place.local, place.local); + self.record_local_conflict( + place.local, + dest_place.local, + "asm! operand overlap", + ); } } } @@ -750,6 +784,10 @@ impl Conflicts<'a> { // FIXME: This might be somewhat slow. Conflict graphs are undirected, maybe we can use // something with union-find to speed this up? + trace!("unify({:?}, {:?})", a, b); + trace!("{:?} conflicts: {:?}", a, self.matrix.iter(a).format(", ")); + trace!("{:?} conflicts: {:?}", b, self.matrix.iter(b).format(", ")); + // Make all locals that conflict with `a` also conflict with `b`, and vice versa. self.unify_cache.clear(); for conflicts_with_a in self.matrix.iter(a) { From 484db5b08a83bd8875e0e938a0f78ce0a220bb17 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 24 Jun 2020 02:23:53 +0200 Subject: [PATCH 0627/1052] Properly inherit conflicts when merging locals --- compiler/rustc_mir/src/transform/dest_prop.rs | 113 ++++++++++-------- src/test/ui/dest-prop/skeptic-miscompile.rs | 24 ++++ 2 files changed, 84 insertions(+), 53 deletions(-) create mode 100644 src/test/ui/dest-prop/skeptic-miscompile.rs diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs index d8f62e3506270..cd3708374054a 100644 --- a/compiler/rustc_mir/src/transform/dest_prop.rs +++ b/compiler/rustc_mir/src/transform/dest_prop.rs @@ -166,20 +166,24 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { let mut replacements = Replacements::new(body.local_decls.len()); for candidate @ CandidateAssignment { dest, src, loc } in candidates { // Merge locals that don't conflict. - if conflicts.contains(dest.local, src) { + if !conflicts.can_unify(dest.local, src) { debug!("at assignment {:?}, conflict {:?} vs. {:?}", loc, dest.local, src); continue; } + if replacements.for_src(candidate.src).is_some() { + debug!("src {:?} already has replacement", candidate.src); + continue; + } + if !tcx.consider_optimizing(|| { format!("DestinationPropagation {:?} {:?}", source.def_id(), candidate) }) { break; } - if replacements.push(candidate).is_ok() { - conflicts.unify(candidate.src, candidate.dest.local); - } + replacements.push(candidate); + conflicts.unify(candidate.src, candidate.dest.local); } replacements.flatten(tcx); @@ -220,61 +224,21 @@ struct Replacements<'tcx> { /// Whose locals' live ranges to kill. kill: BitSet, - - /// Tracks locals that have already been merged together to prevent cycles. - unified_locals: InPlaceUnificationTable, } impl Replacements<'tcx> { fn new(locals: usize) -> Self { - Self { - map: IndexVec::from_elem_n(None, locals), - kill: BitSet::new_empty(locals), - unified_locals: { - let mut table = InPlaceUnificationTable::new(); - for local in 0..locals { - assert_eq!(table.new_key(()), UnifyLocal(Local::from_usize(local))); - } - table - }, - } + Self { map: IndexVec::from_elem_n(None, locals), kill: BitSet::new_empty(locals) } } - fn push(&mut self, candidate: CandidateAssignment<'tcx>) -> Result<(), ()> { - if self.unified_locals.unioned(candidate.src, candidate.dest.local) { - // Candidate conflicts with previous replacement (ie. could possibly form a cycle and - // hang). - - let replacement = self.map[candidate.src].as_mut().unwrap(); - - // If the current replacement is for the same `dest` local, there are 2 or more - // equivalent `src = dest;` assignments. This is fine, the replacer will `nop` out all - // of them. - if replacement.local == candidate.dest.local { - assert_eq!(replacement.projection, candidate.dest.projection); - } - - // We still return `Err` in any case, as `src` and `dest` do not need to be unified - // *again*. - trace!("push({:?}): already unified", candidate); - return Err(()); - } - + fn push(&mut self, candidate: CandidateAssignment<'tcx>) { + trace!("Replacements::push({:?})", candidate); let entry = &mut self.map[candidate.src]; - if entry.is_some() { - // We're already replacing `src` with something else, so this candidate is out. - trace!("push({:?}): src already has replacement", candidate); - return Err(()); - } - - self.unified_locals.union(candidate.src, candidate.dest.local); + assert!(entry.is_none()); *entry = Some(candidate.dest); self.kill.insert(candidate.src); self.kill.insert(candidate.dest.local); - - trace!("push({:?}): accepted", candidate); - Ok(()) } /// Applies the stored replacements to all replacements, until no replacements would result in @@ -410,6 +374,9 @@ struct Conflicts<'a> { /// Preallocated `BitSet` used by `unify`. unify_cache: BitSet, + + /// Tracks locals that have been merged together to prevent cycles and propagate conflicts. + unified_locals: InPlaceUnificationTable, } impl Conflicts<'a> { @@ -495,6 +462,15 @@ impl Conflicts<'a> { relevant_locals, matrix: conflicts, unify_cache: BitSet::new_empty(body.local_decls.len()), + unified_locals: { + let mut table = InPlaceUnificationTable::new(); + // Pre-fill table with all locals (this creates N nodes / "connected" components, + // "graph"-ically speaking). + for local in 0..body.local_decls.len() { + assert_eq!(table.new_key(()), UnifyLocal(Local::from_usize(local))); + } + table + }, }; let mut live_and_init_locals = Vec::new(); @@ -761,11 +737,31 @@ impl Conflicts<'a> { } } - fn contains(&self, a: Local, b: Local) -> bool { - self.matrix.contains(a, b) + /// Checks whether `a` and `b` may be merged. Returns `false` if there's a conflict. + fn can_unify(&mut self, a: Local, b: Local) -> bool { + // After some locals have been unified, their conflicts are only tracked in the root key, + // so look that up. + let a = self.unified_locals.find(a).0; + let b = self.unified_locals.find(b).0; + + if a == b { + // Already merged (part of the same connected component). + return false; + } + + if self.matrix.contains(a, b) { + // Conflict (derived via dataflow, intra-statement conflicts, or inherited from another + // local during unification). + return false; + } + + true } /// Merges the conflicts of `a` and `b`, so that each one inherits all conflicts of the other. + /// + /// `can_unify` must have returned `true` for the same locals, or this may panic or lead to + /// miscompiles. /// /// This is called when the pass makes the decision to unify `a` and `b` (or parts of `a` and /// `b`) and is needed to ensure that future unification decisions take potentially newly @@ -781,13 +777,24 @@ impl Conflicts<'a> { /// `_2` with `_0`, which also doesn't have a conflict in the above list. However `_2` is now /// `_3`, which does conflict with `_0`. fn unify(&mut self, a: Local, b: Local) { - // FIXME: This might be somewhat slow. Conflict graphs are undirected, maybe we can use - // something with union-find to speed this up? - trace!("unify({:?}, {:?})", a, b); + + // Get the root local of the connected components. The root local stores the conflicts of + // all locals in the connected component (and *is stored* as the conflicting local of other + // locals). + let a = self.unified_locals.find(a).0; + let b = self.unified_locals.find(b).0; + assert_ne!(a, b); + + trace!("roots: a={:?}, b={:?}", a, b); trace!("{:?} conflicts: {:?}", a, self.matrix.iter(a).format(", ")); trace!("{:?} conflicts: {:?}", b, self.matrix.iter(b).format(", ")); + self.unified_locals.union(a, b); + + let root = self.unified_locals.find(a).0; + assert!(root == a || root == b); + // Make all locals that conflict with `a` also conflict with `b`, and vice versa. self.unify_cache.clear(); for conflicts_with_a in self.matrix.iter(a) { diff --git a/src/test/ui/dest-prop/skeptic-miscompile.rs b/src/test/ui/dest-prop/skeptic-miscompile.rs new file mode 100644 index 0000000000000..c27a1f04532e7 --- /dev/null +++ b/src/test/ui/dest-prop/skeptic-miscompile.rs @@ -0,0 +1,24 @@ +// run-pass + +// compile-flags: -Zmir-opt-level=2 + +trait IterExt: Iterator { + fn fold_ex(mut self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + let mut accum = init; + while let Some(x) = self.next() { + accum = f(accum, x); + } + accum + } +} + +impl IterExt for T {} + +fn main() { + let test = &["\n"]; + test.iter().fold_ex(String::new(), |_, b| b.to_string()); +} From 572883444899ea0aecd5cd6cdf3466255dd4c7e0 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 24 Jun 2020 02:47:16 +0200 Subject: [PATCH 0628/1052] Fix rebase fallout --- compiler/rustc_mir/src/transform/dest_prop.rs | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs index cd3708374054a..f9071ab9d802c 100644 --- a/compiler/rustc_mir/src/transform/dest_prop.rs +++ b/compiler/rustc_mir/src/transform/dest_prop.rs @@ -585,12 +585,17 @@ impl Conflicts<'a> { fn record_terminator_conflicts(&mut self, term: &Terminator<'_>) { match &term.kind { - TerminatorKind::DropAndReplace { location, value, target: _, unwind: _ } => { + TerminatorKind::DropAndReplace { + place: dropped_place, + value, + target: _, + unwind: _, + } => { if let Some(place) = value.place() { - if !place.is_indirect() && !location.is_indirect() { + if !place.is_indirect() && !dropped_place.is_indirect() { self.record_local_conflict( place.local, - location.local, + dropped_place.local, "DropAndReplace operand overlap", ); } @@ -613,6 +618,7 @@ impl Conflicts<'a> { destination: Some((dest_place, _)), cleanup: _, from_hir_call: _, + fn_span: _, } => { // No arguments may overlap with the destination. for arg in args.iter().chain(Some(func)) { @@ -701,7 +707,7 @@ impl Conflicts<'a> { InlineAsmOperand::Out { reg: _, late: _, place: None } | InlineAsmOperand::Const { value: _ } | InlineAsmOperand::SymFn { value: _ } - | InlineAsmOperand::SymStatic { value: _ } => {} + | InlineAsmOperand::SymStatic { def_id: _ } => {} } } } @@ -717,7 +723,7 @@ impl Conflicts<'a> { | InlineAsmOperand::In { reg: _, value: _ } | InlineAsmOperand::Out { reg: _, late: _, place: None } | InlineAsmOperand::SymFn { value: _ } - | InlineAsmOperand::SymStatic { value: _ } => {} + | InlineAsmOperand::SymStatic { def_id: _ } => {} } } } @@ -732,7 +738,7 @@ impl Conflicts<'a> { | TerminatorKind::Drop { .. } | TerminatorKind::Assert { .. } | TerminatorKind::GeneratorDrop - | TerminatorKind::FalseEdges { .. } + | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } => {} } } @@ -759,7 +765,7 @@ impl Conflicts<'a> { } /// Merges the conflicts of `a` and `b`, so that each one inherits all conflicts of the other. - /// + /// /// `can_unify` must have returned `true` for the same locals, or this may panic or lead to /// miscompiles. /// From 7af964fecf77696e523020a430fd4a0d0d4bc190 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 24 Jun 2020 22:55:12 +0200 Subject: [PATCH 0629/1052] Limit block count --- compiler/rustc_mir/src/transform/dest_prop.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs index f9071ab9d802c..8080f4a0d6502 100644 --- a/compiler/rustc_mir/src/transform/dest_prop.rs +++ b/compiler/rustc_mir/src/transform/dest_prop.rs @@ -115,7 +115,12 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::{self, Ty, TyCtxt}; +// Empirical measurements have resulted in some observations: +// - Running on a body with a single block and 500 locals takes barely any time +// - Running on a body with ~400 blocks and ~300 relevant locals takes "too long" +// ...so we just limit both to somewhat reasonable-ish looking values. const MAX_LOCALS: usize = 500; +const MAX_BLOCKS: usize = 250; pub struct DestinationPropagation; @@ -160,6 +165,15 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { ); return; } + if body.basic_blocks().len() > MAX_BLOCKS { + warn!( + "too many blocks in {:?} ({}, max is {}), not optimizing", + source.def_id(), + body.basic_blocks().len(), + MAX_BLOCKS + ); + return; + } let mut conflicts = Conflicts::build(tcx, body, source, &relevant_locals); From cd5d7201ad1e5bf9d69e9a15e385ba03f678ad87 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 12 Sep 2020 15:18:50 +0200 Subject: [PATCH 0630/1052] Fix rebase fallout --- compiler/rustc_mir/src/transform/dest_prop.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs index 8080f4a0d6502..cb7b69e0231fb 100644 --- a/compiler/rustc_mir/src/transform/dest_prop.rs +++ b/compiler/rustc_mir/src/transform/dest_prop.rs @@ -588,11 +588,12 @@ impl Conflicts<'a> { } StatementKind::SetDiscriminant { .. } - | StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) - | StatementKind::Retag(_, _) - | StatementKind::FakeRead(_, _) - | StatementKind::AscribeUserType(_, _) + | StatementKind::StorageLive(..) + | StatementKind::StorageDead(..) + | StatementKind::Retag(..) + | StatementKind::FakeRead(..) + | StatementKind::AscribeUserType(..) + | StatementKind::Coverage(..) | StatementKind::Nop => {} } } From 682de94e315eac8be64423815edc4a0aa9e36539 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 12 Sep 2020 20:36:29 +0200 Subject: [PATCH 0631/1052] Move inner items outside --- compiler/rustc_mir/src/transform/dest_prop.rs | 288 +++++++++--------- 1 file changed, 144 insertions(+), 144 deletions(-) diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs index cb7b69e0231fb..c8e700909d7ae 100644 --- a/compiler/rustc_mir/src/transform/dest_prop.rs +++ b/compiler/rustc_mir/src/transform/dest_prop.rs @@ -858,98 +858,98 @@ fn find_candidates<'a, 'tcx>( tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, ) -> Vec> { - struct FindAssignments<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, - candidates: Vec>, - ever_borrowed_locals: BitSet, - locals_used_as_array_index: BitSet, - } + let mut visitor = FindAssignments { + tcx, + body, + candidates: Vec::new(), + ever_borrowed_locals: ever_borrowed_locals(body), + locals_used_as_array_index: locals_used_as_array_index(body), + }; + visitor.visit_body(body); + visitor.candidates +} - impl<'a, 'tcx> Visitor<'tcx> for FindAssignments<'a, 'tcx> { - fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - if let StatementKind::Assign(box ( - dest, - Rvalue::Use(Operand::Copy(src) | Operand::Move(src)), - )) = &statement.kind - { - // `dest` must not have pointer indirection. - if dest.is_indirect() { - return; - } +struct FindAssignments<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + candidates: Vec>, + ever_borrowed_locals: BitSet, + locals_used_as_array_index: BitSet, +} - // `src` must be a plain local. - if !src.projection.is_empty() { - return; - } +impl<'a, 'tcx> Visitor<'tcx> for FindAssignments<'a, 'tcx> { + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + if let StatementKind::Assign(box ( + dest, + Rvalue::Use(Operand::Copy(src) | Operand::Move(src)), + )) = &statement.kind + { + // `dest` must not have pointer indirection. + if dest.is_indirect() { + return; + } - // Since we want to replace `src` with `dest`, `src` must not be required. - if is_local_required(src.local, self.body) { - return; - } + // `src` must be a plain local. + if !src.projection.is_empty() { + return; + } - // Can't optimize if both locals ever have their address taken (can introduce - // aliasing). - // FIXME: This can be smarter and take `StorageDead` into account (which - // invalidates borrows). - if self.ever_borrowed_locals.contains(dest.local) - && self.ever_borrowed_locals.contains(src.local) - { - return; - } + // Since we want to replace `src` with `dest`, `src` must not be required. + if is_local_required(src.local, self.body) { + return; + } - assert_ne!(dest.local, src.local, "self-assignments are UB"); + // Can't optimize if both locals ever have their address taken (can introduce + // aliasing). + // FIXME: This can be smarter and take `StorageDead` into account (which + // invalidates borrows). + if self.ever_borrowed_locals.contains(dest.local) + && self.ever_borrowed_locals.contains(src.local) + { + return; + } - // We can't replace locals occurring in `PlaceElem::Index` for now. - if self.locals_used_as_array_index.contains(src.local) { - return; - } + assert_ne!(dest.local, src.local, "self-assignments are UB"); - // Handle the "subtle case" described above by rejecting any `dest` that is or - // projects through a union. - let is_union = |ty: Ty<'_>| { - if let ty::Adt(def, _) = ty.kind() { - if def.is_union() { - return true; - } + // We can't replace locals occurring in `PlaceElem::Index` for now. + if self.locals_used_as_array_index.contains(src.local) { + return; + } + + // Handle the "subtle case" described above by rejecting any `dest` that is or + // projects through a union. + let is_union = |ty: Ty<'_>| { + if let ty::Adt(def, _) = ty.kind() { + if def.is_union() { + return true; } + } - false - }; - let mut place_ty = PlaceTy::from_ty(self.body.local_decls[dest.local].ty); - if is_union(place_ty.ty) { + false + }; + let mut place_ty = PlaceTy::from_ty(self.body.local_decls[dest.local].ty); + if is_union(place_ty.ty) { + return; + } + for elem in dest.projection { + if let PlaceElem::Index(_) = elem { + // `dest` contains an indexing projection. return; } - for elem in dest.projection { - if let PlaceElem::Index(_) = elem { - // `dest` contains an indexing projection. - return; - } - place_ty = place_ty.projection_ty(self.tcx, elem); - if is_union(place_ty.ty) { - return; - } + place_ty = place_ty.projection_ty(self.tcx, elem); + if is_union(place_ty.ty) { + return; } - - self.candidates.push(CandidateAssignment { - dest: *dest, - src: src.local, - loc: location, - }); } + + self.candidates.push(CandidateAssignment { + dest: *dest, + src: src.local, + loc: location, + }); } } - - let mut visitor = FindAssignments { - tcx, - body, - candidates: Vec::new(), - ever_borrowed_locals: ever_borrowed_locals(body), - locals_used_as_array_index: locals_used_as_array_index(body), - }; - visitor.visit_body(body); - visitor.candidates } /// Some locals are part of the function's interface and can not be removed. @@ -965,64 +965,64 @@ fn is_local_required(local: Local, body: &Body<'_>) -> bool { /// Walks MIR to find all locals that have their address taken anywhere. fn ever_borrowed_locals(body: &Body<'_>) -> BitSet { - struct BorrowCollector { - locals: BitSet, - } + let mut visitor = BorrowCollector { locals: BitSet::new_empty(body.local_decls.len()) }; + visitor.visit_body(body); + visitor.locals +} - impl<'tcx> Visitor<'tcx> for BorrowCollector { - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { - self.super_rvalue(rvalue, location); +struct BorrowCollector { + locals: BitSet, +} - match rvalue { - Rvalue::AddressOf(_, borrowed_place) | Rvalue::Ref(_, _, borrowed_place) => { - if !borrowed_place.is_indirect() { - self.locals.insert(borrowed_place.local); - } - } +impl<'tcx> Visitor<'tcx> for BorrowCollector { + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + self.super_rvalue(rvalue, location); - Rvalue::Cast(..) - | Rvalue::Use(..) - | Rvalue::Repeat(..) - | Rvalue::Len(..) - | Rvalue::BinaryOp(..) - | Rvalue::CheckedBinaryOp(..) - | Rvalue::NullaryOp(..) - | Rvalue::UnaryOp(..) - | Rvalue::Discriminant(..) - | Rvalue::Aggregate(..) - | Rvalue::ThreadLocalRef(..) => {} + match rvalue { + Rvalue::AddressOf(_, borrowed_place) | Rvalue::Ref(_, _, borrowed_place) => { + if !borrowed_place.is_indirect() { + self.locals.insert(borrowed_place.local); + } } - } - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - self.super_terminator(terminator, location); + Rvalue::Cast(..) + | Rvalue::Use(..) + | Rvalue::Repeat(..) + | Rvalue::Len(..) + | Rvalue::BinaryOp(..) + | Rvalue::CheckedBinaryOp(..) + | Rvalue::NullaryOp(..) + | Rvalue::UnaryOp(..) + | Rvalue::Discriminant(..) + | Rvalue::Aggregate(..) + | Rvalue::ThreadLocalRef(..) => {} + } + } - match terminator.kind { - TerminatorKind::Drop { place: dropped_place, .. } - | TerminatorKind::DropAndReplace { place: dropped_place, .. } => { - self.locals.insert(dropped_place.local); - } + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + self.super_terminator(terminator, location); - TerminatorKind::Abort - | TerminatorKind::Assert { .. } - | TerminatorKind::Call { .. } - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::GeneratorDrop - | TerminatorKind::Goto { .. } - | TerminatorKind::Resume - | TerminatorKind::Return - | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Unreachable - | TerminatorKind::Yield { .. } - | TerminatorKind::InlineAsm { .. } => {} + match terminator.kind { + TerminatorKind::Drop { place: dropped_place, .. } + | TerminatorKind::DropAndReplace { place: dropped_place, .. } => { + self.locals.insert(dropped_place.local); } + + TerminatorKind::Abort + | TerminatorKind::Assert { .. } + | TerminatorKind::Call { .. } + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::Return + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::Unreachable + | TerminatorKind::Yield { .. } + | TerminatorKind::InlineAsm { .. } => {} } } - - let mut visitor = BorrowCollector { locals: BitSet::new_empty(body.local_decls.len()) }; - visitor.visit_body(body); - visitor.locals } /// `PlaceElem::Index` only stores a `Local`, so we can't replace that with a full `Place`. @@ -1030,27 +1030,27 @@ fn ever_borrowed_locals(body: &Body<'_>) -> BitSet { /// Collect locals used as indices so we don't generate candidates that are impossible to apply /// later. fn locals_used_as_array_index(body: &Body<'_>) -> BitSet { - struct IndexCollector { - locals: BitSet, - } - - impl<'tcx> Visitor<'tcx> for IndexCollector { - fn visit_projection_elem( - &mut self, - local: Local, - proj_base: &[PlaceElem<'tcx>], - elem: PlaceElem<'tcx>, - context: PlaceContext, - location: Location, - ) { - if let PlaceElem::Index(i) = elem { - self.locals.insert(i); - } - self.super_projection_elem(local, proj_base, elem, context, location); - } - } - let mut visitor = IndexCollector { locals: BitSet::new_empty(body.local_decls.len()) }; visitor.visit_body(body); visitor.locals } + +struct IndexCollector { + locals: BitSet, +} + +impl<'tcx> Visitor<'tcx> for IndexCollector { + fn visit_projection_elem( + &mut self, + local: Local, + proj_base: &[PlaceElem<'tcx>], + elem: PlaceElem<'tcx>, + context: PlaceContext, + location: Location, + ) { + if let PlaceElem::Index(i) = elem { + self.locals.insert(i); + } + self.super_projection_elem(local, proj_base, elem, context, location); + } +} From ffd9445812cf8dc10a12f62db5135a0a17e066f5 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Thu, 17 Sep 2020 22:17:09 +0200 Subject: [PATCH 0632/1052] Return `Place` by value --- compiler/rustc_mir/src/transform/dest_prop.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs index c8e700909d7ae..d1c98354e0590 100644 --- a/compiler/rustc_mir/src/transform/dest_prop.rs +++ b/compiler/rustc_mir/src/transform/dest_prop.rs @@ -285,8 +285,8 @@ impl Replacements<'tcx> { } } - fn for_src(&self, src: Local) -> Option<&Place<'tcx>> { - self.map[src].as_ref() + fn for_src(&self, src: Local) -> Option> { + self.map[src] } } From 2f9271b14c9ec0e5ed72ec91c2e24e850c580f83 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Thu, 17 Sep 2020 22:19:24 +0200 Subject: [PATCH 0633/1052] Clarify FIXME --- compiler/rustc_mir/src/transform/dest_prop.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs index d1c98354e0590..46cbced2d54bc 100644 --- a/compiler/rustc_mir/src/transform/dest_prop.rs +++ b/compiler/rustc_mir/src/transform/dest_prop.rs @@ -44,8 +44,9 @@ //! and performing the optimization would simply delete the assignment, leaving `dest` //! uninitialized. //! -//! * `src` must be a bare `Local` without any indirections or field projections (FIXME: Why?). -//! It can be copied or moved by the assignment. +//! * `src` must be a bare `Local` without any indirections or field projections (FIXME: Is this a +//! fundamental restriction or just current impl state?). It can be copied or moved by the +//! assignment. //! //! * The `dest` and `src` locals must never be [*live*][liveness] at the same time. If they are, it //! means that they both hold a (potentially different) value that is needed by a future use of From 3f68ae47df90d2803c849503a4cbdb2bb3dbb9a6 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 8 Sep 2020 20:17:23 +0200 Subject: [PATCH 0634/1052] Add `BITS` associated constant to all integer types. --- library/core/src/num/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 050c187e55576..33bcf93676b2a 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -348,6 +348,10 @@ $EndFeature, " pub const MAX: Self = !Self::MIN; } + /// The size of this integer type in bits. + #[unstable(feature = "int_bits_const", issue = "none")] + pub const BITS: u32 = $BITS; + doc_comment! { concat!("Converts a string slice in a given base to an integer. @@ -2601,6 +2605,10 @@ $EndFeature, " pub const MAX: Self = !0; } + /// The size of this integer type in bits. + #[unstable(feature = "int_bits_const", issue = "none")] + pub const BITS: u32 = $BITS; + doc_comment! { concat!("Converts a string slice in a given base to an integer. From 5c30a16fa03efaf87241b363f4323743746c12b0 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 8 Sep 2020 20:24:55 +0200 Subject: [PATCH 0635/1052] Add example/test to ::BITS. --- library/core/src/num/mod.rs | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 33bcf93676b2a..5df67a5f53df7 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -348,9 +348,19 @@ $EndFeature, " pub const MAX: Self = !Self::MIN; } - /// The size of this integer type in bits. - #[unstable(feature = "int_bits_const", issue = "none")] - pub const BITS: u32 = $BITS; + doc_comment! { + concat!("The size of this integer type in bits. + +# Examples + +``` +", $Feature, "#![feature(int_bits_const)] +assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");", +$EndFeature, " +```"), + #[unstable(feature = "int_bits_const", issue = "none")] + pub const BITS: u32 = $BITS; + } doc_comment! { concat!("Converts a string slice in a given base to an integer. @@ -2605,9 +2615,19 @@ $EndFeature, " pub const MAX: Self = !0; } - /// The size of this integer type in bits. - #[unstable(feature = "int_bits_const", issue = "none")] - pub const BITS: u32 = $BITS; + doc_comment! { + concat!("The size of this integer type in bits. + +# Examples + +``` +", $Feature, "#![feature(int_bits_const)] +assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");", +$EndFeature, " +```"), + #[unstable(feature = "int_bits_const", issue = "none")] + pub const BITS: u32 = $BITS; + } doc_comment! { concat!("Converts a string slice in a given base to an integer. From 1e2dba1e7cf15442257f2cd3ddfe5d0462ee9102 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 8 Sep 2020 21:39:13 +0200 Subject: [PATCH 0636/1052] Use `T::BITS` instead of `size_of:: * 8`. --- compiler/rustc_data_structures/src/lib.rs | 1 + .../src/tagged_ptr/copy.rs | 2 +- library/alloc/src/collections/binary_heap.rs | 4 +-- library/alloc/src/lib.rs | 1 + library/alloc/src/raw_vec.rs | 2 +- library/alloc/tests/lib.rs | 1 + library/alloc/tests/string.rs | 5 ++- library/alloc/tests/vec.rs | 2 +- library/core/src/fmt/mod.rs | 2 +- library/core/src/num/bignum.rs | 34 +++++-------------- library/core/src/slice/sort.rs | 6 ++-- library/core/tests/iter.rs | 2 +- library/core/tests/lib.rs | 1 + library/core/tests/num/int_macros.rs | 20 +++++------ library/core/tests/num/uint_macros.rs | 20 +++++------ library/panic_unwind/src/dwarf/mod.rs | 4 +-- library/panic_unwind/src/lib.rs | 1 + 17 files changed, 44 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 88c160e93b66a..06718cc980312 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -14,6 +14,7 @@ #![feature(generators)] #![feature(generator_trait)] #![feature(fn_traits)] +#![feature(int_bits_const)] #![feature(min_specialization)] #![feature(optin_builtin_traits)] #![feature(nll)] diff --git a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs index d39d146db318f..d63bcdb3c2b04 100644 --- a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs @@ -48,7 +48,7 @@ where P: Pointer, T: Tag, { - const TAG_BIT_SHIFT: usize = (8 * std::mem::size_of::()) - T::BITS; + const TAG_BIT_SHIFT: usize = usize::BITS as usize - T::BITS; const ASSERTION: () = { assert!(T::BITS <= P::BITS); // Used for the transmute_copy's below diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index 24d17fdd880ba..8a7dd9d4249a8 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -146,7 +146,7 @@ use core::fmt; use core::iter::{FromIterator, FusedIterator, InPlaceIterable, SourceIter, TrustedLen}; -use core::mem::{self, size_of, swap, ManuallyDrop}; +use core::mem::{self, swap, ManuallyDrop}; use core::ops::{Deref, DerefMut}; use core::ptr; @@ -617,7 +617,7 @@ impl BinaryHeap { #[inline(always)] fn log2_fast(x: usize) -> usize { - 8 * size_of::() - (x.leading_zeros() as usize) - 1 + (usize::BITS - x.leading_zeros() - 1) as usize } // `rebuild` takes O(len1 + len2) operations diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 7881c101f9f60..f3c1eee47c721 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -101,6 +101,7 @@ #![feature(fn_traits)] #![feature(fundamental)] #![feature(inplace_iteration)] +#![feature(int_bits_const)] #![feature(lang_items)] #![feature(layout_for_ptr)] #![feature(libc)] diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 05382d0b5594e..62675665f037f 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -528,7 +528,7 @@ unsafe impl<#[may_dangle] T, A: AllocRef> Drop for RawVec { #[inline] fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> { - if mem::size_of::() < 8 && alloc_size > isize::MAX as usize { + if usize::BITS < 64 && alloc_size > isize::MAX as usize { Err(CapacityOverflow) } else { Ok(()) diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 03737e1ef1f4d..3ee0cfbe74759 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -18,6 +18,7 @@ #![feature(deque_range)] #![feature(inplace_iteration)] #![feature(iter_map_while)] +#![feature(int_bits_const)] use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs index 4e6043541226f..a6e41b21b618c 100644 --- a/library/alloc/tests/string.rs +++ b/library/alloc/tests/string.rs @@ -1,6 +1,5 @@ use std::borrow::Cow; use std::collections::TryReserveError::*; -use std::mem::size_of; use std::ops::Bound::*; pub trait IntoCow<'a, B: ?Sized> @@ -605,7 +604,7 @@ fn test_try_reserve() { // on 64-bit, we assume the OS will give an OOM for such a ridiculous size. // Any platform that succeeds for these requests is technically broken with // ptr::offset because LLVM is the worst. - let guards_against_isize = size_of::() < 8; + let guards_against_isize = usize::BITS < 64; { // Note: basic stuff is checked by test_reserve @@ -686,7 +685,7 @@ fn test_try_reserve_exact() { const MAX_CAP: usize = isize::MAX as usize; const MAX_USIZE: usize = usize::MAX; - let guards_against_isize = size_of::() < 8; + let guards_against_isize = usize::BITS < 64; { let mut empty_string: String = String::new(); diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 368ca4c543219..a49ca7c256a75 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -1341,7 +1341,7 @@ fn test_try_reserve() { // on 64-bit, we assume the OS will give an OOM for such a ridiculous size. // Any platform that succeeds for these requests is technically broken with // ptr::offset because LLVM is the worst. - let guards_against_isize = size_of::() < 8; + let guards_against_isize = usize::BITS < 64; { // Note: basic stuff is checked by test_reserve diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 48b7f2739eeb2..8558cb5a5e8a3 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -2086,7 +2086,7 @@ impl Pointer for *const T { f.flags |= 1 << (FlagV1::SignAwareZeroPad as u32); if f.width.is_none() { - f.width = Some(((mem::size_of::() * 8) / 4) + 2); + f.width = Some((usize::BITS / 4) as usize + 2); } } f.flags |= 1 << (FlagV1::Alternate as u32); diff --git a/library/core/src/num/bignum.rs b/library/core/src/num/bignum.rs index 6f16b93d0488a..6a1a1e1976160 100644 --- a/library/core/src/num/bignum.rs +++ b/library/core/src/num/bignum.rs @@ -20,7 +20,6 @@ #![macro_use] use crate::intrinsics; -use crate::mem; /// Arithmetic operations required by bignums. pub trait FullOps: Sized { @@ -58,25 +57,22 @@ macro_rules! impl_full_ops { // This cannot overflow; // the output is between `0` and `2^nbits * (2^nbits - 1)`. // FIXME: will LLVM optimize this into ADC or similar? - let nbits = mem::size_of::<$ty>() * 8; let v = (self as $bigty) * (other as $bigty) + (carry as $bigty); - ((v >> nbits) as $ty, v as $ty) + ((v >> <$ty>::BITS) as $ty, v as $ty) } fn full_mul_add(self, other: $ty, other2: $ty, carry: $ty) -> ($ty, $ty) { // This cannot overflow; // the output is between `0` and `2^nbits * (2^nbits - 1)`. - let nbits = mem::size_of::<$ty>() * 8; let v = (self as $bigty) * (other as $bigty) + (other2 as $bigty) + (carry as $bigty); - ((v >> nbits) as $ty, v as $ty) + ((v >> <$ty>::BITS) as $ty, v as $ty) } fn full_div_rem(self, other: $ty, borrow: $ty) -> ($ty, $ty) { debug_assert!(borrow < other); // This cannot overflow; the output is between `0` and `other * (2^nbits - 1)`. - let nbits = mem::size_of::<$ty>() * 8; - let lhs = ((borrow as $bigty) << nbits) | (self as $bigty); + let lhs = ((borrow as $bigty) << <$ty>::BITS) | (self as $bigty); let rhs = other as $bigty; ((lhs / rhs) as $ty, (lhs % rhs) as $ty) } @@ -128,13 +124,11 @@ macro_rules! define_bignum { /// Makes a bignum from `u64` value. pub fn from_u64(mut v: u64) -> $name { - use crate::mem; - let mut base = [0; $n]; let mut sz = 0; while v > 0 { base[sz] = v as $ty; - v >>= mem::size_of::<$ty>() * 8; + v >>= <$ty>::BITS; sz += 1; } $name { size: sz, base: base } @@ -150,9 +144,7 @@ macro_rules! define_bignum { /// Returns the `i`-th bit where bit 0 is the least significant one. /// In other words, the bit with weight `2^i`. pub fn get_bit(&self, i: usize) -> u8 { - use crate::mem; - - let digitbits = mem::size_of::<$ty>() * 8; + let digitbits = <$ty>::BITS as usize; let d = i / digitbits; let b = i % digitbits; ((self.base[d] >> b) & 1) as u8 @@ -166,8 +158,6 @@ macro_rules! define_bignum { /// Returns the number of bits necessary to represent this value. Note that zero /// is considered to need 0 bits. pub fn bit_length(&self) -> usize { - use crate::mem; - // Skip over the most significant digits which are zero. let digits = self.digits(); let zeros = digits.iter().rev().take_while(|&&x| x == 0).count(); @@ -180,7 +170,7 @@ macro_rules! define_bignum { } // This could be optimized with leading_zeros() and bit shifts, but that's // probably not worth the hassle. - let digitbits = mem::size_of::<$ty>() * 8; + let digitbits = <$ty>::BITS as usize; let mut i = nonzero.len() * digitbits - 1; while self.get_bit(i) == 0 { i -= 1; @@ -265,9 +255,7 @@ macro_rules! define_bignum { /// Multiplies itself by `2^bits` and returns its own mutable reference. pub fn mul_pow2(&mut self, bits: usize) -> &mut $name { - use crate::mem; - - let digitbits = mem::size_of::<$ty>() * 8; + let digitbits = <$ty>::BITS as usize; let digits = bits / digitbits; let bits = bits % digitbits; @@ -393,13 +381,11 @@ macro_rules! define_bignum { /// Divide self by another bignum, overwriting `q` with the quotient and `r` with the /// remainder. pub fn div_rem(&self, d: &$name, q: &mut $name, r: &mut $name) { - use crate::mem; - // Stupid slow base-2 long division taken from // https://en.wikipedia.org/wiki/Division_algorithm // FIXME use a greater base ($ty) for the long division. assert!(!d.is_zero()); - let digitbits = mem::size_of::<$ty>() * 8; + let digitbits = <$ty>::BITS as usize; for digit in &mut q.base[..] { *digit = 0; } @@ -462,10 +448,8 @@ macro_rules! define_bignum { impl crate::fmt::Debug for $name { fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { - use crate::mem; - let sz = if self.size < 1 { 1 } else { self.size }; - let digitlen = mem::size_of::<$ty>() * 2; + let digitlen = <$ty>::BITS as usize / 4; write!(f, "{:#x}", self.base[sz - 1])?; for &v in self.base[..sz - 1].iter().rev() { diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs index 8c14651bd826c..71d2c2c9b2f4c 100644 --- a/library/core/src/slice/sort.rs +++ b/library/core/src/slice/sort.rs @@ -565,7 +565,7 @@ fn break_patterns(v: &mut [T]) { random }; let mut gen_usize = || { - if mem::size_of::() <= 4 { + if usize::BITS <= 32 { gen_u32() as usize } else { (((gen_u32() as u64) << 32) | (gen_u32() as u64)) as usize @@ -667,7 +667,7 @@ where /// /// `limit` is the number of allowed imbalanced partitions before switching to `heapsort`. If zero, /// this function will immediately switch to heapsort. -fn recurse<'a, T, F>(mut v: &'a mut [T], is_less: &mut F, mut pred: Option<&'a T>, mut limit: usize) +fn recurse<'a, T, F>(mut v: &'a mut [T], is_less: &mut F, mut pred: Option<&'a T>, mut limit: u32) where F: FnMut(&T, &T) -> bool, { @@ -763,7 +763,7 @@ where } // Limit the number of imbalanced partitions to `floor(log2(len)) + 1`. - let limit = mem::size_of::() * 8 - v.len().leading_zeros() as usize; + let limit = usize::BITS - v.len().leading_zeros(); recurse(v, &mut is_less, None, limit); } diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs index 00e3972c42f9d..0eb9af3f454e9 100644 --- a/library/core/tests/iter.rs +++ b/library/core/tests/iter.rs @@ -474,7 +474,7 @@ fn test_iterator_step_by_nth_overflow() { } let mut it = Test(0); - let root = usize::MAX >> (::std::mem::size_of::() * 8 / 2); + let root = usize::MAX >> (usize::BITS / 2); let n = root + 20; (&mut it).step_by(n).nth(n); assert_eq!(it.0, n as Bigger * n as Bigger); diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index a5b1b51e06c64..4db391f3e567e 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -52,6 +52,7 @@ #![feature(partition_point)] #![feature(once_cell)] #![feature(unsafe_block_in_unsafe_fn)] +#![feature(int_bits_const)] #![deny(unsafe_op_in_unsafe_fn)] extern crate test; diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs index 58a585669122c..27e6760e7cbb9 100644 --- a/library/core/tests/num/int_macros.rs +++ b/library/core/tests/num/int_macros.rs @@ -2,7 +2,6 @@ macro_rules! int_module { ($T:ident, $T_i:ident) => { #[cfg(test)] mod tests { - use core::mem; use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; use core::$T_i::*; @@ -82,30 +81,27 @@ macro_rules! int_module { #[test] fn test_count_zeros() { - let bits = mem::size_of::<$T>() * 8; - assert_eq!(A.count_zeros(), bits as u32 - 3); - assert_eq!(B.count_zeros(), bits as u32 - 2); - assert_eq!(C.count_zeros(), bits as u32 - 5); + assert_eq!(A.count_zeros(), $T::BITS - 3); + assert_eq!(B.count_zeros(), $T::BITS - 2); + assert_eq!(C.count_zeros(), $T::BITS - 5); } #[test] fn test_leading_trailing_ones() { - let bits = (mem::size_of::<$T>() * 8) as u32; - let a: $T = 0b0101_1111; assert_eq!(a.trailing_ones(), 5); - assert_eq!((!a).leading_ones(), bits - 7); + assert_eq!((!a).leading_ones(), $T::BITS - 7); assert_eq!(a.reverse_bits().leading_ones(), 5); - assert_eq!(_1.leading_ones(), bits); - assert_eq!(_1.trailing_ones(), bits); + assert_eq!(_1.leading_ones(), $T::BITS); + assert_eq!(_1.trailing_ones(), $T::BITS); assert_eq!((_1 << 1).trailing_ones(), 0); assert_eq!(MAX.leading_ones(), 0); - assert_eq!((_1 << 1).leading_ones(), bits - 1); - assert_eq!(MAX.trailing_ones(), bits - 1); + assert_eq!((_1 << 1).leading_ones(), $T::BITS - 1); + assert_eq!(MAX.trailing_ones(), $T::BITS - 1); assert_eq!(_0.leading_ones(), 0); assert_eq!(_0.trailing_ones(), 0); diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs index b84a8a7d9f88b..952ec188dc138 100644 --- a/library/core/tests/num/uint_macros.rs +++ b/library/core/tests/num/uint_macros.rs @@ -4,7 +4,6 @@ macro_rules! uint_module { mod tests { use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; use core::$T_i::*; - use std::mem; use std::str::FromStr; use crate::num; @@ -47,30 +46,27 @@ macro_rules! uint_module { #[test] fn test_count_zeros() { - let bits = mem::size_of::<$T>() * 8; - assert!(A.count_zeros() == bits as u32 - 3); - assert!(B.count_zeros() == bits as u32 - 2); - assert!(C.count_zeros() == bits as u32 - 5); + assert!(A.count_zeros() == $T::BITS - 3); + assert!(B.count_zeros() == $T::BITS - 2); + assert!(C.count_zeros() == $T::BITS - 5); } #[test] fn test_leading_trailing_ones() { - let bits = (mem::size_of::<$T>() * 8) as u32; - let a: $T = 0b0101_1111; assert_eq!(a.trailing_ones(), 5); - assert_eq!((!a).leading_ones(), bits - 7); + assert_eq!((!a).leading_ones(), $T::BITS - 7); assert_eq!(a.reverse_bits().leading_ones(), 5); - assert_eq!(_1.leading_ones(), bits); - assert_eq!(_1.trailing_ones(), bits); + assert_eq!(_1.leading_ones(), $T::BITS); + assert_eq!(_1.trailing_ones(), $T::BITS); assert_eq!((_1 << 1).trailing_ones(), 0); assert_eq!((_1 >> 1).leading_ones(), 0); - assert_eq!((_1 << 1).leading_ones(), bits - 1); - assert_eq!((_1 >> 1).trailing_ones(), bits - 1); + assert_eq!((_1 << 1).leading_ones(), $T::BITS - 1); + assert_eq!((_1 >> 1).trailing_ones(), $T::BITS - 1); assert_eq!(_0.leading_ones(), 0); assert_eq!(_0.trailing_ones(), 0); diff --git a/library/panic_unwind/src/dwarf/mod.rs b/library/panic_unwind/src/dwarf/mod.rs index 649bbce52a364..652fbe95a14d1 100644 --- a/library/panic_unwind/src/dwarf/mod.rs +++ b/library/panic_unwind/src/dwarf/mod.rs @@ -53,7 +53,7 @@ impl DwarfReader { } pub unsafe fn read_sleb128(&mut self) -> i64 { - let mut shift: usize = 0; + let mut shift: u32 = 0; let mut result: u64 = 0; let mut byte: u8; loop { @@ -65,7 +65,7 @@ impl DwarfReader { } } // sign-extend - if shift < 8 * mem::size_of::() && (byte & 0x40) != 0 { + if shift < u64::BITS && (byte & 0x40) != 0 { result |= (!0 as u64) << shift; } result as i64 diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index 6f31e6dcae70d..162f0386b6692 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -18,6 +18,7 @@ issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/" )] #![feature(core_intrinsics)] +#![feature(int_bits_const)] #![feature(lang_items)] #![feature(libc)] #![feature(nll)] From 1bfe5efe8f635268646da91f1f4f6e616104b71f Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 19 Sep 2020 08:14:41 +0200 Subject: [PATCH 0637/1052] Add tracking issue number for int_bits_const. --- library/core/src/num/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 5df67a5f53df7..eec149cc3e801 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -358,7 +358,7 @@ $EndFeature, " assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");", $EndFeature, " ```"), - #[unstable(feature = "int_bits_const", issue = "none")] + #[unstable(feature = "int_bits_const", issue = "76904")] pub const BITS: u32 = $BITS; } @@ -2625,7 +2625,7 @@ $EndFeature, " assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");", $EndFeature, " ```"), - #[unstable(feature = "int_bits_const", issue = "none")] + #[unstable(feature = "int_bits_const", issue = "76904")] pub const BITS: u32 = $BITS; } From 15eb638dc9c9f663ab9e596a838c33821ae7f772 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 19 Sep 2020 08:23:23 +0200 Subject: [PATCH 0638/1052] Add tracking issue number for string_drain_as_str. --- library/alloc/src/string.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index b9506281ed629..ed6443da830d0 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2475,21 +2475,21 @@ impl<'a> Drain<'a> { /// let _ = drain.next().unwrap(); /// assert_eq!(drain.as_str(), "bc"); /// ``` - #[unstable(feature = "string_drain_as_str", issue = "none")] // Note: uncomment AsRef impls below when stabilizing. + #[unstable(feature = "string_drain_as_str", issue = "76905")] // Note: uncomment AsRef impls below when stabilizing. pub fn as_str(&self) -> &str { self.iter.as_str() } } // Uncomment when stabilizing `string_drain_as_str`. -// #[unstable(feature = "string_drain_as_str", issue = "none")] +// #[unstable(feature = "string_drain_as_str", issue = "76905")] // impl<'a> AsRef for Drain<'a> { // fn as_ref(&self) -> &str { // self.as_str() // } // } // -// #[unstable(feature = "string_drain_as_str", issue = "none")] +// #[unstable(feature = "string_drain_as_str", issue = "76905")] // impl<'a> AsRef<[u8]> for Drain<'a> { // fn as_ref(&self) -> &[u8] { // self.as_str().as_bytes() From 083f1d7a37a5b439c1b9325e7860ef4fd880d418 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 30 Jul 2020 17:58:39 +0200 Subject: [PATCH 0639/1052] Validate constants during `const_eval_raw` --- .../rustc_mir/src/const_eval/eval_queries.rs | 51 +++++++++++++------ compiler/rustc_mir/src/interpret/validity.rs | 18 ++++--- .../ui/consts/const-eval/double_check2.rs | 23 ++++++--- .../ui/consts/const-eval/double_check2.stderr | 22 -------- 4 files changed, 62 insertions(+), 52 deletions(-) delete mode 100644 src/test/ui/consts/const-eval/double_check2.stderr diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index 72151df7230be..dd2731fb0a016 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -193,21 +193,7 @@ fn validate_and_turn_into_const<'tcx>( let ecx = mk_eval_cx(tcx, tcx.def_span(key.value.instance.def_id()), key.param_env, is_static); let val = (|| { let mplace = ecx.raw_const_to_mplace(constant)?; - - // FIXME do not validate promoteds until a decision on - // https://github.com/rust-lang/rust/issues/67465 is made - if cid.promoted.is_none() { - let mut ref_tracking = RefTracking::new(mplace); - while let Some((mplace, path)) = ref_tracking.todo.pop() { - ecx.const_validate_operand( - mplace.into(), - path, - &mut ref_tracking, - /*may_ref_to_static*/ ecx.memory.extra.can_access_statics, - )?; - } - } - // Now that we validated, turn this into a proper constant. + // Turn this into a proper constant. // Statics/promoteds are always `ByRef`, for the rest `op_to_const` decides // whether they become immediates. if is_static || cid.promoted.is_some() { @@ -221,6 +207,7 @@ fn validate_and_turn_into_const<'tcx>( } })(); + // FIXME: Can this ever be an error and not be a compiler bug or can we just ICE here? val.map_err(|error| { let err = ConstEvalErr::new(&ecx, error, None); err.struct_error(ecx.tcx, "it is undefined behavior to use this value", |mut diag| { @@ -319,7 +306,6 @@ pub fn const_eval_raw_provider<'tcx>( let res = ecx.load_mir(cid.instance.def, cid.promoted); res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) - .map(|place| RawConst { alloc_id: place.ptr.assert_ptr().alloc_id, ty: place.layout.ty }) .map_err(|error| { let err = ConstEvalErr::new(&ecx, error, None); // errors in statics are always emitted as fatal errors @@ -397,4 +383,37 @@ pub fn const_eval_raw_provider<'tcx>( err.report_as_error(ecx.tcx.at(ecx.cur_span()), "could not evaluate constant") } }) + .and_then(|mplace| { + // Since evaluation had no errors, valiate the resulting constant: + let validation = try { + // FIXME do not validate promoteds until a decision on + // https://github.com/rust-lang/rust/issues/67465 is made + if cid.promoted.is_none() { + let mut ref_tracking = RefTracking::new(mplace); + while let Some((mplace, path)) = ref_tracking.todo.pop() { + ecx.const_validate_operand( + mplace.into(), + path, + &mut ref_tracking, + /*may_ref_to_static*/ ecx.memory.extra.can_access_statics, + )?; + } + } + }; + if let Err(error) = validation { + // Validation failed, report an error + let err = ConstEvalErr::new(&ecx, error, None); + Err(err.struct_error( + ecx.tcx, + "it is undefined behavior to use this value", + |mut diag| { + diag.note(note_on_undefined_behavior_error()); + diag.emit(); + }, + )) + } else { + // Convert to raw constant + Ok(RawConst { alloc_id: mplace.ptr.assert_ptr().alloc_id, ty: mplace.layout.ty }) + } + }) } diff --git a/compiler/rustc_mir/src/interpret/validity.rs b/compiler/rustc_mir/src/interpret/validity.rs index ca62f0347ffac..7d9507c08fa18 100644 --- a/compiler/rustc_mir/src/interpret/validity.rs +++ b/compiler/rustc_mir/src/interpret/validity.rs @@ -425,26 +425,28 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' let alloc_kind = self.ecx.tcx.get_global_alloc(ptr.alloc_id); if let Some(GlobalAlloc::Static(did)) = alloc_kind { assert!(!self.ecx.tcx.is_thread_local_static(did)); + assert!(self.ecx.tcx.is_static(did)); // See const_eval::machine::MemoryExtra::can_access_statics for why // this check is so important. // This check is reachable when the const just referenced the static, // but never read it (so we never entered `before_access_global`). // We also need to do it here instead of going on to avoid running // into the `before_access_global` check during validation. - if !self.may_ref_to_static && self.ecx.tcx.is_static(did) { + if !self.may_ref_to_static { throw_validation_failure!(self.path, { "a {} pointing to a static variable", kind } ); } - // `extern static` cannot be validated as they have no body. - // FIXME: Statics from other crates are also skipped. - // They might be checked at a different type, but for now we - // want to avoid recursing too deeply. We might miss const-invalid data, + // We skip checking other statics. These statics must be sound by themselves, + // and the only way to get broken statics here is by using unsafe code. + // The reasons we don't check other statics is twofold. For one, in all sound + // cases, the static was already validated on its own, and second, we trigger + // cycle errors if we try to compute the value of the other static and that + // static refers back to us. + // We might miss const-invalid data, // but things are still sound otherwise (in particular re: consts // referring to statics). - if !did.is_local() || self.ecx.tcx.is_foreign_item(did) { - return Ok(()); - } + return Ok(()); } } // Proceed recursively even for ZST, no reason to skip them! diff --git a/src/test/ui/consts/const-eval/double_check2.rs b/src/test/ui/consts/const-eval/double_check2.rs index 8402d62885664..e1f3e5bb27a8f 100644 --- a/src/test/ui/consts/const-eval/double_check2.rs +++ b/src/test/ui/consts/const-eval/double_check2.rs @@ -1,3 +1,11 @@ +// check-pass + +// This test exhibits undefined behavior, but it is impossible to prevent generally during +// const eval, even if possible to prevent in the cases here. The reason it's impossible in general +// is that we run into query cycles even *without* UB, just because we're checking for UB. +// We do not detect it if you create references to statics +// in ways that are UB. + enum Foo { A = 5, B = 42, @@ -13,11 +21,14 @@ union Union { u8: &'static u8, } static BAR: u8 = 5; -static FOO: (&Foo, &Bar) = unsafe {( //~ undefined behavior - Union { u8: &BAR }.foo, - Union { u8: &BAR }.bar, -)}; -static FOO2: (&Foo, &Bar) = unsafe {(std::mem::transmute(&BAR), std::mem::transmute(&BAR))}; -//~^ undefined behavior +static FOO: (&Foo, &Bar) = unsafe { + ( + // undefined behavior + Union { u8: &BAR }.foo, + Union { u8: &BAR }.bar, + ) +}; +static FOO2: (&Foo, &Bar) = unsafe { (std::mem::transmute(&BAR), std::mem::transmute(&BAR)) }; +//^ undefined behavior fn main() {} diff --git a/src/test/ui/consts/const-eval/double_check2.stderr b/src/test/ui/consts/const-eval/double_check2.stderr deleted file mode 100644 index 84f60809156d0..0000000000000 --- a/src/test/ui/consts/const-eval/double_check2.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0080]: it is undefined behavior to use this value - --> $DIR/double_check2.rs:16:1 - | -LL | / static FOO: (&Foo, &Bar) = unsafe {( -LL | | Union { u8: &BAR }.foo, -LL | | Union { u8: &BAR }.bar, -LL | | )}; - | |___^ type validation failed: encountered 0x05 at .1.., but expected a valid enum tag - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - -error[E0080]: it is undefined behavior to use this value - --> $DIR/double_check2.rs:20:1 - | -LL | static FOO2: (&Foo, &Bar) = unsafe {(std::mem::transmute(&BAR), std::mem::transmute(&BAR))}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x05 at .1.., but expected a valid enum tag - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0080`. From 2d7ac728e4ce2aa1a77068e1f668be71d10116a0 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 31 Jul 2020 13:27:54 +0200 Subject: [PATCH 0640/1052] Stop using the `const_eval` query for initializers of statics As a side effect, we now represent most promoteds as `ConstValue::Scalar` again. This is useful because all implict promoteds are just references anyway and most explicit promoteds are numeric arguments to `asm!` or SIMD instructions. --- compiler/rustc_codegen_llvm/src/consts.rs | 7 ++--- compiler/rustc_codegen_ssa/src/mir/block.rs | 26 +++++----------- compiler/rustc_lint/src/builtin.rs | 15 ++++----- .../rustc_mir/src/const_eval/eval_queries.rs | 31 +++++++------------ .../rustc_mir/src/interpret/eval_context.rs | 7 ----- compiler/rustc_mir/src/interpret/operand.rs | 8 ++--- .../rustc_mir/src/monomorphize/collector.rs | 6 ++-- compiler/rustc_mir/src/util/pretty.rs | 7 ++--- compiler/rustc_typeck/src/check/mod.rs | 6 ++-- ...nst-pointer-values-in-various-types.stderr | 12 +++---- src/test/ui/consts/const-eval/ub-enum.stderr | 8 ++--- .../ui/consts/const-eval/ub-nonnull.stderr | 2 +- src/test/ui/consts/const-eval/ub-ref.stderr | 2 +- .../recursive-zst-static.default.stderr | 6 +--- .../recursive-zst-static.unleash.stderr | 6 +--- .../recursive-static-definition.stderr | 6 +--- .../ui/write-to-static-mut-in-static.stderr | 6 +--- 17 files changed, 53 insertions(+), 108 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 2b2bcd979999f..dc09790df0295 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -12,7 +12,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::Node; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::interpret::{ - read_target_uint, Allocation, ConstValue, ErrorHandled, GlobalAlloc, Pointer, + read_target_uint, Allocation, ErrorHandled, GlobalAlloc, Pointer, }; use rustc_middle::mir::mono::MonoItem; use rustc_middle::ty::{self, Instance, Ty}; @@ -85,10 +85,7 @@ pub fn codegen_static_initializer( cx: &CodegenCx<'ll, 'tcx>, def_id: DefId, ) -> Result<(&'ll Value, &'tcx Allocation), ErrorHandled> { - let alloc = match cx.tcx.const_eval_poly(def_id)? { - ConstValue::ByRef { alloc, offset } if offset.bytes() == 0 => alloc, - val => bug!("static const eval returned {:#?}", val), - }; + let alloc = cx.tcx.eval_static_initializer(def_id)?; Ok((const_alloc_to_llvm(cx, alloc), alloc)) } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 4639ce4a5ab5b..23269f7245da6 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -13,7 +13,7 @@ use rustc_ast as ast; use rustc_hir::lang_items::LangItem; use rustc_index::vec::Idx; use rustc_middle::mir; -use rustc_middle::mir::interpret::{AllocId, ConstValue, Pointer, Scalar}; +use rustc_middle::mir::interpret::ConstValue; use rustc_middle::mir::AssertKind; use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt}; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -867,24 +867,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let ty = constant.literal.ty; let size = bx.layout_of(ty).size; let scalar = match const_value { - // Promoted constants are evaluated into a ByRef instead of a Scalar, - // but we want the scalar value here. - ConstValue::ByRef { alloc, offset } => { - let ptr = Pointer::new(AllocId(0), offset); - alloc - .read_scalar(&bx, ptr, size) - .and_then(|s| s.check_init()) - .unwrap_or_else(|e| { - bx.tcx().sess.span_err( - span, - &format!("Could not evaluate asm const: {}", e), - ); - - // We are erroring out, just emit a dummy constant. - Scalar::from_u64(0) - }) - } - _ => span_bug!(span, "expected ByRef for promoted asm const"), + ConstValue::Scalar(s) => s, + _ => span_bug!( + span, + "expected Scalar for promoted asm const, but got {:#?}", + const_value + ), }; let value = scalar.assert_bits(size); let string = match ty.kind() { diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 5b5dbcf192ca1..71d4ae85d3363 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1473,21 +1473,18 @@ declare_lint_pass!( UnusedBrokenConst => [] ); -fn check_const(cx: &LateContext<'_>, body_id: hir::BodyId) { - let def_id = cx.tcx.hir().body_owner_def_id(body_id).to_def_id(); - // trigger the query once for all constants since that will already report the errors - // FIXME: Use ensure here - let _ = cx.tcx.const_eval_poly(def_id); -} - impl<'tcx> LateLintPass<'tcx> for UnusedBrokenConst { fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { match it.kind { hir::ItemKind::Const(_, body_id) => { - check_const(cx, body_id); + let def_id = cx.tcx.hir().body_owner_def_id(body_id).to_def_id(); + // trigger the query once for all constants since that will already report the errors + // FIXME: Use ensure here + let _ = cx.tcx.const_eval_poly(def_id); } hir::ItemKind::Static(_, _, body_id) => { - check_const(cx, body_id); + let def_id = cx.tcx.hir().body_owner_def_id(body_id).to_def_id(); + let _ = cx.tcx.eval_static_initializer(def_id); } _ => {} } diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index dd2731fb0a016..013c67466057b 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -182,7 +182,7 @@ pub(super) fn op_to_const<'tcx>( } } -fn validate_and_turn_into_const<'tcx>( +fn turn_into_const<'tcx>( tcx: TyCtxt<'tcx>, constant: RawConst<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, @@ -191,30 +191,21 @@ fn validate_and_turn_into_const<'tcx>( let def_id = cid.instance.def.def_id(); let is_static = tcx.is_static(def_id); let ecx = mk_eval_cx(tcx, tcx.def_span(key.value.instance.def_id()), key.param_env, is_static); - let val = (|| { - let mplace = ecx.raw_const_to_mplace(constant)?; - // Turn this into a proper constant. - // Statics/promoteds are always `ByRef`, for the rest `op_to_const` decides - // whether they become immediates. - if is_static || cid.promoted.is_some() { - let ptr = mplace.ptr.assert_ptr(); - Ok(ConstValue::ByRef { - alloc: ecx.tcx.global_alloc(ptr.alloc_id).unwrap_memory(), - offset: ptr.offset, - }) - } else { - Ok(op_to_const(&ecx, mplace.into())) - } - })(); - // FIXME: Can this ever be an error and not be a compiler bug or can we just ICE here? - val.map_err(|error| { + let mplace = ecx.raw_const_to_mplace(constant).map_err(|error| { + // FIXME: Can the above ever error and not be a compiler bug or can we just ICE here? let err = ConstEvalErr::new(&ecx, error, None); err.struct_error(ecx.tcx, "it is undefined behavior to use this value", |mut diag| { diag.note(note_on_undefined_behavior_error()); diag.emit(); }) - }) + })?; + assert!( + !is_static || cid.promoted.is_some(), + "the const eval query should not be used for statics, use `const_eval_raw` instead" + ); + // Turn this into a proper constant. + Ok(op_to_const(&ecx, mplace.into())) } pub fn const_eval_validated_provider<'tcx>( @@ -248,7 +239,7 @@ pub fn const_eval_validated_provider<'tcx>( }); } - tcx.const_eval_raw(key).and_then(|val| validate_and_turn_into_const(tcx, val, key)) + tcx.const_eval_raw(key).and_then(|val| turn_into_const(tcx, val, key)) } pub fn const_eval_raw_provider<'tcx>( diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs index f2f6c893eda4e..b2901d8d6a259 100644 --- a/compiler/rustc_mir/src/interpret/eval_context.rs +++ b/compiler/rustc_mir/src/interpret/eval_context.rs @@ -914,13 +914,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } else { self.param_env }; - // We use `const_eval_raw` here, and get an unvalidated result. That is okay: - // Our result will later be validated anyway, and there seems no good reason - // to have to fail early here. This is also more consistent with - // `Memory::get_static_alloc` which has to use `const_eval_raw` to avoid cycles. - // FIXME: We can hit delay_span_bug if this is an invalid const, interning finds - // that problem, but we never run validation to show an error. Can we ensure - // this does not happen? let val = self.tcx.const_eval_raw(param_env.and(gid))?; self.raw_const_to_mplace(val) } diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs index 57245696e576e..2be771a58ef2b 100644 --- a/compiler/rustc_mir/src/interpret/operand.rs +++ b/compiler/rustc_mir/src/interpret/operand.rs @@ -554,11 +554,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::ConstKind::Unevaluated(def, substs, promoted) => { let instance = self.resolve(def.did, substs)?; // We use `const_eval` here and `const_eval_raw` elsewhere in mir interpretation. - // The reason we use `const_eval_raw` everywhere else is to prevent cycles during - // validation, because validation automatically reads through any references, thus - // potentially requiring the current static to be evaluated again. This is not a - // problem here, because we are building an operand which means an actual read is - // happening. + // The reason we use `const_eval` here is that there can never be a `ty::ConstKind` + // that directly mentions the initializer of a static. Statics are always encoded + // as constants with vaule `&STATIC`. return Ok(self.const_eval(GlobalId { instance, promoted }, val.ty)?); } ty::ConstKind::Infer(..) diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs index 0dbb4b1015e79..4ef871b05f47f 100644 --- a/compiler/rustc_mir/src/monomorphize/collector.rs +++ b/compiler/rustc_mir/src/monomorphize/collector.rs @@ -364,8 +364,10 @@ fn collect_items_rec<'tcx>( recursion_depth_reset = None; - if let Ok(val) = tcx.const_eval_poly(def_id) { - collect_const_value(tcx, val, &mut neighbors); + if let Ok(alloc) = tcx.eval_static_initializer(def_id) { + for &((), id) in alloc.relocations().values() { + collect_miri(tcx, id, &mut neighbors); + } } } MonoItem::Fn(instance) => { diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index 75567181b6916..49c644a20bf82 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -631,14 +631,11 @@ pub fn write_allocations<'tcx>( None => write!(w, " (deallocated)")?, Some(GlobalAlloc::Function(inst)) => write!(w, " (fn: {})", inst)?, Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => { - match tcx.const_eval_poly(did) { - Ok(ConstValue::ByRef { alloc, .. }) => { + match tcx.eval_static_initializer(did) { + Ok(alloc) => { write!(w, " (static: {}, ", tcx.def_path_str(did))?; write_allocation_track_relocs(w, alloc)?; } - Ok(_) => { - span_bug!(tcx.def_span(did), " static item without `ByRef` initializer") - } Err(_) => write!( w, " (static: {}, error during initializer evaluation)", diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 9a9e57638d758..e84cc3c9b8684 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -111,7 +111,6 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_infer::infer::{InferCtxt, InferOk, InferResult, RegionVariableOrigin, TyCtxtInferExt}; use rustc_middle::hir::map::blocks::FnLikeNode; -use rustc_middle::mir::interpret::ConstValue; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, }; @@ -2070,8 +2069,8 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: S // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is // the consumer's responsibility to ensure all bytes that have been read // have defined values. - match tcx.const_eval_poly(id.to_def_id()) { - Ok(ConstValue::ByRef { alloc, .. }) => { + match tcx.eval_static_initializer(id.to_def_id()) { + Ok(alloc) => { if alloc.relocations().len() != 0 { let msg = "statics with a custom `#[link_section]` must be a \ simple list of bytes on the wasm target with no \ @@ -2079,7 +2078,6 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: S tcx.sess.span_err(span, msg); } } - Ok(_) => bug!("Matching on non-ByRef static"), Err(_) => {} } } diff --git a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr index d24491e1bc5cb..fb0ed1bd5aa94 100644 --- a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr +++ b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr @@ -36,7 +36,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:37:5 | LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc22, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc18, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -76,7 +76,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:52:5 | LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc47, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc38, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -100,7 +100,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:61:5 | LL | const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc62, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc50, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -148,7 +148,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:79:5 | LL | const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc86, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc71, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -188,7 +188,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:94:5 | LL | const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc101, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc86, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -212,7 +212,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:103:5 | LL | const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc110, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc95, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/const-eval/ub-enum.stderr b/src/test/ui/consts/const-eval/ub-enum.stderr index 7b3ee535c8ec6..db95b996c18c9 100644 --- a/src/test/ui/consts/const-eval/ub-enum.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.stderr @@ -18,7 +18,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:30:1 | LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc13 at .0., but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc12 at .0., but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -34,7 +34,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:44:1 | LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc20 at ., but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc18 at ., but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -42,7 +42,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:47:1 | LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc25 at .0., but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc22 at .0., but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -58,7 +58,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:60:1 | LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc32 at ., but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc28 at ., but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/const-eval/ub-nonnull.stderr b/src/test/ui/consts/const-eval/ub-nonnull.stderr index 38e9bdecdb9d2..afd8a4b9e59ef 100644 --- a/src/test/ui/consts/const-eval/ub-nonnull.stderr +++ b/src/test/ui/consts/const-eval/ub-nonnull.stderr @@ -13,7 +13,7 @@ LL | / const OUT_OF_BOUNDS_PTR: NonNull = { unsafe { LL | | let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle LL | | // Use address-of-element for pointer arithmetic. This could wrap around to NULL! LL | | let out_of_bounds_ptr = &ptr[255]; - | | ^^^^^^^^^ memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of alloc11 which has size 1 + | | ^^^^^^^^^ memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of alloc10 which has size 1 LL | | mem::transmute(out_of_bounds_ptr) LL | | } }; | |____- diff --git a/src/test/ui/consts/const-eval/ub-ref.stderr b/src/test/ui/consts/const-eval/ub-ref.stderr index cd270f2a533bf..429ae69eabfdb 100644 --- a/src/test/ui/consts/const-eval/ub-ref.stderr +++ b/src/test/ui/consts/const-eval/ub-ref.stderr @@ -34,7 +34,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref.rs:23:1 | LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc16, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc14, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/recursive-zst-static.default.stderr b/src/test/ui/consts/recursive-zst-static.default.stderr index 9042c6f6be191..d58f044cf6d04 100644 --- a/src/test/ui/consts/recursive-zst-static.default.stderr +++ b/src/test/ui/consts/recursive-zst-static.default.stderr @@ -10,11 +10,7 @@ note: ...which requires const-evaluating `FOO`... LL | static FOO: () = FOO; | ^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires const-evaluating `FOO`, completing the cycle -note: cycle used when const-evaluating + checking `FOO` - --> $DIR/recursive-zst-static.rs:10:1 - | -LL | static FOO: () = FOO; - | ^^^^^^^^^^^^^^^^^^^^^ + = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/consts/recursive-zst-static.unleash.stderr b/src/test/ui/consts/recursive-zst-static.unleash.stderr index 9042c6f6be191..d58f044cf6d04 100644 --- a/src/test/ui/consts/recursive-zst-static.unleash.stderr +++ b/src/test/ui/consts/recursive-zst-static.unleash.stderr @@ -10,11 +10,7 @@ note: ...which requires const-evaluating `FOO`... LL | static FOO: () = FOO; | ^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires const-evaluating `FOO`, completing the cycle -note: cycle used when const-evaluating + checking `FOO` - --> $DIR/recursive-zst-static.rs:10:1 - | -LL | static FOO: () = FOO; - | ^^^^^^^^^^^^^^^^^^^^^ + = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/recursion/recursive-static-definition.stderr b/src/test/ui/recursion/recursive-static-definition.stderr index 093606e100cb3..97e42a1f126c9 100644 --- a/src/test/ui/recursion/recursive-static-definition.stderr +++ b/src/test/ui/recursion/recursive-static-definition.stderr @@ -10,11 +10,7 @@ note: ...which requires const-evaluating `FOO`... LL | pub static FOO: u32 = FOO; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires const-evaluating `FOO`, completing the cycle -note: cycle used when const-evaluating + checking `FOO` - --> $DIR/recursive-static-definition.rs:1:1 - | -LL | pub static FOO: u32 = FOO; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/write-to-static-mut-in-static.stderr b/src/test/ui/write-to-static-mut-in-static.stderr index 50dfce3448c34..6f21539c119e0 100644 --- a/src/test/ui/write-to-static-mut-in-static.stderr +++ b/src/test/ui/write-to-static-mut-in-static.stderr @@ -16,11 +16,7 @@ note: ...which requires const-evaluating `C`... LL | pub static mut C: u32 = unsafe { C = 1; 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires const-evaluating `C`, completing the cycle -note: cycle used when const-evaluating + checking `C` - --> $DIR/write-to-static-mut-in-static.rs:5:1 - | -LL | pub static mut C: u32 = unsafe { C = 1; 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: cycle used when running analysis passes on this crate error: aborting due to 2 previous errors From 6d3c7bb70ddedfd9770047d7b0b79dd2aae515af Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 31 Jul 2020 19:10:37 +0200 Subject: [PATCH 0641/1052] Update codegen tests --- src/test/codegen/consts.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/codegen/consts.rs b/src/test/codegen/consts.rs index 318f9b0eec3a9..a69a4885bb5df 100644 --- a/src/test/codegen/consts.rs +++ b/src/test/codegen/consts.rs @@ -14,7 +14,7 @@ // This checks the constants from {low,high}_align_const, they share the same // constant, but the alignment differs, so the higher one should be used -// CHECK: [[LOW_HIGH:@[0-9]+]] = {{.*}} getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* @alloc20, i32 0, i32 0, i32 0), {{.*}} +// CHECK: [[LOW_HIGH:@alloc[0-9]+]] = {{.*}}, align 4 #[derive(Copy, Clone)] // repr(i16) is required for the {low,high}_align_const test @@ -43,7 +43,7 @@ pub fn inline_enum_const() -> E { #[no_mangle] pub fn low_align_const() -> E { // Check that low_align_const and high_align_const use the same constant - // CHECK: load %"E"*, %"E"** bitcast (<{ i8*, [0 x i8] }>* [[LOW_HIGH]] to %"E"**), + // CHECK: memcpy.p0i8.p0i8.i64(i8* align 2 %1, i8* align 2 getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), i64 8, i1 false) *&E::A(0) } @@ -51,6 +51,6 @@ pub fn low_align_const() -> E { #[no_mangle] pub fn high_align_const() -> E { // Check that low_align_const and high_align_const use the same constant - // CHECK: load %"E"*, %"E"** bitcast (<{ i8*, [0 x i8] }>* [[LOW_HIGH]] to %"E"**), + // CHECK: memcpy.p0i8.p0i8.i64(i8* align 4 %1, i8* align 4 getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), i64 8, i1 false) *&E::A(0) } From 4397d66d428509ef6867bae78b13a33c828573d0 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 10 Aug 2020 11:48:52 +0200 Subject: [PATCH 0642/1052] Document `op_to_const`'s purpose --- compiler/rustc_mir/src/const_eval/eval_queries.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index 013c67466057b..8b0cbae43334b 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -104,6 +104,8 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>( ) } +/// This function converts an interpreter value into a constant that is meant for use in the +/// type system. pub(super) fn op_to_const<'tcx>( ecx: &CompileTimeEvalContext<'_, 'tcx>, op: OpTy<'tcx>, From b1bd34df0c0757f988353c30766d58df0b4ebe73 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 10 Aug 2020 11:57:20 +0200 Subject: [PATCH 0643/1052] `turn_into_const` is infallible --- .../rustc_mir/src/const_eval/eval_queries.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index 8b0cbae43334b..e52b90dffdecd 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -188,26 +188,22 @@ fn turn_into_const<'tcx>( tcx: TyCtxt<'tcx>, constant: RawConst<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, -) -> ::rustc_middle::mir::interpret::ConstEvalResult<'tcx> { +) -> ConstValue<'tcx> { let cid = key.value; let def_id = cid.instance.def.def_id(); let is_static = tcx.is_static(def_id); let ecx = mk_eval_cx(tcx, tcx.def_span(key.value.instance.def_id()), key.param_env, is_static); - let mplace = ecx.raw_const_to_mplace(constant).map_err(|error| { - // FIXME: Can the above ever error and not be a compiler bug or can we just ICE here? - let err = ConstEvalErr::new(&ecx, error, None); - err.struct_error(ecx.tcx, "it is undefined behavior to use this value", |mut diag| { - diag.note(note_on_undefined_behavior_error()); - diag.emit(); - }) - })?; + let mplace = ecx.raw_const_to_mplace(constant).expect( + "can only fail if layout computation failed, \ + which should have given a good error before ever invoking this function", + ); assert!( !is_static || cid.promoted.is_some(), "the const eval query should not be used for statics, use `const_eval_raw` instead" ); // Turn this into a proper constant. - Ok(op_to_const(&ecx, mplace.into())) + op_to_const(&ecx, mplace.into()) } pub fn const_eval_validated_provider<'tcx>( @@ -241,7 +237,7 @@ pub fn const_eval_validated_provider<'tcx>( }); } - tcx.const_eval_raw(key).and_then(|val| turn_into_const(tcx, val, key)) + tcx.const_eval_raw(key).map(|val| turn_into_const(tcx, val, key)) } pub fn const_eval_raw_provider<'tcx>( From 48f366fced077805b917448f7554a50d23160892 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 10 Aug 2020 12:04:01 +0200 Subject: [PATCH 0644/1052] Replace `and_then` `map_err` `and_then` chain with a match --- .../rustc_mir/src/const_eval/eval_queries.rs | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index e52b90dffdecd..8f2a89d46767f 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -294,8 +294,8 @@ pub fn const_eval_raw_provider<'tcx>( ); let res = ecx.load_mir(cid.instance.def, cid.promoted); - res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) - .map_err(|error| { + match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) { + Err(error) => { let err = ConstEvalErr::new(&ecx, error, None); // errors in statics are always emitted as fatal errors if is_static { @@ -317,7 +317,7 @@ pub fn const_eval_raw_provider<'tcx>( ); } - v + Err(v) } else if let Some(def) = def.as_local() { // constant defined in this crate, we can figure out a lint level! match tcx.def_kind(def.did.to_def_id()) { @@ -331,12 +331,12 @@ pub fn const_eval_raw_provider<'tcx>( // compatibility hazard DefKind::Const | DefKind::AssocConst => { let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); - err.report_as_lint( + Err(err.report_as_lint( tcx.at(tcx.def_span(def.did)), "any use of this value will cause an error", hir_id, Some(err.span), - ) + )) } // promoting runtime code is only allowed to error if it references broken // constants any other kind of error will be reported to the user as a @@ -345,34 +345,34 @@ pub fn const_eval_raw_provider<'tcx>( if let Some(p) = cid.promoted { let span = tcx.promoted_mir_of_opt_const_arg(def.to_global())[p].span; if let err_inval!(ReferencedConstant) = err.error { - err.report_as_error( + Err(err.report_as_error( tcx.at(span), "evaluation of constant expression failed", - ) + )) } else { - err.report_as_lint( + Err(err.report_as_lint( tcx.at(span), "reaching this expression at runtime will panic or abort", tcx.hir().local_def_id_to_hir_id(def.did), Some(err.span), - ) + )) } // anything else (array lengths, enum initializers, constant patterns) are // reported as hard errors } else { - err.report_as_error( + Err(err.report_as_error( ecx.tcx.at(ecx.cur_span()), "evaluation of constant value failed", - ) + )) } } } } else { // use of broken constant from other crate - err.report_as_error(ecx.tcx.at(ecx.cur_span()), "could not evaluate constant") + Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), "could not evaluate constant")) } - }) - .and_then(|mplace| { + } + Ok(mplace) => { // Since evaluation had no errors, valiate the resulting constant: let validation = try { // FIXME do not validate promoteds until a decision on @@ -404,5 +404,6 @@ pub fn const_eval_raw_provider<'tcx>( // Convert to raw constant Ok(RawConst { alloc_id: mplace.ptr.assert_ptr().alloc_id, ty: mplace.layout.ty }) } - }) + } + } } From a6c60bbe5de9a090c8da30d5edbd27582f6b19e6 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 10 Aug 2020 12:08:52 +0200 Subject: [PATCH 0645/1052] Clarify a statement in UB test --- src/test/ui/consts/const-eval/double_check2.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/ui/consts/const-eval/double_check2.rs b/src/test/ui/consts/const-eval/double_check2.rs index e1f3e5bb27a8f..b89db0b97d9fb 100644 --- a/src/test/ui/consts/const-eval/double_check2.rs +++ b/src/test/ui/consts/const-eval/double_check2.rs @@ -1,7 +1,9 @@ // check-pass // This test exhibits undefined behavior, but it is impossible to prevent generally during -// const eval, even if possible to prevent in the cases here. The reason it's impossible in general +// const eval, even if it could be prevented in the cases here if we added expensive and +// complex checks in rustc. +// The reason it's impossible in general // is that we run into query cycles even *without* UB, just because we're checking for UB. // We do not detect it if you create references to statics // in ways that are UB. From dd9702a059eae845624478bfa12b978e8e269157 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 10 Aug 2020 12:40:14 +0200 Subject: [PATCH 0646/1052] Do not call the `const_eval` query in mir interpretation except for caching of nulary intrinsics --- compiler/rustc_mir/src/const_eval/machine.rs | 2 +- .../rustc_mir/src/interpret/eval_context.rs | 29 ++----------------- .../rustc_mir/src/interpret/intrinsics.rs | 5 +++- compiler/rustc_mir/src/interpret/operand.rs | 6 +--- 4 files changed, 8 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index 02e905505c0f5..8b0e993f02dc3 100644 --- a/compiler/rustc_mir/src/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -51,7 +51,7 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { let gid = GlobalId { instance, promoted: None }; - let place = self.const_eval_raw(gid)?; + let place = self.const_eval(gid)?; self.copy_op(place.into(), dest)?; diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs index b2901d8d6a259..2bf14cca877ef 100644 --- a/compiler/rustc_mir/src/interpret/eval_context.rs +++ b/compiler/rustc_mir/src/interpret/eval_context.rs @@ -20,7 +20,7 @@ use rustc_span::{Pos, Span}; use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size, TargetDataLayout}; use super::{ - Immediate, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, OpTy, Operand, Place, PlaceTy, + Immediate, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, Operand, Place, PlaceTy, ScalarMaybeUninit, StackPopJump, }; use crate::transform::validate::equal_up_to_regions; @@ -875,32 +875,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(()) } - pub(super) fn const_eval( - &self, - gid: GlobalId<'tcx>, - ty: Ty<'tcx>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - // For statics we pick `ParamEnv::reveal_all`, because statics don't have generics - // and thus don't care about the parameter environment. While we could just use - // `self.param_env`, that would mean we invoke the query to evaluate the static - // with different parameter environments, thus causing the static to be evaluated - // multiple times. - let param_env = if self.tcx.is_static(gid.instance.def_id()) { - ty::ParamEnv::reveal_all() - } else { - self.param_env - }; - let val = self.tcx.const_eval_global_id(param_env, gid, Some(self.tcx.span))?; - - // Even though `ecx.const_eval` is called from `const_to_op` we can never have a - // recursion deeper than one level, because the `tcx.const_eval` above is guaranteed to not - // return `ConstValue::Unevaluated`, which is the only way that `const_to_op` will call - // `ecx.const_eval`. - let const_ = ty::Const { val: ty::ConstKind::Value(val), ty }; - self.const_to_op(&const_, None) - } - - pub fn const_eval_raw( + pub fn const_eval( &self, gid: GlobalId<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index 47ca71d9642ba..0664f25e409dc 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -152,7 +152,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { sym::type_name => self.tcx.mk_static_str(), _ => bug!("already checked for nullary intrinsics"), }; - let val = self.const_eval(gid, ty)?; + let val = + self.tcx.const_eval_global_id(self.param_env, gid, Some(self.tcx.span))?; + let const_ = ty::Const { val: ty::ConstKind::Value(val), ty }; + let val = self.const_to_op(&const_, None)?; self.copy_op(val, dest)?; } diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs index 2be771a58ef2b..54c43b518fddd 100644 --- a/compiler/rustc_mir/src/interpret/operand.rs +++ b/compiler/rustc_mir/src/interpret/operand.rs @@ -553,11 +553,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::ConstKind::Error(_) => throw_inval!(TypeckError(ErrorReported)), ty::ConstKind::Unevaluated(def, substs, promoted) => { let instance = self.resolve(def.did, substs)?; - // We use `const_eval` here and `const_eval_raw` elsewhere in mir interpretation. - // The reason we use `const_eval` here is that there can never be a `ty::ConstKind` - // that directly mentions the initializer of a static. Statics are always encoded - // as constants with vaule `&STATIC`. - return Ok(self.const_eval(GlobalId { instance, promoted }, val.ty)?); + return Ok(self.const_eval(GlobalId { instance, promoted })?.into()); } ty::ConstKind::Infer(..) | ty::ConstKind::Bound(..) From 40c2087eb5623a724d0a24db925f9c9afcd4df0d Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 10 Aug 2020 12:40:29 +0200 Subject: [PATCH 0647/1052] We can make const eval sound, it's just super expensive --- src/test/ui/consts/const-eval/double_check2.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/test/ui/consts/const-eval/double_check2.rs b/src/test/ui/consts/const-eval/double_check2.rs index b89db0b97d9fb..81f5dde450b47 100644 --- a/src/test/ui/consts/const-eval/double_check2.rs +++ b/src/test/ui/consts/const-eval/double_check2.rs @@ -1,12 +1,8 @@ // check-pass -// This test exhibits undefined behavior, but it is impossible to prevent generally during -// const eval, even if it could be prevented in the cases here if we added expensive and -// complex checks in rustc. -// The reason it's impossible in general -// is that we run into query cycles even *without* UB, just because we're checking for UB. -// We do not detect it if you create references to statics -// in ways that are UB. +// This test exhibits undefined behavior, but it is very expensive and complex to check for such +// UB in constants. +// Thus, we do not detect it if you create references to statics in ways that are UB. enum Foo { A = 5, From 69a6be73e619299a22a8ee7f64bb5532395f938d Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 10 Aug 2020 15:11:40 +0200 Subject: [PATCH 0648/1052] Rename const eval queries to reflect the validation changes --- .../rustc_middle/src/mir/interpret/queries.rs | 6 +++--- compiler/rustc_middle/src/query/mod.rs | 19 ++++++------------- .../rustc_mir/src/const_eval/eval_queries.rs | 14 +++++++------- .../rustc_mir/src/interpret/eval_context.rs | 2 +- compiler/rustc_mir/src/interpret/memory.rs | 2 +- compiler/rustc_mir/src/lib.rs | 4 ++-- 6 files changed, 20 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index dcc1f8b1a4b3c..20577bdc6bdee 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -69,9 +69,9 @@ impl<'tcx> TyCtxt<'tcx> { // improve caching of queries. let inputs = self.erase_regions(¶m_env.and(cid)); if let Some(span) = span { - self.at(span).const_eval_validated(inputs) + self.at(span).const_eval_for_ty(inputs) } else { - self.const_eval_validated(inputs) + self.const_eval_for_ty(inputs) } } @@ -94,7 +94,7 @@ impl<'tcx> TyCtxt<'tcx> { param_env: ty::ParamEnv<'tcx>, ) -> Result<&'tcx mir::Allocation, ErrorHandled> { trace!("eval_to_allocation: Need to compute {:?}", gid); - let raw_const = self.const_eval_raw(param_env.and(gid))?; + let raw_const = self.const_eval(param_env.and(gid))?; Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory()) } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 44d906dada5f0..dc89cf3564897 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -707,13 +707,8 @@ rustc_queries! { } Other { - /// Evaluates a constant without running sanity checks. - /// - /// **Do not use this** outside const eval. Const eval uses this to break query cycles - /// during validation. Please add a comment to every use site explaining why using - /// `const_eval_validated` isn't sufficient. The returned constant also isn't in a suitable - /// form to be used outside of const eval. - query const_eval_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) + /// Evaluates a constant and returns the computed allocation. + query const_eval(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) -> ConstEvalRawResult<'tcx> { desc { |tcx| "const-evaluating `{}`", @@ -721,15 +716,13 @@ rustc_queries! { } } - /// Results of evaluating const items or constants embedded in - /// other items (such as enum variant explicit discriminants). - /// - /// In contrast to `const_eval_raw` this performs some validation on the constant, and - /// returns a proper constant that is usable by the rest of the compiler. + /// Evaluates const items or anonymous constants + /// (such as enum variant explicit discriminants or array lengths) + /// into a representation suitable for the type system and const generics. /// /// **Do not use this** directly, use one of the following wrappers: `tcx.const_eval_poly`, /// `tcx.const_eval_resolve`, `tcx.const_eval_instance`, or `tcx.const_eval_global_id`. - query const_eval_validated(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) + query const_eval_for_ty(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) -> ConstEvalResult<'tcx> { desc { |tcx| "const-evaluating + checking `{}`", diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index 8f2a89d46767f..3b01328df56c0 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -200,21 +200,21 @@ fn turn_into_const<'tcx>( ); assert!( !is_static || cid.promoted.is_some(), - "the const eval query should not be used for statics, use `const_eval_raw` instead" + "the `const_eval_for_ty` query should not be used for statics, use `const_eval` instead" ); // Turn this into a proper constant. op_to_const(&ecx, mplace.into()) } -pub fn const_eval_validated_provider<'tcx>( +pub fn const_eval_for_ty_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc_middle::mir::interpret::ConstEvalResult<'tcx> { - // see comment in const_eval_raw_provider for what we're doing here + // see comment in const_eval_provider for what we're doing here if key.param_env.reveal() == Reveal::All { let mut key = key; key.param_env = key.param_env.with_user_facing(); - match tcx.const_eval_validated(key) { + match tcx.const_eval_for_ty(key) { // try again with reveal all as requested Err(ErrorHandled::TooGeneric) => {} // deduplicate calls @@ -237,10 +237,10 @@ pub fn const_eval_validated_provider<'tcx>( }); } - tcx.const_eval_raw(key).map(|val| turn_into_const(tcx, val, key)) + tcx.const_eval(key).map(|val| turn_into_const(tcx, val, key)) } -pub fn const_eval_raw_provider<'tcx>( +pub fn const_eval_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc_middle::mir::interpret::ConstEvalRawResult<'tcx> { @@ -255,7 +255,7 @@ pub fn const_eval_raw_provider<'tcx>( if key.param_env.reveal() == Reveal::All { let mut key = key; key.param_env = key.param_env.with_user_facing(); - match tcx.const_eval_raw(key) { + match tcx.const_eval(key) { // try again with reveal all as requested Err(ErrorHandled::TooGeneric) => {} // deduplicate calls diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs index 2bf14cca877ef..ef05d136da17b 100644 --- a/compiler/rustc_mir/src/interpret/eval_context.rs +++ b/compiler/rustc_mir/src/interpret/eval_context.rs @@ -889,7 +889,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } else { self.param_env }; - let val = self.tcx.const_eval_raw(param_env.and(gid))?; + let val = self.tcx.const_eval(param_env.and(gid))?; self.raw_const_to_mplace(val) } diff --git a/compiler/rustc_mir/src/interpret/memory.rs b/compiler/rustc_mir/src/interpret/memory.rs index d4be2ce0568fd..64918a7685718 100644 --- a/compiler/rustc_mir/src/interpret/memory.rs +++ b/compiler/rustc_mir/src/interpret/memory.rs @@ -469,7 +469,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // Notice that every static has two `AllocId` that will resolve to the same // thing here: one maps to `GlobalAlloc::Static`, this is the "lazy" ID, // and the other one is maps to `GlobalAlloc::Memory`, this is returned by - // `const_eval_raw` and it is the "resolved" ID. + // `const_eval` and it is the "resolved" ID. // The resolved ID is never used by the interpreted program, it is hidden. // This is relied upon for soundness of const-patterns; a pointer to the resolved // ID would "sidestep" the checks that make sure consts do not point to statics! diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index 42717f273843a..07defa2d66d4d 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -52,8 +52,8 @@ pub fn provide(providers: &mut Providers) { transform::provide(providers); monomorphize::partitioning::provide(providers); monomorphize::polymorphize::provide(providers); - providers.const_eval_validated = const_eval::const_eval_validated_provider; - providers.const_eval_raw = const_eval::const_eval_raw_provider; + providers.const_eval_for_ty = const_eval::const_eval_for_ty_provider; + providers.const_eval = const_eval::const_eval_provider; providers.const_caller_location = const_eval::const_caller_location; providers.destructure_const = |tcx, param_env_and_value| { let (param_env, value) = param_env_and_value.into_parts(); From 888afd50d97f0a92fbbbafb703b3225dc1bb1a70 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 20 Aug 2020 18:55:07 +0200 Subject: [PATCH 0649/1052] Unify the names of const eval queries and their return types --- compiler/rustc_infer/src/infer/mod.rs | 4 ++-- .../rustc_middle/src/mir/interpret/error.rs | 4 ++-- compiler/rustc_middle/src/mir/interpret/mod.rs | 6 +++--- .../rustc_middle/src/mir/interpret/queries.rs | 16 ++++++++-------- .../rustc_middle/src/mir/interpret/value.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 10 ++++++---- compiler/rustc_middle/src/ty/query/mod.rs | 2 +- .../rustc_mir/src/const_eval/eval_queries.rs | 18 +++++++++--------- compiler/rustc_mir/src/const_eval/machine.rs | 2 +- .../rustc_mir/src/interpret/eval_context.rs | 4 ++-- compiler/rustc_mir/src/interpret/operand.rs | 2 +- compiler/rustc_mir/src/lib.rs | 4 ++-- 12 files changed, 38 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 685d2bac94ee3..2cbdc954e2007 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -21,7 +21,7 @@ use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType}; use rustc_middle::mir; -use rustc_middle::mir::interpret::ConstEvalResult; +use rustc_middle::mir::interpret::EvalToConstValueResult; use rustc_middle::traits::select; use rustc_middle::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; @@ -1542,7 +1542,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { substs: SubstsRef<'tcx>, promoted: Option, span: Option, - ) -> ConstEvalResult<'tcx> { + ) -> EvalToConstValueResult<'tcx> { let mut original_values = OriginalQueryValues::default(); let canonical = self.canonicalize_query(&(param_env, substs), &mut original_values); diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 059925088ce1d..62d02250fe0b1 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -27,8 +27,8 @@ CloneTypeFoldableAndLiftImpls! { ErrorHandled, } -pub type ConstEvalRawResult<'tcx> = Result, ErrorHandled>; -pub type ConstEvalResult<'tcx> = Result, ErrorHandled>; +pub type EvalToAllocationRawResult<'tcx> = Result, ErrorHandled>; +pub type EvalToConstValueResult<'tcx> = Result, ErrorHandled>; pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<'tcx> { struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg) diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index cbc362d934ff8..71a99cf95f819 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -118,9 +118,9 @@ use crate::ty::subst::GenericArgKind; use crate::ty::{self, Instance, Ty, TyCtxt}; pub use self::error::{ - struct_error, CheckInAllocMsg, ConstEvalRawResult, ConstEvalResult, ErrorHandled, InterpError, - InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType, ResourceExhaustionInfo, - UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo, + struct_error, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, + InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType, + ResourceExhaustionInfo, UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo, }; pub use self::value::{get_slice_bytes, ConstValue, RawConst, Scalar, ScalarMaybeUninit}; diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 20577bdc6bdee..d545cf6865d29 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -1,4 +1,4 @@ -use super::{ConstEvalResult, ErrorHandled, GlobalId}; +use super::{ErrorHandled, EvalToConstValueResult, GlobalId}; use crate::mir; use crate::ty::subst::{InternalSubsts, SubstsRef}; @@ -10,7 +10,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Evaluates a constant without providing any substitutions. This is useful to evaluate consts /// that can't take any generic arguments like statics, const items or enum discriminants. If a /// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned. - pub fn const_eval_poly(self, def_id: DefId) -> ConstEvalResult<'tcx> { + pub fn const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'tcx> { // In some situations def_id will have substitutions within scope, but they aren't allowed // to be used. So we can't use `Instance::mono`, instead we feed unresolved substitutions // into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are @@ -38,7 +38,7 @@ impl<'tcx> TyCtxt<'tcx> { substs: SubstsRef<'tcx>, promoted: Option, span: Option, - ) -> ConstEvalResult<'tcx> { + ) -> EvalToConstValueResult<'tcx> { match ty::Instance::resolve_opt_const_arg(self, param_env, def, substs) { Ok(Some(instance)) => { let cid = GlobalId { instance, promoted }; @@ -54,7 +54,7 @@ impl<'tcx> TyCtxt<'tcx> { param_env: ty::ParamEnv<'tcx>, instance: ty::Instance<'tcx>, span: Option, - ) -> ConstEvalResult<'tcx> { + ) -> EvalToConstValueResult<'tcx> { self.const_eval_global_id(param_env, GlobalId { instance, promoted: None }, span) } @@ -64,14 +64,14 @@ impl<'tcx> TyCtxt<'tcx> { param_env: ty::ParamEnv<'tcx>, cid: GlobalId<'tcx>, span: Option, - ) -> ConstEvalResult<'tcx> { + ) -> EvalToConstValueResult<'tcx> { // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should // improve caching of queries. let inputs = self.erase_regions(¶m_env.and(cid)); if let Some(span) = span { - self.at(span).const_eval_for_ty(inputs) + self.at(span).eval_to_const_value(inputs) } else { - self.const_eval_for_ty(inputs) + self.eval_to_const_value(inputs) } } @@ -94,7 +94,7 @@ impl<'tcx> TyCtxt<'tcx> { param_env: ty::ParamEnv<'tcx>, ) -> Result<&'tcx mir::Allocation, ErrorHandled> { trace!("eval_to_allocation: Need to compute {:?}", gid); - let raw_const = self.const_eval(param_env.and(gid))?; + let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?; Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory()) } } diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 7d6ff3eb5c1cc..930487153c327 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -12,7 +12,7 @@ use crate::ty::{ParamEnv, Ty, TyCtxt}; use super::{sign_extend, truncate, AllocId, Allocation, InterpResult, Pointer, PointerArithmetic}; -/// Represents the result of a raw const operation, pre-validation. +/// Represents the result of const evaluation via the `eval_to_allocation` query. #[derive(Clone, HashStable)] pub struct RawConst<'tcx> { // the value lives here, at offset 0, and that allocation definitely is a `AllocKind::Memory` diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index dc89cf3564897..ece9dcf66a321 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -708,8 +708,10 @@ rustc_queries! { Other { /// Evaluates a constant and returns the computed allocation. - query const_eval(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) - -> ConstEvalRawResult<'tcx> { + /// + /// **Do not use this** directly, use the `tcx.eval_static_initializer` wrapper. + query eval_to_allocation_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) + -> EvalToAllocationRawResult<'tcx> { desc { |tcx| "const-evaluating `{}`", key.value.display(tcx) @@ -722,8 +724,8 @@ rustc_queries! { /// /// **Do not use this** directly, use one of the following wrappers: `tcx.const_eval_poly`, /// `tcx.const_eval_resolve`, `tcx.const_eval_instance`, or `tcx.const_eval_global_id`. - query const_eval_for_ty(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) - -> ConstEvalResult<'tcx> { + query eval_to_const_value(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) + -> EvalToConstValueResult<'tcx> { desc { |tcx| "const-evaluating + checking `{}`", key.value.display(tcx) diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query/mod.rs index ee9b203b15180..d3a7412ef14e7 100644 --- a/compiler/rustc_middle/src/ty/query/mod.rs +++ b/compiler/rustc_middle/src/ty/query/mod.rs @@ -14,7 +14,7 @@ use crate::middle::resolve_lifetime::{ObjectLifetimeDefault, Region, ResolveLife use crate::middle::stability::{self, DeprecationEntry}; use crate::mir; use crate::mir::interpret::GlobalId; -use crate::mir::interpret::{ConstEvalRawResult, ConstEvalResult, ConstValue}; +use crate::mir::interpret::{ConstValue, EvalToAllocationRawResult, EvalToConstValueResult}; use crate::mir::interpret::{LitToConstError, LitToConstInput}; use crate::mir::mono::CodegenUnit; use crate::traits::query::{ diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index 3b01328df56c0..7dae12cf41127 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -200,21 +200,21 @@ fn turn_into_const<'tcx>( ); assert!( !is_static || cid.promoted.is_some(), - "the `const_eval_for_ty` query should not be used for statics, use `const_eval` instead" + "the `eval_to_const_value` query should not be used for statics, use `eval_to_allocation` instead" ); // Turn this into a proper constant. op_to_const(&ecx, mplace.into()) } -pub fn const_eval_for_ty_provider<'tcx>( +pub fn eval_to_const_value_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, -) -> ::rustc_middle::mir::interpret::ConstEvalResult<'tcx> { - // see comment in const_eval_provider for what we're doing here +) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> { + // see comment in const_eval_raw_provider for what we're doing here if key.param_env.reveal() == Reveal::All { let mut key = key; key.param_env = key.param_env.with_user_facing(); - match tcx.const_eval_for_ty(key) { + match tcx.eval_to_const_value(key) { // try again with reveal all as requested Err(ErrorHandled::TooGeneric) => {} // deduplicate calls @@ -237,13 +237,13 @@ pub fn const_eval_for_ty_provider<'tcx>( }); } - tcx.const_eval(key).map(|val| turn_into_const(tcx, val, key)) + tcx.eval_to_allocation_raw(key).map(|val| turn_into_const(tcx, val, key)) } -pub fn const_eval_provider<'tcx>( +pub fn eval_to_allocation_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, -) -> ::rustc_middle::mir::interpret::ConstEvalRawResult<'tcx> { +) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> { // Because the constant is computed twice (once per value of `Reveal`), we are at risk of // reporting the same error twice here. To resolve this, we check whether we can evaluate the // constant in the more restrictive `Reveal::UserFacing`, which most likely already was @@ -255,7 +255,7 @@ pub fn const_eval_provider<'tcx>( if key.param_env.reveal() == Reveal::All { let mut key = key; key.param_env = key.param_env.with_user_facing(); - match tcx.const_eval(key) { + match tcx.eval_to_allocation_raw(key) { // try again with reveal all as requested Err(ErrorHandled::TooGeneric) => {} // deduplicate calls diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index 8b0e993f02dc3..73ca7e0d471ca 100644 --- a/compiler/rustc_mir/src/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -51,7 +51,7 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { let gid = GlobalId { instance, promoted: None }; - let place = self.const_eval(gid)?; + let place = self.eval_to_allocation(gid)?; self.copy_op(place.into(), dest)?; diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs index ef05d136da17b..00d6ffb14eaf2 100644 --- a/compiler/rustc_mir/src/interpret/eval_context.rs +++ b/compiler/rustc_mir/src/interpret/eval_context.rs @@ -875,7 +875,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(()) } - pub fn const_eval( + pub fn eval_to_allocation( &self, gid: GlobalId<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { @@ -889,7 +889,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } else { self.param_env }; - let val = self.tcx.const_eval(param_env.and(gid))?; + let val = self.tcx.eval_to_allocation_raw(param_env.and(gid))?; self.raw_const_to_mplace(val) } diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs index 54c43b518fddd..8c4bb19866e3f 100644 --- a/compiler/rustc_mir/src/interpret/operand.rs +++ b/compiler/rustc_mir/src/interpret/operand.rs @@ -553,7 +553,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::ConstKind::Error(_) => throw_inval!(TypeckError(ErrorReported)), ty::ConstKind::Unevaluated(def, substs, promoted) => { let instance = self.resolve(def.did, substs)?; - return Ok(self.const_eval(GlobalId { instance, promoted })?.into()); + return Ok(self.eval_to_allocation(GlobalId { instance, promoted })?.into()); } ty::ConstKind::Infer(..) | ty::ConstKind::Bound(..) diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index 07defa2d66d4d..bbbb25117c00c 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -52,8 +52,8 @@ pub fn provide(providers: &mut Providers) { transform::provide(providers); monomorphize::partitioning::provide(providers); monomorphize::polymorphize::provide(providers); - providers.const_eval_for_ty = const_eval::const_eval_for_ty_provider; - providers.const_eval = const_eval::const_eval_provider; + providers.eval_to_const_value = const_eval::eval_to_const_value_provider; + providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider; providers.const_caller_location = const_eval::const_caller_location; providers.destructure_const = |tcx, param_env_and_value| { let (param_env, value) = param_env_and_value.into_parts(); From 90708c15c45572842f2abd60ce32c672d80bdbf8 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 21 Aug 2020 10:33:28 +0200 Subject: [PATCH 0650/1052] Fix rebase fallout and make the test work with debug info --- src/test/ui/consts/const-eval/const-eval-query-stack.stderr | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr index dc2661ee79685..672076f0affef 100644 --- a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr +++ b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr @@ -9,9 +9,9 @@ LL | let x: &'static i32 = &(1 / 0); = note: `#[deny(const_err)]` on by default query stack during panic: -#0 [const_eval_raw] const-evaluating `main::promoted[1]` -#1 [const_eval_validated] const-evaluating + checking `main::promoted[1]` -#2 [const_eval_validated] const-evaluating + checking `main::promoted[1]` +#0 [eval_to_allocation_raw] const-evaluating `main::promoted[1]` +#1 [eval_to_const_value] const-evaluating + checking `main::promoted[1]` +#2 [eval_to_const_value] const-evaluating + checking `main::promoted[1]` #3 [normalize_generic_arg_after_erasing_regions] normalizing `main::promoted[1]` #4 [optimized_mir] optimizing MIR for `main` #5 [collect_and_partition_mono_items] collect_and_partition_mono_items From 182ed8544d2f2ecd4690535a7fcdb809d72e4a86 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 7 Sep 2020 17:30:38 +0200 Subject: [PATCH 0651/1052] Address review comments --- .../rustc_middle/src/mir/interpret/error.rs | 4 +-- .../rustc_middle/src/mir/interpret/mod.rs | 2 +- .../rustc_middle/src/mir/interpret/value.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 4 +-- .../rustc_mir/src/const_eval/eval_queries.rs | 10 +++--- compiler/rustc_mir/src/interpret/memory.rs | 2 +- compiler/rustc_mir/src/interpret/place.rs | 8 ++--- compiler/rustc_mir/src/interpret/validity.rs | 34 +++++++++---------- .../defaults-cyclic-fail.stderr | 14 ++++---- ...9-assoc-const-static-recursion-impl.stderr | 14 ++++---- ...onst-static-recursion-trait-default.stderr | 14 ++++---- ...-assoc-const-static-recursion-trait.stderr | 14 ++++---- .../const-eval/const-eval-query-stack.stderr | 6 ++-- src/test/ui/consts/const-size_of-cycle.stderr | 12 +++---- .../recursive-zst-static.default.stderr | 6 ++-- src/test/ui/consts/recursive-zst-static.rs | 2 +- .../recursive-zst-static.unleash.stderr | 6 ++-- .../infinite/infinite-recursion-const-fn.rs | 11 ++++-- .../infinite-recursion-const-fn.stderr | 16 ++++----- src/test/ui/issues/issue-17252.stderr | 8 ++--- src/test/ui/issues/issue-23302-1.stderr | 8 ++--- src/test/ui/issues/issue-23302-2.stderr | 8 ++--- src/test/ui/issues/issue-23302-3.stderr | 14 ++++---- src/test/ui/issues/issue-36163.stderr | 14 ++++---- .../recursion/recursive-static-definition.rs | 2 +- .../recursive-static-definition.stderr | 6 ++-- .../self-in-enum-definition.rs | 4 +-- .../self-in-enum-definition.stderr | 10 +++--- .../ui/write-to-static-mut-in-static.stderr | 6 ++-- 29 files changed, 133 insertions(+), 128 deletions(-) diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 62d02250fe0b1..13333dc45de0c 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -1,4 +1,4 @@ -use super::{AllocId, Pointer, RawConst, Scalar}; +use super::{AllocId, ConstAlloc, Pointer, Scalar}; use crate::mir::interpret::ConstValue; use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty}; @@ -27,7 +27,7 @@ CloneTypeFoldableAndLiftImpls! { ErrorHandled, } -pub type EvalToAllocationRawResult<'tcx> = Result, ErrorHandled>; +pub type EvalToAllocationRawResult<'tcx> = Result, ErrorHandled>; pub type EvalToConstValueResult<'tcx> = Result, ErrorHandled>; pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<'tcx> { diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 71a99cf95f819..adf551ee43306 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -123,7 +123,7 @@ pub use self::error::{ ResourceExhaustionInfo, UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo, }; -pub use self::value::{get_slice_bytes, ConstValue, RawConst, Scalar, ScalarMaybeUninit}; +pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar, ScalarMaybeUninit}; pub use self::allocation::{Allocation, AllocationExtra, InitMask, Relocations}; diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 930487153c327..ded1a9c62762b 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -14,7 +14,7 @@ use super::{sign_extend, truncate, AllocId, Allocation, InterpResult, Pointer, P /// Represents the result of const evaluation via the `eval_to_allocation` query. #[derive(Clone, HashStable)] -pub struct RawConst<'tcx> { +pub struct ConstAlloc<'tcx> { // the value lives here, at offset 0, and that allocation definitely is a `AllocKind::Memory` // (so you can use `AllocMap::unwrap_memory`). pub alloc_id: AllocId, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index ece9dcf66a321..dbc0e73968bc1 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -713,7 +713,7 @@ rustc_queries! { query eval_to_allocation_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) -> EvalToAllocationRawResult<'tcx> { desc { |tcx| - "const-evaluating `{}`", + "const-evaluating + checking `{}`", key.value.display(tcx) } } @@ -727,7 +727,7 @@ rustc_queries! { query eval_to_const_value(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) -> EvalToConstValueResult<'tcx> { desc { |tcx| - "const-evaluating + checking `{}`", + "simplifying constant for the type system `{}`", key.value.display(tcx) } cache_on_disk_if(_, opt_result) { diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index 7dae12cf41127..00b675dbc4adf 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -2,7 +2,7 @@ use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalErr, Memory use crate::interpret::eval_nullary_intrinsic; use crate::interpret::{ intern_const_alloc_recursive, Allocation, ConstValue, GlobalId, Immediate, InternKind, - InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RawConst, RefTracking, Scalar, + InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, ConstAlloc, RefTracking, Scalar, ScalarMaybeUninit, StackPopCleanup, }; @@ -184,9 +184,9 @@ pub(super) fn op_to_const<'tcx>( } } -fn turn_into_const<'tcx>( +fn turn_into_const_value<'tcx>( tcx: TyCtxt<'tcx>, - constant: RawConst<'tcx>, + constant: ConstAlloc<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ConstValue<'tcx> { let cid = key.value; @@ -237,7 +237,7 @@ pub fn eval_to_const_value_provider<'tcx>( }); } - tcx.eval_to_allocation_raw(key).map(|val| turn_into_const(tcx, val, key)) + tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key)) } pub fn eval_to_allocation_raw_provider<'tcx>( @@ -402,7 +402,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>( )) } else { // Convert to raw constant - Ok(RawConst { alloc_id: mplace.ptr.assert_ptr().alloc_id, ty: mplace.layout.ty }) + Ok(ConstAlloc { alloc_id: mplace.ptr.assert_ptr().alloc_id, ty: mplace.layout.ty }) } } } diff --git a/compiler/rustc_mir/src/interpret/memory.rs b/compiler/rustc_mir/src/interpret/memory.rs index 64918a7685718..86e242c67d520 100644 --- a/compiler/rustc_mir/src/interpret/memory.rs +++ b/compiler/rustc_mir/src/interpret/memory.rs @@ -469,7 +469,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // Notice that every static has two `AllocId` that will resolve to the same // thing here: one maps to `GlobalAlloc::Static`, this is the "lazy" ID, // and the other one is maps to `GlobalAlloc::Memory`, this is returned by - // `const_eval` and it is the "resolved" ID. + // `eval_static_initializer` and it is the "resolved" ID. // The resolved ID is never used by the interpreted program, it is hidden. // This is relied upon for soundness of const-patterns; a pointer to the resolved // ID would "sidestep" the checks that make sure consts do not point to statics! diff --git a/compiler/rustc_mir/src/interpret/place.rs b/compiler/rustc_mir/src/interpret/place.rs index 9e16063bd21af..055141a3de63d 100644 --- a/compiler/rustc_mir/src/interpret/place.rs +++ b/compiler/rustc_mir/src/interpret/place.rs @@ -13,9 +13,9 @@ use rustc_target::abi::{Abi, Align, FieldsShape, TagEncoding}; use rustc_target::abi::{HasDataLayout, LayoutOf, Size, VariantIdx, Variants}; use super::{ - mir_assign_valid_types, truncate, AllocId, AllocMap, Allocation, AllocationExtra, ImmTy, - Immediate, InterpCx, InterpResult, LocalValue, Machine, MemoryKind, OpTy, Operand, Pointer, - PointerArithmetic, RawConst, Scalar, ScalarMaybeUninit, + mir_assign_valid_types, truncate, AllocId, AllocMap, Allocation, AllocationExtra, ConstAlloc, + ImmTy, Immediate, InterpCx, InterpResult, LocalValue, Machine, MemoryKind, OpTy, Operand, + Pointer, PointerArithmetic, Scalar, ScalarMaybeUninit, }; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)] @@ -1122,7 +1122,7 @@ where pub fn raw_const_to_mplace( &self, - raw: RawConst<'tcx>, + raw: ConstAlloc<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { // This must be an allocation in `tcx` let _ = self.tcx.global_alloc(raw.alloc_id); diff --git a/compiler/rustc_mir/src/interpret/validity.rs b/compiler/rustc_mir/src/interpret/validity.rs index 7d9507c08fa18..2b83e1c8134ef 100644 --- a/compiler/rustc_mir/src/interpret/validity.rs +++ b/compiler/rustc_mir/src/interpret/validity.rs @@ -426,27 +426,27 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' if let Some(GlobalAlloc::Static(did)) = alloc_kind { assert!(!self.ecx.tcx.is_thread_local_static(did)); assert!(self.ecx.tcx.is_static(did)); - // See const_eval::machine::MemoryExtra::can_access_statics for why - // this check is so important. - // This check is reachable when the const just referenced the static, - // but never read it (so we never entered `before_access_global`). - // We also need to do it here instead of going on to avoid running - // into the `before_access_global` check during validation. - if !self.may_ref_to_static { + if self.may_ref_to_static { + // We skip checking other statics. These statics must be sound by + // themselves, and the only way to get broken statics here is by using + // unsafe code. + // The reasons we don't check other statics is twofold. For one, in all + // sound cases, the static was already validated on its own, and second, we + // trigger cycle errors if we try to compute the value of the other static + // and that static refers back to us. + // We might miss const-invalid data, + // but things are still sound otherwise (in particular re: consts + // referring to statics). + return Ok(()); + } else { + // See const_eval::machine::MemoryExtra::can_access_statics for why + // this check is so important. + // This check is reachable when the const just referenced the static, + // but never read it (so we never entered `before_access_global`). throw_validation_failure!(self.path, { "a {} pointing to a static variable", kind } ); } - // We skip checking other statics. These statics must be sound by themselves, - // and the only way to get broken statics here is by using unsafe code. - // The reasons we don't check other statics is twofold. For one, in all sound - // cases, the static was already validated on its own, and second, we trigger - // cycle errors if we try to compute the value of the other static and that - // static refers back to us. - // We might miss const-invalid data, - // but things are still sound otherwise (in particular re: consts - // referring to statics). - return Ok(()); } } // Proceed recursively even for ZST, no reason to skip them! diff --git a/src/test/ui/associated-const/defaults-cyclic-fail.stderr b/src/test/ui/associated-const/defaults-cyclic-fail.stderr index e6075f745776a..616ac9053fd53 100644 --- a/src/test/ui/associated-const/defaults-cyclic-fail.stderr +++ b/src/test/ui/associated-const/defaults-cyclic-fail.stderr @@ -1,38 +1,38 @@ error[E0391]: cycle detected when normalizing `<() as Tr>::A` | -note: ...which requires const-evaluating + checking `Tr::A`... +note: ...which requires simplifying constant for the type system `Tr::A`... --> $DIR/defaults-cyclic-fail.rs:6:5 | LL | const A: u8 = Self::B; | ^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `Tr::A`... +note: ...which requires simplifying constant for the type system `Tr::A`... --> $DIR/defaults-cyclic-fail.rs:6:5 | LL | const A: u8 = Self::B; | ^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `Tr::A`... +note: ...which requires const-evaluating + checking `Tr::A`... --> $DIR/defaults-cyclic-fail.rs:6:5 | LL | const A: u8 = Self::B; | ^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `<() as Tr>::B`... -note: ...which requires const-evaluating + checking `Tr::B`... +note: ...which requires simplifying constant for the type system `Tr::B`... --> $DIR/defaults-cyclic-fail.rs:8:5 | LL | const B: u8 = Self::A; | ^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `Tr::B`... +note: ...which requires simplifying constant for the type system `Tr::B`... --> $DIR/defaults-cyclic-fail.rs:8:5 | LL | const B: u8 = Self::A; | ^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `Tr::B`... +note: ...which requires const-evaluating + checking `Tr::B`... --> $DIR/defaults-cyclic-fail.rs:8:5 | LL | const B: u8 = Self::A; | ^^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires normalizing `<() as Tr>::A`, completing the cycle -note: cycle used when const-evaluating `main::promoted[2]` +note: cycle used when const-evaluating + checking `main::promoted[2]` --> $DIR/defaults-cyclic-fail.rs:14:1 | LL | fn main() { diff --git a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr index 1b4326ea56aaa..d9bb7386565fa 100644 --- a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr +++ b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr @@ -1,31 +1,31 @@ -error[E0391]: cycle detected when const-evaluating + checking `IMPL_REF_BAR` +error[E0391]: cycle detected when simplifying constant for the type system `IMPL_REF_BAR` --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1 | LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating + checking `IMPL_REF_BAR`... +note: ...which requires simplifying constant for the type system `IMPL_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1 | LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `IMPL_REF_BAR`... +note: ...which requires const-evaluating + checking `IMPL_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1 | LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `::BAR`... -note: ...which requires const-evaluating + checking `::BAR`... +note: ...which requires simplifying constant for the type system `::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5 | LL | const BAR: u32 = IMPL_REF_BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `::BAR`... +note: ...which requires simplifying constant for the type system `::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5 | LL | const BAR: u32 = IMPL_REF_BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `::BAR`... +note: ...which requires const-evaluating + checking `::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5 | LL | const BAR: u32 = IMPL_REF_BAR; @@ -36,7 +36,7 @@ note: ...which requires optimizing MIR for ` $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1 | LL | const DEFAULT_REF_BAR: u32 = ::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating + checking `DEFAULT_REF_BAR`... +note: ...which requires simplifying constant for the type system `DEFAULT_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1 | LL | const DEFAULT_REF_BAR: u32 = ::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `DEFAULT_REF_BAR`... +note: ...which requires const-evaluating + checking `DEFAULT_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1 | LL | const DEFAULT_REF_BAR: u32 = ::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `::BAR`... -note: ...which requires const-evaluating + checking `FooDefault::BAR`... +note: ...which requires simplifying constant for the type system `FooDefault::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5 | LL | const BAR: u32 = DEFAULT_REF_BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `FooDefault::BAR`... +note: ...which requires simplifying constant for the type system `FooDefault::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5 | LL | const BAR: u32 = DEFAULT_REF_BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `FooDefault::BAR`... +note: ...which requires const-evaluating + checking `FooDefault::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5 | LL | const BAR: u32 = DEFAULT_REF_BAR; @@ -36,7 +36,7 @@ note: ...which requires optimizing MIR for `FooDefault::BAR`... LL | const BAR: u32 = DEFAULT_REF_BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `DEFAULT_REF_BAR`... - = note: ...which again requires const-evaluating + checking `DEFAULT_REF_BAR`, completing the cycle + = note: ...which again requires simplifying constant for the type system `DEFAULT_REF_BAR`, completing the cycle = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr index 78ce1a28a3fdc..62d2051b6c23a 100644 --- a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr +++ b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr @@ -1,31 +1,31 @@ -error[E0391]: cycle detected when const-evaluating + checking `TRAIT_REF_BAR` +error[E0391]: cycle detected when simplifying constant for the type system `TRAIT_REF_BAR` --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1 | LL | const TRAIT_REF_BAR: u32 = ::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating + checking `TRAIT_REF_BAR`... +note: ...which requires simplifying constant for the type system `TRAIT_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1 | LL | const TRAIT_REF_BAR: u32 = ::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `TRAIT_REF_BAR`... +note: ...which requires const-evaluating + checking `TRAIT_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1 | LL | const TRAIT_REF_BAR: u32 = ::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `::BAR`... -note: ...which requires const-evaluating + checking `::BAR`... +note: ...which requires simplifying constant for the type system `::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5 | LL | const BAR: u32 = TRAIT_REF_BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `::BAR`... +note: ...which requires simplifying constant for the type system `::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5 | LL | const BAR: u32 = TRAIT_REF_BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `::BAR`... +note: ...which requires const-evaluating + checking `::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5 | LL | const BAR: u32 = TRAIT_REF_BAR; @@ -36,7 +36,7 @@ note: ...which requires optimizing MIR for ` $DIR/const-size_of-cycle.rs:4:17 | LL | bytes: [u8; std::mem::size_of::()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}#0`... +note: ...which requires simplifying constant for the type system `Foo::bytes::{{constant}}#0`... --> $DIR/const-size_of-cycle.rs:4:17 | LL | bytes: [u8; std::mem::size_of::()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `Foo::bytes::{{constant}}#0`... +note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}#0`... --> $DIR/const-size_of-cycle.rs:4:17 | LL | bytes: [u8; std::mem::size_of::()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `std::mem::size_of`... +note: ...which requires const-evaluating + checking `std::mem::size_of`... --> $SRC_DIR/core/src/mem/mod.rs:LL:COL | LL | pub const fn size_of() -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `std::intrinsics::size_of`... +note: ...which requires simplifying constant for the type system `std::intrinsics::size_of`... --> $SRC_DIR/core/src/intrinsics.rs:LL:COL | LL | pub fn size_of() -> usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires computing layout of `Foo`... = note: ...which requires normalizing `[u8; _]`... - = note: ...which again requires const-evaluating + checking `Foo::bytes::{{constant}}#0`, completing the cycle + = note: ...which again requires simplifying constant for the type system `Foo::bytes::{{constant}}#0`, completing the cycle note: cycle used when checking that `Foo` is well-formed --> $DIR/const-size_of-cycle.rs:3:1 | diff --git a/src/test/ui/consts/recursive-zst-static.default.stderr b/src/test/ui/consts/recursive-zst-static.default.stderr index d58f044cf6d04..03f8f5c5a0e5d 100644 --- a/src/test/ui/consts/recursive-zst-static.default.stderr +++ b/src/test/ui/consts/recursive-zst-static.default.stderr @@ -1,15 +1,15 @@ -error[E0391]: cycle detected when const-evaluating `FOO` +error[E0391]: cycle detected when const-evaluating + checking `FOO` --> $DIR/recursive-zst-static.rs:10:1 | LL | static FOO: () = FOO; | ^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating `FOO`... +note: ...which requires const-evaluating + checking `FOO`... --> $DIR/recursive-zst-static.rs:10:1 | LL | static FOO: () = FOO; | ^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires const-evaluating `FOO`, completing the cycle + = note: ...which again requires const-evaluating + checking `FOO`, completing the cycle = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/consts/recursive-zst-static.rs b/src/test/ui/consts/recursive-zst-static.rs index 29a467c006a49..4e61634b349e0 100644 --- a/src/test/ui/consts/recursive-zst-static.rs +++ b/src/test/ui/consts/recursive-zst-static.rs @@ -7,7 +7,7 @@ // can depend on this fact and will thus do unsound things when it is violated. // See https://github.com/rust-lang/rust/issues/71078 for more details. -static FOO: () = FOO; //~ cycle detected when const-evaluating `FOO` +static FOO: () = FOO; //~ cycle detected when const-evaluating + checking `FOO` fn main() { FOO diff --git a/src/test/ui/consts/recursive-zst-static.unleash.stderr b/src/test/ui/consts/recursive-zst-static.unleash.stderr index d58f044cf6d04..03f8f5c5a0e5d 100644 --- a/src/test/ui/consts/recursive-zst-static.unleash.stderr +++ b/src/test/ui/consts/recursive-zst-static.unleash.stderr @@ -1,15 +1,15 @@ -error[E0391]: cycle detected when const-evaluating `FOO` +error[E0391]: cycle detected when const-evaluating + checking `FOO` --> $DIR/recursive-zst-static.rs:10:1 | LL | static FOO: () = FOO; | ^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating `FOO`... +note: ...which requires const-evaluating + checking `FOO`... --> $DIR/recursive-zst-static.rs:10:1 | LL | static FOO: () = FOO; | ^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires const-evaluating `FOO`, completing the cycle + = note: ...which again requires const-evaluating + checking `FOO`, completing the cycle = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/infinite/infinite-recursion-const-fn.rs b/src/test/ui/infinite/infinite-recursion-const-fn.rs index 8289a3db6fc5b..34580407926f1 100644 --- a/src/test/ui/infinite/infinite-recursion-const-fn.rs +++ b/src/test/ui/infinite/infinite-recursion-const-fn.rs @@ -1,7 +1,12 @@ //https://github.com/rust-lang/rust/issues/31364 -const fn a() -> usize { b() } //~ ERROR cycle detected when const-evaluating `a` [E0391] -const fn b() -> usize { a() } +const fn a() -> usize { + //~^ ERROR cycle detected when const-evaluating + checking `a` [E0391] + b() +} +const fn b() -> usize { + a() +} const ARR: [i32; a()] = [5; 6]; -fn main(){} +fn main() {} diff --git a/src/test/ui/infinite/infinite-recursion-const-fn.stderr b/src/test/ui/infinite/infinite-recursion-const-fn.stderr index de0c579f63089..3c106895305dc 100644 --- a/src/test/ui/infinite/infinite-recursion-const-fn.stderr +++ b/src/test/ui/infinite/infinite-recursion-const-fn.stderr @@ -1,17 +1,17 @@ -error[E0391]: cycle detected when const-evaluating `a` +error[E0391]: cycle detected when const-evaluating + checking `a` --> $DIR/infinite-recursion-const-fn.rs:3:1 | -LL | const fn a() -> usize { b() } +LL | const fn a() -> usize { | ^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating `b`... - --> $DIR/infinite-recursion-const-fn.rs:4:1 +note: ...which requires const-evaluating + checking `b`... + --> $DIR/infinite-recursion-const-fn.rs:7:1 | -LL | const fn b() -> usize { a() } +LL | const fn b() -> usize { | ^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires const-evaluating `a`, completing the cycle -note: cycle used when const-evaluating `ARR::{{constant}}#0` - --> $DIR/infinite-recursion-const-fn.rs:5:18 + = note: ...which again requires const-evaluating + checking `a`, completing the cycle +note: cycle used when const-evaluating + checking `ARR::{{constant}}#0` + --> $DIR/infinite-recursion-const-fn.rs:10:18 | LL | const ARR: [i32; a()] = [5; 6]; | ^^^ diff --git a/src/test/ui/issues/issue-17252.stderr b/src/test/ui/issues/issue-17252.stderr index ee621a8cb1473..0a27848b801c9 100644 --- a/src/test/ui/issues/issue-17252.stderr +++ b/src/test/ui/issues/issue-17252.stderr @@ -1,22 +1,22 @@ error[E0391]: cycle detected when normalizing `FOO` | -note: ...which requires const-evaluating + checking `FOO`... +note: ...which requires simplifying constant for the type system `FOO`... --> $DIR/issue-17252.rs:1:1 | LL | const FOO: usize = FOO; | ^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `FOO`... +note: ...which requires simplifying constant for the type system `FOO`... --> $DIR/issue-17252.rs:1:1 | LL | const FOO: usize = FOO; | ^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `FOO`... +note: ...which requires const-evaluating + checking `FOO`... --> $DIR/issue-17252.rs:1:1 | LL | const FOO: usize = FOO; | ^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires normalizing `FOO`, completing the cycle -note: cycle used when const-evaluating `main::{{constant}}#0` +note: cycle used when const-evaluating + checking `main::{{constant}}#0` --> $DIR/issue-17252.rs:4:18 | LL | let _x: [u8; FOO]; // caused stack overflow prior to fix diff --git a/src/test/ui/issues/issue-23302-1.stderr b/src/test/ui/issues/issue-23302-1.stderr index b6c85b9e22749..45372c7f53bd4 100644 --- a/src/test/ui/issues/issue-23302-1.stderr +++ b/src/test/ui/issues/issue-23302-1.stderr @@ -1,21 +1,21 @@ -error[E0391]: cycle detected when const-evaluating + checking `X::A::{{constant}}#0` +error[E0391]: cycle detected when simplifying constant for the type system `X::A::{{constant}}#0` --> $DIR/issue-23302-1.rs:4:9 | LL | A = X::A as isize, | ^^^^^^^^^^^^^ | -note: ...which requires const-evaluating + checking `X::A::{{constant}}#0`... +note: ...which requires simplifying constant for the type system `X::A::{{constant}}#0`... --> $DIR/issue-23302-1.rs:4:9 | LL | A = X::A as isize, | ^^^^^^^^^^^^^ -note: ...which requires const-evaluating `X::A::{{constant}}#0`... +note: ...which requires const-evaluating + checking `X::A::{{constant}}#0`... --> $DIR/issue-23302-1.rs:4:9 | LL | A = X::A as isize, | ^^^^^^^^^^^^^ = note: ...which requires normalizing `X::A as isize`... - = note: ...which again requires const-evaluating + checking `X::A::{{constant}}#0`, completing the cycle + = note: ...which again requires simplifying constant for the type system `X::A::{{constant}}#0`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/issue-23302-1.rs:3:1 | diff --git a/src/test/ui/issues/issue-23302-2.stderr b/src/test/ui/issues/issue-23302-2.stderr index d014922fe2069..33bc1f6c48d5e 100644 --- a/src/test/ui/issues/issue-23302-2.stderr +++ b/src/test/ui/issues/issue-23302-2.stderr @@ -1,21 +1,21 @@ -error[E0391]: cycle detected when const-evaluating + checking `Y::A::{{constant}}#0` +error[E0391]: cycle detected when simplifying constant for the type system `Y::A::{{constant}}#0` --> $DIR/issue-23302-2.rs:4:9 | LL | A = Y::B as isize, | ^^^^^^^^^^^^^ | -note: ...which requires const-evaluating + checking `Y::A::{{constant}}#0`... +note: ...which requires simplifying constant for the type system `Y::A::{{constant}}#0`... --> $DIR/issue-23302-2.rs:4:9 | LL | A = Y::B as isize, | ^^^^^^^^^^^^^ -note: ...which requires const-evaluating `Y::A::{{constant}}#0`... +note: ...which requires const-evaluating + checking `Y::A::{{constant}}#0`... --> $DIR/issue-23302-2.rs:4:9 | LL | A = Y::B as isize, | ^^^^^^^^^^^^^ = note: ...which requires normalizing `Y::B as isize`... - = note: ...which again requires const-evaluating + checking `Y::A::{{constant}}#0`, completing the cycle + = note: ...which again requires simplifying constant for the type system `Y::A::{{constant}}#0`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/issue-23302-2.rs:3:1 | diff --git a/src/test/ui/issues/issue-23302-3.stderr b/src/test/ui/issues/issue-23302-3.stderr index b30b1214271a0..5233b832ecc79 100644 --- a/src/test/ui/issues/issue-23302-3.stderr +++ b/src/test/ui/issues/issue-23302-3.stderr @@ -1,37 +1,37 @@ -error[E0391]: cycle detected when const-evaluating + checking `A` +error[E0391]: cycle detected when simplifying constant for the type system `A` --> $DIR/issue-23302-3.rs:1:1 | LL | const A: i32 = B; | ^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating + checking `A`... +note: ...which requires simplifying constant for the type system `A`... --> $DIR/issue-23302-3.rs:1:1 | LL | const A: i32 = B; | ^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `A`... +note: ...which requires const-evaluating + checking `A`... --> $DIR/issue-23302-3.rs:1:1 | LL | const A: i32 = B; | ^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `B`... -note: ...which requires const-evaluating + checking `B`... +note: ...which requires simplifying constant for the type system `B`... --> $DIR/issue-23302-3.rs:3:1 | LL | const B: i32 = A; | ^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `B`... +note: ...which requires simplifying constant for the type system `B`... --> $DIR/issue-23302-3.rs:3:1 | LL | const B: i32 = A; | ^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `B`... +note: ...which requires const-evaluating + checking `B`... --> $DIR/issue-23302-3.rs:3:1 | LL | const B: i32 = A; | ^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `A`... - = note: ...which again requires const-evaluating + checking `A`, completing the cycle + = note: ...which again requires simplifying constant for the type system `A`, completing the cycle = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/issues/issue-36163.stderr b/src/test/ui/issues/issue-36163.stderr index 7c2da9dce6e9d..3fd1f4b59beca 100644 --- a/src/test/ui/issues/issue-36163.stderr +++ b/src/test/ui/issues/issue-36163.stderr @@ -1,37 +1,37 @@ -error[E0391]: cycle detected when const-evaluating + checking `Foo::B::{{constant}}#0` +error[E0391]: cycle detected when simplifying constant for the type system `Foo::B::{{constant}}#0` --> $DIR/issue-36163.rs:4:9 | LL | B = A, | ^ | -note: ...which requires const-evaluating + checking `Foo::B::{{constant}}#0`... +note: ...which requires simplifying constant for the type system `Foo::B::{{constant}}#0`... --> $DIR/issue-36163.rs:4:9 | LL | B = A, | ^ -note: ...which requires const-evaluating `Foo::B::{{constant}}#0`... +note: ...which requires const-evaluating + checking `Foo::B::{{constant}}#0`... --> $DIR/issue-36163.rs:4:9 | LL | B = A, | ^ = note: ...which requires normalizing `A`... -note: ...which requires const-evaluating + checking `A`... +note: ...which requires simplifying constant for the type system `A`... --> $DIR/issue-36163.rs:1:1 | LL | const A: isize = Foo::B as isize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `A`... +note: ...which requires simplifying constant for the type system `A`... --> $DIR/issue-36163.rs:1:1 | LL | const A: isize = Foo::B as isize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `A`... +note: ...which requires const-evaluating + checking `A`... --> $DIR/issue-36163.rs:1:1 | LL | const A: isize = Foo::B as isize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `A`... - = note: ...which again requires const-evaluating + checking `Foo::B::{{constant}}#0`, completing the cycle + = note: ...which again requires simplifying constant for the type system `Foo::B::{{constant}}#0`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/issue-36163.rs:1:1 | diff --git a/src/test/ui/recursion/recursive-static-definition.rs b/src/test/ui/recursion/recursive-static-definition.rs index e816ce4e0c452..f59ef7316d890 100644 --- a/src/test/ui/recursion/recursive-static-definition.rs +++ b/src/test/ui/recursion/recursive-static-definition.rs @@ -1,4 +1,4 @@ pub static FOO: u32 = FOO; -//~^ ERROR cycle detected when const-evaluating `FOO` +//~^ ERROR cycle detected when const-evaluating + checking `FOO` fn main() {} diff --git a/src/test/ui/recursion/recursive-static-definition.stderr b/src/test/ui/recursion/recursive-static-definition.stderr index 97e42a1f126c9..ee73b026a0b75 100644 --- a/src/test/ui/recursion/recursive-static-definition.stderr +++ b/src/test/ui/recursion/recursive-static-definition.stderr @@ -1,15 +1,15 @@ -error[E0391]: cycle detected when const-evaluating `FOO` +error[E0391]: cycle detected when const-evaluating + checking `FOO` --> $DIR/recursive-static-definition.rs:1:1 | LL | pub static FOO: u32 = FOO; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating `FOO`... +note: ...which requires const-evaluating + checking `FOO`... --> $DIR/recursive-static-definition.rs:1:1 | LL | pub static FOO: u32 = FOO; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires const-evaluating `FOO`, completing the cycle + = note: ...which again requires const-evaluating + checking `FOO`, completing the cycle = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/type-alias-enum-variants/self-in-enum-definition.rs b/src/test/ui/type-alias-enum-variants/self-in-enum-definition.rs index 63b21faa62bd2..8dadd77fc16d5 100644 --- a/src/test/ui/type-alias-enum-variants/self-in-enum-definition.rs +++ b/src/test/ui/type-alias-enum-variants/self-in-enum-definition.rs @@ -1,8 +1,8 @@ #[repr(u8)] enum Alpha { V1 = 41, - V2 = Self::V1 as u8 + 1, // OK; See #50072. - V3 = Self::V1 {} as u8 + 2, //~ ERROR cycle detected when const-evaluating + V2 = Self::V1 as u8 + 1, // OK; See #50072. + V3 = Self::V1 {} as u8 + 2, //~ ERROR cycle detected when simplifying constant } fn main() {} diff --git a/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr b/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr index db535b53fcf37..fbe6279ca9226 100644 --- a/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr +++ b/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr @@ -1,28 +1,28 @@ -error[E0391]: cycle detected when const-evaluating + checking `Alpha::V3::{{constant}}#0` +error[E0391]: cycle detected when simplifying constant for the type system `Alpha::V3::{{constant}}#0` --> $DIR/self-in-enum-definition.rs:5:10 | LL | V3 = Self::V1 {} as u8 + 2, | ^^^^^^^^ | -note: ...which requires const-evaluating + checking `Alpha::V3::{{constant}}#0`... +note: ...which requires simplifying constant for the type system `Alpha::V3::{{constant}}#0`... --> $DIR/self-in-enum-definition.rs:5:10 | LL | V3 = Self::V1 {} as u8 + 2, | ^^^^^^^^ -note: ...which requires const-evaluating `Alpha::V3::{{constant}}#0`... +note: ...which requires const-evaluating + checking `Alpha::V3::{{constant}}#0`... --> $DIR/self-in-enum-definition.rs:5:10 | LL | V3 = Self::V1 {} as u8 + 2, | ^^^^^^^^ = note: ...which requires computing layout of `Alpha`... - = note: ...which again requires const-evaluating + checking `Alpha::V3::{{constant}}#0`, completing the cycle + = note: ...which again requires simplifying constant for the type system `Alpha::V3::{{constant}}#0`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/self-in-enum-definition.rs:1:1 | LL | / #[repr(u8)] LL | | enum Alpha { LL | | V1 = 41, -LL | | V2 = Self::V1 as u8 + 1, // OK; See #50072. +LL | | V2 = Self::V1 as u8 + 1, // OK; See #50072. ... | LL | | LL | | fn main() {} diff --git a/src/test/ui/write-to-static-mut-in-static.stderr b/src/test/ui/write-to-static-mut-in-static.stderr index 6f21539c119e0..789919bd1668d 100644 --- a/src/test/ui/write-to-static-mut-in-static.stderr +++ b/src/test/ui/write-to-static-mut-in-static.stderr @@ -4,18 +4,18 @@ error[E0080]: could not evaluate static initializer LL | pub static mut B: () = unsafe { A = 1; }; | ^^^^^ modifying a static's initial value from another static's initializer -error[E0391]: cycle detected when const-evaluating `C` +error[E0391]: cycle detected when const-evaluating + checking `C` --> $DIR/write-to-static-mut-in-static.rs:5:1 | LL | pub static mut C: u32 = unsafe { C = 1; 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating `C`... +note: ...which requires const-evaluating + checking `C`... --> $DIR/write-to-static-mut-in-static.rs:5:1 | LL | pub static mut C: u32 = unsafe { C = 1; 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires const-evaluating `C`, completing the cycle + = note: ...which again requires const-evaluating + checking `C`, completing the cycle = note: cycle used when running analysis passes on this crate error: aborting due to 2 previous errors From c3c8c981a859d6190adeec0dc32b2765bace1b3d Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 9 Sep 2020 11:40:09 +0200 Subject: [PATCH 0652/1052] Rustfmt --- compiler/rustc_mir/src/const_eval/eval_queries.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index 00b675dbc4adf..753917d7a3e2c 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -1,8 +1,8 @@ use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalErr, MemoryExtra}; use crate::interpret::eval_nullary_intrinsic; use crate::interpret::{ - intern_const_alloc_recursive, Allocation, ConstValue, GlobalId, Immediate, InternKind, - InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, ConstAlloc, RefTracking, Scalar, + intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, GlobalId, Immediate, + InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, Scalar, ScalarMaybeUninit, StackPopCleanup, }; From ef04e68462914c8e0c45736852758b012e809590 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 9 Sep 2020 12:25:55 +0200 Subject: [PATCH 0653/1052] Update compile-fail tests --- src/test/compile-fail/issue-44415.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/compile-fail/issue-44415.rs b/src/test/compile-fail/issue-44415.rs index 763f85748736e..71e764620d140 100644 --- a/src/test/compile-fail/issue-44415.rs +++ b/src/test/compile-fail/issue-44415.rs @@ -4,7 +4,7 @@ use std::intrinsics; struct Foo { bytes: [u8; unsafe { intrinsics::size_of::() }], - //~^ ERROR cycle detected when const-evaluating + checking + //~^ ERROR cycle detected when simplifying constant for the type system x: usize, } From c5889e4dabf4c7a40785949ff16a0c6f80bd8062 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 9 Sep 2020 14:04:27 +0200 Subject: [PATCH 0654/1052] Update incremental tests --- src/test/incremental/issue-54242.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/incremental/issue-54242.rs b/src/test/incremental/issue-54242.rs index 1c700d44dd80b..25dc7cdf129d5 100644 --- a/src/test/incremental/issue-54242.rs +++ b/src/test/incremental/issue-54242.rs @@ -11,7 +11,7 @@ impl Tr for str { type Arr = [u8; 8]; #[cfg(cfail)] type Arr = [u8; Self::C]; - //[cfail]~^ ERROR cycle detected when const-evaluating + //[cfail]~^ ERROR cycle detected when simplifying constant } fn main() {} From b8e6883a2fb1e43747f410d3e906ec6371215d49 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 19 Sep 2020 10:57:14 +0200 Subject: [PATCH 0655/1052] Reflect the "do not call this query directly" mentality in its name --- compiler/rustc_lint/src/builtin.rs | 1 + compiler/rustc_middle/src/mir/interpret/queries.rs | 4 ++-- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_mir/src/const_eval/eval_queries.rs | 6 +++--- compiler/rustc_mir/src/lib.rs | 2 +- src/test/ui/consts/const-eval/const-eval-query-stack.stderr | 4 ++-- 6 files changed, 10 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 71d4ae85d3363..8c4c4b61daa8a 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1484,6 +1484,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedBrokenConst { } hir::ItemKind::Static(_, _, body_id) => { let def_id = cx.tcx.hir().body_owner_def_id(body_id).to_def_id(); + // FIXME: Use ensure here let _ = cx.tcx.eval_static_initializer(def_id); } _ => {} diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index d545cf6865d29..f366681bc75e9 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -69,9 +69,9 @@ impl<'tcx> TyCtxt<'tcx> { // improve caching of queries. let inputs = self.erase_regions(¶m_env.and(cid)); if let Some(span) = span { - self.at(span).eval_to_const_value(inputs) + self.at(span).eval_to_const_value_raw(inputs) } else { - self.eval_to_const_value(inputs) + self.eval_to_const_value_raw(inputs) } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index dbc0e73968bc1..c0a606a586b6b 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -724,7 +724,7 @@ rustc_queries! { /// /// **Do not use this** directly, use one of the following wrappers: `tcx.const_eval_poly`, /// `tcx.const_eval_resolve`, `tcx.const_eval_instance`, or `tcx.const_eval_global_id`. - query eval_to_const_value(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) + query eval_to_const_value_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) -> EvalToConstValueResult<'tcx> { desc { |tcx| "simplifying constant for the type system `{}`", diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index 753917d7a3e2c..a0ee7fdc072ef 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -200,13 +200,13 @@ fn turn_into_const_value<'tcx>( ); assert!( !is_static || cid.promoted.is_some(), - "the `eval_to_const_value` query should not be used for statics, use `eval_to_allocation` instead" + "the `eval_to_const_value_raw` query should not be used for statics, use `eval_to_allocation` instead" ); // Turn this into a proper constant. op_to_const(&ecx, mplace.into()) } -pub fn eval_to_const_value_provider<'tcx>( +pub fn eval_to_const_value_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> { @@ -214,7 +214,7 @@ pub fn eval_to_const_value_provider<'tcx>( if key.param_env.reveal() == Reveal::All { let mut key = key; key.param_env = key.param_env.with_user_facing(); - match tcx.eval_to_const_value(key) { + match tcx.eval_to_const_value_raw(key) { // try again with reveal all as requested Err(ErrorHandled::TooGeneric) => {} // deduplicate calls diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index bbbb25117c00c..49770b96a995d 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -52,7 +52,7 @@ pub fn provide(providers: &mut Providers) { transform::provide(providers); monomorphize::partitioning::provide(providers); monomorphize::polymorphize::provide(providers); - providers.eval_to_const_value = const_eval::eval_to_const_value_provider; + providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider; providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider; providers.const_caller_location = const_eval::const_caller_location; providers.destructure_const = |tcx, param_env_and_value| { diff --git a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr index 26d396a181983..8c57fd37e88f6 100644 --- a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr +++ b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr @@ -10,8 +10,8 @@ LL | let x: &'static i32 = &(1 / 0); query stack during panic: #0 [eval_to_allocation_raw] const-evaluating + checking `main::promoted[1]` -#1 [eval_to_const_value] simplifying constant for the type system `main::promoted[1]` -#2 [eval_to_const_value] simplifying constant for the type system `main::promoted[1]` +#1 [eval_to_const_value_raw] simplifying constant for the type system `main::promoted[1]` +#2 [eval_to_const_value_raw] simplifying constant for the type system `main::promoted[1]` #3 [normalize_generic_arg_after_erasing_regions] normalizing `main::promoted[1]` #4 [optimized_mir] optimizing MIR for `main` #5 [collect_and_partition_mono_items] collect_and_partition_mono_items From 4debbdc6b9cfe35295ba0e245b0aad8f8079ec8a Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 19 Sep 2020 10:57:13 +0200 Subject: [PATCH 0656/1052] transmute: use diagnostic item --- compiler/rustc_lint/src/builtin.rs | 9 +-------- compiler/rustc_lint/src/context.rs | 2 ++ compiler/rustc_passes/src/diagnostic_items.rs | 14 +++++++++++++- library/core/src/intrinsics.rs | 1 + 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 5b5dbcf192ca1..6cbcbc3173b07 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2350,13 +2350,6 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { /// Determine if this expression is a "dangerous initialization". fn is_dangerous_init(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option { - // `transmute` is inside an anonymous module (the `extern` block?); - // `Invalid` represents the empty string and matches that. - // FIXME(#66075): use diagnostic items. Somehow, that does not seem to work - // on intrinsics right now. - const TRANSMUTE_PATH: &[Symbol] = - &[sym::core, sym::intrinsics, kw::Invalid, sym::transmute]; - if let hir::ExprKind::Call(ref path_expr, ref args) = expr.kind { // Find calls to `mem::{uninitialized,zeroed}` methods. if let hir::ExprKind::Path(ref qpath) = path_expr.kind { @@ -2366,7 +2359,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { return Some(InitKind::Zeroed); } else if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, def_id) { return Some(InitKind::Uninit); - } else if cx.match_def_path(def_id, TRANSMUTE_PATH) { + } else if cx.tcx.is_diagnostic_item(sym::transmute, def_id) { if is_zero(&args[0]) { return Some(InitKind::Zeroed); } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index f0342b69c9261..ec275dda1f4b7 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -720,6 +720,8 @@ impl<'tcx> LateContext<'tcx> { /// Anonymous scopes such as `extern` imports are matched with `kw::Invalid`; /// inherent `impl` blocks are matched with the name of the type. /// + /// If possible, consider using a `rustc_diagnostic_item` instead. + /// /// # Examples /// /// ```rust,ignore (no context or def id available) diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs index df0f9f157aedf..94592935c7f91 100644 --- a/compiler/rustc_passes/src/diagnostic_items.rs +++ b/compiler/rustc_passes/src/diagnostic_items.rs @@ -12,11 +12,11 @@ use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::Session; +use rustc_span::def_id::{DefId, LOCAL_CRATE}; use rustc_span::symbol::{sym, Symbol}; struct DiagnosticItemCollector<'tcx> { @@ -100,6 +100,18 @@ fn collect<'tcx>(tcx: TyCtxt<'tcx>) -> FxHashMap { // 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) { + 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), + } + } + } collector.items } diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index dd9af2d07e770..f3f0a2f02c57d 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1071,6 +1071,7 @@ extern "rust-intrinsic" { // NOTE: While this makes the intrinsic const stable, we have some custom code in const fn // checks that prevent its use within `const fn`. #[rustc_const_stable(feature = "const_transmute", since = "1.46.0")] + #[rustc_diagnostic_item = "transmute"] pub fn transmute(e: T) -> U; /// Returns `true` if the actual type given as `T` requires drop From 39f125918d05176d711ef9da3c0bbd4c861bb14e Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 19 Sep 2020 11:17:44 +0200 Subject: [PATCH 0657/1052] cfg bootstrap --- library/core/src/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index f3f0a2f02c57d..abb9bfec127be 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1071,7 +1071,7 @@ extern "rust-intrinsic" { // NOTE: While this makes the intrinsic const stable, we have some custom code in const fn // checks that prevent its use within `const fn`. #[rustc_const_stable(feature = "const_transmute", since = "1.46.0")] - #[rustc_diagnostic_item = "transmute"] + #[cfg_attr(not(bootstrap), rustc_diagnostic_item = "transmute")] pub fn transmute(e: T) -> U; /// Returns `true` if the actual type given as `T` requires drop From 0eecbd4f9731d3dc574691344997b640dd023315 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 19 Sep 2020 11:32:55 +0200 Subject: [PATCH 0658/1052] wording --- compiler/rustc_lint/src/context.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index ec275dda1f4b7..f4f25752e3f5a 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -720,7 +720,8 @@ impl<'tcx> LateContext<'tcx> { /// Anonymous scopes such as `extern` imports are matched with `kw::Invalid`; /// inherent `impl` blocks are matched with the name of the type. /// - /// If possible, consider using a `rustc_diagnostic_item` instead. + /// Instead of using this method, it is often preferable to instead use + /// `rustc_diagnostic_item` or a `lang_item`, which is less prone to errors. /// /// # Examples /// From f7d5080ec3c21c5418649a1c5b3f830ff37734f1 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Fri, 18 Sep 2020 20:49:25 +0200 Subject: [PATCH 0659/1052] don't take `TyCtxt` by reference --- compiler/rustc_middle/src/middle/lang_items.rs | 6 +++--- compiler/rustc_middle/src/mir/interpret/mod.rs | 18 +++++++++--------- compiler/rustc_middle/src/ty/context.rs | 18 +++++++++--------- compiler/rustc_middle/src/ty/error.rs | 12 ++++++------ compiler/rustc_middle/src/ty/fold.rs | 8 ++++---- compiler/rustc_middle/src/ty/util.rs | 10 ++++------ 6 files changed, 35 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs index 7194a035e89f6..cc9706f2d867c 100644 --- a/compiler/rustc_middle/src/middle/lang_items.rs +++ b/compiler/rustc_middle/src/middle/lang_items.rs @@ -17,7 +17,7 @@ use rustc_target::spec::PanicStrategy; impl<'tcx> TyCtxt<'tcx> { /// Returns the `DefId` for a given `LangItem`. /// If not found, fatally aborts compilation. - pub fn require_lang_item(&self, lang_item: LangItem, span: Option) -> DefId { + pub fn require_lang_item(self, lang_item: LangItem, span: Option) -> DefId { self.lang_items().require(lang_item).unwrap_or_else(|msg| { if let Some(span) = span { self.sess.span_fatal(span, &msg) @@ -27,7 +27,7 @@ impl<'tcx> TyCtxt<'tcx> { }) } - pub fn fn_trait_kind_from_lang_item(&self, id: DefId) -> Option { + pub fn fn_trait_kind_from_lang_item(self, id: DefId) -> Option { let items = self.lang_items(); match Some(id) { x if x == items.fn_trait() => Some(ty::ClosureKind::Fn), @@ -37,7 +37,7 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub fn is_weak_lang_item(&self, item_def_id: DefId) -> bool { + pub fn is_weak_lang_item(self, item_def_id: DefId) -> bool { self.lang_items().is_weak_lang_item(item_def_id) } } diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index cbc362d934ff8..51642fceb1d93 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -447,14 +447,14 @@ impl<'tcx> TyCtxt<'tcx> { /// /// Make sure to call `set_alloc_id_memory` or `set_alloc_id_same_memory` before returning such /// an `AllocId` from a query. - pub fn reserve_alloc_id(&self) -> AllocId { + pub fn reserve_alloc_id(self) -> AllocId { self.alloc_map.lock().reserve() } /// Reserves a new ID *if* this allocation has not been dedup-reserved before. /// Should only be used for function pointers and statics, we don't want /// to dedup IDs for "real" memory! - fn reserve_and_set_dedup(&self, alloc: GlobalAlloc<'tcx>) -> AllocId { + fn reserve_and_set_dedup(self, alloc: GlobalAlloc<'tcx>) -> AllocId { let mut alloc_map = self.alloc_map.lock(); match alloc { GlobalAlloc::Function(..) | GlobalAlloc::Static(..) => {} @@ -472,13 +472,13 @@ impl<'tcx> TyCtxt<'tcx> { /// Generates an `AllocId` for a static or return a cached one in case this function has been /// called on the same static before. - pub fn create_static_alloc(&self, static_id: DefId) -> AllocId { + pub fn create_static_alloc(self, static_id: DefId) -> AllocId { self.reserve_and_set_dedup(GlobalAlloc::Static(static_id)) } /// Generates an `AllocId` for a function. Depending on the function type, /// this might get deduplicated or assigned a new ID each time. - pub fn create_fn_alloc(&self, instance: Instance<'tcx>) -> AllocId { + pub fn create_fn_alloc(self, instance: Instance<'tcx>) -> AllocId { // Functions cannot be identified by pointers, as asm-equal functions can get deduplicated // by the linker (we set the "unnamed_addr" attribute for LLVM) and functions can be // duplicated across crates. @@ -507,7 +507,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Statics with identical content will still point to the same `Allocation`, i.e., /// their data will be deduplicated through `Allocation` interning -- but they /// are different places in memory and as such need different IDs. - pub fn create_memory_alloc(&self, mem: &'tcx Allocation) -> AllocId { + pub fn create_memory_alloc(self, mem: &'tcx Allocation) -> AllocId { let id = self.reserve_alloc_id(); self.set_alloc_id_memory(id, mem); id @@ -519,7 +519,7 @@ impl<'tcx> TyCtxt<'tcx> { /// This function exists to allow const eval to detect the difference between evaluation- /// local dangling pointers and allocations in constants/statics. #[inline] - pub fn get_global_alloc(&self, id: AllocId) -> Option> { + pub fn get_global_alloc(self, id: AllocId) -> Option> { self.alloc_map.lock().alloc_map.get(&id).cloned() } @@ -529,7 +529,7 @@ impl<'tcx> TyCtxt<'tcx> { /// constants (as all constants must pass interning and validation that check for dangling /// ids), this function is frequently used throughout rustc, but should not be used within /// the miri engine. - pub fn global_alloc(&self, id: AllocId) -> GlobalAlloc<'tcx> { + pub fn global_alloc(self, id: AllocId) -> GlobalAlloc<'tcx> { match self.get_global_alloc(id) { Some(alloc) => alloc, None => bug!("could not find allocation for {}", id), @@ -538,7 +538,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. Trying to /// call this function twice, even with the same `Allocation` will ICE the compiler. - pub fn set_alloc_id_memory(&self, id: AllocId, mem: &'tcx Allocation) { + pub fn set_alloc_id_memory(self, id: AllocId, mem: &'tcx Allocation) { if let Some(old) = self.alloc_map.lock().alloc_map.insert(id, GlobalAlloc::Memory(mem)) { bug!("tried to set allocation ID {}, but it was already existing as {:#?}", id, old); } @@ -546,7 +546,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. May be called /// twice for the same `(AllocId, Allocation)` pair. - fn set_alloc_id_same_memory(&self, id: AllocId, mem: &'tcx Allocation) { + fn set_alloc_id_same_memory(self, id: AllocId, mem: &'tcx Allocation) { self.alloc_map.lock().alloc_map.insert_same(id, GlobalAlloc::Memory(mem)); } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 56746666e2f1f..39bf5472b76f8 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1403,7 +1403,7 @@ impl<'tcx> TyCtxt<'tcx> { } // Returns the `DefId` and the `BoundRegion` corresponding to the given region. - pub fn is_suitable_region(&self, region: Region<'tcx>) -> Option { + pub fn is_suitable_region(self, region: Region<'tcx>) -> Option { let (suitable_region_binding_scope, bound_region) = match *region { ty::ReFree(ref free_region) => { (free_region.scope.expect_local(), free_region.bound_region) @@ -1433,7 +1433,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Given a `DefId` for an `fn`, return all the `dyn` and `impl` traits in its return type. pub fn return_type_impl_or_dyn_traits( - &self, + self, scope_def_id: LocalDefId, ) -> Vec<&'tcx hir::Ty<'tcx>> { let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id); @@ -1479,7 +1479,7 @@ impl<'tcx> TyCtxt<'tcx> { v.0 } - pub fn return_type_impl_trait(&self, scope_def_id: LocalDefId) -> Option<(Ty<'tcx>, Span)> { + pub fn return_type_impl_trait(self, scope_def_id: LocalDefId) -> Option<(Ty<'tcx>, Span)> { // HACK: `type_of_def_id()` will fail on these (#55796), so return `None`. let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id); match self.hir().get(hir_id) { @@ -1497,7 +1497,7 @@ impl<'tcx> TyCtxt<'tcx> { let ret_ty = self.type_of(scope_def_id); match ret_ty.kind() { ty::FnDef(_, _) => { - let sig = ret_ty.fn_sig(*self); + let sig = ret_ty.fn_sig(self); let output = self.erase_late_bound_regions(&sig.output()); if output.is_impl_trait() { let fn_decl = self.hir().fn_decl_by_hir_id(hir_id).unwrap(); @@ -1511,7 +1511,7 @@ impl<'tcx> TyCtxt<'tcx> { } // Checks if the bound region is in Impl Item. - pub fn is_bound_region_in_impl_item(&self, suitable_region_binding_scope: LocalDefId) -> bool { + pub fn is_bound_region_in_impl_item(self, suitable_region_binding_scope: LocalDefId) -> bool { let container_id = self.associated_item(suitable_region_binding_scope.to_def_id()).container.id(); if self.impl_trait_ref(container_id).is_some() { @@ -1528,21 +1528,21 @@ impl<'tcx> TyCtxt<'tcx> { /// Determines whether identifiers in the assembly have strict naming rules. /// Currently, only NVPTX* targets need it. - pub fn has_strict_asm_symbol_naming(&self) -> bool { + pub fn has_strict_asm_symbol_naming(self) -> bool { self.sess.target.target.arch.contains("nvptx") } /// Returns `&'static core::panic::Location<'static>`. - pub fn caller_location_ty(&self) -> Ty<'tcx> { + pub fn caller_location_ty(self) -> Ty<'tcx> { self.mk_imm_ref( self.lifetimes.re_static, self.type_of(self.require_lang_item(LangItem::PanicLocation, None)) - .subst(*self, self.mk_substs([self.lifetimes.re_static.into()].iter())), + .subst(self, self.mk_substs([self.lifetimes.re_static.into()].iter())), ) } /// Returns a displayable description and article for the given `def_id` (e.g. `("a", "struct")`). - pub fn article_and_description(&self, def_id: DefId) -> (&'static str, &'static str) { + pub fn article_and_description(self, def_id: DefId) -> (&'static str, &'static str) { match self.def_kind(def_id) { DefKind::Generator => match self.generator_kind(def_id).unwrap() { rustc_hir::GeneratorKind::Async(..) => ("an", "async closure"), diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 7226a906e5c97..475c3101c1e98 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -546,7 +546,7 @@ impl Trait for X { } fn suggest_constraint( - &self, + self, db: &mut DiagnosticBuilder<'_>, msg: &str, body_owner_def_id: DefId, @@ -554,14 +554,14 @@ impl Trait for X { ty: Ty<'tcx>, ) -> bool { let assoc = self.associated_item(proj_ty.item_def_id); - let trait_ref = proj_ty.trait_ref(*self); + let trait_ref = proj_ty.trait_ref(self); if let Some(item) = self.hir().get_if_local(body_owner_def_id) { if let Some(hir_generics) = item.generics() { // Get the `DefId` for the type parameter corresponding to `A` in `::Foo`. // This will also work for `impl Trait`. let def_id = if let ty::Param(param_ty) = proj_ty.self_ty().kind() { let generics = self.generics_of(body_owner_def_id); - generics.type_param(¶m_ty, *self).def_id + generics.type_param(param_ty, self).def_id } else { return false; }; @@ -629,7 +629,7 @@ impl Trait for X { /// and the `impl`, we provide a generic `help` to constrain the assoc type or call an assoc /// fn that returns the type. fn expected_projection( - &self, + self, db: &mut DiagnosticBuilder<'_>, proj_ty: &ty::ProjectionTy<'tcx>, values: &ExpectedFound>, @@ -734,7 +734,7 @@ fn foo(&self) -> Self::T { String::new() } } fn point_at_methods_that_satisfy_associated_type( - &self, + self, db: &mut DiagnosticBuilder<'_>, assoc_container_id: DefId, current_method_ident: Option, @@ -789,7 +789,7 @@ fn foo(&self) -> Self::T { String::new() } } fn point_at_associated_type( - &self, + self, db: &mut DiagnosticBuilder<'_>, body_owner_def_id: DefId, found: Ty<'tcx>, diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 5e8fb95dc2985..84134bedef0bc 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -623,7 +623,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Replaces any late-bound regions bound in `value` with /// free variants attached to `all_outlive_scope`. pub fn liberate_late_bound_regions( - &self, + self, all_outlive_scope: DefId, value: &ty::Binder, ) -> T @@ -644,7 +644,7 @@ impl<'tcx> TyCtxt<'tcx> { /// variables and equate `value` with something else, those /// variables will also be equated. pub fn collect_constrained_late_bound_regions( - &self, + self, value: &Binder, ) -> FxHashSet where @@ -655,7 +655,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns a set of all late-bound regions that appear in `value` anywhere. pub fn collect_referenced_late_bound_regions( - &self, + self, value: &Binder, ) -> FxHashSet where @@ -665,7 +665,7 @@ impl<'tcx> TyCtxt<'tcx> { } fn collect_late_bound_regions( - &self, + self, value: &Binder, just_constraint: bool, ) -> FxHashSet diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index f3eb7c35f0494..4127b6535bca6 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -170,9 +170,7 @@ impl<'tcx> TyCtxt<'tcx> { }); hasher.finish() } -} -impl<'tcx> TyCtxt<'tcx> { pub fn has_error_field(self, ty: Ty<'tcx>) -> bool { if let ty::Adt(def, substs) = *ty.kind() { for field in def.all_fields() { @@ -526,22 +524,22 @@ impl<'tcx> TyCtxt<'tcx> { } /// Returns `true` if the node pointed to by `def_id` is a `static` item. - pub fn is_static(&self, def_id: DefId) -> bool { + pub fn is_static(self, def_id: DefId) -> bool { self.static_mutability(def_id).is_some() } /// Returns `true` if this is a `static` item with the `#[thread_local]` attribute. - pub fn is_thread_local_static(&self, def_id: DefId) -> bool { + pub fn is_thread_local_static(self, def_id: DefId) -> bool { self.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) } /// Returns `true` if the node pointed to by `def_id` is a mutable `static` item. - pub fn is_mutable_static(&self, def_id: DefId) -> bool { + pub fn is_mutable_static(self, def_id: DefId) -> bool { self.static_mutability(def_id) == Some(hir::Mutability::Mut) } /// Get the type of the pointer to the static that we use in MIR. - pub fn static_ptr_ty(&self, def_id: DefId) -> Ty<'tcx> { + pub fn static_ptr_ty(self, def_id: DefId) -> Ty<'tcx> { // Make sure that any constants in the static's type are evaluated. let static_ty = self.normalize_erasing_regions(ty::ParamEnv::empty(), self.type_of(def_id)); From a219ad64a6ee025b9a5c83de390280f818cd81c6 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 19 Sep 2020 12:34:31 +0200 Subject: [PATCH 0660/1052] extend `is_ty_or_ty_ctxt` to self types --- compiler/rustc_lint/src/internal.rs | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 100e555f299ae..2bac4517409b4 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -5,7 +5,9 @@ use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext} use rustc_ast::{Item, ItemKind}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; +use rustc_hir::def::Res; use rustc_hir::{GenericArg, HirId, MutTy, Mutability, Path, PathSegment, QPath, Ty, TyKind}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::symbol::{sym, Ident, Symbol}; @@ -177,11 +179,25 @@ fn lint_ty_kind_usage(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> bool { fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, ty: &Ty<'_>) -> Option { if let TyKind::Path(qpath) = &ty.kind { if let QPath::Resolved(_, path) = qpath { - let did = path.res.opt_def_id()?; - if cx.tcx.is_diagnostic_item(sym::Ty, did) { - return Some(format!("Ty{}", gen_args(path.segments.last().unwrap()))); - } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, did) { - return Some(format!("TyCtxt{}", gen_args(path.segments.last().unwrap()))); + match path.res { + Res::Def(_, did) => { + if cx.tcx.is_diagnostic_item(sym::Ty, did) { + return Some(format!("Ty{}", gen_args(path.segments.last().unwrap()))); + } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, did) { + return Some(format!("TyCtxt{}", gen_args(path.segments.last().unwrap()))); + } + } + // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait. + Res::SelfTy(None, Some((did, _))) => { + if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() { + if cx.tcx.is_diagnostic_item(sym::Ty, adt.did) { + return Some(format!("Ty<{}>", substs[0])); + } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, adt.did) { + return Some(format!("TyCtxt<{}>", substs[0])); + } + } + } + _ => (), } } } From 67f319c30bed5c83ae3b4872109999a8a574f29e Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 19 Sep 2020 12:38:24 +0200 Subject: [PATCH 0661/1052] take `TyCtxt` by value --- compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_middle/src/ty/error.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 39bf5472b76f8..5a575677f9e4a 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1179,7 +1179,7 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_const(ty::Const { val: ty::ConstKind::Error(DelaySpanBugEmitted(())), ty }) } - pub fn consider_optimizing String>(&self, msg: T) -> bool { + pub fn consider_optimizing String>(self, msg: T) -> bool { let cname = self.crate_name(LOCAL_CRATE).as_str(); self.sess.consider_optimizing(&cname, msg) } diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 475c3101c1e98..82d2e9b987472 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -851,7 +851,7 @@ fn foo(&self) -> Self::T { String::new() } /// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref` /// requirement, provide a strucuted suggestion to constrain it to a given type `ty`. fn constrain_generic_bound_associated_type_structured_suggestion( - &self, + self, db: &mut DiagnosticBuilder<'_>, trait_ref: &ty::TraitRef<'tcx>, bounds: hir::GenericBounds<'_>, @@ -875,7 +875,7 @@ fn foo(&self) -> Self::T { String::new() } /// Given a span corresponding to a bound, provide a structured suggestion to set an /// associated type to a given type `ty`. fn constrain_associated_type_structured_suggestion( - &self, + self, db: &mut DiagnosticBuilder<'_>, span: Span, assoc: &ty::AssocItem, From 7c98f6f58440d80f6116e4d060778ab0a9b98131 Mon Sep 17 00:00:00 2001 From: ishitatsuyuki Date: Sat, 19 Sep 2020 22:00:10 +0900 Subject: [PATCH 0662/1052] Add fast path for match checking --- .../src/thir/pattern/_match.rs | 108 +++++++++++++++--- 1 file changed, 95 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/_match.rs b/compiler/rustc_mir_build/src/thir/pattern/_match.rs index ad94740c16066..1cbfc73a9c6dc 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/_match.rs @@ -276,7 +276,7 @@ use self::Usefulness::*; use self::WitnessPreference::*; use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::vec::Idx; use super::{compare_const_vals, PatternFoldable, PatternFolder}; @@ -504,13 +504,27 @@ impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> { } } +/// Depending on the match patterns, the specialization process might be able to use a fast path. +/// Tracks whether we can use the fast path and the lookup table needed in those cases. +#[derive(Clone, Debug)] +enum SpecializationCache { + /// Patterns consist of only enum variants. + Variants { lookup: FxHashMap>, wilds: SmallVec<[usize; 1]> }, + /// Does not belong to the cases above, use the slow path. + Incompatible, +} + /// A 2D matrix. #[derive(Clone)] -crate struct Matrix<'p, 'tcx>(Vec>); +crate struct Matrix<'p, 'tcx> { + patterns: Vec>, + cache: SpecializationCache, +} impl<'p, 'tcx> Matrix<'p, 'tcx> { crate fn empty() -> Self { - Matrix(vec![]) + // Use SpecializationCache::Incompatible as a placeholder; the initialization is in push(). + Matrix { patterns: vec![], cache: SpecializationCache::Incompatible } } /// Pushes a new row to the matrix. If the row starts with an or-pattern, this expands it. @@ -522,18 +536,65 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { self.push(row) } } else { - self.0.push(row); + if self.patterns.is_empty() { + self.cache = if row.is_empty() { + SpecializationCache::Incompatible + } else { + match *row.head().kind { + PatKind::Variant { .. } => SpecializationCache::Variants { + lookup: FxHashMap::default(), + wilds: SmallVec::new(), + }, + // Note: If the first pattern is a wildcard, then all patterns after that is not + // useful. The check is simple enough so we treat it as the same as unsupported + // patterns. + _ => SpecializationCache::Incompatible, + } + }; + } + let idx_to_insert = self.patterns.len(); + match &mut self.cache { + SpecializationCache::Variants { ref mut lookup, ref mut wilds } => { + let head = row.head(); + match *head.kind { + _ if head.is_wildcard() => { + for (_, v) in lookup.iter_mut() { + v.push(idx_to_insert); + } + wilds.push(idx_to_insert); + } + PatKind::Variant { adt_def, variant_index, .. } => { + lookup + .entry(adt_def.variants[variant_index].def_id) + .or_insert_with(|| wilds.clone()) + .push(idx_to_insert); + } + _ => { + self.cache = SpecializationCache::Incompatible; + } + } + } + SpecializationCache::Incompatible => {} + } + self.patterns.push(row); } } /// Iterate over the first component of each row fn heads<'a>(&'a self) -> impl Iterator> + Captures<'p> { - self.0.iter().map(|r| r.head()) + self.patterns.iter().map(|r| r.head()) } /// This computes `D(self)`. See top of the file for explanations. fn specialize_wildcard(&self) -> Self { - self.0.iter().filter_map(|r| r.specialize_wildcard()).collect() + match &self.cache { + SpecializationCache::Variants { wilds, .. } => { + wilds.iter().filter_map(|&i| self.patterns[i].specialize_wildcard()).collect() + } + SpecializationCache::Incompatible => { + self.patterns.iter().filter_map(|r| r.specialize_wildcard()).collect() + } + } } /// This computes `S(constructor, self)`. See top of the file for explanations. @@ -543,10 +604,31 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { constructor: &Constructor<'tcx>, ctor_wild_subpatterns: &Fields<'p, 'tcx>, ) -> Matrix<'p, 'tcx> { - self.0 - .iter() - .filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns)) - .collect() + match &self.cache { + SpecializationCache::Variants { lookup, wilds } => { + if let Constructor::Variant(id) = constructor { + lookup + .get(id) + .unwrap_or(&wilds) + .iter() + .filter_map(|&i| { + self.patterns[i].specialize_constructor( + cx, + constructor, + ctor_wild_subpatterns, + ) + }) + .collect() + } else { + unreachable!() + } + } + SpecializationCache::Incompatible => self + .patterns + .iter() + .filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns)) + .collect(), + } } } @@ -568,7 +650,7 @@ impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "\n")?; - let &Matrix(ref m) = self; + let Matrix { patterns: m, .. } = self; let pretty_printed_matrix: Vec> = m.iter().map(|row| row.iter().map(|pat| format!("{:?}", pat)).collect()).collect(); @@ -1824,7 +1906,7 @@ crate fn is_useful<'p, 'tcx>( is_under_guard: bool, is_top_level: bool, ) -> Usefulness<'tcx> { - let &Matrix(ref rows) = matrix; + let Matrix { patterns: rows, .. } = matrix; debug!("is_useful({:#?}, {:#?})", matrix, v); // The base case. We are pattern-matching on () and the return value is @@ -2266,7 +2348,7 @@ fn split_grouped_constructors<'p, 'tcx>( // `borders` is the set of borders between equivalence classes: each equivalence // class lies between 2 borders. let row_borders = matrix - .0 + .patterns .iter() .flat_map(|row| { IntRange::from_pat(tcx, param_env, row.head()).map(|r| (r, row.len())) From cad050b002ff36c65b68833fcd90824eceee1993 Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Thu, 17 Sep 2020 18:27:49 +0200 Subject: [PATCH 0663/1052] Add regression test showcasing miscompilation --- ..._regression.encode.SimplifyBranchSame.diff | 30 +++++++++++++++++++ src/test/mir-opt/76803_regression.rs | 19 ++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 src/test/mir-opt/76803_regression.encode.SimplifyBranchSame.diff create mode 100644 src/test/mir-opt/76803_regression.rs diff --git a/src/test/mir-opt/76803_regression.encode.SimplifyBranchSame.diff b/src/test/mir-opt/76803_regression.encode.SimplifyBranchSame.diff new file mode 100644 index 0000000000000..63139285209b6 --- /dev/null +++ b/src/test/mir-opt/76803_regression.encode.SimplifyBranchSame.diff @@ -0,0 +1,30 @@ +- // MIR for `encode` before SimplifyBranchSame ++ // MIR for `encode` after SimplifyBranchSame + + fn encode(_1: Type) -> Type { + debug v => _1; // in scope 0 at $DIR/76803_regression.rs:10:15: 10:16 + let mut _0: Type; // return place in scope 0 at $DIR/76803_regression.rs:10:27: 10:31 + let mut _2: isize; // in scope 0 at $DIR/76803_regression.rs:12:9: 12:16 + + bb0: { + _2 = discriminant(_1); // scope 0 at $DIR/76803_regression.rs:12:9: 12:16 +- switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/76803_regression.rs:12:9: 12:16 ++ goto -> bb1; // scope 0 at $DIR/76803_regression.rs:12:9: 12:16 + } + + bb1: { + _0 = move _1; // scope 0 at $DIR/76803_regression.rs:13:14: 13:15 +- goto -> bb3; // scope 0 at $DIR/76803_regression.rs:11:5: 14:6 ++ goto -> bb2; // scope 0 at $DIR/76803_regression.rs:11:5: 14:6 + } + + bb2: { +- discriminant(_0) = 1; // scope 0 at $DIR/76803_regression.rs:12:20: 12:27 +- goto -> bb3; // scope 0 at $DIR/76803_regression.rs:11:5: 14:6 +- } +- +- bb3: { + return; // scope 0 at $DIR/76803_regression.rs:15:2: 15:2 + } + } + diff --git a/src/test/mir-opt/76803_regression.rs b/src/test/mir-opt/76803_regression.rs new file mode 100644 index 0000000000000..05dc3c9784109 --- /dev/null +++ b/src/test/mir-opt/76803_regression.rs @@ -0,0 +1,19 @@ +// compile-flags: -Z mir-opt-level=1 +// EMIT_MIR 76803_regression.encode.SimplifyBranchSame.diff + +#[derive(Debug, Eq, PartialEq)] +pub enum Type { + A, + B, +} + +pub fn encode(v: Type) -> Type { + match v { + Type::A => Type::B, + _ => v, + } +} + +fn main() { + assert_eq!(Type::B, encode(Type::A)); +} From bfa2030ccbbabc4944b719c9194e190e1726fc8c Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 19 Sep 2020 15:36:53 +0200 Subject: [PATCH 0664/1052] update docs --- compiler/rustc_lint/src/context.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index f4f25752e3f5a..0265fc323b3b3 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -721,7 +721,8 @@ impl<'tcx> LateContext<'tcx> { /// inherent `impl` blocks are matched with the name of the type. /// /// Instead of using this method, it is often preferable to instead use - /// `rustc_diagnostic_item` or a `lang_item`, which is less prone to errors. + /// `rustc_diagnostic_item` or a `lang_item`. This is less prone to errors + /// as paths get invalidated if the target definition moves. /// /// # Examples /// From 738ed9b5ec62259eb0f2aced549feec2f7e7c75a Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Thu, 17 Sep 2020 19:10:47 +0200 Subject: [PATCH 0665/1052] Fix #76803 Check that the variant index matches the target value from the SwitchInt we came from --- .../rustc_mir/src/transform/simplify_try.rs | 56 +++++++++++-------- ..._regression.encode.SimplifyBranchSame.diff | 16 +++--- .../simplify_arm.id.SimplifyBranchSame.diff | 27 +++++---- 3 files changed, 55 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_mir/src/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs index 9a11d92724020..bf6fdebb3d3c7 100644 --- a/compiler/rustc_mir/src/transform/simplify_try.rs +++ b/compiler/rustc_mir/src/transform/simplify_try.rs @@ -16,7 +16,7 @@ use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::{self, List, Ty, TyCtxt}; use rustc_target::abi::VariantIdx; -use std::iter::{Enumerate, Peekable}; +use std::iter::{once, Enumerate, Peekable}; use std::slice::Iter; /// Simplifies arms of form `Variant(x) => Variant(x)` to just a move. @@ -551,6 +551,12 @@ struct SimplifyBranchSameOptimization { bb_to_opt_terminator: BasicBlock, } +struct SwitchTargetAndValue { + target: BasicBlock, + // None in case of the `otherwise` case + value: Option, +} + struct SimplifyBranchSameOptimizationFinder<'a, 'tcx> { body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, @@ -562,8 +568,15 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { .basic_blocks() .iter_enumerated() .filter_map(|(bb_idx, bb)| { - let (discr_switched_on, targets) = match &bb.terminator().kind { - TerminatorKind::SwitchInt { targets, discr, .. } => (discr, targets), + let (discr_switched_on, targets_and_values):(_, Vec<_>) = match &bb.terminator().kind { + TerminatorKind::SwitchInt { targets, discr, values, .. } => { + // if values.len() == targets.len() - 1, we need to include None where no value is present + // such that the zip does not throw away targets. If no `otherwise` case is in targets, the zip will simply throw away the added None + let values_extended = values.iter().map(|x|Some(*x)).chain(once(None)); + let targets_and_values = targets.iter().zip(values_extended) + .map(|(target, value)| SwitchTargetAndValue{target:*target, value:value}) + .collect(); + (discr, targets_and_values)}, _ => return None, }; @@ -587,9 +600,9 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { }, }; - let mut iter_bbs_reachable = targets + let mut iter_bbs_reachable = targets_and_values .iter() - .map(|idx| (*idx, &self.body.basic_blocks()[*idx])) + .map(|target_and_value| (target_and_value, &self.body.basic_blocks()[target_and_value.target])) .filter(|(_, bb)| { // Reaching `unreachable` is UB so assume it doesn't happen. bb.terminator().kind != TerminatorKind::Unreachable @@ -603,16 +616,16 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { }) .peekable(); - let bb_first = iter_bbs_reachable.peek().map(|(idx, _)| *idx).unwrap_or(targets[0]); + let bb_first = iter_bbs_reachable.peek().map(|(idx, _)| *idx).unwrap_or(&targets_and_values[0]); let mut all_successors_equivalent = StatementEquality::TrivialEqual; // All successor basic blocks must be equal or contain statements that are pairwise considered equal. - for ((bb_l_idx,bb_l), (bb_r_idx,bb_r)) in iter_bbs_reachable.tuple_windows() { + for ((target_and_value_l,bb_l), (target_and_value_r,bb_r)) in iter_bbs_reachable.tuple_windows() { let trivial_checks = bb_l.is_cleanup == bb_r.is_cleanup && bb_l.terminator().kind == bb_r.terminator().kind; let statement_check = || { bb_l.statements.iter().zip(&bb_r.statements).try_fold(StatementEquality::TrivialEqual, |acc,(l,r)| { - let stmt_equality = self.statement_equality(*adt_matched_on, &l, bb_l_idx, &r, bb_r_idx, self.tcx.sess.opts.debugging_opts.mir_opt_level); + let stmt_equality = self.statement_equality(*adt_matched_on, &l, target_and_value_l, &r, target_and_value_r); if matches!(stmt_equality, StatementEquality::NotEqual) { // short circuit None @@ -634,7 +647,7 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { // statements are trivially equal, so just take first trace!("Statements are trivially equal"); Some(SimplifyBranchSameOptimization { - bb_to_goto: bb_first, + bb_to_goto: bb_first.target, bb_to_opt_terminator: bb_idx, }) } @@ -669,10 +682,9 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { &self, adt_matched_on: Place<'tcx>, x: &Statement<'tcx>, - x_bb_idx: BasicBlock, + x_target_and_value: &SwitchTargetAndValue, y: &Statement<'tcx>, - y_bb_idx: BasicBlock, - mir_opt_level: usize, + y_target_and_value: &SwitchTargetAndValue, ) -> StatementEquality { let helper = |rhs: &Rvalue<'tcx>, place: &Place<'tcx>, @@ -691,13 +703,7 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { match rhs { Rvalue::Use(operand) if operand.place() == Some(adt_matched_on) => { - // FIXME(76803): This logic is currently broken because it does not take into - // account the current discriminant value. - if mir_opt_level > 2 { - StatementEquality::ConsideredEqual(side_to_choose) - } else { - StatementEquality::NotEqual - } + StatementEquality::ConsideredEqual(side_to_choose) } _ => { trace!( @@ -717,16 +723,20 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { ( StatementKind::Assign(box (_, rhs)), StatementKind::SetDiscriminant { place, variant_index }, - ) => { + ) + // we need to make sure that the switch value that targets the bb with SetDiscriminant (y), is the same as the variant index + if Some(variant_index.index() as u128) == y_target_and_value.value => { // choose basic block of x, as that has the assign - helper(rhs, place, variant_index, x_bb_idx) + helper(rhs, place, variant_index, x_target_and_value.target) } ( StatementKind::SetDiscriminant { place, variant_index }, StatementKind::Assign(box (_, rhs)), - ) => { + ) + // we need to make sure that the switch value that targets the bb with SetDiscriminant (x), is the same as the variant index + if Some(variant_index.index() as u128) == x_target_and_value.value => { // choose basic block of y, as that has the assign - helper(rhs, place, variant_index, y_bb_idx) + helper(rhs, place, variant_index, y_target_and_value.target) } _ => { trace!("NO: statements `{:?}` and `{:?}` not considered equal", x, y); diff --git a/src/test/mir-opt/76803_regression.encode.SimplifyBranchSame.diff b/src/test/mir-opt/76803_regression.encode.SimplifyBranchSame.diff index 63139285209b6..28b8329606c1b 100644 --- a/src/test/mir-opt/76803_regression.encode.SimplifyBranchSame.diff +++ b/src/test/mir-opt/76803_regression.encode.SimplifyBranchSame.diff @@ -8,22 +8,20 @@ bb0: { _2 = discriminant(_1); // scope 0 at $DIR/76803_regression.rs:12:9: 12:16 -- switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/76803_regression.rs:12:9: 12:16 -+ goto -> bb1; // scope 0 at $DIR/76803_regression.rs:12:9: 12:16 + switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/76803_regression.rs:12:9: 12:16 } bb1: { _0 = move _1; // scope 0 at $DIR/76803_regression.rs:13:14: 13:15 -- goto -> bb3; // scope 0 at $DIR/76803_regression.rs:11:5: 14:6 -+ goto -> bb2; // scope 0 at $DIR/76803_regression.rs:11:5: 14:6 + goto -> bb3; // scope 0 at $DIR/76803_regression.rs:11:5: 14:6 } bb2: { -- discriminant(_0) = 1; // scope 0 at $DIR/76803_regression.rs:12:20: 12:27 -- goto -> bb3; // scope 0 at $DIR/76803_regression.rs:11:5: 14:6 -- } -- -- bb3: { + discriminant(_0) = 1; // scope 0 at $DIR/76803_regression.rs:12:20: 12:27 + goto -> bb3; // scope 0 at $DIR/76803_regression.rs:11:5: 14:6 + } + + bb3: { return; // scope 0 at $DIR/76803_regression.rs:15:2: 15:2 } } diff --git a/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff b/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff index 06f359da2e70d..81a0e6ba0b4ee 100644 --- a/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff +++ b/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff @@ -13,24 +13,27 @@ bb0: { _2 = discriminant(_1); // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16 - switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16 +- switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16 ++ goto -> bb1; // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16 } bb1: { - discriminant(_0) = 0; // scope 0 at $DIR/simplify-arm.rs:12:17: 12:21 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6 - } - - bb2: { - unreachable; // scope 0 at $DIR/simplify-arm.rs:10:11: 10:12 - } - - bb3: { +- discriminant(_0) = 0; // scope 0 at $DIR/simplify-arm.rs:12:17: 12:21 +- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6 +- } +- +- bb2: { +- unreachable; // scope 0 at $DIR/simplify-arm.rs:10:11: 10:12 +- } +- +- bb3: { _0 = move _1; // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6 +- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6 ++ goto -> bb2; // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6 } - bb4: { +- bb4: { ++ bb2: { return; // scope 0 at $DIR/simplify-arm.rs:14:2: 14:2 } } From baecad9c392ec74fe0cccee2dc5876cf157e4966 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 4 Sep 2020 13:07:03 +0000 Subject: [PATCH 0666/1052] Move NonZero* to its file --- library/core/src/num/mod.rs | 183 ++---------------------------- library/core/src/num/nonzero.rs | 190 ++++++++++++++++++++++++++++++++ 2 files changed, 197 insertions(+), 176 deletions(-) create mode 100644 library/core/src/num/nonzero.rs diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index eec149cc3e801..fdf7695fbc8a5 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -8,7 +8,6 @@ use crate::convert::Infallible; use crate::fmt; use crate::intrinsics; use crate::mem; -use crate::ops::{BitOr, BitOrAssign}; use crate::str::FromStr; // Used because the `?` operator is not allowed in a const context. @@ -28,20 +27,6 @@ macro_rules! unlikely { }; } -macro_rules! impl_nonzero_fmt { - ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { - $( - #[$stability] - impl fmt::$Trait for $Ty { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.get().fmt(f) - } - } - )+ - } -} - macro_rules! doc_comment { ($x:expr, $($tt:tt)*) => { #[doc = $x] @@ -49,167 +34,6 @@ macro_rules! doc_comment { }; } -macro_rules! nonzero_integers { - ( $( #[$stability: meta] $Ty: ident($Int: ty); )+ ) => { - $( - doc_comment! { - concat!("An integer that is known not to equal zero. - -This enables some memory layout optimization. -For example, `Option<", stringify!($Ty), ">` is the same size as `", stringify!($Int), "`: - -```rust -use std::mem::size_of; -assert_eq!(size_of::>(), size_of::<", stringify!($Int), -">()); -```"), - #[$stability] - #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] - #[repr(transparent)] - #[rustc_layout_scalar_valid_range_start(1)] - #[rustc_nonnull_optimization_guaranteed] - pub struct $Ty($Int); - } - - impl $Ty { - /// Creates a non-zero without checking the value. - /// - /// # Safety - /// - /// The value must not be zero. - #[$stability] - #[rustc_const_stable(feature = "nonzero", since = "1.34.0")] - #[inline] - pub const unsafe fn new_unchecked(n: $Int) -> Self { - // SAFETY: this is guaranteed to be safe by the caller. - unsafe { Self(n) } - } - - /// Creates a non-zero if the given value is not zero. - #[$stability] - #[rustc_const_stable(feature = "const_nonzero_int_methods", since = "1.47.0")] - #[inline] - pub const fn new(n: $Int) -> Option { - if n != 0 { - // SAFETY: we just checked that there's no `0` - Some(unsafe { Self(n) }) - } else { - None - } - } - - /// Returns the value as a primitive type. - #[$stability] - #[inline] - #[rustc_const_stable(feature = "nonzero", since = "1.34.0")] - pub const fn get(self) -> $Int { - self.0 - } - - } - - #[stable(feature = "from_nonzero", since = "1.31.0")] - impl From<$Ty> for $Int { - doc_comment! { - concat!( -"Converts a `", stringify!($Ty), "` into an `", stringify!($Int), "`"), - fn from(nonzero: $Ty) -> Self { - nonzero.0 - } - } - } - - #[stable(feature = "nonzero_bitor", since = "1.45.0")] - impl BitOr for $Ty { - type Output = Self; - #[inline] - fn bitor(self, rhs: Self) -> Self::Output { - // SAFETY: since `self` and `rhs` are both nonzero, the - // result of the bitwise-or will be nonzero. - unsafe { $Ty::new_unchecked(self.get() | rhs.get()) } - } - } - - #[stable(feature = "nonzero_bitor", since = "1.45.0")] - impl BitOr<$Int> for $Ty { - type Output = Self; - #[inline] - fn bitor(self, rhs: $Int) -> Self::Output { - // SAFETY: since `self` is nonzero, the result of the - // bitwise-or will be nonzero regardless of the value of - // `rhs`. - unsafe { $Ty::new_unchecked(self.get() | rhs) } - } - } - - #[stable(feature = "nonzero_bitor", since = "1.45.0")] - impl BitOr<$Ty> for $Int { - type Output = $Ty; - #[inline] - fn bitor(self, rhs: $Ty) -> Self::Output { - // SAFETY: since `rhs` is nonzero, the result of the - // bitwise-or will be nonzero regardless of the value of - // `self`. - unsafe { $Ty::new_unchecked(self | rhs.get()) } - } - } - - #[stable(feature = "nonzero_bitor", since = "1.45.0")] - impl BitOrAssign for $Ty { - #[inline] - fn bitor_assign(&mut self, rhs: Self) { - *self = *self | rhs; - } - } - - #[stable(feature = "nonzero_bitor", since = "1.45.0")] - impl BitOrAssign<$Int> for $Ty { - #[inline] - fn bitor_assign(&mut self, rhs: $Int) { - *self = *self | rhs; - } - } - - impl_nonzero_fmt! { - #[$stability] (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty - } - )+ - } -} - -nonzero_integers! { - #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU8(u8); - #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU16(u16); - #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU32(u32); - #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU64(u64); - #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU128(u128); - #[stable(feature = "nonzero", since = "1.28.0")] NonZeroUsize(usize); - #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI8(i8); - #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI16(i16); - #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI32(i32); - #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI64(i64); - #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI128(i128); - #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroIsize(isize); -} - -macro_rules! from_str_radix_nzint_impl { - ($($t:ty)*) => {$( - #[stable(feature = "nonzero_parse", since = "1.35.0")] - impl FromStr for $t { - type Err = ParseIntError; - fn from_str(src: &str) -> Result { - Self::new(from_str_radix(src, 10)?) - .ok_or(ParseIntError { - kind: IntErrorKind::Zero - }) - } - } - )*} -} - -from_str_radix_nzint_impl! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize -NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 NonZeroIsize } - /// Provides intentionally-wrapped arithmetic on `T`. /// /// Operations like `+` on `u32` values are intended to never overflow, @@ -289,8 +113,15 @@ pub mod dec2flt; pub mod diy_float; pub mod flt2dec; +mod nonzero; mod wrapping; +#[stable(feature = "nonzero", since = "1.28.0")] +pub use nonzero::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; + +#[stable(feature = "signed_nonzero", since = "1.34.0")] +pub use nonzero::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize}; + macro_rules! usize_isize_to_xe_bytes_doc { () => { " diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs new file mode 100644 index 0000000000000..382f799bfe5f9 --- /dev/null +++ b/library/core/src/num/nonzero.rs @@ -0,0 +1,190 @@ +//! Definitions of integer that is known not to equal zero. + +use crate::fmt; +use crate::ops::{BitOr, BitOrAssign}; +use crate::str::FromStr; + +use super::from_str_radix; +use super::{IntErrorKind, ParseIntError}; + +macro_rules! doc_comment { + ($x:expr, $($tt:tt)*) => { + #[doc = $x] + $($tt)* + }; +} + +macro_rules! impl_nonzero_fmt { + ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { + $( + #[$stability] + impl fmt::$Trait for $Ty { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.get().fmt(f) + } + } + )+ + } +} + +macro_rules! nonzero_integers { + ( $( #[$stability: meta] $Ty: ident($Int: ty); )+ ) => { + $( + doc_comment! { + concat!("An integer that is known not to equal zero. + +This enables some memory layout optimization. +For example, `Option<", stringify!($Ty), ">` is the same size as `", stringify!($Int), "`: + +```rust +use std::mem::size_of; +assert_eq!(size_of::>(), size_of::<", stringify!($Int), +">()); +```"), + #[$stability] + #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] + #[repr(transparent)] + #[rustc_layout_scalar_valid_range_start(1)] + #[rustc_nonnull_optimization_guaranteed] + pub struct $Ty($Int); + } + + impl $Ty { + /// Creates a non-zero without checking the value. + /// + /// # Safety + /// + /// The value must not be zero. + #[$stability] + #[rustc_const_stable(feature = "nonzero", since = "1.34.0")] + #[inline] + pub const unsafe fn new_unchecked(n: $Int) -> Self { + // SAFETY: this is guaranteed to be safe by the caller. + unsafe { Self(n) } + } + + /// Creates a non-zero if the given value is not zero. + #[$stability] + #[rustc_const_stable(feature = "const_nonzero_int_methods", since = "1.47.0")] + #[inline] + pub const fn new(n: $Int) -> Option { + if n != 0 { + // SAFETY: we just checked that there's no `0` + Some(unsafe { Self(n) }) + } else { + None + } + } + + /// Returns the value as a primitive type. + #[$stability] + #[inline] + #[rustc_const_stable(feature = "nonzero", since = "1.34.0")] + pub const fn get(self) -> $Int { + self.0 + } + + } + + #[stable(feature = "from_nonzero", since = "1.31.0")] + impl From<$Ty> for $Int { + doc_comment! { + concat!( +"Converts a `", stringify!($Ty), "` into an `", stringify!($Int), "`"), + fn from(nonzero: $Ty) -> Self { + nonzero.0 + } + } + } + + #[stable(feature = "nonzero_bitor", since = "1.45.0")] + impl BitOr for $Ty { + type Output = Self; + #[inline] + fn bitor(self, rhs: Self) -> Self::Output { + // SAFETY: since `self` and `rhs` are both nonzero, the + // result of the bitwise-or will be nonzero. + unsafe { $Ty::new_unchecked(self.get() | rhs.get()) } + } + } + + #[stable(feature = "nonzero_bitor", since = "1.45.0")] + impl BitOr<$Int> for $Ty { + type Output = Self; + #[inline] + fn bitor(self, rhs: $Int) -> Self::Output { + // SAFETY: since `self` is nonzero, the result of the + // bitwise-or will be nonzero regardless of the value of + // `rhs`. + unsafe { $Ty::new_unchecked(self.get() | rhs) } + } + } + + #[stable(feature = "nonzero_bitor", since = "1.45.0")] + impl BitOr<$Ty> for $Int { + type Output = $Ty; + #[inline] + fn bitor(self, rhs: $Ty) -> Self::Output { + // SAFETY: since `rhs` is nonzero, the result of the + // bitwise-or will be nonzero regardless of the value of + // `self`. + unsafe { $Ty::new_unchecked(self | rhs.get()) } + } + } + + #[stable(feature = "nonzero_bitor", since = "1.45.0")] + impl BitOrAssign for $Ty { + #[inline] + fn bitor_assign(&mut self, rhs: Self) { + *self = *self | rhs; + } + } + + #[stable(feature = "nonzero_bitor", since = "1.45.0")] + impl BitOrAssign<$Int> for $Ty { + #[inline] + fn bitor_assign(&mut self, rhs: $Int) { + *self = *self | rhs; + } + } + + impl_nonzero_fmt! { + #[$stability] (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty + } + )+ + } +} + +nonzero_integers! { + #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU8(u8); + #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU16(u16); + #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU32(u32); + #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU64(u64); + #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU128(u128); + #[stable(feature = "nonzero", since = "1.28.0")] NonZeroUsize(usize); + #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI8(i8); + #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI16(i16); + #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI32(i32); + #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI64(i64); + #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI128(i128); + #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroIsize(isize); +} + +macro_rules! from_str_radix_nzint_impl { + ($($t:ty)*) => {$( + #[stable(feature = "nonzero_parse", since = "1.35.0")] + impl FromStr for $t { + type Err = ParseIntError; + fn from_str(src: &str) -> Result { + Self::new(from_str_radix(src, 10)?) + .ok_or(ParseIntError { + kind: IntErrorKind::Zero + }) + } + } + )*} +} + +from_str_radix_nzint_impl! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize +NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 NonZeroIsize } From 7125a481ce16fba90f833d4f2d9650d032229a83 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 4 Sep 2020 13:14:39 +0000 Subject: [PATCH 0667/1052] Move Wrapping definition to wrapping mod --- library/core/src/num/mod.rs | 76 ++---------------------------- library/core/src/num/wrapping.rs | 81 +++++++++++++++++++++++++++++++- 2 files changed, 82 insertions(+), 75 deletions(-) diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index fdf7695fbc8a5..ee9c9cf82f01a 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -34,79 +34,6 @@ macro_rules! doc_comment { }; } -/// Provides intentionally-wrapped arithmetic on `T`. -/// -/// Operations like `+` on `u32` values are intended to never overflow, -/// and in some debug configurations overflow is detected and results -/// in a panic. While most arithmetic falls into this category, some -/// code explicitly expects and relies upon modular arithmetic (e.g., -/// hashing). -/// -/// Wrapping arithmetic can be achieved either through methods like -/// `wrapping_add`, or through the `Wrapping` type, which says that -/// all standard arithmetic operations on the underlying value are -/// intended to have wrapping semantics. -/// -/// The underlying value can be retrieved through the `.0` index of the -/// `Wrapping` tuple. -/// -/// # Examples -/// -/// ``` -/// use std::num::Wrapping; -/// -/// let zero = Wrapping(0u32); -/// let one = Wrapping(1u32); -/// -/// assert_eq!(u32::MAX, (zero - one).0); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Hash)] -#[repr(transparent)] -pub struct Wrapping(#[stable(feature = "rust1", since = "1.0.0")] pub T); - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Wrapping { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -#[stable(feature = "wrapping_display", since = "1.10.0")] -impl fmt::Display for Wrapping { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -#[stable(feature = "wrapping_fmt", since = "1.11.0")] -impl fmt::Binary for Wrapping { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -#[stable(feature = "wrapping_fmt", since = "1.11.0")] -impl fmt::Octal for Wrapping { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -#[stable(feature = "wrapping_fmt", since = "1.11.0")] -impl fmt::LowerHex for Wrapping { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -#[stable(feature = "wrapping_fmt", since = "1.11.0")] -impl fmt::UpperHex for Wrapping { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - // All these modules are technically private and only exposed for coretests: pub mod bignum; pub mod dec2flt; @@ -116,6 +43,9 @@ pub mod flt2dec; mod nonzero; mod wrapping; +#[stable(feature = "rust1", since = "1.0.0")] +pub use wrapping::Wrapping; + #[stable(feature = "nonzero", since = "1.28.0")] pub use nonzero::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; diff --git a/library/core/src/num/wrapping.rs b/library/core/src/num/wrapping.rs index f6acb8f8b9a92..5324dfdeddde2 100644 --- a/library/core/src/num/wrapping.rs +++ b/library/core/src/num/wrapping.rs @@ -1,6 +1,83 @@ -use super::Wrapping; +//! Definitions of `Wrapping`. + +use crate::fmt; +use crate::ops::{Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign}; +use crate::ops::{BitXor, BitXorAssign, Div, DivAssign}; +use crate::ops::{Mul, MulAssign, Neg, Not, Rem, RemAssign}; +use crate::ops::{Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign}; + +/// Provides intentionally-wrapped arithmetic on `T`. +/// +/// Operations like `+` on `u32` values are intended to never overflow, +/// and in some debug configurations overflow is detected and results +/// in a panic. While most arithmetic falls into this category, some +/// code explicitly expects and relies upon modular arithmetic (e.g., +/// hashing). +/// +/// Wrapping arithmetic can be achieved either through methods like +/// `wrapping_add`, or through the `Wrapping` type, which says that +/// all standard arithmetic operations on the underlying value are +/// intended to have wrapping semantics. +/// +/// The underlying value can be retrieved through the `.0` index of the +/// `Wrapping` tuple. +/// +/// # Examples +/// +/// ``` +/// use std::num::Wrapping; +/// +/// let zero = Wrapping(0u32); +/// let one = Wrapping(1u32); +/// +/// assert_eq!(u32::MAX, (zero - one).0); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Hash)] +#[repr(transparent)] +pub struct Wrapping(#[stable(feature = "rust1", since = "1.0.0")] pub T); + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Wrapping { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +#[stable(feature = "wrapping_display", since = "1.10.0")] +impl fmt::Display for Wrapping { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +#[stable(feature = "wrapping_fmt", since = "1.11.0")] +impl fmt::Binary for Wrapping { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} -use crate::ops::*; +#[stable(feature = "wrapping_fmt", since = "1.11.0")] +impl fmt::Octal for Wrapping { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +#[stable(feature = "wrapping_fmt", since = "1.11.0")] +impl fmt::LowerHex for Wrapping { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +#[stable(feature = "wrapping_fmt", since = "1.11.0")] +impl fmt::UpperHex for Wrapping { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} #[allow(unused_macros)] macro_rules! sh_impl_signed { From 550939f654f08bfb25723f0fb4cbee0871dfb063 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 4 Sep 2020 13:37:15 +0000 Subject: [PATCH 0668/1052] Move error structs to new mod --- library/core/src/num/error.rs | 151 +++++++++++++++++++++++++++ library/core/src/num/mod.rs | 185 +++++----------------------------- 2 files changed, 174 insertions(+), 162 deletions(-) create mode 100644 library/core/src/num/error.rs diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs new file mode 100644 index 0000000000000..aab1715518611 --- /dev/null +++ b/library/core/src/num/error.rs @@ -0,0 +1,151 @@ +//! Error types for conversion to integral types. + +use crate::convert::Infallible; +use crate::fmt; + +/// The error type returned when a checked integral type conversion fails. +#[stable(feature = "try_from", since = "1.34.0")] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct TryFromIntError(pub(crate) ()); + +impl TryFromIntError { + #[unstable( + feature = "int_error_internals", + reason = "available through Error trait and this method should \ + not be exposed publicly", + issue = "none" + )] + #[doc(hidden)] + pub fn __description(&self) -> &str { + "out of range integral type conversion attempted" + } +} + +#[stable(feature = "try_from", since = "1.34.0")] +impl fmt::Display for TryFromIntError { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + self.__description().fmt(fmt) + } +} + +#[stable(feature = "try_from", since = "1.34.0")] +impl From for TryFromIntError { + fn from(x: Infallible) -> TryFromIntError { + match x {} + } +} + +#[unstable(feature = "never_type", issue = "35121")] +impl From for TryFromIntError { + fn from(never: !) -> TryFromIntError { + // Match rather than coerce to make sure that code like + // `From for TryFromIntError` above will keep working + // when `Infallible` becomes an alias to `!`. + match never {} + } +} + +/// An error which can be returned when parsing an integer. +/// +/// This error is used as the error type for the `from_str_radix()` functions +/// on the primitive integer types, such as [`i8::from_str_radix`]. +/// +/// # Potential causes +/// +/// Among other causes, `ParseIntError` can be thrown because of leading or trailing whitespace +/// in the string e.g., when it is obtained from the standard input. +/// Using the [`str.trim()`] method ensures that no whitespace remains before parsing. +/// +/// [`str.trim()`]: ../../std/primitive.str.html#method.trim +/// [`i8::from_str_radix`]: ../../std/primitive.i8.html#method.from_str_radix +/// +/// # Example +/// +/// ``` +/// if let Err(e) = i32::from_str_radix("a12", 10) { +/// println!("Failed conversion to i32: {}", e); +/// } +/// ``` +#[derive(Debug, Clone, PartialEq, Eq)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct ParseIntError { + pub(super) kind: IntErrorKind, +} + +/// Enum to store the various types of errors that can cause parsing an integer to fail. +/// +/// # Example +/// +/// ``` +/// #![feature(int_error_matching)] +/// +/// # fn main() { +/// if let Err(e) = i32::from_str_radix("a12", 10) { +/// println!("Failed conversion to i32: {:?}", e.kind()); +/// } +/// # } +/// ``` +#[unstable( + feature = "int_error_matching", + reason = "it can be useful to match errors when making error messages \ + for integer parsing", + issue = "22639" +)] +#[derive(Debug, Clone, PartialEq, Eq)] +#[non_exhaustive] +pub enum IntErrorKind { + /// Value being parsed is empty. + /// + /// Among other causes, this variant will be constructed when parsing an empty string. + Empty, + /// Contains an invalid digit. + /// + /// Among other causes, this variant will be constructed when parsing a string that + /// contains a letter. + InvalidDigit, + /// Integer is too large to store in target integer type. + Overflow, + /// Integer is too small to store in target integer type. + Underflow, + /// Value was Zero + /// + /// This variant will be emitted when the parsing string has a value of zero, which + /// would be illegal for non-zero types. + Zero, +} + +impl ParseIntError { + /// Outputs the detailed cause of parsing an integer failing. + #[unstable( + feature = "int_error_matching", + reason = "it can be useful to match errors when making error messages \ + for integer parsing", + issue = "22639" + )] + pub fn kind(&self) -> &IntErrorKind { + &self.kind + } + #[unstable( + feature = "int_error_internals", + reason = "available through Error trait and this method should \ + not be exposed publicly", + issue = "none" + )] + #[doc(hidden)] + pub fn __description(&self) -> &str { + match self.kind { + IntErrorKind::Empty => "cannot parse integer from empty string", + IntErrorKind::InvalidDigit => "invalid digit found in string", + IntErrorKind::Overflow => "number too large to fit in target type", + IntErrorKind::Underflow => "number too small to fit in target type", + IntErrorKind::Zero => "number would be zero for non-zero type", + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for ParseIntError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.__description().fmt(f) + } +} diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index ee9c9cf82f01a..adcdee4219fe1 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -4,8 +4,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use crate::convert::Infallible; -use crate::fmt; use crate::intrinsics; use crate::mem; use crate::str::FromStr; @@ -40,18 +38,31 @@ pub mod dec2flt; pub mod diy_float; pub mod flt2dec; +mod error; mod nonzero; mod wrapping; #[stable(feature = "rust1", since = "1.0.0")] pub use wrapping::Wrapping; +#[stable(feature = "rust1", since = "1.0.0")] +pub use dec2flt::ParseFloatError; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use error::ParseIntError; + #[stable(feature = "nonzero", since = "1.28.0")] pub use nonzero::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; #[stable(feature = "signed_nonzero", since = "1.34.0")] pub use nonzero::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize}; +#[stable(feature = "try_from", since = "1.34.0")] +pub use error::TryFromIntError; + +#[unstable(feature = "int_error_matching", issue = "22639")] +pub use error::IntErrorKind; + macro_rules! usize_isize_to_xe_bytes_doc { () => { " @@ -4904,6 +4915,16 @@ pub enum FpCategory { Normal, } +#[doc(hidden)] +trait FromStrRadixHelper: PartialOrd + Copy { + fn min_value() -> Self; + fn max_value() -> Self; + fn from_u32(u: u32) -> Self; + fn checked_mul(&self, other: u32) -> Option; + fn checked_sub(&self, other: u32) -> Option; + fn checked_add(&self, other: u32) -> Option; +} + macro_rules! from_str_radix_int_impl { ($($t:ty)*) => {$( #[stable(feature = "rust1", since = "1.0.0")] @@ -4917,58 +4938,6 @@ macro_rules! from_str_radix_int_impl { } from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 } -/// The error type returned when a checked integral type conversion fails. -#[stable(feature = "try_from", since = "1.34.0")] -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct TryFromIntError(pub(crate) ()); - -impl TryFromIntError { - #[unstable( - feature = "int_error_internals", - reason = "available through Error trait and this method should \ - not be exposed publicly", - issue = "none" - )] - #[doc(hidden)] - pub fn __description(&self) -> &str { - "out of range integral type conversion attempted" - } -} - -#[stable(feature = "try_from", since = "1.34.0")] -impl fmt::Display for TryFromIntError { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - self.__description().fmt(fmt) - } -} - -#[stable(feature = "try_from", since = "1.34.0")] -impl From for TryFromIntError { - fn from(x: Infallible) -> TryFromIntError { - match x {} - } -} - -#[unstable(feature = "never_type", issue = "35121")] -impl From for TryFromIntError { - fn from(never: !) -> TryFromIntError { - // Match rather than coerce to make sure that code like - // `From for TryFromIntError` above will keep working - // when `Infallible` becomes an alias to `!`. - match never {} - } -} - -#[doc(hidden)] -trait FromStrRadixHelper: PartialOrd + Copy { - fn min_value() -> Self; - fn max_value() -> Self; - fn from_u32(u: u32) -> Self; - fn checked_mul(&self, other: u32) -> Option; - fn checked_sub(&self, other: u32) -> Option; - fn checked_add(&self, other: u32) -> Option; -} - macro_rules! doit { ($($t:ty)*) => ($(impl FromStrRadixHelper for $t { #[inline] @@ -5061,111 +5030,3 @@ fn from_str_radix(src: &str, radix: u32) -> Result &IntErrorKind { - &self.kind - } - #[unstable( - feature = "int_error_internals", - reason = "available through Error trait and this method should \ - not be exposed publicly", - issue = "none" - )] - #[doc(hidden)] - pub fn __description(&self) -> &str { - match self.kind { - IntErrorKind::Empty => "cannot parse integer from empty string", - IntErrorKind::InvalidDigit => "invalid digit found in string", - IntErrorKind::Overflow => "number too large to fit in target type", - IntErrorKind::Underflow => "number too small to fit in target type", - IntErrorKind::Zero => "number would be zero for non-zero type", - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for ParseIntError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.__description().fmt(f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -pub use crate::num::dec2flt::ParseFloatError; From a54584319e746df7a31cdead3deb360d23eeb6a8 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 4 Sep 2020 14:00:38 +0000 Subject: [PATCH 0669/1052] Move dummy integer modules (like core::u32) to shells dir --- library/core/src/lib.rs | 26 +++++++++---------- library/core/src/num/{ => shells}/i128.rs | 0 library/core/src/num/{ => shells}/i16.rs | 0 library/core/src/num/{ => shells}/i32.rs | 0 library/core/src/num/{ => shells}/i64.rs | 0 library/core/src/num/{ => shells}/i8.rs | 0 .../core/src/num/{ => shells}/int_macros.rs | 0 library/core/src/num/{ => shells}/isize.rs | 0 library/core/src/num/{ => shells}/u128.rs | 0 library/core/src/num/{ => shells}/u16.rs | 0 library/core/src/num/{ => shells}/u32.rs | 0 library/core/src/num/{ => shells}/u64.rs | 0 library/core/src/num/{ => shells}/u8.rs | 0 library/core/src/num/{ => shells}/usize.rs | 0 14 files changed, 13 insertions(+), 13 deletions(-) rename library/core/src/num/{ => shells}/i128.rs (100%) rename library/core/src/num/{ => shells}/i16.rs (100%) rename library/core/src/num/{ => shells}/i32.rs (100%) rename library/core/src/num/{ => shells}/i64.rs (100%) rename library/core/src/num/{ => shells}/i8.rs (100%) rename library/core/src/num/{ => shells}/int_macros.rs (100%) rename library/core/src/num/{ => shells}/isize.rs (100%) rename library/core/src/num/{ => shells}/u128.rs (100%) rename library/core/src/num/{ => shells}/u16.rs (100%) rename library/core/src/num/{ => shells}/u32.rs (100%) rename library/core/src/num/{ => shells}/u64.rs (100%) rename library/core/src/num/{ => shells}/u8.rs (100%) rename library/core/src/num/{ => shells}/usize.rs (100%) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 3bddc3772e600..4cb81fb2a45ec 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -169,34 +169,34 @@ mod macros; #[macro_use] mod internal_macros; -#[path = "num/int_macros.rs"] +#[path = "num/shells/int_macros.rs"] #[macro_use] mod int_macros; -#[path = "num/i128.rs"] +#[path = "num/shells/i128.rs"] pub mod i128; -#[path = "num/i16.rs"] +#[path = "num/shells/i16.rs"] pub mod i16; -#[path = "num/i32.rs"] +#[path = "num/shells/i32.rs"] pub mod i32; -#[path = "num/i64.rs"] +#[path = "num/shells/i64.rs"] pub mod i64; -#[path = "num/i8.rs"] +#[path = "num/shells/i8.rs"] pub mod i8; -#[path = "num/isize.rs"] +#[path = "num/shells/isize.rs"] pub mod isize; -#[path = "num/u128.rs"] +#[path = "num/shells/u128.rs"] pub mod u128; -#[path = "num/u16.rs"] +#[path = "num/shells/u16.rs"] pub mod u16; -#[path = "num/u32.rs"] +#[path = "num/shells/u32.rs"] pub mod u32; -#[path = "num/u64.rs"] +#[path = "num/shells/u64.rs"] pub mod u64; -#[path = "num/u8.rs"] +#[path = "num/shells/u8.rs"] pub mod u8; -#[path = "num/usize.rs"] +#[path = "num/shells/usize.rs"] pub mod usize; #[path = "num/f32.rs"] diff --git a/library/core/src/num/i128.rs b/library/core/src/num/shells/i128.rs similarity index 100% rename from library/core/src/num/i128.rs rename to library/core/src/num/shells/i128.rs diff --git a/library/core/src/num/i16.rs b/library/core/src/num/shells/i16.rs similarity index 100% rename from library/core/src/num/i16.rs rename to library/core/src/num/shells/i16.rs diff --git a/library/core/src/num/i32.rs b/library/core/src/num/shells/i32.rs similarity index 100% rename from library/core/src/num/i32.rs rename to library/core/src/num/shells/i32.rs diff --git a/library/core/src/num/i64.rs b/library/core/src/num/shells/i64.rs similarity index 100% rename from library/core/src/num/i64.rs rename to library/core/src/num/shells/i64.rs diff --git a/library/core/src/num/i8.rs b/library/core/src/num/shells/i8.rs similarity index 100% rename from library/core/src/num/i8.rs rename to library/core/src/num/shells/i8.rs diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/shells/int_macros.rs similarity index 100% rename from library/core/src/num/int_macros.rs rename to library/core/src/num/shells/int_macros.rs diff --git a/library/core/src/num/isize.rs b/library/core/src/num/shells/isize.rs similarity index 100% rename from library/core/src/num/isize.rs rename to library/core/src/num/shells/isize.rs diff --git a/library/core/src/num/u128.rs b/library/core/src/num/shells/u128.rs similarity index 100% rename from library/core/src/num/u128.rs rename to library/core/src/num/shells/u128.rs diff --git a/library/core/src/num/u16.rs b/library/core/src/num/shells/u16.rs similarity index 100% rename from library/core/src/num/u16.rs rename to library/core/src/num/shells/u16.rs diff --git a/library/core/src/num/u32.rs b/library/core/src/num/shells/u32.rs similarity index 100% rename from library/core/src/num/u32.rs rename to library/core/src/num/shells/u32.rs diff --git a/library/core/src/num/u64.rs b/library/core/src/num/shells/u64.rs similarity index 100% rename from library/core/src/num/u64.rs rename to library/core/src/num/shells/u64.rs diff --git a/library/core/src/num/u8.rs b/library/core/src/num/shells/u8.rs similarity index 100% rename from library/core/src/num/u8.rs rename to library/core/src/num/shells/u8.rs diff --git a/library/core/src/num/usize.rs b/library/core/src/num/shells/usize.rs similarity index 100% rename from library/core/src/num/usize.rs rename to library/core/src/num/shells/usize.rs From a60f97849b240c69052e58ada45cff5515fb66b2 Mon Sep 17 00:00:00 2001 From: rijenkii <5338332+rijenkii@users.noreply.github.com> Date: Sat, 19 Sep 2020 21:55:01 +0700 Subject: [PATCH 0670/1052] Add tracking issue for feature(unix_socket_peek) --- library/std/src/sys/unix/ext/net.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/unix/ext/net.rs b/library/std/src/sys/unix/ext/net.rs index f3da8f9f58488..3d2366554b5b2 100644 --- a/library/std/src/sys/unix/ext/net.rs +++ b/library/std/src/sys/unix/ext/net.rs @@ -667,7 +667,7 @@ impl UnixStream { /// Ok(()) /// } /// ``` - #[unstable(feature = "unix_socket_peek", issue = "none")] + #[unstable(feature = "unix_socket_peek", issue = "76923")] pub fn peek(&self, buf: &mut [u8]) -> io::Result { self.0.peek(buf) } @@ -1708,7 +1708,7 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` - #[unstable(feature = "unix_socket_peek", issue = "none")] + #[unstable(feature = "unix_socket_peek", issue = "76923")] pub fn peek(&self, buf: &mut [u8]) -> io::Result { self.0.peek(buf) } @@ -1740,7 +1740,7 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` - #[unstable(feature = "unix_socket_peek", issue = "none")] + #[unstable(feature = "unix_socket_peek", issue = "76923")] pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { self.recv_from_flags(buf, libc::MSG_PEEK) } From 3ee724e6100706caca76c182939a2d7bced7d997 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 4 Sep 2020 14:20:01 +0000 Subject: [PATCH 0671/1052] Move (u)int_impl macros to their own files --- library/core/src/num/int_macros.rs | 2201 ++++++++++++++ library/core/src/num/mod.rs | 4277 +-------------------------- library/core/src/num/uint_macros.rs | 1955 ++++++++++++ 3 files changed, 4218 insertions(+), 4215 deletions(-) create mode 100644 library/core/src/num/int_macros.rs create mode 100644 library/core/src/num/uint_macros.rs diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs new file mode 100644 index 0000000000000..369175fb6ab1e --- /dev/null +++ b/library/core/src/num/int_macros.rs @@ -0,0 +1,2201 @@ +macro_rules! int_impl { + ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $Min:expr, $Max:expr, $Feature:expr, + $EndFeature:expr, $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr, + $reversed:expr, $le_bytes:expr, $be_bytes:expr, + $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => { + doc_comment! { + concat!("The smallest value that can be represented by this integer type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(", stringify!($SelfT), "::MIN, ", stringify!($Min), ");", +$EndFeature, " +```"), + #[stable(feature = "assoc_int_consts", since = "1.43.0")] + pub const MIN: Self = !0 ^ ((!0 as $UnsignedT) >> 1) as Self; + } + + doc_comment! { + concat!("The largest value that can be represented by this integer type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($Max), ");", +$EndFeature, " +```"), + #[stable(feature = "assoc_int_consts", since = "1.43.0")] + pub const MAX: Self = !Self::MIN; + } + + doc_comment! { + concat!("The size of this integer type in bits. + +# Examples + +``` +", $Feature, "#![feature(int_bits_const)] +assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");", +$EndFeature, " +```"), + #[unstable(feature = "int_bits_const", issue = "76904")] + pub const BITS: u32 = $BITS; + } + + doc_comment! { + concat!("Converts a string slice in a given base to an integer. + +The string is expected to be an optional `+` or `-` sign followed by digits. +Leading and trailing whitespace represent an error. Digits are a subset of these characters, +depending on `radix`: + + * `0-9` + * `a-z` + * `A-Z` + +# Panics + +This function panics if `radix` is not in the range from 2 to 36. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + pub fn from_str_radix(src: &str, radix: u32) -> Result { + from_str_radix(src, radix) + } + } + + doc_comment! { + concat!("Returns the number of ones in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0b100_0000", stringify!($SelfT), "; + +assert_eq!(n.count_ones(), 1);", +$EndFeature, " +``` +"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } + } + + doc_comment! { + concat!("Returns the number of zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 1);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn count_zeros(self) -> u32 { + (!self).count_ones() + } + } + + doc_comment! { + concat!("Returns the number of leading zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = -1", stringify!($SelfT), "; + +assert_eq!(n.leading_zeros(), 0);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn leading_zeros(self) -> u32 { + (self as $UnsignedT).leading_zeros() + } + } + + doc_comment! { + concat!("Returns the number of trailing zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = -4", stringify!($SelfT), "; + +assert_eq!(n.trailing_zeros(), 2);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn trailing_zeros(self) -> u32 { + (self as $UnsignedT).trailing_zeros() + } + } + + doc_comment! { + concat!("Returns the number of leading ones in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = -1", stringify!($SelfT), "; + +assert_eq!(n.leading_ones(), ", stringify!($BITS), ");", +$EndFeature, " +```"), + #[stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[inline] + pub const fn leading_ones(self) -> u32 { + (self as $UnsignedT).leading_ones() + } + } + + doc_comment! { + concat!("Returns the number of trailing ones in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 3", stringify!($SelfT), "; + +assert_eq!(n.trailing_ones(), 2);", +$EndFeature, " +```"), + #[stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[inline] + pub const fn trailing_ones(self) -> u32 { + (self as $UnsignedT).trailing_ones() + } + } + + doc_comment! { + concat!("Shifts the bits to the left by a specified amount, `n`, +wrapping the truncated bits to the end of the resulting integer. + +Please note this isn't the same operation as the `<<` shifting operator! + +# Examples + +Basic usage: + +``` +let n = ", $rot_op, stringify!($SelfT), "; +let m = ", $rot_result, "; + +assert_eq!(n.rotate_left(", $rot, "), m); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn rotate_left(self, n: u32) -> Self { + (self as $UnsignedT).rotate_left(n) as Self + } + } + + doc_comment! { + concat!("Shifts the bits to the right by a specified amount, `n`, +wrapping the truncated bits to the beginning of the resulting +integer. + +Please note this isn't the same operation as the `>>` shifting operator! + +# Examples + +Basic usage: + +``` +let n = ", $rot_result, stringify!($SelfT), "; +let m = ", $rot_op, "; + +assert_eq!(n.rotate_right(", $rot, "), m); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn rotate_right(self, n: u32) -> Self { + (self as $UnsignedT).rotate_right(n) as Self + } + } + + doc_comment! { + concat!("Reverses the byte order of the integer. + +# Examples + +Basic usage: + +``` +let n = ", $swap_op, stringify!($SelfT), "; + +let m = n.swap_bytes(); + +assert_eq!(m, ", $swapped, "); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn swap_bytes(self) -> Self { + (self as $UnsignedT).swap_bytes() as Self + } + } + + doc_comment! { + concat!("Reverses the bit pattern of the integer. + +# Examples + +Basic usage: + +``` +let n = ", $swap_op, stringify!($SelfT), "; +let m = n.reverse_bits(); + +assert_eq!(m, ", $reversed, "); +```"), + #[stable(feature = "reverse_bits", since = "1.37.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + #[must_use] + pub const fn reverse_bits(self) -> Self { + (self as $UnsignedT).reverse_bits() as Self + } + } + + doc_comment! { + concat!("Converts an integer from big endian to the target's endianness. + +On big endian this is a no-op. On little endian the bytes are swapped. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0x1A", stringify!($SelfT), "; + +if cfg!(target_endian = \"big\") { + assert_eq!(", stringify!($SelfT), "::from_be(n), n) +} else { + assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes()) +}", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] + #[inline] + pub const fn from_be(x: Self) -> Self { + #[cfg(target_endian = "big")] + { + x + } + #[cfg(not(target_endian = "big"))] + { + x.swap_bytes() + } + } + } + + doc_comment! { + concat!("Converts an integer from little endian to the target's endianness. + +On little endian this is a no-op. On big endian the bytes are swapped. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0x1A", stringify!($SelfT), "; + +if cfg!(target_endian = \"little\") { + assert_eq!(", stringify!($SelfT), "::from_le(n), n) +} else { + assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes()) +}", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] + #[inline] + pub const fn from_le(x: Self) -> Self { + #[cfg(target_endian = "little")] + { + x + } + #[cfg(not(target_endian = "little"))] + { + x.swap_bytes() + } + } + } + + doc_comment! { + concat!("Converts `self` to big endian from the target's endianness. + +On big endian this is a no-op. On little endian the bytes are swapped. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0x1A", stringify!($SelfT), "; + +if cfg!(target_endian = \"big\") { + assert_eq!(n.to_be(), n) +} else { + assert_eq!(n.to_be(), n.swap_bytes()) +}", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] + #[inline] + pub const fn to_be(self) -> Self { // or not to be? + #[cfg(target_endian = "big")] + { + self + } + #[cfg(not(target_endian = "big"))] + { + self.swap_bytes() + } + } + } + + doc_comment! { + concat!("Converts `self` to little endian from the target's endianness. + +On little endian this is a no-op. On big endian the bytes are swapped. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0x1A", stringify!($SelfT), "; + +if cfg!(target_endian = \"little\") { + assert_eq!(n.to_le(), n) +} else { + assert_eq!(n.to_le(), n.swap_bytes()) +}", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] + #[inline] + pub const fn to_le(self) -> Self { + #[cfg(target_endian = "little")] + { + self + } + #[cfg(not(target_endian = "little"))] + { + self.swap_bytes() + } + } + } + + doc_comment! { + concat!("Checked integer addition. Computes `self + rhs`, returning `None` +if overflow occurred. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!((", stringify!($SelfT), +"::MAX - 2).checked_add(1), Some(", stringify!($SelfT), "::MAX - 1)); +assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_add(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_add(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Unchecked integer addition. Computes `self + rhs`, assuming overflow +cannot occur. This results in undefined behavior when `self + rhs > ", stringify!($SelfT), +"::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`."), + #[unstable( + feature = "unchecked_math", + reason = "niche optimization path", + issue = "none", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub unsafe fn unchecked_add(self, rhs: Self) -> Self { + // SAFETY: the caller must uphold the safety contract for + // `unchecked_add`. + unsafe { intrinsics::unchecked_add(self, rhs) } + } + } + + doc_comment! { + concat!("Checked integer subtraction. Computes `self - rhs`, returning `None` if +overflow occurred. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!((", stringify!($SelfT), +"::MIN + 2).checked_sub(1), Some(", stringify!($SelfT), "::MIN + 1)); +assert_eq!((", stringify!($SelfT), "::MIN + 2).checked_sub(3), None);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_sub(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_sub(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Unchecked integer subtraction. Computes `self - rhs`, assuming overflow +cannot occur. This results in undefined behavior when `self - rhs > ", stringify!($SelfT), +"::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`."), + #[unstable( + feature = "unchecked_math", + reason = "niche optimization path", + issue = "none", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub unsafe fn unchecked_sub(self, rhs: Self) -> Self { + // SAFETY: the caller must uphold the safety contract for + // `unchecked_sub`. + unsafe { intrinsics::unchecked_sub(self, rhs) } + } + } + + doc_comment! { + concat!("Checked integer multiplication. Computes `self * rhs`, returning `None` if +overflow occurred. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(", stringify!($SelfT), +"::MAX.checked_mul(1), Some(", stringify!($SelfT), "::MAX)); +assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_mul(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_mul(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Unchecked integer multiplication. Computes `self * rhs`, assuming overflow +cannot occur. This results in undefined behavior when `self * rhs > ", stringify!($SelfT), +"::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`."), + #[unstable( + feature = "unchecked_math", + reason = "niche optimization path", + issue = "none", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub unsafe fn unchecked_mul(self, rhs: Self) -> Self { + // SAFETY: the caller must uphold the safety contract for + // `unchecked_mul`. + unsafe { intrinsics::unchecked_mul(self, rhs) } + } + } + + doc_comment! { + concat!("Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0` +or the division results in overflow. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!((", stringify!($SelfT), +"::MIN + 1).checked_div(-1), Some(", stringify!($Max), ")); +assert_eq!(", stringify!($SelfT), "::MIN.checked_div(-1), None); +assert_eq!((1", stringify!($SelfT), ").checked_div(0), None);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_div(self, rhs: Self) -> Option { + if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { + None + } else { + // SAFETY: div by zero and by INT_MIN have been checked above + Some(unsafe { intrinsics::unchecked_div(self, rhs) }) + } + } + } + + doc_comment! { + concat!("Checked Euclidean division. Computes `self.div_euclid(rhs)`, +returning `None` if `rhs == 0` or the division results in overflow. + +# Examples + +Basic usage: + +``` +assert_eq!((", stringify!($SelfT), +"::MIN + 1).checked_div_euclid(-1), Some(", stringify!($Max), ")); +assert_eq!(", stringify!($SelfT), "::MIN.checked_div_euclid(-1), None); +assert_eq!((1", stringify!($SelfT), ").checked_div_euclid(0), None); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_div_euclid(self, rhs: Self) -> Option { + if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { + None + } else { + Some(self.div_euclid(rhs)) + } + } + } + + doc_comment! { + concat!("Checked integer remainder. Computes `self % rhs`, returning `None` if +`rhs == 0` or the division results in overflow. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1)); +assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None); +assert_eq!(", stringify!($SelfT), "::MIN.checked_rem(-1), None);", +$EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_rem(self, rhs: Self) -> Option { + if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { + None + } else { + // SAFETY: div by zero and by INT_MIN have been checked above + Some(unsafe { intrinsics::unchecked_rem(self, rhs) }) + } + } + } + + doc_comment! { + concat!("Checked Euclidean remainder. Computes `self.rem_euclid(rhs)`, returning `None` +if `rhs == 0` or the division results in overflow. + +# Examples + +Basic usage: + +``` +assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1)); +assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None); +assert_eq!(", stringify!($SelfT), "::MIN.checked_rem_euclid(-1), None); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_rem_euclid(self, rhs: Self) -> Option { + if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { + None + } else { + Some(self.rem_euclid(rhs)) + } + } + } + + doc_comment! { + concat!("Checked negation. Computes `-self`, returning `None` if `self == MIN`. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!(5", stringify!($SelfT), ".checked_neg(), Some(-5)); +assert_eq!(", stringify!($SelfT), "::MIN.checked_neg(), None);", +$EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[inline] + pub const fn checked_neg(self) -> Option { + let (a, b) = self.overflowing_neg(); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Checked shift left. Computes `self << rhs`, returning `None` if `rhs` is larger +than or equal to the number of bits in `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10)); +assert_eq!(0x1", stringify!($SelfT), ".checked_shl(129), None);", +$EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_shl(self, rhs: u32) -> Option { + let (a, b) = self.overflowing_shl(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is +larger than or equal to the number of bits in `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1)); +assert_eq!(0x10", stringify!($SelfT), ".checked_shr(128), None);", +$EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_shr(self, rhs: u32) -> Option { + let (a, b) = self.overflowing_shr(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Checked absolute value. Computes `self.abs()`, returning `None` if +`self == MIN`. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!((-5", stringify!($SelfT), ").checked_abs(), Some(5)); +assert_eq!(", stringify!($SelfT), "::MIN.checked_abs(), None);", +$EndFeature, " +```"), + #[stable(feature = "no_panic_abs", since = "1.13.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[inline] + pub const fn checked_abs(self) -> Option { + if self.is_negative() { + self.checked_neg() + } else { + Some(self) + } + } + } + + doc_comment! { + concat!("Checked exponentiation. Computes `self.pow(exp)`, returning `None` if +overflow occurred. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(8", stringify!($SelfT), ".checked_pow(2), Some(64)); +assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);", +$EndFeature, " +```"), + + #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_pow(self, mut exp: u32) -> Option { + if exp == 0 { + return Some(1); + } + let mut base = self; + let mut acc: Self = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = try_opt!(acc.checked_mul(base)); + } + exp /= 2; + base = try_opt!(base.checked_mul(base)); + } + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + Some(try_opt!(acc.checked_mul(base))) + } + } + + doc_comment! { + concat!("Saturating integer addition. Computes `self + rhs`, saturating at the numeric +bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101); +assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(100), ", stringify!($SelfT), +"::MAX); +assert_eq!(", stringify!($SelfT), "::MIN.saturating_add(-1), ", stringify!($SelfT), +"::MIN);", +$EndFeature, " +```"), + + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_add(self, rhs: Self) -> Self { + intrinsics::saturating_add(self, rhs) + } + } + + doc_comment! { + concat!("Saturating integer subtraction. Computes `self - rhs`, saturating at the +numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(127), -27); +assert_eq!(", stringify!($SelfT), "::MIN.saturating_sub(100), ", stringify!($SelfT), +"::MIN); +assert_eq!(", stringify!($SelfT), "::MAX.saturating_sub(-1), ", stringify!($SelfT), +"::MAX);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_sub(self, rhs: Self) -> Self { + intrinsics::saturating_sub(self, rhs) + } + } + + doc_comment! { + concat!("Saturating integer negation. Computes `-self`, returning `MAX` if `self == MIN` +instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_neg(), -100); +assert_eq!((-100", stringify!($SelfT), ").saturating_neg(), 100); +assert_eq!(", stringify!($SelfT), "::MIN.saturating_neg(), ", stringify!($SelfT), +"::MAX); +assert_eq!(", stringify!($SelfT), "::MAX.saturating_neg(), ", stringify!($SelfT), +"::MIN + 1);", +$EndFeature, " +```"), + + #[stable(feature = "saturating_neg", since = "1.45.0")] + #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] + #[inline] + pub const fn saturating_neg(self) -> Self { + intrinsics::saturating_sub(0, self) + } + } + + doc_comment! { + concat!("Saturating absolute value. Computes `self.abs()`, returning `MAX` if `self == +MIN` instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_abs(), 100); +assert_eq!((-100", stringify!($SelfT), ").saturating_abs(), 100); +assert_eq!(", stringify!($SelfT), "::MIN.saturating_abs(), ", stringify!($SelfT), +"::MAX); +assert_eq!((", stringify!($SelfT), "::MIN + 1).saturating_abs(), ", stringify!($SelfT), +"::MAX);", +$EndFeature, " +```"), + + #[stable(feature = "saturating_neg", since = "1.45.0")] + #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] + #[inline] + pub const fn saturating_abs(self) -> Self { + if self.is_negative() { + self.saturating_neg() + } else { + self + } + } + } + + doc_comment! { + concat!("Saturating integer multiplication. Computes `self * rhs`, saturating at the +numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!(10", stringify!($SelfT), ".saturating_mul(12), 120); +assert_eq!(", stringify!($SelfT), "::MAX.saturating_mul(10), ", stringify!($SelfT), "::MAX); +assert_eq!(", stringify!($SelfT), "::MIN.saturating_mul(10), ", stringify!($SelfT), "::MIN);", +$EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_mul(self, rhs: Self) -> Self { + match self.checked_mul(rhs) { + Some(x) => x, + None => if (self < 0) == (rhs < 0) { + Self::MAX + } else { + Self::MIN + } + } + } + } + + doc_comment! { + concat!("Saturating integer exponentiation. Computes `self.pow(exp)`, +saturating at the numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!((-4", stringify!($SelfT), ").saturating_pow(3), -64); +assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(2), ", stringify!($SelfT), "::MAX); +assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(3), ", stringify!($SelfT), "::MIN);", +$EndFeature, " +```"), + #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_pow(self, exp: u32) -> Self { + match self.checked_pow(exp) { + Some(x) => x, + None if self < 0 && exp % 2 == 1 => Self::MIN, + None => Self::MAX, + } + } + } + + doc_comment! { + concat!("Wrapping (modular) addition. Computes `self + rhs`, wrapping around at the +boundary of the type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_add(27), 127); +assert_eq!(", stringify!($SelfT), "::MAX.wrapping_add(2), ", stringify!($SelfT), +"::MIN + 1);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_add(self, rhs: Self) -> Self { + intrinsics::wrapping_add(self, rhs) + } + } + + doc_comment! { + concat!("Wrapping (modular) subtraction. Computes `self - rhs`, wrapping around at the +boundary of the type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(0", stringify!($SelfT), ".wrapping_sub(127), -127); +assert_eq!((-2", stringify!($SelfT), ").wrapping_sub(", stringify!($SelfT), "::MAX), ", +stringify!($SelfT), "::MAX);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_sub(self, rhs: Self) -> Self { + intrinsics::wrapping_sub(self, rhs) + } + } + + doc_comment! { + concat!("Wrapping (modular) multiplication. Computes `self * rhs`, wrapping around at +the boundary of the type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(10", stringify!($SelfT), ".wrapping_mul(12), 120); +assert_eq!(11i8.wrapping_mul(12), -124);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_mul(self, rhs: Self) -> Self { + intrinsics::wrapping_mul(self, rhs) + } + } + + doc_comment! { + concat!("Wrapping (modular) division. Computes `self / rhs`, wrapping around at the +boundary of the type. + +The only case where such wrapping can occur is when one divides `MIN / -1` on a signed type (where +`MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value +that is too large to represent in the type. In such a case, this function returns `MIN` itself. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10); +assert_eq!((-128i8).wrapping_div(-1), -128);", +$EndFeature, " +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_div(self, rhs: Self) -> Self { + self.overflowing_div(rhs).0 + } + } + + doc_comment! { + concat!("Wrapping Euclidean division. Computes `self.div_euclid(rhs)`, +wrapping around at the boundary of the type. + +Wrapping will only occur in `MIN / -1` on a signed type (where `MIN` is the negative minimal value +for the type). This is equivalent to `-MIN`, a positive value that is too large to represent in the +type. In this case, this method returns `MIN` itself. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10); +assert_eq!((-128i8).wrapping_div_euclid(-1), -128); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_div_euclid(self, rhs: Self) -> Self { + self.overflowing_div_euclid(rhs).0 + } + } + + doc_comment! { + concat!("Wrapping (modular) remainder. Computes `self % rhs`, wrapping around at the +boundary of the type. + +Such wrap-around never actually occurs mathematically; implementation artifacts make `x % y` +invalid for `MIN / -1` on a signed type (where `MIN` is the negative minimal value). In such a case, +this function returns `0`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0); +assert_eq!((-128i8).wrapping_rem(-1), 0);", +$EndFeature, " +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_rem(self, rhs: Self) -> Self { + self.overflowing_rem(rhs).0 + } + } + + doc_comment! { + concat!("Wrapping Euclidean remainder. Computes `self.rem_euclid(rhs)`, wrapping around +at the boundary of the type. + +Wrapping will only occur in `MIN % -1` on a signed type (where `MIN` is the negative minimal value +for the type). In this case, this method returns 0. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0); +assert_eq!((-128i8).wrapping_rem_euclid(-1), 0); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self { + self.overflowing_rem_euclid(rhs).0 + } + } + + doc_comment! { + concat!("Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary +of the type. + +The only case where such wrapping can occur is when one negates `MIN` on a signed type (where `MIN` +is the negative minimal value for the type); this is a positive value that is too large to represent +in the type. In such a case, this function returns `MIN` itself. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_neg(), -100); +assert_eq!(", stringify!($SelfT), "::MIN.wrapping_neg(), ", stringify!($SelfT), +"::MIN);", +$EndFeature, " +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn wrapping_neg(self) -> Self { + self.overflowing_neg().0 + } + } + + doc_comment! { + concat!("Panic-free bitwise shift-left; yields `self << mask(rhs)`, where `mask` removes +any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type. + +Note that this is *not* the same as a rotate-left; the RHS of a wrapping shift-left is restricted to +the range of the type, rather than the bits shifted out of the LHS being returned to the other end. +The primitive integer types all implement a `[`rotate_left`](#method.rotate_left) function, +which may be what you want instead. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(7), -128); +assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(128), -1);", +$EndFeature, " +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_shl(self, rhs: u32) -> Self { + // SAFETY: the masking by the bitsize of the type ensures that we do not shift + // out of bounds + unsafe { + intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT) + } + } + } + + doc_comment! { + concat!("Panic-free bitwise shift-right; yields `self >> mask(rhs)`, where `mask` +removes any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type. + +Note that this is *not* the same as a rotate-right; the RHS of a wrapping shift-right is restricted +to the range of the type, rather than the bits shifted out of the LHS being returned to the other +end. The primitive integer types all implement a [`rotate_right`](#method.rotate_right) function, +which may be what you want instead. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!((-128", stringify!($SelfT), ").wrapping_shr(7), -1); +assert_eq!((-128i16).wrapping_shr(64), -128);", +$EndFeature, " +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_shr(self, rhs: u32) -> Self { + // SAFETY: the masking by the bitsize of the type ensures that we do not shift + // out of bounds + unsafe { + intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT) + } + } + } + + doc_comment! { + concat!("Wrapping (modular) absolute value. Computes `self.abs()`, wrapping around at +the boundary of the type. + +The only case where such wrapping can occur is when one takes the absolute value of the negative +minimal value for the type; this is a positive value that is too large to represent in the type. In +such a case, this function returns `MIN` itself. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_abs(), 100); +assert_eq!((-100", stringify!($SelfT), ").wrapping_abs(), 100); +assert_eq!(", stringify!($SelfT), "::MIN.wrapping_abs(), ", stringify!($SelfT), +"::MIN); +assert_eq!((-128i8).wrapping_abs() as u8, 128);", +$EndFeature, " +```"), + #[stable(feature = "no_panic_abs", since = "1.13.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[allow(unused_attributes)] + #[inline] + pub const fn wrapping_abs(self) -> Self { + if self.is_negative() { + self.wrapping_neg() + } else { + self + } + } + } + + doc_comment! { + concat!("Computes the absolute value of `self` without any wrapping +or panicking. + + +# Examples + +Basic usage: + +``` +", $Feature, "#![feature(unsigned_abs)] +assert_eq!(100", stringify!($SelfT), ".unsigned_abs(), 100", stringify!($UnsignedT), "); +assert_eq!((-100", stringify!($SelfT), ").unsigned_abs(), 100", stringify!($UnsignedT), "); +assert_eq!((-128i8).unsigned_abs(), 128u8);", +$EndFeature, " +```"), + #[unstable(feature = "unsigned_abs", issue = "74913")] + #[inline] + pub const fn unsigned_abs(self) -> $UnsignedT { + self.wrapping_abs() as $UnsignedT + } + } + + doc_comment! { + concat!("Wrapping (modular) exponentiation. Computes `self.pow(exp)`, +wrapping around at the boundary of the type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(4), 81); +assert_eq!(3i8.wrapping_pow(5), -13); +assert_eq!(3i8.wrapping_pow(6), -39);", +$EndFeature, " +```"), + #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_pow(self, mut exp: u32) -> Self { + if exp == 0 { + return 1; + } + let mut base = self; + let mut acc: Self = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = acc.wrapping_mul(base); + } + exp /= 2; + base = base.wrapping_mul(base); + } + + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + acc.wrapping_mul(base) + } + } + + doc_comment! { + concat!("Calculates `self` + `rhs` + +Returns a tuple of the addition along with a boolean indicating whether an arithmetic overflow would +occur. If an overflow would have occurred then the wrapped value is returned. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false)); +assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (", stringify!($SelfT), +"::MIN, true));", $EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) { + let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT); + (a as Self, b) + } + } + + doc_comment! { + concat!("Calculates `self` - `rhs` + +Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow +would occur. If an overflow would have occurred then the wrapped value is returned. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_sub(1), (", stringify!($SelfT), +"::MAX, true));", $EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { + let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT); + (a as Self, b) + } + } + + doc_comment! { + concat!("Calculates the multiplication of `self` and `rhs`. + +Returns a tuple of the multiplication along with a boolean indicating whether an arithmetic overflow +would occur. If an overflow would have occurred then the wrapped value is returned. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_mul(2), (10, false)); +assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true));", +$EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) { + let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT); + (a as Self, b) + } + } + + doc_comment! { + concat!("Calculates the divisor when `self` is divided by `rhs`. + +Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would +occur. If an overflow would occur then self is returned. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div(-1), (", stringify!($SelfT), +"::MIN, true));", +$EndFeature, " +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) { + if unlikely!(self == Self::MIN && rhs == -1) { + (self, true) + } else { + (self / rhs, false) + } + } + } + + doc_comment! { + concat!("Calculates the quotient of Euclidean division `self.div_euclid(rhs)`. + +Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would +occur. If an overflow would occur then `self` is returned. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div_euclid(-1), (", stringify!($SelfT), +"::MIN, true)); +```"), + #[inline] + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { + if unlikely!(self == Self::MIN && rhs == -1) { + (self, true) + } else { + (self.div_euclid(rhs), false) + } + } + } + + doc_comment! { + concat!("Calculates the remainder when `self` is divided by `rhs`. + +Returns a tuple of the remainder after dividing along with a boolean indicating whether an +arithmetic overflow would occur. If an overflow would occur then 0 is returned. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem(-1), (0, true));", +$EndFeature, " +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) { + if unlikely!(self == Self::MIN && rhs == -1) { + (0, true) + } else { + (self % rhs, false) + } + } + } + + + doc_comment! { + concat!("Overflowing Euclidean remainder. Calculates `self.rem_euclid(rhs)`. + +Returns a tuple of the remainder after dividing along with a boolean indicating whether an +arithmetic overflow would occur. If an overflow would occur then 0 is returned. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem_euclid(-1), (0, true)); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { + if unlikely!(self == Self::MIN && rhs == -1) { + (0, true) + } else { + (self.rem_euclid(rhs), false) + } + } + } + + + doc_comment! { + concat!("Negates self, overflowing if this is equal to the minimum value. + +Returns a tuple of the negated version of self along with a boolean indicating whether an overflow +happened. If `self` is the minimum value (e.g., `i32::MIN` for values of type `i32`), then the +minimum value will be returned again and `true` will be returned for an overflow happening. + +# Examples + +Basic usage: + +``` +assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_neg(), (", stringify!($SelfT), +"::MIN, true));", $EndFeature, " +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[allow(unused_attributes)] + pub const fn overflowing_neg(self) -> (Self, bool) { + if unlikely!(self == Self::MIN) { + (Self::MIN, true) + } else { + (-self, false) + } + } + } + + doc_comment! { + concat!("Shifts self left by `rhs` bits. + +Returns a tuple of the shifted version of self along with a boolean indicating whether the shift +value was larger than or equal to the number of bits. If the shift value is too large, then value is +masked (N-1) where N is the number of bits, and this value is then used to perform the shift. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(0x1", stringify!($SelfT),".overflowing_shl(4), (0x10, false)); +assert_eq!(0x1i32.overflowing_shl(36), (0x10, true));", +$EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) { + (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) + } + } + + doc_comment! { + concat!("Shifts self right by `rhs` bits. + +Returns a tuple of the shifted version of self along with a boolean indicating whether the shift +value was larger than or equal to the number of bits. If the shift value is too large, then value is +masked (N-1) where N is the number of bits, and this value is then used to perform the shift. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false)); +assert_eq!(0x10i32.overflowing_shr(36), (0x1, true));", +$EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) { + (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) + } + } + + doc_comment! { + concat!("Computes the absolute value of `self`. + +Returns a tuple of the absolute version of self along with a boolean indicating whether an overflow +happened. If self is the minimum value (e.g., ", stringify!($SelfT), "::MIN for values of type + ", stringify!($SelfT), "), then the minimum value will be returned again and true will be returned +for an overflow happening. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(10", stringify!($SelfT), ".overflowing_abs(), (10, false)); +assert_eq!((-10", stringify!($SelfT), ").overflowing_abs(), (10, false)); +assert_eq!((", stringify!($SelfT), "::MIN).overflowing_abs(), (", stringify!($SelfT), +"::MIN, true));", +$EndFeature, " +```"), + #[stable(feature = "no_panic_abs", since = "1.13.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn overflowing_abs(self) -> (Self, bool) { + (self.wrapping_abs(), self == Self::MIN) + } + } + + doc_comment! { + concat!("Raises self to the power of `exp`, using exponentiation by squaring. + +Returns a tuple of the exponentiation along with a bool indicating +whether an overflow happened. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(4), (81, false)); +assert_eq!(3i8.overflowing_pow(5), (-13, true));", +$EndFeature, " +```"), + #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) { + if exp == 0 { + return (1,false); + } + let mut base = self; + let mut acc: Self = 1; + let mut overflown = false; + // Scratch space for storing results of overflowing_mul. + let mut r; + + while exp > 1 { + if (exp & 1) == 1 { + r = acc.overflowing_mul(base); + acc = r.0; + overflown |= r.1; + } + exp /= 2; + r = base.overflowing_mul(base); + base = r.0; + overflown |= r.1; + } + + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + r = acc.overflowing_mul(base); + r.1 |= overflown; + r + } + } + + doc_comment! { + concat!("Raises self to the power of `exp`, using exponentiation by squaring. + +# Examples + +Basic usage: + +``` +", $Feature, "let x: ", stringify!($SelfT), " = 2; // or any other integer type + +assert_eq!(x.pow(5), 32);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn pow(self, mut exp: u32) -> Self { + if exp == 0 { + return 1; + } + let mut base = self; + let mut acc = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = acc * base; + } + exp /= 2; + base = base * base; + } + + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + acc * base + } + } + + doc_comment! { + concat!("Calculates the quotient of Euclidean division of `self` by `rhs`. + +This computes the integer `n` such that `self = n * rhs + self.rem_euclid(rhs)`, +with `0 <= self.rem_euclid(rhs) < rhs`. + +In other words, the result is `self / rhs` rounded to the integer `n` +such that `self >= n * rhs`. +If `self > 0`, this is equal to round towards zero (the default in Rust); +if `self < 0`, this is equal to round towards +/- infinity. + +# Panics + +This function will panic if `rhs` is 0 or the division results in overflow. + +# Examples + +Basic usage: + +``` +let a: ", stringify!($SelfT), " = 7; // or any other integer type +let b = 4; + +assert_eq!(a.div_euclid(b), 1); // 7 >= 4 * 1 +assert_eq!(a.div_euclid(-b), -1); // 7 >= -4 * -1 +assert_eq!((-a).div_euclid(b), -2); // -7 >= 4 * -2 +assert_eq!((-a).div_euclid(-b), 2); // -7 >= -4 * 2 +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn div_euclid(self, rhs: Self) -> Self { + let q = self / rhs; + if self % rhs < 0 { + return if rhs > 0 { q - 1 } else { q + 1 } + } + q + } + } + + + doc_comment! { + concat!("Calculates the least nonnegative remainder of `self (mod rhs)`. + +This is done as if by the Euclidean division algorithm -- given +`r = self.rem_euclid(rhs)`, `self = rhs * self.div_euclid(rhs) + r`, and +`0 <= r < abs(rhs)`. + +# Panics + +This function will panic if `rhs` is 0 or the division results in overflow. + +# Examples + +Basic usage: + +``` +let a: ", stringify!($SelfT), " = 7; // or any other integer type +let b = 4; + +assert_eq!(a.rem_euclid(b), 3); +assert_eq!((-a).rem_euclid(b), 1); +assert_eq!(a.rem_euclid(-b), 3); +assert_eq!((-a).rem_euclid(-b), 1); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn rem_euclid(self, rhs: Self) -> Self { + let r = self % rhs; + if r < 0 { + if rhs < 0 { + r - rhs + } else { + r + rhs + } + } else { + r + } + } + } + + doc_comment! { + concat!("Computes the absolute value of `self`. + +# Overflow behavior + +The absolute value of `", stringify!($SelfT), "::MIN` cannot be represented as an +`", stringify!($SelfT), "`, and attempting to calculate it will cause an overflow. This means that +code in debug mode will trigger a panic on this case and optimized code will return `", +stringify!($SelfT), "::MIN` without a panic. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(10", stringify!($SelfT), ".abs(), 10); +assert_eq!((-10", stringify!($SelfT), ").abs(), 10);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[allow(unused_attributes)] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn abs(self) -> Self { + // Note that the #[inline] above means that the overflow + // semantics of the subtraction depend on the crate we're being + // inlined into. + if self.is_negative() { + -self + } else { + self + } + } + } + + doc_comment! { + concat!("Returns a number representing sign of `self`. + + - `0` if the number is zero + - `1` if the number is positive + - `-1` if the number is negative + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(10", stringify!($SelfT), ".signum(), 1); +assert_eq!(0", stringify!($SelfT), ".signum(), 0); +assert_eq!((-10", stringify!($SelfT), ").signum(), -1);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_sign", since = "1.47.0")] + #[inline] + pub const fn signum(self) -> Self { + match self { + n if n > 0 => 1, + 0 => 0, + _ => -1, + } + } + } + + doc_comment! { + concat!("Returns `true` if `self` is positive and `false` if the number is zero or +negative. + +# Examples + +Basic usage: + +``` +", $Feature, "assert!(10", stringify!($SelfT), ".is_positive()); +assert!(!(-10", stringify!($SelfT), ").is_positive());", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn is_positive(self) -> bool { self > 0 } + } + + doc_comment! { + concat!("Returns `true` if `self` is negative and `false` if the number is zero or +positive. + +# Examples + +Basic usage: + +``` +", $Feature, "assert!((-10", stringify!($SelfT), ").is_negative()); +assert!(!10", stringify!($SelfT), ".is_negative());", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn is_negative(self) -> bool { self < 0 } + } + + doc_comment! { + concat!("Return the memory representation of this integer as a byte array in +big-endian (network) byte order. +", +$to_xe_bytes_doc, +" +# Examples + +``` +let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes(); +assert_eq!(bytes, ", $be_bytes, "); +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[inline] + pub const fn to_be_bytes(self) -> [u8; mem::size_of::()] { + self.to_be().to_ne_bytes() + } + } + +doc_comment! { + concat!("Return the memory representation of this integer as a byte array in +little-endian byte order. +", +$to_xe_bytes_doc, +" +# Examples + +``` +let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes(); +assert_eq!(bytes, ", $le_bytes, "); +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[inline] + pub const fn to_le_bytes(self) -> [u8; mem::size_of::()] { + self.to_le().to_ne_bytes() + } + } + + doc_comment! { + concat!(" +Return the memory representation of this integer as a byte array in +native byte order. + +As the target platform's native endianness is used, portable code +should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, +instead. +", +$to_xe_bytes_doc, +" +[`to_be_bytes`]: #method.to_be_bytes +[`to_le_bytes`]: #method.to_le_bytes + +# Examples + +``` +let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes(); +assert_eq!( + bytes, + if cfg!(target_endian = \"big\") { + ", $be_bytes, " + } else { + ", $le_bytes, " + } +); +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + // SAFETY: const sound because integers are plain old datatypes so we can always + // transmute them to arrays of bytes + #[allow_internal_unstable(const_fn_transmute)] + #[inline] + pub const fn to_ne_bytes(self) -> [u8; mem::size_of::()] { + // SAFETY: integers are plain old datatypes so we can always transmute them to + // arrays of bytes + unsafe { mem::transmute(self) } + } + } + +doc_comment! { + concat!("Create an integer value from its representation as a byte array in +big endian. +", +$from_xe_bytes_doc, +" +# Examples + +``` +let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, "); +assert_eq!(value, ", $swap_op, "); +``` + +When starting from a slice rather than an array, fallible conversion APIs can be used: + +``` +use std::convert::TryInto; + +fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { + let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); + *input = rest; + ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap()) +} +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[inline] + pub const fn from_be_bytes(bytes: [u8; mem::size_of::()]) -> Self { + Self::from_be(Self::from_ne_bytes(bytes)) + } + } + +doc_comment! { + concat!(" +Create an integer value from its representation as a byte array in +little endian. +", +$from_xe_bytes_doc, +" +# Examples + +``` +let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, "); +assert_eq!(value, ", $swap_op, "); +``` + +When starting from a slice rather than an array, fallible conversion APIs can be used: + +``` +use std::convert::TryInto; + +fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { + let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); + *input = rest; + ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap()) +} +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[inline] + pub const fn from_le_bytes(bytes: [u8; mem::size_of::()]) -> Self { + Self::from_le(Self::from_ne_bytes(bytes)) + } + } + + doc_comment! { + concat!("Create an integer value from its memory representation as a byte +array in native endianness. + +As the target platform's native endianness is used, portable code +likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as +appropriate instead. + +[`from_be_bytes`]: #method.from_be_bytes +[`from_le_bytes`]: #method.from_le_bytes +", +$from_xe_bytes_doc, +" +# Examples + +``` +let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") { + ", $be_bytes, " +} else { + ", $le_bytes, " +}); +assert_eq!(value, ", $swap_op, "); +``` + +When starting from a slice rather than an array, fallible conversion APIs can be used: + +``` +use std::convert::TryInto; + +fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { + let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); + *input = rest; + ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap()) +} +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + // SAFETY: const sound because integers are plain old datatypes so we can always + // transmute to them + #[allow_internal_unstable(const_fn_transmute)] + #[inline] + pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { + // SAFETY: integers are plain old datatypes so we can always transmute to them + unsafe { mem::transmute(bytes) } + } + } + + doc_comment! { + concat!("**This method is soft-deprecated.** + +Although using it won’t cause a compilation warning, +new code should use [`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN) instead. + +Returns the smallest value that can be represented by this integer type."), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline(always)] + #[rustc_promotable] + #[rustc_const_stable(feature = "const_min_value", since = "1.32.0")] + pub const fn min_value() -> Self { + Self::MIN + } + } + + doc_comment! { + concat!("**This method is soft-deprecated.** + +Although using it won’t cause a compilation warning, +new code should use [`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX) instead. + +Returns the largest value that can be represented by this integer type."), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline(always)] + #[rustc_promotable] + #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")] + pub const fn max_value() -> Self { + Self::MAX + } + } + } +} diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index adcdee4219fe1..5388a5c04b86d 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -38,6 +38,11 @@ pub mod dec2flt; pub mod diy_float; pub mod flt2dec; +#[macro_use] +mod int_macros; // import int_impl! +#[macro_use] +mod uint_macros; // import uint_impl! + mod error; mod nonzero; mod wrapping; @@ -85,4228 +90,70 @@ depending on the target pointer size. }; } -macro_rules! int_impl { - ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $Min:expr, $Max:expr, $Feature:expr, - $EndFeature:expr, $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr, - $reversed:expr, $le_bytes:expr, $be_bytes:expr, - $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => { - doc_comment! { - concat!("The smallest value that can be represented by this integer type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), "::MIN, ", stringify!($Min), ");", -$EndFeature, " -```"), - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MIN: Self = !0 ^ ((!0 as $UnsignedT) >> 1) as Self; - } - - doc_comment! { - concat!("The largest value that can be represented by this integer type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($Max), ");", -$EndFeature, " -```"), - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MAX: Self = !Self::MIN; - } - - doc_comment! { - concat!("The size of this integer type in bits. - -# Examples - -``` -", $Feature, "#![feature(int_bits_const)] -assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");", -$EndFeature, " -```"), - #[unstable(feature = "int_bits_const", issue = "76904")] - pub const BITS: u32 = $BITS; - } - - doc_comment! { - concat!("Converts a string slice in a given base to an integer. - -The string is expected to be an optional `+` or `-` sign followed by digits. -Leading and trailing whitespace represent an error. Digits are a subset of these characters, -depending on `radix`: - - * `0-9` - * `a-z` - * `A-Z` - -# Panics - -This function panics if `radix` is not in the range from 2 to 36. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - pub fn from_str_radix(src: &str, radix: u32) -> Result { - from_str_radix(src, radix) - } - } - - doc_comment! { - concat!("Returns the number of ones in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0b100_0000", stringify!($SelfT), "; - -assert_eq!(n.count_ones(), 1);", -$EndFeature, " -``` -"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } - } - - doc_comment! { - concat!("Returns the number of zeros in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 1);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn count_zeros(self) -> u32 { - (!self).count_ones() - } - } - - doc_comment! { - concat!("Returns the number of leading zeros in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = -1", stringify!($SelfT), "; - -assert_eq!(n.leading_zeros(), 0);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn leading_zeros(self) -> u32 { - (self as $UnsignedT).leading_zeros() - } - } - - doc_comment! { - concat!("Returns the number of trailing zeros in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = -4", stringify!($SelfT), "; - -assert_eq!(n.trailing_zeros(), 2);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn trailing_zeros(self) -> u32 { - (self as $UnsignedT).trailing_zeros() - } - } - - doc_comment! { - concat!("Returns the number of leading ones in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = -1", stringify!($SelfT), "; - -assert_eq!(n.leading_ones(), ", stringify!($BITS), ");", -$EndFeature, " -```"), - #[stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[inline] - pub const fn leading_ones(self) -> u32 { - (self as $UnsignedT).leading_ones() - } - } - - doc_comment! { - concat!("Returns the number of trailing ones in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 3", stringify!($SelfT), "; - -assert_eq!(n.trailing_ones(), 2);", -$EndFeature, " -```"), - #[stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[inline] - pub const fn trailing_ones(self) -> u32 { - (self as $UnsignedT).trailing_ones() - } - } - - doc_comment! { - concat!("Shifts the bits to the left by a specified amount, `n`, -wrapping the truncated bits to the end of the resulting integer. - -Please note this isn't the same operation as the `<<` shifting operator! - -# Examples - -Basic usage: - -``` -let n = ", $rot_op, stringify!($SelfT), "; -let m = ", $rot_result, "; - -assert_eq!(n.rotate_left(", $rot, "), m); -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn rotate_left(self, n: u32) -> Self { - (self as $UnsignedT).rotate_left(n) as Self - } - } - - doc_comment! { - concat!("Shifts the bits to the right by a specified amount, `n`, -wrapping the truncated bits to the beginning of the resulting -integer. - -Please note this isn't the same operation as the `>>` shifting operator! - -# Examples - -Basic usage: - -``` -let n = ", $rot_result, stringify!($SelfT), "; -let m = ", $rot_op, "; - -assert_eq!(n.rotate_right(", $rot, "), m); -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn rotate_right(self, n: u32) -> Self { - (self as $UnsignedT).rotate_right(n) as Self - } - } - - doc_comment! { - concat!("Reverses the byte order of the integer. - -# Examples - -Basic usage: - -``` -let n = ", $swap_op, stringify!($SelfT), "; - -let m = n.swap_bytes(); - -assert_eq!(m, ", $swapped, "); -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn swap_bytes(self) -> Self { - (self as $UnsignedT).swap_bytes() as Self - } - } - - doc_comment! { - concat!("Reverses the bit pattern of the integer. - -# Examples - -Basic usage: - -``` -let n = ", $swap_op, stringify!($SelfT), "; -let m = n.reverse_bits(); - -assert_eq!(m, ", $reversed, "); -```"), - #[stable(feature = "reverse_bits", since = "1.37.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - #[must_use] - pub const fn reverse_bits(self) -> Self { - (self as $UnsignedT).reverse_bits() as Self - } - } - - doc_comment! { - concat!("Converts an integer from big endian to the target's endianness. - -On big endian this is a no-op. On little endian the bytes are swapped. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0x1A", stringify!($SelfT), "; - -if cfg!(target_endian = \"big\") { - assert_eq!(", stringify!($SelfT), "::from_be(n), n) -} else { - assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes()) -}", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] - #[inline] - pub const fn from_be(x: Self) -> Self { - #[cfg(target_endian = "big")] - { - x - } - #[cfg(not(target_endian = "big"))] - { - x.swap_bytes() - } - } - } - - doc_comment! { - concat!("Converts an integer from little endian to the target's endianness. - -On little endian this is a no-op. On big endian the bytes are swapped. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0x1A", stringify!($SelfT), "; - -if cfg!(target_endian = \"little\") { - assert_eq!(", stringify!($SelfT), "::from_le(n), n) -} else { - assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes()) -}", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] - #[inline] - pub const fn from_le(x: Self) -> Self { - #[cfg(target_endian = "little")] - { - x - } - #[cfg(not(target_endian = "little"))] - { - x.swap_bytes() - } - } - } - - doc_comment! { - concat!("Converts `self` to big endian from the target's endianness. - -On big endian this is a no-op. On little endian the bytes are swapped. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0x1A", stringify!($SelfT), "; - -if cfg!(target_endian = \"big\") { - assert_eq!(n.to_be(), n) -} else { - assert_eq!(n.to_be(), n.swap_bytes()) -}", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] - #[inline] - pub const fn to_be(self) -> Self { // or not to be? - #[cfg(target_endian = "big")] - { - self - } - #[cfg(not(target_endian = "big"))] - { - self.swap_bytes() - } - } - } - - doc_comment! { - concat!("Converts `self` to little endian from the target's endianness. - -On little endian this is a no-op. On big endian the bytes are swapped. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0x1A", stringify!($SelfT), "; - -if cfg!(target_endian = \"little\") { - assert_eq!(n.to_le(), n) -} else { - assert_eq!(n.to_le(), n.swap_bytes()) -}", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] - #[inline] - pub const fn to_le(self) -> Self { - #[cfg(target_endian = "little")] - { - self - } - #[cfg(not(target_endian = "little"))] - { - self.swap_bytes() - } - } - } - - doc_comment! { - concat!("Checked integer addition. Computes `self + rhs`, returning `None` -if overflow occurred. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!((", stringify!($SelfT), -"::MAX - 2).checked_add(1), Some(", stringify!($SelfT), "::MAX - 1)); -assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_add(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_add(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Unchecked integer addition. Computes `self + rhs`, assuming overflow -cannot occur. This results in undefined behavior when `self + rhs > ", stringify!($SelfT), -"::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`."), - #[unstable( - feature = "unchecked_math", - reason = "niche optimization path", - issue = "none", - )] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub unsafe fn unchecked_add(self, rhs: Self) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_add`. - unsafe { intrinsics::unchecked_add(self, rhs) } - } - } - - doc_comment! { - concat!("Checked integer subtraction. Computes `self - rhs`, returning `None` if -overflow occurred. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!((", stringify!($SelfT), -"::MIN + 2).checked_sub(1), Some(", stringify!($SelfT), "::MIN + 1)); -assert_eq!((", stringify!($SelfT), "::MIN + 2).checked_sub(3), None);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_sub(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_sub(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Unchecked integer subtraction. Computes `self - rhs`, assuming overflow -cannot occur. This results in undefined behavior when `self - rhs > ", stringify!($SelfT), -"::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`."), - #[unstable( - feature = "unchecked_math", - reason = "niche optimization path", - issue = "none", - )] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub unsafe fn unchecked_sub(self, rhs: Self) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_sub`. - unsafe { intrinsics::unchecked_sub(self, rhs) } - } - } - - doc_comment! { - concat!("Checked integer multiplication. Computes `self * rhs`, returning `None` if -overflow occurred. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), -"::MAX.checked_mul(1), Some(", stringify!($SelfT), "::MAX)); -assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_mul(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_mul(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Unchecked integer multiplication. Computes `self * rhs`, assuming overflow -cannot occur. This results in undefined behavior when `self * rhs > ", stringify!($SelfT), -"::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`."), - #[unstable( - feature = "unchecked_math", - reason = "niche optimization path", - issue = "none", - )] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub unsafe fn unchecked_mul(self, rhs: Self) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_mul`. - unsafe { intrinsics::unchecked_mul(self, rhs) } - } - } - - doc_comment! { - concat!("Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0` -or the division results in overflow. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!((", stringify!($SelfT), -"::MIN + 1).checked_div(-1), Some(", stringify!($Max), ")); -assert_eq!(", stringify!($SelfT), "::MIN.checked_div(-1), None); -assert_eq!((1", stringify!($SelfT), ").checked_div(0), None);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_div(self, rhs: Self) -> Option { - if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { - None - } else { - // SAFETY: div by zero and by INT_MIN have been checked above - Some(unsafe { intrinsics::unchecked_div(self, rhs) }) - } - } - } - - doc_comment! { - concat!("Checked Euclidean division. Computes `self.div_euclid(rhs)`, -returning `None` if `rhs == 0` or the division results in overflow. - -# Examples - -Basic usage: - -``` -assert_eq!((", stringify!($SelfT), -"::MIN + 1).checked_div_euclid(-1), Some(", stringify!($Max), ")); -assert_eq!(", stringify!($SelfT), "::MIN.checked_div_euclid(-1), None); -assert_eq!((1", stringify!($SelfT), ").checked_div_euclid(0), None); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_div_euclid(self, rhs: Self) -> Option { - if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { - None - } else { - Some(self.div_euclid(rhs)) - } - } - } - - doc_comment! { - concat!("Checked integer remainder. Computes `self % rhs`, returning `None` if -`rhs == 0` or the division results in overflow. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1)); -assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None); -assert_eq!(", stringify!($SelfT), "::MIN.checked_rem(-1), None);", -$EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_rem(self, rhs: Self) -> Option { - if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { - None - } else { - // SAFETY: div by zero and by INT_MIN have been checked above - Some(unsafe { intrinsics::unchecked_rem(self, rhs) }) - } - } - } - - doc_comment! { - concat!("Checked Euclidean remainder. Computes `self.rem_euclid(rhs)`, returning `None` -if `rhs == 0` or the division results in overflow. - -# Examples - -Basic usage: - -``` -assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1)); -assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None); -assert_eq!(", stringify!($SelfT), "::MIN.checked_rem_euclid(-1), None); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_rem_euclid(self, rhs: Self) -> Option { - if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { - None - } else { - Some(self.rem_euclid(rhs)) - } - } - } - - doc_comment! { - concat!("Checked negation. Computes `-self`, returning `None` if `self == MIN`. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!(5", stringify!($SelfT), ".checked_neg(), Some(-5)); -assert_eq!(", stringify!($SelfT), "::MIN.checked_neg(), None);", -$EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[inline] - pub const fn checked_neg(self) -> Option { - let (a, b) = self.overflowing_neg(); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Checked shift left. Computes `self << rhs`, returning `None` if `rhs` is larger -than or equal to the number of bits in `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10)); -assert_eq!(0x1", stringify!($SelfT), ".checked_shl(129), None);", -$EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_shl(self, rhs: u32) -> Option { - let (a, b) = self.overflowing_shl(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is -larger than or equal to the number of bits in `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1)); -assert_eq!(0x10", stringify!($SelfT), ".checked_shr(128), None);", -$EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_shr(self, rhs: u32) -> Option { - let (a, b) = self.overflowing_shr(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Checked absolute value. Computes `self.abs()`, returning `None` if -`self == MIN`. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!((-5", stringify!($SelfT), ").checked_abs(), Some(5)); -assert_eq!(", stringify!($SelfT), "::MIN.checked_abs(), None);", -$EndFeature, " -```"), - #[stable(feature = "no_panic_abs", since = "1.13.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[inline] - pub const fn checked_abs(self) -> Option { - if self.is_negative() { - self.checked_neg() - } else { - Some(self) - } - } - } - - doc_comment! { - concat!("Checked exponentiation. Computes `self.pow(exp)`, returning `None` if -overflow occurred. - -# Examples - -Basic usage: +#[lang = "i8"] +impl i8 { + int_impl! { i8, i8, u8, 8, -128, 127, "", "", 2, "-0x7e", "0xa", "0x12", "0x12", "0x48", + "[0x12]", "[0x12]", "", "" } +} -``` -", $Feature, "assert_eq!(8", stringify!($SelfT), ".checked_pow(2), Some(64)); -assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);", -$EndFeature, " -```"), +#[lang = "i16"] +impl i16 { + int_impl! { i16, i16, u16, 16, -32768, 32767, "", "", 4, "-0x5ffd", "0x3a", "0x1234", "0x3412", + "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" } +} - #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_pow(self, mut exp: u32) -> Option { - if exp == 0 { - return Some(1); - } - let mut base = self; - let mut acc: Self = 1; +#[lang = "i32"] +impl i32 { + int_impl! { i32, i32, u32, 32, -2147483648, 2147483647, "", "", 8, "0x10000b3", "0xb301", + "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", + "[0x12, 0x34, 0x56, 0x78]", "", "" } +} - while exp > 1 { - if (exp & 1) == 1 { - acc = try_opt!(acc.checked_mul(base)); - } - exp /= 2; - base = try_opt!(base.checked_mul(base)); - } - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - Some(try_opt!(acc.checked_mul(base))) - } - } +#[lang = "i64"] +impl i64 { + int_impl! { i64, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "", 12, + "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", + "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", + "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", "", "" } +} - doc_comment! { - concat!("Saturating integer addition. Computes `self + rhs`, saturating at the numeric -bounds instead of overflowing. +#[lang = "i128"] +impl i128 { + int_impl! { i128, i128, u128, 128, -170141183460469231731687303715884105728, + 170141183460469231731687303715884105727, "", "", 16, + "0x13f40000000000000000000000004f76", "0x4f7613f4", "0x12345678901234567890123456789012", + "0x12907856341290785634129078563412", "0x48091e6a2c48091e6a2c48091e6a2c48", + "[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \ + 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", + "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, \ + 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]", "", "" } +} -# Examples +#[cfg(target_pointer_width = "16")] +#[lang = "isize"] +impl isize { + int_impl! { isize, i16, u16, 16, -32768, 32767, "", "", 4, "-0x5ffd", "0x3a", "0x1234", + "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", + usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } +} -Basic usage: +#[cfg(target_pointer_width = "32")] +#[lang = "isize"] +impl isize { + int_impl! { isize, i32, u32, 32, -2147483648, 2147483647, "", "", 8, "0x10000b3", "0xb301", + "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", + "[0x12, 0x34, 0x56, 0x78]", + usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } +} -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101); -assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(100), ", stringify!($SelfT), -"::MAX); -assert_eq!(", stringify!($SelfT), "::MIN.saturating_add(-1), ", stringify!($SelfT), -"::MIN);", -$EndFeature, " -```"), - - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn saturating_add(self, rhs: Self) -> Self { - intrinsics::saturating_add(self, rhs) - } - } - - doc_comment! { - concat!("Saturating integer subtraction. Computes `self - rhs`, saturating at the -numeric bounds instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(127), -27); -assert_eq!(", stringify!($SelfT), "::MIN.saturating_sub(100), ", stringify!($SelfT), -"::MIN); -assert_eq!(", stringify!($SelfT), "::MAX.saturating_sub(-1), ", stringify!($SelfT), -"::MAX);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn saturating_sub(self, rhs: Self) -> Self { - intrinsics::saturating_sub(self, rhs) - } - } - - doc_comment! { - concat!("Saturating integer negation. Computes `-self`, returning `MAX` if `self == MIN` -instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_neg(), -100); -assert_eq!((-100", stringify!($SelfT), ").saturating_neg(), 100); -assert_eq!(", stringify!($SelfT), "::MIN.saturating_neg(), ", stringify!($SelfT), -"::MAX); -assert_eq!(", stringify!($SelfT), "::MAX.saturating_neg(), ", stringify!($SelfT), -"::MIN + 1);", -$EndFeature, " -```"), - - #[stable(feature = "saturating_neg", since = "1.45.0")] - #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] - #[inline] - pub const fn saturating_neg(self) -> Self { - intrinsics::saturating_sub(0, self) - } - } - - doc_comment! { - concat!("Saturating absolute value. Computes `self.abs()`, returning `MAX` if `self == -MIN` instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_abs(), 100); -assert_eq!((-100", stringify!($SelfT), ").saturating_abs(), 100); -assert_eq!(", stringify!($SelfT), "::MIN.saturating_abs(), ", stringify!($SelfT), -"::MAX); -assert_eq!((", stringify!($SelfT), "::MIN + 1).saturating_abs(), ", stringify!($SelfT), -"::MAX);", -$EndFeature, " -```"), - - #[stable(feature = "saturating_neg", since = "1.45.0")] - #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] - #[inline] - pub const fn saturating_abs(self) -> Self { - if self.is_negative() { - self.saturating_neg() - } else { - self - } - } - } - - doc_comment! { - concat!("Saturating integer multiplication. Computes `self * rhs`, saturating at the -numeric bounds instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!(10", stringify!($SelfT), ".saturating_mul(12), 120); -assert_eq!(", stringify!($SelfT), "::MAX.saturating_mul(10), ", stringify!($SelfT), "::MAX); -assert_eq!(", stringify!($SelfT), "::MIN.saturating_mul(10), ", stringify!($SelfT), "::MIN);", -$EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn saturating_mul(self, rhs: Self) -> Self { - match self.checked_mul(rhs) { - Some(x) => x, - None => if (self < 0) == (rhs < 0) { - Self::MAX - } else { - Self::MIN - } - } - } - } - - doc_comment! { - concat!("Saturating integer exponentiation. Computes `self.pow(exp)`, -saturating at the numeric bounds instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!((-4", stringify!($SelfT), ").saturating_pow(3), -64); -assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(2), ", stringify!($SelfT), "::MAX); -assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(3), ", stringify!($SelfT), "::MIN);", -$EndFeature, " -```"), - #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn saturating_pow(self, exp: u32) -> Self { - match self.checked_pow(exp) { - Some(x) => x, - None if self < 0 && exp % 2 == 1 => Self::MIN, - None => Self::MAX, - } - } - } - - doc_comment! { - concat!("Wrapping (modular) addition. Computes `self + rhs`, wrapping around at the -boundary of the type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_add(27), 127); -assert_eq!(", stringify!($SelfT), "::MAX.wrapping_add(2), ", stringify!($SelfT), -"::MIN + 1);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_add(self, rhs: Self) -> Self { - intrinsics::wrapping_add(self, rhs) - } - } - - doc_comment! { - concat!("Wrapping (modular) subtraction. Computes `self - rhs`, wrapping around at the -boundary of the type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(0", stringify!($SelfT), ".wrapping_sub(127), -127); -assert_eq!((-2", stringify!($SelfT), ").wrapping_sub(", stringify!($SelfT), "::MAX), ", -stringify!($SelfT), "::MAX);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_sub(self, rhs: Self) -> Self { - intrinsics::wrapping_sub(self, rhs) - } - } - - doc_comment! { - concat!("Wrapping (modular) multiplication. Computes `self * rhs`, wrapping around at -the boundary of the type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(10", stringify!($SelfT), ".wrapping_mul(12), 120); -assert_eq!(11i8.wrapping_mul(12), -124);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_mul(self, rhs: Self) -> Self { - intrinsics::wrapping_mul(self, rhs) - } - } - - doc_comment! { - concat!("Wrapping (modular) division. Computes `self / rhs`, wrapping around at the -boundary of the type. - -The only case where such wrapping can occur is when one divides `MIN / -1` on a signed type (where -`MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value -that is too large to represent in the type. In such a case, this function returns `MIN` itself. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10); -assert_eq!((-128i8).wrapping_div(-1), -128);", -$EndFeature, " -```"), - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_div(self, rhs: Self) -> Self { - self.overflowing_div(rhs).0 - } - } - - doc_comment! { - concat!("Wrapping Euclidean division. Computes `self.div_euclid(rhs)`, -wrapping around at the boundary of the type. - -Wrapping will only occur in `MIN / -1` on a signed type (where `MIN` is the negative minimal value -for the type). This is equivalent to `-MIN`, a positive value that is too large to represent in the -type. In this case, this method returns `MIN` itself. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10); -assert_eq!((-128i8).wrapping_div_euclid(-1), -128); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_div_euclid(self, rhs: Self) -> Self { - self.overflowing_div_euclid(rhs).0 - } - } - - doc_comment! { - concat!("Wrapping (modular) remainder. Computes `self % rhs`, wrapping around at the -boundary of the type. - -Such wrap-around never actually occurs mathematically; implementation artifacts make `x % y` -invalid for `MIN / -1` on a signed type (where `MIN` is the negative minimal value). In such a case, -this function returns `0`. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0); -assert_eq!((-128i8).wrapping_rem(-1), 0);", -$EndFeature, " -```"), - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_rem(self, rhs: Self) -> Self { - self.overflowing_rem(rhs).0 - } - } - - doc_comment! { - concat!("Wrapping Euclidean remainder. Computes `self.rem_euclid(rhs)`, wrapping around -at the boundary of the type. - -Wrapping will only occur in `MIN % -1` on a signed type (where `MIN` is the negative minimal value -for the type). In this case, this method returns 0. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0); -assert_eq!((-128i8).wrapping_rem_euclid(-1), 0); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self { - self.overflowing_rem_euclid(rhs).0 - } - } - - doc_comment! { - concat!("Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary -of the type. - -The only case where such wrapping can occur is when one negates `MIN` on a signed type (where `MIN` -is the negative minimal value for the type); this is a positive value that is too large to represent -in the type. In such a case, this function returns `MIN` itself. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_neg(), -100); -assert_eq!(", stringify!($SelfT), "::MIN.wrapping_neg(), ", stringify!($SelfT), -"::MIN);", -$EndFeature, " -```"), - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn wrapping_neg(self) -> Self { - self.overflowing_neg().0 - } - } - - doc_comment! { - concat!("Panic-free bitwise shift-left; yields `self << mask(rhs)`, where `mask` removes -any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type. - -Note that this is *not* the same as a rotate-left; the RHS of a wrapping shift-left is restricted to -the range of the type, rather than the bits shifted out of the LHS being returned to the other end. -The primitive integer types all implement a `[`rotate_left`](#method.rotate_left) function, -which may be what you want instead. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(7), -128); -assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(128), -1);", -$EndFeature, " -```"), - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_shl(self, rhs: u32) -> Self { - // SAFETY: the masking by the bitsize of the type ensures that we do not shift - // out of bounds - unsafe { - intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT) - } - } - } - - doc_comment! { - concat!("Panic-free bitwise shift-right; yields `self >> mask(rhs)`, where `mask` -removes any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type. - -Note that this is *not* the same as a rotate-right; the RHS of a wrapping shift-right is restricted -to the range of the type, rather than the bits shifted out of the LHS being returned to the other -end. The primitive integer types all implement a [`rotate_right`](#method.rotate_right) function, -which may be what you want instead. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!((-128", stringify!($SelfT), ").wrapping_shr(7), -1); -assert_eq!((-128i16).wrapping_shr(64), -128);", -$EndFeature, " -```"), - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_shr(self, rhs: u32) -> Self { - // SAFETY: the masking by the bitsize of the type ensures that we do not shift - // out of bounds - unsafe { - intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT) - } - } - } - - doc_comment! { - concat!("Wrapping (modular) absolute value. Computes `self.abs()`, wrapping around at -the boundary of the type. - -The only case where such wrapping can occur is when one takes the absolute value of the negative -minimal value for the type; this is a positive value that is too large to represent in the type. In -such a case, this function returns `MIN` itself. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_abs(), 100); -assert_eq!((-100", stringify!($SelfT), ").wrapping_abs(), 100); -assert_eq!(", stringify!($SelfT), "::MIN.wrapping_abs(), ", stringify!($SelfT), -"::MIN); -assert_eq!((-128i8).wrapping_abs() as u8, 128);", -$EndFeature, " -```"), - #[stable(feature = "no_panic_abs", since = "1.13.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[allow(unused_attributes)] - #[inline] - pub const fn wrapping_abs(self) -> Self { - if self.is_negative() { - self.wrapping_neg() - } else { - self - } - } - } - - doc_comment! { - concat!("Computes the absolute value of `self` without any wrapping -or panicking. - - -# Examples - -Basic usage: - -``` -", $Feature, "#![feature(unsigned_abs)] -assert_eq!(100", stringify!($SelfT), ".unsigned_abs(), 100", stringify!($UnsignedT), "); -assert_eq!((-100", stringify!($SelfT), ").unsigned_abs(), 100", stringify!($UnsignedT), "); -assert_eq!((-128i8).unsigned_abs(), 128u8);", -$EndFeature, " -```"), - #[unstable(feature = "unsigned_abs", issue = "74913")] - #[inline] - pub const fn unsigned_abs(self) -> $UnsignedT { - self.wrapping_abs() as $UnsignedT - } - } - - doc_comment! { - concat!("Wrapping (modular) exponentiation. Computes `self.pow(exp)`, -wrapping around at the boundary of the type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(4), 81); -assert_eq!(3i8.wrapping_pow(5), -13); -assert_eq!(3i8.wrapping_pow(6), -39);", -$EndFeature, " -```"), - #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_pow(self, mut exp: u32) -> Self { - if exp == 0 { - return 1; - } - let mut base = self; - let mut acc: Self = 1; - - while exp > 1 { - if (exp & 1) == 1 { - acc = acc.wrapping_mul(base); - } - exp /= 2; - base = base.wrapping_mul(base); - } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - acc.wrapping_mul(base) - } - } - - doc_comment! { - concat!("Calculates `self` + `rhs` - -Returns a tuple of the addition along with a boolean indicating whether an arithmetic overflow would -occur. If an overflow would have occurred then the wrapped value is returned. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false)); -assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (", stringify!($SelfT), -"::MIN, true));", $EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) { - let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT); - (a as Self, b) - } - } - - doc_comment! { - concat!("Calculates `self` - `rhs` - -Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow -would occur. If an overflow would have occurred then the wrapped value is returned. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false)); -assert_eq!(", stringify!($SelfT), "::MIN.overflowing_sub(1), (", stringify!($SelfT), -"::MAX, true));", $EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { - let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT); - (a as Self, b) - } - } - - doc_comment! { - concat!("Calculates the multiplication of `self` and `rhs`. - -Returns a tuple of the multiplication along with a boolean indicating whether an arithmetic overflow -would occur. If an overflow would have occurred then the wrapped value is returned. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_mul(2), (10, false)); -assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true));", -$EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) { - let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT); - (a as Self, b) - } - } - - doc_comment! { - concat!("Calculates the divisor when `self` is divided by `rhs`. - -Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would -occur. If an overflow would occur then self is returned. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false)); -assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div(-1), (", stringify!($SelfT), -"::MIN, true));", -$EndFeature, " -```"), - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) { - if unlikely!(self == Self::MIN && rhs == -1) { - (self, true) - } else { - (self / rhs, false) - } - } - } - - doc_comment! { - concat!("Calculates the quotient of Euclidean division `self.div_euclid(rhs)`. - -Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would -occur. If an overflow would occur then `self` is returned. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false)); -assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div_euclid(-1), (", stringify!($SelfT), -"::MIN, true)); -```"), - #[inline] - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { - if unlikely!(self == Self::MIN && rhs == -1) { - (self, true) - } else { - (self.div_euclid(rhs), false) - } - } - } - - doc_comment! { - concat!("Calculates the remainder when `self` is divided by `rhs`. - -Returns a tuple of the remainder after dividing along with a boolean indicating whether an -arithmetic overflow would occur. If an overflow would occur then 0 is returned. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false)); -assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem(-1), (0, true));", -$EndFeature, " -```"), - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) { - if unlikely!(self == Self::MIN && rhs == -1) { - (0, true) - } else { - (self % rhs, false) - } - } - } - - - doc_comment! { - concat!("Overflowing Euclidean remainder. Calculates `self.rem_euclid(rhs)`. - -Returns a tuple of the remainder after dividing along with a boolean indicating whether an -arithmetic overflow would occur. If an overflow would occur then 0 is returned. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false)); -assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem_euclid(-1), (0, true)); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { - if unlikely!(self == Self::MIN && rhs == -1) { - (0, true) - } else { - (self.rem_euclid(rhs), false) - } - } - } - - - doc_comment! { - concat!("Negates self, overflowing if this is equal to the minimum value. - -Returns a tuple of the negated version of self along with a boolean indicating whether an overflow -happened. If `self` is the minimum value (e.g., `i32::MIN` for values of type `i32`), then the -minimum value will be returned again and `true` will be returned for an overflow happening. - -# Examples - -Basic usage: - -``` -assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2, false)); -assert_eq!(", stringify!($SelfT), "::MIN.overflowing_neg(), (", stringify!($SelfT), -"::MIN, true));", $EndFeature, " -```"), - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[allow(unused_attributes)] - pub const fn overflowing_neg(self) -> (Self, bool) { - if unlikely!(self == Self::MIN) { - (Self::MIN, true) - } else { - (-self, false) - } - } - } - - doc_comment! { - concat!("Shifts self left by `rhs` bits. - -Returns a tuple of the shifted version of self along with a boolean indicating whether the shift -value was larger than or equal to the number of bits. If the shift value is too large, then value is -masked (N-1) where N is the number of bits, and this value is then used to perform the shift. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(0x1", stringify!($SelfT),".overflowing_shl(4), (0x10, false)); -assert_eq!(0x1i32.overflowing_shl(36), (0x10, true));", -$EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) { - (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) - } - } - - doc_comment! { - concat!("Shifts self right by `rhs` bits. - -Returns a tuple of the shifted version of self along with a boolean indicating whether the shift -value was larger than or equal to the number of bits. If the shift value is too large, then value is -masked (N-1) where N is the number of bits, and this value is then used to perform the shift. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false)); -assert_eq!(0x10i32.overflowing_shr(36), (0x1, true));", -$EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) { - (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) - } - } - - doc_comment! { - concat!("Computes the absolute value of `self`. - -Returns a tuple of the absolute version of self along with a boolean indicating whether an overflow -happened. If self is the minimum value (e.g., ", stringify!($SelfT), "::MIN for values of type - ", stringify!($SelfT), "), then the minimum value will be returned again and true will be returned -for an overflow happening. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(10", stringify!($SelfT), ".overflowing_abs(), (10, false)); -assert_eq!((-10", stringify!($SelfT), ").overflowing_abs(), (10, false)); -assert_eq!((", stringify!($SelfT), "::MIN).overflowing_abs(), (", stringify!($SelfT), -"::MIN, true));", -$EndFeature, " -```"), - #[stable(feature = "no_panic_abs", since = "1.13.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn overflowing_abs(self) -> (Self, bool) { - (self.wrapping_abs(), self == Self::MIN) - } - } - - doc_comment! { - concat!("Raises self to the power of `exp`, using exponentiation by squaring. - -Returns a tuple of the exponentiation along with a bool indicating -whether an overflow happened. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(4), (81, false)); -assert_eq!(3i8.overflowing_pow(5), (-13, true));", -$EndFeature, " -```"), - #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) { - if exp == 0 { - return (1,false); - } - let mut base = self; - let mut acc: Self = 1; - let mut overflown = false; - // Scratch space for storing results of overflowing_mul. - let mut r; - - while exp > 1 { - if (exp & 1) == 1 { - r = acc.overflowing_mul(base); - acc = r.0; - overflown |= r.1; - } - exp /= 2; - r = base.overflowing_mul(base); - base = r.0; - overflown |= r.1; - } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - r = acc.overflowing_mul(base); - r.1 |= overflown; - r - } - } - - doc_comment! { - concat!("Raises self to the power of `exp`, using exponentiation by squaring. - -# Examples - -Basic usage: - -``` -", $Feature, "let x: ", stringify!($SelfT), " = 2; // or any other integer type - -assert_eq!(x.pow(5), 32);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - #[rustc_inherit_overflow_checks] - pub const fn pow(self, mut exp: u32) -> Self { - if exp == 0 { - return 1; - } - let mut base = self; - let mut acc = 1; - - while exp > 1 { - if (exp & 1) == 1 { - acc = acc * base; - } - exp /= 2; - base = base * base; - } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - acc * base - } - } - - doc_comment! { - concat!("Calculates the quotient of Euclidean division of `self` by `rhs`. - -This computes the integer `n` such that `self = n * rhs + self.rem_euclid(rhs)`, -with `0 <= self.rem_euclid(rhs) < rhs`. - -In other words, the result is `self / rhs` rounded to the integer `n` -such that `self >= n * rhs`. -If `self > 0`, this is equal to round towards zero (the default in Rust); -if `self < 0`, this is equal to round towards +/- infinity. - -# Panics - -This function will panic if `rhs` is 0 or the division results in overflow. - -# Examples - -Basic usage: - -``` -let a: ", stringify!($SelfT), " = 7; // or any other integer type -let b = 4; - -assert_eq!(a.div_euclid(b), 1); // 7 >= 4 * 1 -assert_eq!(a.div_euclid(-b), -1); // 7 >= -4 * -1 -assert_eq!((-a).div_euclid(b), -2); // -7 >= 4 * -2 -assert_eq!((-a).div_euclid(-b), 2); // -7 >= -4 * 2 -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - #[rustc_inherit_overflow_checks] - pub const fn div_euclid(self, rhs: Self) -> Self { - let q = self / rhs; - if self % rhs < 0 { - return if rhs > 0 { q - 1 } else { q + 1 } - } - q - } - } - - - doc_comment! { - concat!("Calculates the least nonnegative remainder of `self (mod rhs)`. - -This is done as if by the Euclidean division algorithm -- given -`r = self.rem_euclid(rhs)`, `self = rhs * self.div_euclid(rhs) + r`, and -`0 <= r < abs(rhs)`. - -# Panics - -This function will panic if `rhs` is 0 or the division results in overflow. - -# Examples - -Basic usage: - -``` -let a: ", stringify!($SelfT), " = 7; // or any other integer type -let b = 4; - -assert_eq!(a.rem_euclid(b), 3); -assert_eq!((-a).rem_euclid(b), 1); -assert_eq!(a.rem_euclid(-b), 3); -assert_eq!((-a).rem_euclid(-b), 1); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - #[rustc_inherit_overflow_checks] - pub const fn rem_euclid(self, rhs: Self) -> Self { - let r = self % rhs; - if r < 0 { - if rhs < 0 { - r - rhs - } else { - r + rhs - } - } else { - r - } - } - } - - doc_comment! { - concat!("Computes the absolute value of `self`. - -# Overflow behavior - -The absolute value of `", stringify!($SelfT), "::MIN` cannot be represented as an -`", stringify!($SelfT), "`, and attempting to calculate it will cause an overflow. This means that -code in debug mode will trigger a panic on this case and optimized code will return `", -stringify!($SelfT), "::MIN` without a panic. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(10", stringify!($SelfT), ".abs(), 10); -assert_eq!((-10", stringify!($SelfT), ").abs(), 10);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[allow(unused_attributes)] - #[inline] - #[rustc_inherit_overflow_checks] - pub const fn abs(self) -> Self { - // Note that the #[inline] above means that the overflow - // semantics of the subtraction depend on the crate we're being - // inlined into. - if self.is_negative() { - -self - } else { - self - } - } - } - - doc_comment! { - concat!("Returns a number representing sign of `self`. - - - `0` if the number is zero - - `1` if the number is positive - - `-1` if the number is negative - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(10", stringify!($SelfT), ".signum(), 1); -assert_eq!(0", stringify!($SelfT), ".signum(), 0); -assert_eq!((-10", stringify!($SelfT), ").signum(), -1);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_sign", since = "1.47.0")] - #[inline] - pub const fn signum(self) -> Self { - match self { - n if n > 0 => 1, - 0 => 0, - _ => -1, - } - } - } - - doc_comment! { - concat!("Returns `true` if `self` is positive and `false` if the number is zero or -negative. - -# Examples - -Basic usage: - -``` -", $Feature, "assert!(10", stringify!($SelfT), ".is_positive()); -assert!(!(-10", stringify!($SelfT), ").is_positive());", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn is_positive(self) -> bool { self > 0 } - } - - doc_comment! { - concat!("Returns `true` if `self` is negative and `false` if the number is zero or -positive. - -# Examples - -Basic usage: - -``` -", $Feature, "assert!((-10", stringify!($SelfT), ").is_negative()); -assert!(!10", stringify!($SelfT), ".is_negative());", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn is_negative(self) -> bool { self < 0 } - } - - doc_comment! { - concat!("Return the memory representation of this integer as a byte array in -big-endian (network) byte order. -", -$to_xe_bytes_doc, -" -# Examples - -``` -let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes(); -assert_eq!(bytes, ", $be_bytes, "); -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[inline] - pub const fn to_be_bytes(self) -> [u8; mem::size_of::()] { - self.to_be().to_ne_bytes() - } - } - -doc_comment! { - concat!("Return the memory representation of this integer as a byte array in -little-endian byte order. -", -$to_xe_bytes_doc, -" -# Examples - -``` -let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes(); -assert_eq!(bytes, ", $le_bytes, "); -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[inline] - pub const fn to_le_bytes(self) -> [u8; mem::size_of::()] { - self.to_le().to_ne_bytes() - } - } - - doc_comment! { - concat!(" -Return the memory representation of this integer as a byte array in -native byte order. - -As the target platform's native endianness is used, portable code -should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, -instead. -", -$to_xe_bytes_doc, -" -[`to_be_bytes`]: #method.to_be_bytes -[`to_le_bytes`]: #method.to_le_bytes - -# Examples - -``` -let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes(); -assert_eq!( - bytes, - if cfg!(target_endian = \"big\") { - ", $be_bytes, " - } else { - ", $le_bytes, " - } -); -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - // SAFETY: const sound because integers are plain old datatypes so we can always - // transmute them to arrays of bytes - #[allow_internal_unstable(const_fn_transmute)] - #[inline] - pub const fn to_ne_bytes(self) -> [u8; mem::size_of::()] { - // SAFETY: integers are plain old datatypes so we can always transmute them to - // arrays of bytes - unsafe { mem::transmute(self) } - } - } - -doc_comment! { - concat!("Create an integer value from its representation as a byte array in -big endian. -", -$from_xe_bytes_doc, -" -# Examples - -``` -let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, "); -assert_eq!(value, ", $swap_op, "); -``` - -When starting from a slice rather than an array, fallible conversion APIs can be used: - -``` -use std::convert::TryInto; - -fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { - let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); - *input = rest; - ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap()) -} -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[inline] - pub const fn from_be_bytes(bytes: [u8; mem::size_of::()]) -> Self { - Self::from_be(Self::from_ne_bytes(bytes)) - } - } - -doc_comment! { - concat!(" -Create an integer value from its representation as a byte array in -little endian. -", -$from_xe_bytes_doc, -" -# Examples - -``` -let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, "); -assert_eq!(value, ", $swap_op, "); -``` - -When starting from a slice rather than an array, fallible conversion APIs can be used: - -``` -use std::convert::TryInto; - -fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { - let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); - *input = rest; - ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap()) -} -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[inline] - pub const fn from_le_bytes(bytes: [u8; mem::size_of::()]) -> Self { - Self::from_le(Self::from_ne_bytes(bytes)) - } - } - - doc_comment! { - concat!("Create an integer value from its memory representation as a byte -array in native endianness. - -As the target platform's native endianness is used, portable code -likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as -appropriate instead. - -[`from_be_bytes`]: #method.from_be_bytes -[`from_le_bytes`]: #method.from_le_bytes -", -$from_xe_bytes_doc, -" -# Examples - -``` -let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") { - ", $be_bytes, " -} else { - ", $le_bytes, " -}); -assert_eq!(value, ", $swap_op, "); -``` - -When starting from a slice rather than an array, fallible conversion APIs can be used: - -``` -use std::convert::TryInto; - -fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { - let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); - *input = rest; - ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap()) -} -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - // SAFETY: const sound because integers are plain old datatypes so we can always - // transmute to them - #[allow_internal_unstable(const_fn_transmute)] - #[inline] - pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { - // SAFETY: integers are plain old datatypes so we can always transmute to them - unsafe { mem::transmute(bytes) } - } - } - - doc_comment! { - concat!("**This method is soft-deprecated.** - -Although using it won’t cause a compilation warning, -new code should use [`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN) instead. - -Returns the smallest value that can be represented by this integer type."), - #[stable(feature = "rust1", since = "1.0.0")] - #[inline(always)] - #[rustc_promotable] - #[rustc_const_stable(feature = "const_min_value", since = "1.32.0")] - pub const fn min_value() -> Self { - Self::MIN - } - } - - doc_comment! { - concat!("**This method is soft-deprecated.** - -Although using it won’t cause a compilation warning, -new code should use [`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX) instead. - -Returns the largest value that can be represented by this integer type."), - #[stable(feature = "rust1", since = "1.0.0")] - #[inline(always)] - #[rustc_promotable] - #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")] - pub const fn max_value() -> Self { - Self::MAX - } - } - } -} - -#[lang = "i8"] -impl i8 { - int_impl! { i8, i8, u8, 8, -128, 127, "", "", 2, "-0x7e", "0xa", "0x12", "0x12", "0x48", - "[0x12]", "[0x12]", "", "" } -} - -#[lang = "i16"] -impl i16 { - int_impl! { i16, i16, u16, 16, -32768, 32767, "", "", 4, "-0x5ffd", "0x3a", "0x1234", "0x3412", - "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" } -} - -#[lang = "i32"] -impl i32 { - int_impl! { i32, i32, u32, 32, -2147483648, 2147483647, "", "", 8, "0x10000b3", "0xb301", - "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", - "[0x12, 0x34, 0x56, 0x78]", "", "" } -} - -#[lang = "i64"] -impl i64 { - int_impl! { i64, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "", 12, - "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", - "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", - "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", "", "" } -} - -#[lang = "i128"] -impl i128 { - int_impl! { i128, i128, u128, 128, -170141183460469231731687303715884105728, - 170141183460469231731687303715884105727, "", "", 16, - "0x13f40000000000000000000000004f76", "0x4f7613f4", "0x12345678901234567890123456789012", - "0x12907856341290785634129078563412", "0x48091e6a2c48091e6a2c48091e6a2c48", - "[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \ - 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", - "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, \ - 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]", "", "" } -} - -#[cfg(target_pointer_width = "16")] -#[lang = "isize"] -impl isize { - int_impl! { isize, i16, u16, 16, -32768, 32767, "", "", 4, "-0x5ffd", "0x3a", "0x1234", - "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", - usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } -} - -#[cfg(target_pointer_width = "32")] -#[lang = "isize"] -impl isize { - int_impl! { isize, i32, u32, 32, -2147483648, 2147483647, "", "", 8, "0x10000b3", "0xb301", - "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", - "[0x12, 0x34, 0x56, 0x78]", - usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } -} - -#[cfg(target_pointer_width = "64")] -#[lang = "isize"] -impl isize { - int_impl! { isize, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "", - 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", - "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", - "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", - usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } -} - -macro_rules! uint_impl { - ($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr, $Feature:expr, $EndFeature:expr, - $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr, - $reversed:expr, $le_bytes:expr, $be_bytes:expr, - $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => { - doc_comment! { - concat!("The smallest value that can be represented by this integer type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), "::MIN, 0);", $EndFeature, " -```"), - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MIN: Self = 0; - } - - doc_comment! { - concat!("The largest value that can be represented by this integer type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($MaxV), ");", -$EndFeature, " -```"), - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MAX: Self = !0; - } - - doc_comment! { - concat!("The size of this integer type in bits. - -# Examples - -``` -", $Feature, "#![feature(int_bits_const)] -assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");", -$EndFeature, " -```"), - #[unstable(feature = "int_bits_const", issue = "76904")] - pub const BITS: u32 = $BITS; - } - - doc_comment! { - concat!("Converts a string slice in a given base to an integer. - -The string is expected to be an optional `+` sign -followed by digits. -Leading and trailing whitespace represent an error. -Digits are a subset of these characters, depending on `radix`: - -* `0-9` -* `a-z` -* `A-Z` - -# Panics - -This function panics if `radix` is not in the range from 2 to 36. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - pub fn from_str_radix(src: &str, radix: u32) -> Result { - from_str_radix(src, radix) - } - } - - doc_comment! { - concat!("Returns the number of ones in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0b01001100", stringify!($SelfT), "; - -assert_eq!(n.count_ones(), 3);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn count_ones(self) -> u32 { - intrinsics::ctpop(self as $ActualT) as u32 - } - } - - doc_comment! { - concat!("Returns the number of zeros in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 0);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn count_zeros(self) -> u32 { - (!self).count_ones() - } - } - - doc_comment! { - concat!("Returns the number of leading zeros in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = ", stringify!($SelfT), "::MAX >> 2; - -assert_eq!(n.leading_zeros(), 2);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn leading_zeros(self) -> u32 { - intrinsics::ctlz(self as $ActualT) as u32 - } - } - - doc_comment! { - concat!("Returns the number of trailing zeros in the binary representation -of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0b0101000", stringify!($SelfT), "; - -assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn trailing_zeros(self) -> u32 { - intrinsics::cttz(self) as u32 - } - } - - doc_comment! { - concat!("Returns the number of leading ones in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = !(", stringify!($SelfT), "::MAX >> 2); - -assert_eq!(n.leading_ones(), 2);", $EndFeature, " -```"), - #[stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[inline] - pub const fn leading_ones(self) -> u32 { - (!self).leading_zeros() - } - } - - doc_comment! { - concat!("Returns the number of trailing ones in the binary representation -of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0b1010111", stringify!($SelfT), "; - -assert_eq!(n.trailing_ones(), 3);", $EndFeature, " -```"), - #[stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[inline] - pub const fn trailing_ones(self) -> u32 { - (!self).trailing_zeros() - } - } - - doc_comment! { - concat!("Shifts the bits to the left by a specified amount, `n`, -wrapping the truncated bits to the end of the resulting integer. - -Please note this isn't the same operation as the `<<` shifting operator! - -# Examples - -Basic usage: - -``` -let n = ", $rot_op, stringify!($SelfT), "; -let m = ", $rot_result, "; - -assert_eq!(n.rotate_left(", $rot, "), m); -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn rotate_left(self, n: u32) -> Self { - intrinsics::rotate_left(self, n as $SelfT) - } - } - - doc_comment! { - concat!("Shifts the bits to the right by a specified amount, `n`, -wrapping the truncated bits to the beginning of the resulting -integer. - -Please note this isn't the same operation as the `>>` shifting operator! - -# Examples - -Basic usage: - -``` -let n = ", $rot_result, stringify!($SelfT), "; -let m = ", $rot_op, "; - -assert_eq!(n.rotate_right(", $rot, "), m); -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn rotate_right(self, n: u32) -> Self { - intrinsics::rotate_right(self, n as $SelfT) - } - } - - doc_comment! { - concat!(" -Reverses the byte order of the integer. - -# Examples - -Basic usage: - -``` -let n = ", $swap_op, stringify!($SelfT), "; -let m = n.swap_bytes(); - -assert_eq!(m, ", $swapped, "); -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn swap_bytes(self) -> Self { - intrinsics::bswap(self as $ActualT) as Self - } - } - - doc_comment! { - concat!("Reverses the bit pattern of the integer. - -# Examples - -Basic usage: - -``` -let n = ", $swap_op, stringify!($SelfT), "; -let m = n.reverse_bits(); - -assert_eq!(m, ", $reversed, "); -```"), - #[stable(feature = "reverse_bits", since = "1.37.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - #[must_use] - pub const fn reverse_bits(self) -> Self { - intrinsics::bitreverse(self as $ActualT) as Self - } - } - - doc_comment! { - concat!("Converts an integer from big endian to the target's endianness. - -On big endian this is a no-op. On little endian the bytes are -swapped. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0x1A", stringify!($SelfT), "; - -if cfg!(target_endian = \"big\") { - assert_eq!(", stringify!($SelfT), "::from_be(n), n) -} else { - assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes()) -}", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn from_be(x: Self) -> Self { - #[cfg(target_endian = "big")] - { - x - } - #[cfg(not(target_endian = "big"))] - { - x.swap_bytes() - } - } - } - - doc_comment! { - concat!("Converts an integer from little endian to the target's endianness. - -On little endian this is a no-op. On big endian the bytes are -swapped. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0x1A", stringify!($SelfT), "; - -if cfg!(target_endian = \"little\") { - assert_eq!(", stringify!($SelfT), "::from_le(n), n) -} else { - assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes()) -}", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn from_le(x: Self) -> Self { - #[cfg(target_endian = "little")] - { - x - } - #[cfg(not(target_endian = "little"))] - { - x.swap_bytes() - } - } - } - - doc_comment! { - concat!("Converts `self` to big endian from the target's endianness. - -On big endian this is a no-op. On little endian the bytes are -swapped. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0x1A", stringify!($SelfT), "; - -if cfg!(target_endian = \"big\") { - assert_eq!(n.to_be(), n) -} else { - assert_eq!(n.to_be(), n.swap_bytes()) -}", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn to_be(self) -> Self { // or not to be? - #[cfg(target_endian = "big")] - { - self - } - #[cfg(not(target_endian = "big"))] - { - self.swap_bytes() - } - } - } - - doc_comment! { - concat!("Converts `self` to little endian from the target's endianness. - -On little endian this is a no-op. On big endian the bytes are -swapped. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0x1A", stringify!($SelfT), "; - -if cfg!(target_endian = \"little\") { - assert_eq!(n.to_le(), n) -} else { - assert_eq!(n.to_le(), n.swap_bytes()) -}", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn to_le(self) -> Self { - #[cfg(target_endian = "little")] - { - self - } - #[cfg(not(target_endian = "little"))] - { - self.swap_bytes() - } - } - } - - doc_comment! { - concat!("Checked integer addition. Computes `self + rhs`, returning `None` -if overflow occurred. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(1), ", -"Some(", stringify!($SelfT), "::MAX - 1)); -assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_add(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_add(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Unchecked integer addition. Computes `self + rhs`, assuming overflow -cannot occur. This results in undefined behavior when `self + rhs > ", stringify!($SelfT), -"::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`."), - #[unstable( - feature = "unchecked_math", - reason = "niche optimization path", - issue = "none", - )] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub unsafe fn unchecked_add(self, rhs: Self) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_add`. - unsafe { intrinsics::unchecked_add(self, rhs) } - } - } - - doc_comment! { - concat!("Checked integer subtraction. Computes `self - rhs`, returning -`None` if overflow occurred. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(1", stringify!($SelfT), ".checked_sub(1), Some(0)); -assert_eq!(0", stringify!($SelfT), ".checked_sub(1), None);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_sub(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_sub(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Unchecked integer subtraction. Computes `self - rhs`, assuming overflow -cannot occur. This results in undefined behavior when `self - rhs > ", stringify!($SelfT), -"::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`."), - #[unstable( - feature = "unchecked_math", - reason = "niche optimization path", - issue = "none", - )] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub unsafe fn unchecked_sub(self, rhs: Self) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_sub`. - unsafe { intrinsics::unchecked_sub(self, rhs) } - } - } - - doc_comment! { - concat!("Checked integer multiplication. Computes `self * rhs`, returning -`None` if overflow occurred. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(5", stringify!($SelfT), ".checked_mul(1), Some(5)); -assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_mul(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_mul(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Unchecked integer multiplication. Computes `self * rhs`, assuming overflow -cannot occur. This results in undefined behavior when `self * rhs > ", stringify!($SelfT), -"::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`."), - #[unstable( - feature = "unchecked_math", - reason = "niche optimization path", - issue = "none", - )] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub unsafe fn unchecked_mul(self, rhs: Self) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_mul`. - unsafe { intrinsics::unchecked_mul(self, rhs) } - } - } - - doc_comment! { - concat!("Checked integer division. Computes `self / rhs`, returning `None` -if `rhs == 0`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(128", stringify!($SelfT), ".checked_div(2), Some(64)); -assert_eq!(1", stringify!($SelfT), ".checked_div(0), None);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_div(self, rhs: Self) -> Option { - if unlikely!(rhs == 0) { - None - } else { - // SAFETY: div by zero has been checked above and unsigned types have no other - // failure modes for division - Some(unsafe { intrinsics::unchecked_div(self, rhs) }) - } - } - } - - doc_comment! { - concat!("Checked Euclidean division. Computes `self.div_euclid(rhs)`, returning `None` -if `rhs == 0`. - -# Examples - -Basic usage: - -``` -assert_eq!(128", stringify!($SelfT), ".checked_div_euclid(2), Some(64)); -assert_eq!(1", stringify!($SelfT), ".checked_div_euclid(0), None); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_div_euclid(self, rhs: Self) -> Option { - if unlikely!(rhs == 0) { - None - } else { - Some(self.div_euclid(rhs)) - } - } - } - - - doc_comment! { - concat!("Checked integer remainder. Computes `self % rhs`, returning `None` -if `rhs == 0`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1)); -assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);", $EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_rem(self, rhs: Self) -> Option { - if unlikely!(rhs == 0) { - None - } else { - // SAFETY: div by zero has been checked above and unsigned types have no other - // failure modes for division - Some(unsafe { intrinsics::unchecked_rem(self, rhs) }) - } - } - } - - doc_comment! { - concat!("Checked Euclidean modulo. Computes `self.rem_euclid(rhs)`, returning `None` -if `rhs == 0`. - -# Examples - -Basic usage: - -``` -assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1)); -assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_rem_euclid(self, rhs: Self) -> Option { - if unlikely!(rhs == 0) { - None - } else { - Some(self.rem_euclid(rhs)) - } - } - } - - doc_comment! { - concat!("Checked negation. Computes `-self`, returning `None` unless `self == -0`. - -Note that negating any positive integer will overflow. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(0", stringify!($SelfT), ".checked_neg(), Some(0)); -assert_eq!(1", stringify!($SelfT), ".checked_neg(), None);", $EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[inline] - pub const fn checked_neg(self) -> Option { - let (a, b) = self.overflowing_neg(); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Checked shift left. Computes `self << rhs`, returning `None` -if `rhs` is larger than or equal to the number of bits in `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10)); -assert_eq!(0x10", stringify!($SelfT), ".checked_shl(129), None);", $EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_shl(self, rhs: u32) -> Option { - let (a, b) = self.overflowing_shl(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Checked shift right. Computes `self >> rhs`, returning `None` -if `rhs` is larger than or equal to the number of bits in `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1)); -assert_eq!(0x10", stringify!($SelfT), ".checked_shr(129), None);", $EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_shr(self, rhs: u32) -> Option { - let (a, b) = self.overflowing_shr(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Checked exponentiation. Computes `self.pow(exp)`, returning `None` if -overflow occurred. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(2", stringify!($SelfT), ".checked_pow(5), Some(32)); -assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);", $EndFeature, " -```"), - #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_pow(self, mut exp: u32) -> Option { - if exp == 0 { - return Some(1); - } - let mut base = self; - let mut acc: Self = 1; - - while exp > 1 { - if (exp & 1) == 1 { - acc = try_opt!(acc.checked_mul(base)); - } - exp /= 2; - base = try_opt!(base.checked_mul(base)); - } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - - Some(try_opt!(acc.checked_mul(base))) - } - } - - doc_comment! { - concat!("Saturating integer addition. Computes `self + rhs`, saturating at -the numeric bounds instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101); -assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(127), ", stringify!($SelfT), "::MAX);", -$EndFeature, " -```"), - - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] - #[inline] - pub const fn saturating_add(self, rhs: Self) -> Self { - intrinsics::saturating_add(self, rhs) - } - } - - doc_comment! { - concat!("Saturating integer subtraction. Computes `self - rhs`, saturating -at the numeric bounds instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(27), 73); -assert_eq!(13", stringify!($SelfT), ".saturating_sub(127), 0);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] - #[inline] - pub const fn saturating_sub(self, rhs: Self) -> Self { - intrinsics::saturating_sub(self, rhs) - } - } - - doc_comment! { - concat!("Saturating integer multiplication. Computes `self * rhs`, -saturating at the numeric bounds instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!(2", stringify!($SelfT), ".saturating_mul(10), 20); -assert_eq!((", stringify!($SelfT), "::MAX).saturating_mul(10), ", stringify!($SelfT), -"::MAX);", $EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn saturating_mul(self, rhs: Self) -> Self { - match self.checked_mul(rhs) { - Some(x) => x, - None => Self::MAX, - } - } - } - - doc_comment! { - concat!("Saturating integer exponentiation. Computes `self.pow(exp)`, -saturating at the numeric bounds instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!(4", stringify!($SelfT), ".saturating_pow(3), 64); -assert_eq!(", stringify!($SelfT), "::MAX.saturating_pow(2), ", stringify!($SelfT), "::MAX);", -$EndFeature, " -```"), - #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn saturating_pow(self, exp: u32) -> Self { - match self.checked_pow(exp) { - Some(x) => x, - None => Self::MAX, - } - } - } - - doc_comment! { - concat!("Wrapping (modular) addition. Computes `self + rhs`, -wrapping around at the boundary of the type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(200", stringify!($SelfT), ".wrapping_add(55), 255); -assert_eq!(200", stringify!($SelfT), ".wrapping_add(", stringify!($SelfT), "::MAX), 199);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_add(self, rhs: Self) -> Self { - intrinsics::wrapping_add(self, rhs) - } - } - - doc_comment! { - concat!("Wrapping (modular) subtraction. Computes `self - rhs`, -wrapping around at the boundary of the type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_sub(100), 0); -assert_eq!(100", stringify!($SelfT), ".wrapping_sub(", stringify!($SelfT), "::MAX), 101);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_sub(self, rhs: Self) -> Self { - intrinsics::wrapping_sub(self, rhs) - } - } - - /// Wrapping (modular) multiplication. Computes `self * - /// rhs`, wrapping around at the boundary of the type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// Please note that this example is shared between integer types. - /// Which explains why `u8` is used here. - /// - /// ``` - /// assert_eq!(10u8.wrapping_mul(12), 120); - /// assert_eq!(25u8.wrapping_mul(12), 44); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_mul(self, rhs: Self) -> Self { - intrinsics::wrapping_mul(self, rhs) - } - - doc_comment! { - concat!("Wrapping (modular) division. Computes `self / rhs`. -Wrapped division on unsigned types is just normal division. -There's no way wrapping could ever happen. -This function exists, so that all operations -are accounted for in the wrapping operations. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10);", $EndFeature, " -```"), - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_div(self, rhs: Self) -> Self { - self / rhs - } - } - - doc_comment! { - concat!("Wrapping Euclidean division. Computes `self.div_euclid(rhs)`. -Wrapped division on unsigned types is just normal division. -There's no way wrapping could ever happen. -This function exists, so that all operations -are accounted for in the wrapping operations. -Since, for the positive integers, all common -definitions of division are equal, this -is exactly equal to `self.wrapping_div(rhs)`. - -# Examples - -Basic usage: - -``` -assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_div_euclid(self, rhs: Self) -> Self { - self / rhs - } - } - - doc_comment! { - concat!("Wrapping (modular) remainder. Computes `self % rhs`. -Wrapped remainder calculation on unsigned types is -just the regular remainder calculation. -There's no way wrapping could ever happen. -This function exists, so that all operations -are accounted for in the wrapping operations. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0);", $EndFeature, " -```"), - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_rem(self, rhs: Self) -> Self { - self % rhs - } - } - - doc_comment! { - concat!("Wrapping Euclidean modulo. Computes `self.rem_euclid(rhs)`. -Wrapped modulo calculation on unsigned types is -just the regular remainder calculation. -There's no way wrapping could ever happen. -This function exists, so that all operations -are accounted for in the wrapping operations. -Since, for the positive integers, all common -definitions of division are equal, this -is exactly equal to `self.wrapping_rem(rhs)`. - -# Examples - -Basic usage: - -``` -assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self { - self % rhs - } - } - - /// Wrapping (modular) negation. Computes `-self`, - /// wrapping around at the boundary of the type. - /// - /// Since unsigned types do not have negative equivalents - /// all applications of this function will wrap (except for `-0`). - /// For values smaller than the corresponding signed type's maximum - /// the result is the same as casting the corresponding signed value. - /// Any larger values are equivalent to `MAX + 1 - (val - MAX - 1)` where - /// `MAX` is the corresponding signed type's maximum. - /// - /// # Examples - /// - /// Basic usage: - /// - /// Please note that this example is shared between integer types. - /// Which explains why `i8` is used here. - /// - /// ``` - /// assert_eq!(100i8.wrapping_neg(), -100); - /// assert_eq!((-128i8).wrapping_neg(), -128); - /// ``` - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - #[inline] - pub const fn wrapping_neg(self) -> Self { - self.overflowing_neg().0 - } - - doc_comment! { - concat!("Panic-free bitwise shift-left; yields `self << mask(rhs)`, -where `mask` removes any high-order bits of `rhs` that -would cause the shift to exceed the bitwidth of the type. - -Note that this is *not* the same as a rotate-left; the -RHS of a wrapping shift-left is restricted to the range -of the type, rather than the bits shifted out of the LHS -being returned to the other end. The primitive integer -types all implement a [`rotate_left`](#method.rotate_left) function, -which may be what you want instead. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(1", stringify!($SelfT), ".wrapping_shl(7), 128); -assert_eq!(1", stringify!($SelfT), ".wrapping_shl(128), 1);", $EndFeature, " -```"), - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_shl(self, rhs: u32) -> Self { - // SAFETY: the masking by the bitsize of the type ensures that we do not shift - // out of bounds - unsafe { - intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT) - } - } - } - - doc_comment! { - concat!("Panic-free bitwise shift-right; yields `self >> mask(rhs)`, -where `mask` removes any high-order bits of `rhs` that -would cause the shift to exceed the bitwidth of the type. - -Note that this is *not* the same as a rotate-right; the -RHS of a wrapping shift-right is restricted to the range -of the type, rather than the bits shifted out of the LHS -being returned to the other end. The primitive integer -types all implement a [`rotate_right`](#method.rotate_right) function, -which may be what you want instead. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(128", stringify!($SelfT), ".wrapping_shr(7), 1); -assert_eq!(128", stringify!($SelfT), ".wrapping_shr(128), 128);", $EndFeature, " -```"), - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_shr(self, rhs: u32) -> Self { - // SAFETY: the masking by the bitsize of the type ensures that we do not shift - // out of bounds - unsafe { - intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT) - } - } - } - - doc_comment! { - concat!("Wrapping (modular) exponentiation. Computes `self.pow(exp)`, -wrapping around at the boundary of the type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(5), 243); -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")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_pow(self, mut exp: u32) -> Self { - if exp == 0 { - return 1; - } - let mut base = self; - let mut acc: Self = 1; - - while exp > 1 { - if (exp & 1) == 1 { - acc = acc.wrapping_mul(base); - } - exp /= 2; - base = base.wrapping_mul(base); - } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - acc.wrapping_mul(base) - } - } - - doc_comment! { - concat!("Calculates `self` + `rhs` - -Returns a tuple of the addition along with a boolean indicating -whether an arithmetic overflow would occur. If an overflow would -have occurred then the wrapped value is returned. - -# Examples - -Basic usage - -``` -", $Feature, " -assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false)); -assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (0, true));", $EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) { - let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT); - (a as Self, b) - } - } - - doc_comment! { - concat!("Calculates `self` - `rhs` - -Returns a tuple of the subtraction along with a boolean indicating -whether an arithmetic overflow would occur. If an overflow would -have occurred then the wrapped value is returned. - -# Examples - -Basic usage - -``` -", $Feature, " -assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false)); -assert_eq!(0", stringify!($SelfT), ".overflowing_sub(1), (", stringify!($SelfT), "::MAX, true));", -$EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { - let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT); - (a as Self, b) - } - } - - /// Calculates the multiplication of `self` and `rhs`. - /// - /// Returns a tuple of the multiplication along with a boolean - /// indicating whether an arithmetic overflow would occur. If an - /// overflow would have occurred then the wrapped value is returned. - /// - /// # Examples - /// - /// Basic usage: - /// - /// Please note that this example is shared between integer types. - /// Which explains why `u32` is used here. - /// - /// ``` - /// assert_eq!(5u32.overflowing_mul(2), (10, false)); - /// assert_eq!(1_000_000_000u32.overflowing_mul(10), (1410065408, true)); - /// ``` - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) { - let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT); - (a as Self, b) - } - - doc_comment! { - concat!("Calculates the divisor when `self` is divided by `rhs`. - -Returns a tuple of the divisor along with a boolean indicating -whether an arithmetic overflow would occur. Note that for unsigned -integers overflow never occurs, so the second value is always -`false`. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage - -``` -", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false));", $EndFeature, " -```"), - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) { - (self / rhs, false) - } - } - - doc_comment! { - concat!("Calculates the quotient of Euclidean division `self.div_euclid(rhs)`. - -Returns a tuple of the divisor along with a boolean indicating -whether an arithmetic overflow would occur. Note that for unsigned -integers overflow never occurs, so the second value is always -`false`. -Since, for the positive integers, all common -definitions of division are equal, this -is exactly equal to `self.overflowing_div(rhs)`. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage - -``` -assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false)); -```"), - #[inline] - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { - (self / rhs, false) - } - } - - doc_comment! { - concat!("Calculates the remainder when `self` is divided by `rhs`. - -Returns a tuple of the remainder after dividing along with a boolean -indicating whether an arithmetic overflow would occur. Note that for -unsigned integers overflow never occurs, so the second value is -always `false`. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage - -``` -", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false));", $EndFeature, " -```"), - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) { - (self % rhs, false) - } - } - - doc_comment! { - concat!("Calculates the remainder `self.rem_euclid(rhs)` as if by Euclidean division. - -Returns a tuple of the modulo after dividing along with a boolean -indicating whether an arithmetic overflow would occur. Note that for -unsigned integers overflow never occurs, so the second value is -always `false`. -Since, for the positive integers, all common -definitions of division are equal, this operation -is exactly equal to `self.overflowing_rem(rhs)`. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage - -``` -assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false)); -```"), - #[inline] - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { - (self % rhs, false) - } - } - - doc_comment! { - concat!("Negates self in an overflowing fashion. - -Returns `!self + 1` using wrapping operations to return the value -that represents the negation of this unsigned value. Note that for -positive unsigned values overflow always occurs, but negating 0 does -not overflow. - -# Examples - -Basic usage - -``` -", $Feature, "assert_eq!(0", stringify!($SelfT), ".overflowing_neg(), (0, false)); -assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2i32 as ", stringify!($SelfT), -", true));", $EndFeature, " -```"), - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - pub const fn overflowing_neg(self) -> (Self, bool) { - ((!self).wrapping_add(1), self != 0) - } - } - - doc_comment! { - concat!("Shifts self left by `rhs` bits. - -Returns a tuple of the shifted version of self along with a boolean -indicating whether the shift value was larger than or equal to the -number of bits. If the shift value is too large, then value is -masked (N-1) where N is the number of bits, and this value is then -used to perform the shift. - -# Examples - -Basic usage - -``` -", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(4), (0x10, false)); -assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(132), (0x10, true));", $EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) { - (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) - } - } - - doc_comment! { - concat!("Shifts self right by `rhs` bits. - -Returns a tuple of the shifted version of self along with a boolean -indicating whether the shift value was larger than or equal to the -number of bits. If the shift value is too large, then value is -masked (N-1) where N is the number of bits, and this value is then -used to perform the shift. - -# Examples - -Basic usage - -``` -", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false)); -assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(132), (0x1, true));", $EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) { - (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) - } - } - - doc_comment! { - concat!("Raises self to the power of `exp`, using exponentiation by squaring. - -Returns a tuple of the exponentiation along with a bool indicating -whether an overflow happened. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(5), (243, false)); -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")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) { - if exp == 0{ - return (1,false); - } - let mut base = self; - let mut acc: Self = 1; - let mut overflown = false; - // Scratch space for storing results of overflowing_mul. - let mut r; - - while exp > 1 { - if (exp & 1) == 1 { - r = acc.overflowing_mul(base); - acc = r.0; - overflown |= r.1; - } - exp /= 2; - r = base.overflowing_mul(base); - base = r.0; - overflown |= r.1; - } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - r = acc.overflowing_mul(base); - r.1 |= overflown; - - r - } - } - - doc_comment! { - concat!("Raises self to the power of `exp`, using exponentiation by squaring. - -# Examples - -Basic usage: - -``` -", $Feature, "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")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - #[rustc_inherit_overflow_checks] - pub const fn pow(self, mut exp: u32) -> Self { - if exp == 0 { - return 1; - } - let mut base = self; - let mut acc = 1; - - while exp > 1 { - if (exp & 1) == 1 { - acc = acc * base; - } - exp /= 2; - base = base * base; - } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - acc * base - } - } - - doc_comment! { - concat!("Performs Euclidean division. - -Since, for the positive integers, all common -definitions of division are equal, this -is exactly equal to `self / rhs`. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -assert_eq!(7", stringify!($SelfT), ".div_euclid(4), 1); // or any other integer type -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - #[rustc_inherit_overflow_checks] - pub const fn div_euclid(self, rhs: Self) -> Self { - self / rhs - } - } - - - doc_comment! { - concat!("Calculates the least remainder of `self (mod rhs)`. - -Since, for the positive integers, all common -definitions of division are equal, this -is exactly equal to `self % rhs`. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -assert_eq!(7", stringify!($SelfT), ".rem_euclid(4), 3); // or any other integer type -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - #[rustc_inherit_overflow_checks] - pub const fn rem_euclid(self, rhs: Self) -> Self { - self % rhs - } - } - - doc_comment! { - concat!("Returns `true` if and only if `self == 2^k` for some `k`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert!(16", stringify!($SelfT), ".is_power_of_two()); -assert!(!10", stringify!($SelfT), ".is_power_of_two());", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_is_power_of_two", since = "1.32.0")] - #[inline] - pub const fn is_power_of_two(self) -> bool { - self.count_ones() == 1 - } - } - - // Returns one less than next power of two. - // (For 8u8 next power of two is 8u8 and for 6u8 it is 8u8) - // - // 8u8.one_less_than_next_power_of_two() == 7 - // 6u8.one_less_than_next_power_of_two() == 7 - // - // This method cannot overflow, as in the `next_power_of_two` - // 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")] - const fn one_less_than_next_power_of_two(self) -> Self { - if self <= 1 { return 0; } - - let p = self - 1; - // SAFETY: Because `p > 0`, it cannot consist entirely of leading zeros. - // That means the shift is always in-bounds, and some processors - // (such as intel pre-haswell) have more efficient ctlz - // intrinsics when the argument is non-zero. - let z = unsafe { intrinsics::ctlz_nonzero(p) }; - <$SelfT>::MAX >> z - } - - doc_comment! { - concat!("Returns the smallest power of two greater than or equal to `self`. - -When return value overflows (i.e., `self > (1 << (N-1))` for type -`uN`), it panics in debug mode and return value is wrapped to 0 in -release mode (the only situation in which method can return 0). - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(2", stringify!($SelfT), ".next_power_of_two(), 2); -assert_eq!(3", stringify!($SelfT), ".next_power_of_two(), 4);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[inline] - #[rustc_inherit_overflow_checks] - pub const fn next_power_of_two(self) -> Self { - self.one_less_than_next_power_of_two() + 1 - } - } - - doc_comment! { - concat!("Returns the smallest power of two greater than or equal to `n`. If -the next power of two is greater than the type's maximum value, -`None` is returned, otherwise the power of two is wrapped in `Some`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(2", stringify!($SelfT), -".checked_next_power_of_two(), Some(2)); -assert_eq!(3", stringify!($SelfT), ".checked_next_power_of_two(), Some(4)); -assert_eq!(", stringify!($SelfT), "::MAX.checked_next_power_of_two(), None);", -$EndFeature, " -```"), - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - pub const fn checked_next_power_of_two(self) -> Option { - self.one_less_than_next_power_of_two().checked_add(1) - } - } - - doc_comment! { - concat!("Returns the smallest power of two greater than or equal to `n`. If -the next power of two is greater than the type's maximum value, -the return value is wrapped to `0`. - -# Examples - -Basic usage: - -``` -#![feature(wrapping_next_power_of_two)] -", $Feature, " -assert_eq!(2", stringify!($SelfT), ".wrapping_next_power_of_two(), 2); -assert_eq!(3", stringify!($SelfT), ".wrapping_next_power_of_two(), 4); -assert_eq!(", stringify!($SelfT), "::MAX.wrapping_next_power_of_two(), 0);", -$EndFeature, " -```"), - #[unstable(feature = "wrapping_next_power_of_two", issue = "32463", - reason = "needs decision on wrapping behaviour")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - pub const fn wrapping_next_power_of_two(self) -> Self { - self.one_less_than_next_power_of_two().wrapping_add(1) - } - } - - doc_comment! { - concat!("Return the memory representation of this integer as a byte array in -big-endian (network) byte order. -", -$to_xe_bytes_doc, -" -# Examples - -``` -let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes(); -assert_eq!(bytes, ", $be_bytes, "); -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[inline] - pub const fn to_be_bytes(self) -> [u8; mem::size_of::()] { - self.to_be().to_ne_bytes() - } - } - - doc_comment! { - concat!("Return the memory representation of this integer as a byte array in -little-endian byte order. -", -$to_xe_bytes_doc, -" -# Examples - -``` -let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes(); -assert_eq!(bytes, ", $le_bytes, "); -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[inline] - pub const fn to_le_bytes(self) -> [u8; mem::size_of::()] { - self.to_le().to_ne_bytes() - } - } - - doc_comment! { - concat!(" -Return the memory representation of this integer as a byte array in -native byte order. - -As the target platform's native endianness is used, portable code -should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, -instead. -", -$to_xe_bytes_doc, -" -[`to_be_bytes`]: #method.to_be_bytes -[`to_le_bytes`]: #method.to_le_bytes - -# Examples - -``` -let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes(); -assert_eq!( - bytes, - if cfg!(target_endian = \"big\") { - ", $be_bytes, " - } else { - ", $le_bytes, " - } -); -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - // SAFETY: const sound because integers are plain old datatypes so we can always - // transmute them to arrays of bytes - #[allow_internal_unstable(const_fn_transmute)] - #[inline] - pub const fn to_ne_bytes(self) -> [u8; mem::size_of::()] { - // SAFETY: integers are plain old datatypes so we can always transmute them to - // arrays of bytes - unsafe { mem::transmute(self) } - } - } - - doc_comment! { - concat!("Create a native endian integer value from its representation -as a byte array in big endian. -", -$from_xe_bytes_doc, -" -# Examples - -``` -let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, "); -assert_eq!(value, ", $swap_op, "); -``` - -When starting from a slice rather than an array, fallible conversion APIs can be used: - -``` -use std::convert::TryInto; - -fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { - let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); - *input = rest; - ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap()) -} -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[inline] - pub const fn from_be_bytes(bytes: [u8; mem::size_of::()]) -> Self { - Self::from_be(Self::from_ne_bytes(bytes)) - } - } - - doc_comment! { - concat!(" -Create a native endian integer value from its representation -as a byte array in little endian. -", -$from_xe_bytes_doc, -" -# Examples - -``` -let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, "); -assert_eq!(value, ", $swap_op, "); -``` - -When starting from a slice rather than an array, fallible conversion APIs can be used: - -``` -use std::convert::TryInto; - -fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { - let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); - *input = rest; - ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap()) -} -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[inline] - pub const fn from_le_bytes(bytes: [u8; mem::size_of::()]) -> Self { - Self::from_le(Self::from_ne_bytes(bytes)) - } - } - - doc_comment! { - concat!("Create a native endian integer value from its memory representation -as a byte array in native endianness. - -As the target platform's native endianness is used, portable code -likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as -appropriate instead. - -[`from_be_bytes`]: #method.from_be_bytes -[`from_le_bytes`]: #method.from_le_bytes -", -$from_xe_bytes_doc, -" -# Examples - -``` -let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") { - ", $be_bytes, " -} else { - ", $le_bytes, " -}); -assert_eq!(value, ", $swap_op, "); -``` - -When starting from a slice rather than an array, fallible conversion APIs can be used: - -``` -use std::convert::TryInto; - -fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { - let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); - *input = rest; - ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap()) -} -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - // SAFETY: const sound because integers are plain old datatypes so we can always - // transmute to them - #[allow_internal_unstable(const_fn_transmute)] - #[inline] - pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { - // SAFETY: integers are plain old datatypes so we can always transmute to them - unsafe { mem::transmute(bytes) } - } - } - - doc_comment! { - concat!("**This method is soft-deprecated.** - -Although using it won’t cause compilation warning, -new code should use [`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN) instead. - -Returns the smallest value that can be represented by this integer type."), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_promotable] - #[inline(always)] - #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")] - pub const fn min_value() -> Self { Self::MIN } - } - - doc_comment! { - concat!("**This method is soft-deprecated.** - -Although using it won’t cause compilation warning, -new code should use [`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX) instead. - -Returns the largest value that can be represented by this integer type."), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_promotable] - #[inline(always)] - #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")] - pub const fn max_value() -> Self { Self::MAX } - } - } +#[cfg(target_pointer_width = "64")] +#[lang = "isize"] +impl isize { + int_impl! { isize, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "", + 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", + "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", + "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", + usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } #[lang = "u8"] diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs new file mode 100644 index 0000000000000..234c309961c9c --- /dev/null +++ b/library/core/src/num/uint_macros.rs @@ -0,0 +1,1955 @@ +macro_rules! uint_impl { + ($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr, $Feature:expr, $EndFeature:expr, + $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr, + $reversed:expr, $le_bytes:expr, $be_bytes:expr, + $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => { + doc_comment! { + concat!("The smallest value that can be represented by this integer type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(", stringify!($SelfT), "::MIN, 0);", $EndFeature, " +```"), + #[stable(feature = "assoc_int_consts", since = "1.43.0")] + pub const MIN: Self = 0; + } + + doc_comment! { + concat!("The largest value that can be represented by this integer type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($MaxV), ");", +$EndFeature, " +```"), + #[stable(feature = "assoc_int_consts", since = "1.43.0")] + pub const MAX: Self = !0; + } + + doc_comment! { + concat!("The size of this integer type in bits. + +# Examples + +``` +", $Feature, "#![feature(int_bits_const)] +assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");", +$EndFeature, " +```"), + #[unstable(feature = "int_bits_const", issue = "76904")] + pub const BITS: u32 = $BITS; + } + + doc_comment! { + concat!("Converts a string slice in a given base to an integer. + +The string is expected to be an optional `+` sign +followed by digits. +Leading and trailing whitespace represent an error. +Digits are a subset of these characters, depending on `radix`: + +* `0-9` +* `a-z` +* `A-Z` + +# Panics + +This function panics if `radix` is not in the range from 2 to 36. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + pub fn from_str_radix(src: &str, radix: u32) -> Result { + from_str_radix(src, radix) + } + } + + doc_comment! { + concat!("Returns the number of ones in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0b01001100", stringify!($SelfT), "; + +assert_eq!(n.count_ones(), 3);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn count_ones(self) -> u32 { + intrinsics::ctpop(self as $ActualT) as u32 + } + } + + doc_comment! { + concat!("Returns the number of zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 0);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn count_zeros(self) -> u32 { + (!self).count_ones() + } + } + + doc_comment! { + concat!("Returns the number of leading zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = ", stringify!($SelfT), "::MAX >> 2; + +assert_eq!(n.leading_zeros(), 2);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn leading_zeros(self) -> u32 { + intrinsics::ctlz(self as $ActualT) as u32 + } + } + + doc_comment! { + concat!("Returns the number of trailing zeros in the binary representation +of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0b0101000", stringify!($SelfT), "; + +assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn trailing_zeros(self) -> u32 { + intrinsics::cttz(self) as u32 + } + } + + doc_comment! { + concat!("Returns the number of leading ones in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = !(", stringify!($SelfT), "::MAX >> 2); + +assert_eq!(n.leading_ones(), 2);", $EndFeature, " +```"), + #[stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[inline] + pub const fn leading_ones(self) -> u32 { + (!self).leading_zeros() + } + } + + doc_comment! { + concat!("Returns the number of trailing ones in the binary representation +of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0b1010111", stringify!($SelfT), "; + +assert_eq!(n.trailing_ones(), 3);", $EndFeature, " +```"), + #[stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[inline] + pub const fn trailing_ones(self) -> u32 { + (!self).trailing_zeros() + } + } + + doc_comment! { + concat!("Shifts the bits to the left by a specified amount, `n`, +wrapping the truncated bits to the end of the resulting integer. + +Please note this isn't the same operation as the `<<` shifting operator! + +# Examples + +Basic usage: + +``` +let n = ", $rot_op, stringify!($SelfT), "; +let m = ", $rot_result, "; + +assert_eq!(n.rotate_left(", $rot, "), m); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn rotate_left(self, n: u32) -> Self { + intrinsics::rotate_left(self, n as $SelfT) + } + } + + doc_comment! { + concat!("Shifts the bits to the right by a specified amount, `n`, +wrapping the truncated bits to the beginning of the resulting +integer. + +Please note this isn't the same operation as the `>>` shifting operator! + +# Examples + +Basic usage: + +``` +let n = ", $rot_result, stringify!($SelfT), "; +let m = ", $rot_op, "; + +assert_eq!(n.rotate_right(", $rot, "), m); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn rotate_right(self, n: u32) -> Self { + intrinsics::rotate_right(self, n as $SelfT) + } + } + + doc_comment! { + concat!(" +Reverses the byte order of the integer. + +# Examples + +Basic usage: + +``` +let n = ", $swap_op, stringify!($SelfT), "; +let m = n.swap_bytes(); + +assert_eq!(m, ", $swapped, "); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn swap_bytes(self) -> Self { + intrinsics::bswap(self as $ActualT) as Self + } + } + + doc_comment! { + concat!("Reverses the bit pattern of the integer. + +# Examples + +Basic usage: + +``` +let n = ", $swap_op, stringify!($SelfT), "; +let m = n.reverse_bits(); + +assert_eq!(m, ", $reversed, "); +```"), + #[stable(feature = "reverse_bits", since = "1.37.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + #[must_use] + pub const fn reverse_bits(self) -> Self { + intrinsics::bitreverse(self as $ActualT) as Self + } + } + + doc_comment! { + concat!("Converts an integer from big endian to the target's endianness. + +On big endian this is a no-op. On little endian the bytes are +swapped. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0x1A", stringify!($SelfT), "; + +if cfg!(target_endian = \"big\") { + assert_eq!(", stringify!($SelfT), "::from_be(n), n) +} else { + assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes()) +}", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn from_be(x: Self) -> Self { + #[cfg(target_endian = "big")] + { + x + } + #[cfg(not(target_endian = "big"))] + { + x.swap_bytes() + } + } + } + + doc_comment! { + concat!("Converts an integer from little endian to the target's endianness. + +On little endian this is a no-op. On big endian the bytes are +swapped. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0x1A", stringify!($SelfT), "; + +if cfg!(target_endian = \"little\") { + assert_eq!(", stringify!($SelfT), "::from_le(n), n) +} else { + assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes()) +}", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn from_le(x: Self) -> Self { + #[cfg(target_endian = "little")] + { + x + } + #[cfg(not(target_endian = "little"))] + { + x.swap_bytes() + } + } + } + + doc_comment! { + concat!("Converts `self` to big endian from the target's endianness. + +On big endian this is a no-op. On little endian the bytes are +swapped. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0x1A", stringify!($SelfT), "; + +if cfg!(target_endian = \"big\") { + assert_eq!(n.to_be(), n) +} else { + assert_eq!(n.to_be(), n.swap_bytes()) +}", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn to_be(self) -> Self { // or not to be? + #[cfg(target_endian = "big")] + { + self + } + #[cfg(not(target_endian = "big"))] + { + self.swap_bytes() + } + } + } + + doc_comment! { + concat!("Converts `self` to little endian from the target's endianness. + +On little endian this is a no-op. On big endian the bytes are +swapped. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0x1A", stringify!($SelfT), "; + +if cfg!(target_endian = \"little\") { + assert_eq!(n.to_le(), n) +} else { + assert_eq!(n.to_le(), n.swap_bytes()) +}", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn to_le(self) -> Self { + #[cfg(target_endian = "little")] + { + self + } + #[cfg(not(target_endian = "little"))] + { + self.swap_bytes() + } + } + } + + doc_comment! { + concat!("Checked integer addition. Computes `self + rhs`, returning `None` +if overflow occurred. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(1), ", +"Some(", stringify!($SelfT), "::MAX - 1)); +assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_add(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_add(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Unchecked integer addition. Computes `self + rhs`, assuming overflow +cannot occur. This results in undefined behavior when `self + rhs > ", stringify!($SelfT), +"::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`."), + #[unstable( + feature = "unchecked_math", + reason = "niche optimization path", + issue = "none", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub unsafe fn unchecked_add(self, rhs: Self) -> Self { + // SAFETY: the caller must uphold the safety contract for + // `unchecked_add`. + unsafe { intrinsics::unchecked_add(self, rhs) } + } + } + + doc_comment! { + concat!("Checked integer subtraction. Computes `self - rhs`, returning +`None` if overflow occurred. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(1", stringify!($SelfT), ".checked_sub(1), Some(0)); +assert_eq!(0", stringify!($SelfT), ".checked_sub(1), None);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_sub(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_sub(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Unchecked integer subtraction. Computes `self - rhs`, assuming overflow +cannot occur. This results in undefined behavior when `self - rhs > ", stringify!($SelfT), +"::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`."), + #[unstable( + feature = "unchecked_math", + reason = "niche optimization path", + issue = "none", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub unsafe fn unchecked_sub(self, rhs: Self) -> Self { + // SAFETY: the caller must uphold the safety contract for + // `unchecked_sub`. + unsafe { intrinsics::unchecked_sub(self, rhs) } + } + } + + doc_comment! { + concat!("Checked integer multiplication. Computes `self * rhs`, returning +`None` if overflow occurred. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(5", stringify!($SelfT), ".checked_mul(1), Some(5)); +assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_mul(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_mul(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Unchecked integer multiplication. Computes `self * rhs`, assuming overflow +cannot occur. This results in undefined behavior when `self * rhs > ", stringify!($SelfT), +"::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`."), + #[unstable( + feature = "unchecked_math", + reason = "niche optimization path", + issue = "none", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub unsafe fn unchecked_mul(self, rhs: Self) -> Self { + // SAFETY: the caller must uphold the safety contract for + // `unchecked_mul`. + unsafe { intrinsics::unchecked_mul(self, rhs) } + } + } + + doc_comment! { + concat!("Checked integer division. Computes `self / rhs`, returning `None` +if `rhs == 0`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(128", stringify!($SelfT), ".checked_div(2), Some(64)); +assert_eq!(1", stringify!($SelfT), ".checked_div(0), None);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_div(self, rhs: Self) -> Option { + if unlikely!(rhs == 0) { + None + } else { + // SAFETY: div by zero has been checked above and unsigned types have no other + // failure modes for division + Some(unsafe { intrinsics::unchecked_div(self, rhs) }) + } + } + } + + doc_comment! { + concat!("Checked Euclidean division. Computes `self.div_euclid(rhs)`, returning `None` +if `rhs == 0`. + +# Examples + +Basic usage: + +``` +assert_eq!(128", stringify!($SelfT), ".checked_div_euclid(2), Some(64)); +assert_eq!(1", stringify!($SelfT), ".checked_div_euclid(0), None); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_div_euclid(self, rhs: Self) -> Option { + if unlikely!(rhs == 0) { + None + } else { + Some(self.div_euclid(rhs)) + } + } + } + + + doc_comment! { + concat!("Checked integer remainder. Computes `self % rhs`, returning `None` +if `rhs == 0`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1)); +assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);", $EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_rem(self, rhs: Self) -> Option { + if unlikely!(rhs == 0) { + None + } else { + // SAFETY: div by zero has been checked above and unsigned types have no other + // failure modes for division + Some(unsafe { intrinsics::unchecked_rem(self, rhs) }) + } + } + } + + doc_comment! { + concat!("Checked Euclidean modulo. Computes `self.rem_euclid(rhs)`, returning `None` +if `rhs == 0`. + +# Examples + +Basic usage: + +``` +assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1)); +assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_rem_euclid(self, rhs: Self) -> Option { + if unlikely!(rhs == 0) { + None + } else { + Some(self.rem_euclid(rhs)) + } + } + } + + doc_comment! { + concat!("Checked negation. Computes `-self`, returning `None` unless `self == +0`. + +Note that negating any positive integer will overflow. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(0", stringify!($SelfT), ".checked_neg(), Some(0)); +assert_eq!(1", stringify!($SelfT), ".checked_neg(), None);", $EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[inline] + pub const fn checked_neg(self) -> Option { + let (a, b) = self.overflowing_neg(); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Checked shift left. Computes `self << rhs`, returning `None` +if `rhs` is larger than or equal to the number of bits in `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10)); +assert_eq!(0x10", stringify!($SelfT), ".checked_shl(129), None);", $EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_shl(self, rhs: u32) -> Option { + let (a, b) = self.overflowing_shl(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Checked shift right. Computes `self >> rhs`, returning `None` +if `rhs` is larger than or equal to the number of bits in `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1)); +assert_eq!(0x10", stringify!($SelfT), ".checked_shr(129), None);", $EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_shr(self, rhs: u32) -> Option { + let (a, b) = self.overflowing_shr(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Checked exponentiation. Computes `self.pow(exp)`, returning `None` if +overflow occurred. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(2", stringify!($SelfT), ".checked_pow(5), Some(32)); +assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);", $EndFeature, " +```"), + #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_pow(self, mut exp: u32) -> Option { + if exp == 0 { + return Some(1); + } + let mut base = self; + let mut acc: Self = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = try_opt!(acc.checked_mul(base)); + } + exp /= 2; + base = try_opt!(base.checked_mul(base)); + } + + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + + Some(try_opt!(acc.checked_mul(base))) + } + } + + doc_comment! { + concat!("Saturating integer addition. Computes `self + rhs`, saturating at +the numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101); +assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(127), ", stringify!($SelfT), "::MAX);", +$EndFeature, " +```"), + + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] + #[inline] + pub const fn saturating_add(self, rhs: Self) -> Self { + intrinsics::saturating_add(self, rhs) + } + } + + doc_comment! { + concat!("Saturating integer subtraction. Computes `self - rhs`, saturating +at the numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(27), 73); +assert_eq!(13", stringify!($SelfT), ".saturating_sub(127), 0);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] + #[inline] + pub const fn saturating_sub(self, rhs: Self) -> Self { + intrinsics::saturating_sub(self, rhs) + } + } + + doc_comment! { + concat!("Saturating integer multiplication. Computes `self * rhs`, +saturating at the numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!(2", stringify!($SelfT), ".saturating_mul(10), 20); +assert_eq!((", stringify!($SelfT), "::MAX).saturating_mul(10), ", stringify!($SelfT), +"::MAX);", $EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_mul(self, rhs: Self) -> Self { + match self.checked_mul(rhs) { + Some(x) => x, + None => Self::MAX, + } + } + } + + doc_comment! { + concat!("Saturating integer exponentiation. Computes `self.pow(exp)`, +saturating at the numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!(4", stringify!($SelfT), ".saturating_pow(3), 64); +assert_eq!(", stringify!($SelfT), "::MAX.saturating_pow(2), ", stringify!($SelfT), "::MAX);", +$EndFeature, " +```"), + #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_pow(self, exp: u32) -> Self { + match self.checked_pow(exp) { + Some(x) => x, + None => Self::MAX, + } + } + } + + doc_comment! { + concat!("Wrapping (modular) addition. Computes `self + rhs`, +wrapping around at the boundary of the type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(200", stringify!($SelfT), ".wrapping_add(55), 255); +assert_eq!(200", stringify!($SelfT), ".wrapping_add(", stringify!($SelfT), "::MAX), 199);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_add(self, rhs: Self) -> Self { + intrinsics::wrapping_add(self, rhs) + } + } + + doc_comment! { + concat!("Wrapping (modular) subtraction. Computes `self - rhs`, +wrapping around at the boundary of the type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_sub(100), 0); +assert_eq!(100", stringify!($SelfT), ".wrapping_sub(", stringify!($SelfT), "::MAX), 101);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_sub(self, rhs: Self) -> Self { + intrinsics::wrapping_sub(self, rhs) + } + } + + /// Wrapping (modular) multiplication. Computes `self * + /// rhs`, wrapping around at the boundary of the type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `u8` is used here. + /// + /// ``` + /// assert_eq!(10u8.wrapping_mul(12), 120); + /// assert_eq!(25u8.wrapping_mul(12), 44); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_mul(self, rhs: Self) -> Self { + intrinsics::wrapping_mul(self, rhs) + } + + doc_comment! { + concat!("Wrapping (modular) division. Computes `self / rhs`. +Wrapped division on unsigned types is just normal division. +There's no way wrapping could ever happen. +This function exists, so that all operations +are accounted for in the wrapping operations. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10);", $EndFeature, " +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_div(self, rhs: Self) -> Self { + self / rhs + } + } + + doc_comment! { + concat!("Wrapping Euclidean division. Computes `self.div_euclid(rhs)`. +Wrapped division on unsigned types is just normal division. +There's no way wrapping could ever happen. +This function exists, so that all operations +are accounted for in the wrapping operations. +Since, for the positive integers, all common +definitions of division are equal, this +is exactly equal to `self.wrapping_div(rhs)`. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_div_euclid(self, rhs: Self) -> Self { + self / rhs + } + } + + doc_comment! { + concat!("Wrapping (modular) remainder. Computes `self % rhs`. +Wrapped remainder calculation on unsigned types is +just the regular remainder calculation. +There's no way wrapping could ever happen. +This function exists, so that all operations +are accounted for in the wrapping operations. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0);", $EndFeature, " +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_rem(self, rhs: Self) -> Self { + self % rhs + } + } + + doc_comment! { + concat!("Wrapping Euclidean modulo. Computes `self.rem_euclid(rhs)`. +Wrapped modulo calculation on unsigned types is +just the regular remainder calculation. +There's no way wrapping could ever happen. +This function exists, so that all operations +are accounted for in the wrapping operations. +Since, for the positive integers, all common +definitions of division are equal, this +is exactly equal to `self.wrapping_rem(rhs)`. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self { + self % rhs + } + } + + /// Wrapping (modular) negation. Computes `-self`, + /// wrapping around at the boundary of the type. + /// + /// Since unsigned types do not have negative equivalents + /// all applications of this function will wrap (except for `-0`). + /// For values smaller than the corresponding signed type's maximum + /// the result is the same as casting the corresponding signed value. + /// Any larger values are equivalent to `MAX + 1 - (val - MAX - 1)` where + /// `MAX` is the corresponding signed type's maximum. + /// + /// # Examples + /// + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `i8` is used here. + /// + /// ``` + /// assert_eq!(100i8.wrapping_neg(), -100); + /// assert_eq!((-128i8).wrapping_neg(), -128); + /// ``` + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + #[inline] + pub const fn wrapping_neg(self) -> Self { + self.overflowing_neg().0 + } + + doc_comment! { + concat!("Panic-free bitwise shift-left; yields `self << mask(rhs)`, +where `mask` removes any high-order bits of `rhs` that +would cause the shift to exceed the bitwidth of the type. + +Note that this is *not* the same as a rotate-left; the +RHS of a wrapping shift-left is restricted to the range +of the type, rather than the bits shifted out of the LHS +being returned to the other end. The primitive integer +types all implement a [`rotate_left`](#method.rotate_left) function, +which may be what you want instead. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(1", stringify!($SelfT), ".wrapping_shl(7), 128); +assert_eq!(1", stringify!($SelfT), ".wrapping_shl(128), 1);", $EndFeature, " +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_shl(self, rhs: u32) -> Self { + // SAFETY: the masking by the bitsize of the type ensures that we do not shift + // out of bounds + unsafe { + intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT) + } + } + } + + doc_comment! { + concat!("Panic-free bitwise shift-right; yields `self >> mask(rhs)`, +where `mask` removes any high-order bits of `rhs` that +would cause the shift to exceed the bitwidth of the type. + +Note that this is *not* the same as a rotate-right; the +RHS of a wrapping shift-right is restricted to the range +of the type, rather than the bits shifted out of the LHS +being returned to the other end. The primitive integer +types all implement a [`rotate_right`](#method.rotate_right) function, +which may be what you want instead. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(128", stringify!($SelfT), ".wrapping_shr(7), 1); +assert_eq!(128", stringify!($SelfT), ".wrapping_shr(128), 128);", $EndFeature, " +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_shr(self, rhs: u32) -> Self { + // SAFETY: the masking by the bitsize of the type ensures that we do not shift + // out of bounds + unsafe { + intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT) + } + } + } + + doc_comment! { + concat!("Wrapping (modular) exponentiation. Computes `self.pow(exp)`, +wrapping around at the boundary of the type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(5), 243); +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")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_pow(self, mut exp: u32) -> Self { + if exp == 0 { + return 1; + } + let mut base = self; + let mut acc: Self = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = acc.wrapping_mul(base); + } + exp /= 2; + base = base.wrapping_mul(base); + } + + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + acc.wrapping_mul(base) + } + } + + doc_comment! { + concat!("Calculates `self` + `rhs` + +Returns a tuple of the addition along with a boolean indicating +whether an arithmetic overflow would occur. If an overflow would +have occurred then the wrapped value is returned. + +# Examples + +Basic usage + +``` +", $Feature, " +assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false)); +assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (0, true));", $EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) { + let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT); + (a as Self, b) + } + } + + doc_comment! { + concat!("Calculates `self` - `rhs` + +Returns a tuple of the subtraction along with a boolean indicating +whether an arithmetic overflow would occur. If an overflow would +have occurred then the wrapped value is returned. + +# Examples + +Basic usage + +``` +", $Feature, " +assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false)); +assert_eq!(0", stringify!($SelfT), ".overflowing_sub(1), (", stringify!($SelfT), "::MAX, true));", +$EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { + let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT); + (a as Self, b) + } + } + + /// Calculates the multiplication of `self` and `rhs`. + /// + /// Returns a tuple of the multiplication along with a boolean + /// indicating whether an arithmetic overflow would occur. If an + /// overflow would have occurred then the wrapped value is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `u32` is used here. + /// + /// ``` + /// assert_eq!(5u32.overflowing_mul(2), (10, false)); + /// assert_eq!(1_000_000_000u32.overflowing_mul(10), (1410065408, true)); + /// ``` + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) { + let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT); + (a as Self, b) + } + + doc_comment! { + concat!("Calculates the divisor when `self` is divided by `rhs`. + +Returns a tuple of the divisor along with a boolean indicating +whether an arithmetic overflow would occur. Note that for unsigned +integers overflow never occurs, so the second value is always +`false`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage + +``` +", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false));", $EndFeature, " +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) { + (self / rhs, false) + } + } + + doc_comment! { + concat!("Calculates the quotient of Euclidean division `self.div_euclid(rhs)`. + +Returns a tuple of the divisor along with a boolean indicating +whether an arithmetic overflow would occur. Note that for unsigned +integers overflow never occurs, so the second value is always +`false`. +Since, for the positive integers, all common +definitions of division are equal, this +is exactly equal to `self.overflowing_div(rhs)`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage + +``` +assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false)); +```"), + #[inline] + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { + (self / rhs, false) + } + } + + doc_comment! { + concat!("Calculates the remainder when `self` is divided by `rhs`. + +Returns a tuple of the remainder after dividing along with a boolean +indicating whether an arithmetic overflow would occur. Note that for +unsigned integers overflow never occurs, so the second value is +always `false`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage + +``` +", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false));", $EndFeature, " +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) { + (self % rhs, false) + } + } + + doc_comment! { + concat!("Calculates the remainder `self.rem_euclid(rhs)` as if by Euclidean division. + +Returns a tuple of the modulo after dividing along with a boolean +indicating whether an arithmetic overflow would occur. Note that for +unsigned integers overflow never occurs, so the second value is +always `false`. +Since, for the positive integers, all common +definitions of division are equal, this operation +is exactly equal to `self.overflowing_rem(rhs)`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage + +``` +assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false)); +```"), + #[inline] + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { + (self % rhs, false) + } + } + + doc_comment! { + concat!("Negates self in an overflowing fashion. + +Returns `!self + 1` using wrapping operations to return the value +that represents the negation of this unsigned value. Note that for +positive unsigned values overflow always occurs, but negating 0 does +not overflow. + +# Examples + +Basic usage + +``` +", $Feature, "assert_eq!(0", stringify!($SelfT), ".overflowing_neg(), (0, false)); +assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2i32 as ", stringify!($SelfT), +", true));", $EndFeature, " +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + pub const fn overflowing_neg(self) -> (Self, bool) { + ((!self).wrapping_add(1), self != 0) + } + } + + doc_comment! { + concat!("Shifts self left by `rhs` bits. + +Returns a tuple of the shifted version of self along with a boolean +indicating whether the shift value was larger than or equal to the +number of bits. If the shift value is too large, then value is +masked (N-1) where N is the number of bits, and this value is then +used to perform the shift. + +# Examples + +Basic usage + +``` +", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(4), (0x10, false)); +assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(132), (0x10, true));", $EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) { + (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) + } + } + + doc_comment! { + concat!("Shifts self right by `rhs` bits. + +Returns a tuple of the shifted version of self along with a boolean +indicating whether the shift value was larger than or equal to the +number of bits. If the shift value is too large, then value is +masked (N-1) where N is the number of bits, and this value is then +used to perform the shift. + +# Examples + +Basic usage + +``` +", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false)); +assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(132), (0x1, true));", $EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) { + (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) + } + } + + doc_comment! { + concat!("Raises self to the power of `exp`, using exponentiation by squaring. + +Returns a tuple of the exponentiation along with a bool indicating +whether an overflow happened. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(5), (243, false)); +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")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) { + if exp == 0{ + return (1,false); + } + let mut base = self; + let mut acc: Self = 1; + let mut overflown = false; + // Scratch space for storing results of overflowing_mul. + let mut r; + + while exp > 1 { + if (exp & 1) == 1 { + r = acc.overflowing_mul(base); + acc = r.0; + overflown |= r.1; + } + exp /= 2; + r = base.overflowing_mul(base); + base = r.0; + overflown |= r.1; + } + + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + r = acc.overflowing_mul(base); + r.1 |= overflown; + + r + } + } + + doc_comment! { + concat!("Raises self to the power of `exp`, using exponentiation by squaring. + +# Examples + +Basic usage: + +``` +", $Feature, "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")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn pow(self, mut exp: u32) -> Self { + if exp == 0 { + return 1; + } + let mut base = self; + let mut acc = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = acc * base; + } + exp /= 2; + base = base * base; + } + + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + acc * base + } + } + + doc_comment! { + concat!("Performs Euclidean division. + +Since, for the positive integers, all common +definitions of division are equal, this +is exactly equal to `self / rhs`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +assert_eq!(7", stringify!($SelfT), ".div_euclid(4), 1); // or any other integer type +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn div_euclid(self, rhs: Self) -> Self { + self / rhs + } + } + + + doc_comment! { + concat!("Calculates the least remainder of `self (mod rhs)`. + +Since, for the positive integers, all common +definitions of division are equal, this +is exactly equal to `self % rhs`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +assert_eq!(7", stringify!($SelfT), ".rem_euclid(4), 3); // or any other integer type +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn rem_euclid(self, rhs: Self) -> Self { + self % rhs + } + } + + doc_comment! { + concat!("Returns `true` if and only if `self == 2^k` for some `k`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert!(16", stringify!($SelfT), ".is_power_of_two()); +assert!(!10", stringify!($SelfT), ".is_power_of_two());", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_is_power_of_two", since = "1.32.0")] + #[inline] + pub const fn is_power_of_two(self) -> bool { + self.count_ones() == 1 + } + } + + // Returns one less than next power of two. + // (For 8u8 next power of two is 8u8 and for 6u8 it is 8u8) + // + // 8u8.one_less_than_next_power_of_two() == 7 + // 6u8.one_less_than_next_power_of_two() == 7 + // + // This method cannot overflow, as in the `next_power_of_two` + // 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")] + const fn one_less_than_next_power_of_two(self) -> Self { + if self <= 1 { return 0; } + + let p = self - 1; + // SAFETY: Because `p > 0`, it cannot consist entirely of leading zeros. + // That means the shift is always in-bounds, and some processors + // (such as intel pre-haswell) have more efficient ctlz + // intrinsics when the argument is non-zero. + let z = unsafe { intrinsics::ctlz_nonzero(p) }; + <$SelfT>::MAX >> z + } + + doc_comment! { + concat!("Returns the smallest power of two greater than or equal to `self`. + +When return value overflows (i.e., `self > (1 << (N-1))` for type +`uN`), it panics in debug mode and return value is wrapped to 0 in +release mode (the only situation in which method can return 0). + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(2", stringify!($SelfT), ".next_power_of_two(), 2); +assert_eq!(3", stringify!($SelfT), ".next_power_of_two(), 4);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn next_power_of_two(self) -> Self { + self.one_less_than_next_power_of_two() + 1 + } + } + + doc_comment! { + concat!("Returns the smallest power of two greater than or equal to `n`. If +the next power of two is greater than the type's maximum value, +`None` is returned, otherwise the power of two is wrapped in `Some`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(2", stringify!($SelfT), +".checked_next_power_of_two(), Some(2)); +assert_eq!(3", stringify!($SelfT), ".checked_next_power_of_two(), Some(4)); +assert_eq!(", stringify!($SelfT), "::MAX.checked_next_power_of_two(), None);", +$EndFeature, " +```"), + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + pub const fn checked_next_power_of_two(self) -> Option { + self.one_less_than_next_power_of_two().checked_add(1) + } + } + + doc_comment! { + concat!("Returns the smallest power of two greater than or equal to `n`. If +the next power of two is greater than the type's maximum value, +the return value is wrapped to `0`. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_next_power_of_two)] +", $Feature, " +assert_eq!(2", stringify!($SelfT), ".wrapping_next_power_of_two(), 2); +assert_eq!(3", stringify!($SelfT), ".wrapping_next_power_of_two(), 4); +assert_eq!(", stringify!($SelfT), "::MAX.wrapping_next_power_of_two(), 0);", +$EndFeature, " +```"), + #[unstable(feature = "wrapping_next_power_of_two", issue = "32463", + reason = "needs decision on wrapping behaviour")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + pub const fn wrapping_next_power_of_two(self) -> Self { + self.one_less_than_next_power_of_two().wrapping_add(1) + } + } + + doc_comment! { + concat!("Return the memory representation of this integer as a byte array in +big-endian (network) byte order. +", +$to_xe_bytes_doc, +" +# Examples + +``` +let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes(); +assert_eq!(bytes, ", $be_bytes, "); +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[inline] + pub const fn to_be_bytes(self) -> [u8; mem::size_of::()] { + self.to_be().to_ne_bytes() + } + } + + doc_comment! { + concat!("Return the memory representation of this integer as a byte array in +little-endian byte order. +", +$to_xe_bytes_doc, +" +# Examples + +``` +let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes(); +assert_eq!(bytes, ", $le_bytes, "); +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[inline] + pub const fn to_le_bytes(self) -> [u8; mem::size_of::()] { + self.to_le().to_ne_bytes() + } + } + + doc_comment! { + concat!(" +Return the memory representation of this integer as a byte array in +native byte order. + +As the target platform's native endianness is used, portable code +should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, +instead. +", +$to_xe_bytes_doc, +" +[`to_be_bytes`]: #method.to_be_bytes +[`to_le_bytes`]: #method.to_le_bytes + +# Examples + +``` +let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes(); +assert_eq!( + bytes, + if cfg!(target_endian = \"big\") { + ", $be_bytes, " + } else { + ", $le_bytes, " + } +); +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + // SAFETY: const sound because integers are plain old datatypes so we can always + // transmute them to arrays of bytes + #[allow_internal_unstable(const_fn_transmute)] + #[inline] + pub const fn to_ne_bytes(self) -> [u8; mem::size_of::()] { + // SAFETY: integers are plain old datatypes so we can always transmute them to + // arrays of bytes + unsafe { mem::transmute(self) } + } + } + + doc_comment! { + concat!("Create a native endian integer value from its representation +as a byte array in big endian. +", +$from_xe_bytes_doc, +" +# Examples + +``` +let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, "); +assert_eq!(value, ", $swap_op, "); +``` + +When starting from a slice rather than an array, fallible conversion APIs can be used: + +``` +use std::convert::TryInto; + +fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { + let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); + *input = rest; + ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap()) +} +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[inline] + pub const fn from_be_bytes(bytes: [u8; mem::size_of::()]) -> Self { + Self::from_be(Self::from_ne_bytes(bytes)) + } + } + + doc_comment! { + concat!(" +Create a native endian integer value from its representation +as a byte array in little endian. +", +$from_xe_bytes_doc, +" +# Examples + +``` +let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, "); +assert_eq!(value, ", $swap_op, "); +``` + +When starting from a slice rather than an array, fallible conversion APIs can be used: + +``` +use std::convert::TryInto; + +fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { + let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); + *input = rest; + ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap()) +} +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[inline] + pub const fn from_le_bytes(bytes: [u8; mem::size_of::()]) -> Self { + Self::from_le(Self::from_ne_bytes(bytes)) + } + } + + doc_comment! { + concat!("Create a native endian integer value from its memory representation +as a byte array in native endianness. + +As the target platform's native endianness is used, portable code +likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as +appropriate instead. + +[`from_be_bytes`]: #method.from_be_bytes +[`from_le_bytes`]: #method.from_le_bytes +", +$from_xe_bytes_doc, +" +# Examples + +``` +let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") { + ", $be_bytes, " +} else { + ", $le_bytes, " +}); +assert_eq!(value, ", $swap_op, "); +``` + +When starting from a slice rather than an array, fallible conversion APIs can be used: + +``` +use std::convert::TryInto; + +fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { + let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); + *input = rest; + ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap()) +} +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + // SAFETY: const sound because integers are plain old datatypes so we can always + // transmute to them + #[allow_internal_unstable(const_fn_transmute)] + #[inline] + pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { + // SAFETY: integers are plain old datatypes so we can always transmute to them + unsafe { mem::transmute(bytes) } + } + } + + doc_comment! { + concat!("**This method is soft-deprecated.** + +Although using it won’t cause compilation warning, +new code should use [`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN) instead. + +Returns the smallest value that can be represented by this integer type."), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_promotable] + #[inline(always)] + #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")] + pub const fn min_value() -> Self { Self::MIN } + } + + doc_comment! { + concat!("**This method is soft-deprecated.** + +Although using it won’t cause compilation warning, +new code should use [`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX) instead. + +Returns the largest value that can be represented by this integer type."), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_promotable] + #[inline(always)] + #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")] + pub const fn max_value() -> Self { Self::MAX } + } + } +} From a50ec5f144b414d3c14fe04fc07f935c2ea0ab0f Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 4 Sep 2020 15:31:23 +0000 Subject: [PATCH 0672/1052] Remove outdated ignored tidy comment --- library/core/src/num/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 5388a5c04b86d..4f64e30ccf84a 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -1,5 +1,3 @@ -// ignore-tidy-filelength - //! Numeric traits and functions for the built-in numeric types. #![stable(feature = "rust1", since = "1.0.0")] From c6a8cfbde848352271ee143fe5d458dcac7c397f Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Sun, 16 Aug 2020 22:39:01 +0200 Subject: [PATCH 0673/1052] BTreeMap: code readability tweaks --- library/alloc/src/collections/btree/map.rs | 2 +- library/alloc/src/collections/btree/navigate.rs | 4 ++-- library/alloc/src/collections/btree/node.rs | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index aed898be08fb6..469381e7235d2 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1719,7 +1719,7 @@ impl<'a, K: 'a, V: 'a> DrainFilterInner<'a, K, V> { /// Allow Debug implementations to predict the next element. pub(super) fn peek(&self) -> Option<(&K, &V)> { let edge = self.cur_leaf_edge.as_ref()?; - edge.reborrow().next_kv().ok().map(|kv| kv.into_kv()) + edge.reborrow().next_kv().ok().map(Handle::into_kv) } /// Implementation of a typical `DrainFilter::next` method, given the predicate. diff --git a/library/alloc/src/collections/btree/navigate.rs b/library/alloc/src/collections/btree/navigate.rs index 69f7ef57218df..55ce7d275464e 100644 --- a/library/alloc/src/collections/btree/navigate.rs +++ b/library/alloc/src/collections/btree/navigate.rs @@ -218,7 +218,7 @@ impl Handle, marker::E let mut edge = self.forget_node_type(); loop { edge = match edge.right_kv() { - Ok(internal_kv) => return Ok(internal_kv), + Ok(kv) => return Ok(kv), Err(last_edge) => match last_edge.into_node().ascend() { Ok(parent_edge) => parent_edge.forget_node_type(), Err(root) => return Err(root), @@ -239,7 +239,7 @@ impl Handle, marker::E let mut edge = self.forget_node_type(); loop { edge = match edge.left_kv() { - Ok(internal_kv) => return Ok(internal_kv), + Ok(kv) => return Ok(kv), Err(last_edge) => match last_edge.into_node().ascend() { Ok(parent_edge) => parent_edge.forget_node_type(), Err(root) => return Err(root), diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 8776a5efbe4f5..5e01f7e1c72ec 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -927,14 +927,14 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, mark /// The returned pointer points to the inserted value. fn insert(mut self, key: K, val: V) -> (InsertResult<'a, K, V, marker::Leaf>, *mut V) { if self.node.len() < CAPACITY { - let ptr = self.insert_fit(key, val); + let val_ptr = self.insert_fit(key, val); let kv = unsafe { Handle::new_kv(self.node, self.idx) }; - (InsertResult::Fit(kv), ptr) + (InsertResult::Fit(kv), val_ptr) } 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 ptr = match insertion { + let val_ptr = match insertion { InsertionPlace::Left(insert_idx) => unsafe { Handle::new_edge(left.reborrow_mut(), insert_idx).insert_fit(key, val) }, @@ -946,7 +946,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, mark .insert_fit(key, val) }, }; - (InsertResult::Split(SplitResult { left: left.forget_type(), k, v, right }), ptr) + (InsertResult::Split(SplitResult { left: left.forget_type(), k, v, right }), val_ptr) } } } From 1146c39da74b3875e6667aeeafde2773644dc8b6 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 19 Sep 2020 17:27:13 +0200 Subject: [PATCH 0674/1052] cache types during normalization --- Cargo.lock | 1 + compiler/rustc_data_structures/Cargo.toml | 1 + compiler/rustc_data_structures/src/lib.rs | 12 ++-- .../rustc_data_structures/src/mini_map.rs | 61 +++++++++++++++++++ compiler/rustc_index/Cargo.toml | 2 +- compiler/rustc_infer/src/infer/combine.rs | 61 +------------------ .../src/traits/query/normalize.rs | 13 +++- 7 files changed, 83 insertions(+), 68 deletions(-) create mode 100644 compiler/rustc_data_structures/src/mini_map.rs diff --git a/Cargo.lock b/Cargo.lock index c9f75aa1d438d..825ded3eeeebc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3435,6 +3435,7 @@ dependencies = [ name = "rustc_data_structures" version = "0.0.0" dependencies = [ + "arrayvec", "bitflags", "cfg-if", "crossbeam-utils 0.7.2", diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 3dc55cab95a11..7a6f4b82b52f2 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" doctest = false [dependencies] +arrayvec = { version = "0.5.1", default-features = false } ena = "0.14" indexmap = "1.5.1" tracing = "0.1" diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 88c160e93b66a..7d4aed14be16b 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -87,25 +87,27 @@ pub mod sorted_map; pub mod stable_set; #[macro_use] pub mod stable_hasher; +mod atomic_ref; +pub mod fingerprint; +pub mod profiling; pub mod sharded; pub mod stack; pub mod sync; pub mod thin_vec; pub mod tiny_list; pub mod transitive_relation; -pub use ena::undo_log; -pub use ena::unify; -mod atomic_ref; -pub mod fingerprint; -pub mod profiling; pub mod vec_linked_list; pub mod work_queue; pub use atomic_ref::AtomicRef; pub mod frozen; +pub mod mini_map; pub mod tagged_ptr; pub mod temp_dir; pub mod unhash; +pub use ena::undo_log; +pub use ena::unify; + pub struct OnDrop(pub F); impl OnDrop { diff --git a/compiler/rustc_data_structures/src/mini_map.rs b/compiler/rustc_data_structures/src/mini_map.rs new file mode 100644 index 0000000000000..cd3e949d3831a --- /dev/null +++ b/compiler/rustc_data_structures/src/mini_map.rs @@ -0,0 +1,61 @@ +use crate::fx::FxHashMap; +use arrayvec::ArrayVec; + +use std::hash::Hash; + +/// Small-storage-optimized implementation of a map +/// made specifically for caching results. +/// +/// Stores elements in a small array up to a certain length +/// and switches to `HashMap` when that length is exceeded. +pub enum MiniMap { + Array(ArrayVec<[(K, V); 8]>), + Map(FxHashMap), +} + +impl MiniMap { + /// Creates an empty `MiniMap`. + pub fn new() -> Self { + MiniMap::Array(ArrayVec::new()) + } + + /// Inserts or updates value in the map. + pub fn insert(&mut self, key: K, value: V) { + match self { + MiniMap::Array(array) => { + for pair in array.iter_mut() { + if pair.0 == key { + pair.1 = value; + return; + } + } + if let Err(error) = array.try_push((key, value)) { + let mut map: FxHashMap = array.drain(..).collect(); + let (key, value) = error.element(); + map.insert(key, value); + *self = MiniMap::Map(map); + } + } + MiniMap::Map(map) => { + map.insert(key, value); + } + } + } + + /// Return value by key if any. + pub fn get(&self, key: &K) -> Option<&V> { + match self { + MiniMap::Array(array) => { + for pair in array { + if pair.0 == *key { + return Some(&pair.1); + } + } + return None; + } + MiniMap::Map(map) => { + return map.get(key); + } + } + } +} diff --git a/compiler/rustc_index/Cargo.toml b/compiler/rustc_index/Cargo.toml index 6ac7c06ee838c..6e1471df195b1 100644 --- a/compiler/rustc_index/Cargo.toml +++ b/compiler/rustc_index/Cargo.toml @@ -8,6 +8,6 @@ edition = "2018" doctest = false [dependencies] -arrayvec = "0.5.1" +arrayvec = { version = "0.5.1", default-features = false } rustc_serialize = { path = "../rustc_serialize" } rustc_macros = { path = "../rustc_macros" } diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 5bd6c667fd7f6..982973878c626 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -31,13 +31,11 @@ use super::unify_key::replace_if_possible; use super::unify_key::{ConstVarValue, ConstVariableValue}; use super::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use super::{InferCtxt, MiscVariable, TypeTrace}; -use arrayvec::ArrayVec; -use rustc_data_structures::fx::FxHashMap; -use std::hash::Hash; use crate::traits::{Obligation, PredicateObligations}; use rustc_ast as ast; +use rustc_data_structures::mini_map::MiniMap; use rustc_hir::def_id::DefId; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::TypeError; @@ -47,63 +45,6 @@ use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{IntType, UintType}; use rustc_span::DUMMY_SP; -/// Small-storage-optimized implementation of a map -/// made specifically for caching results. -/// -/// Stores elements in a small array up to a certain length -/// and switches to `HashMap` when that length is exceeded. -enum MiniMap { - Array(ArrayVec<[(K, V); 8]>), - Map(FxHashMap), -} - -impl MiniMap { - /// Creates an empty `MiniMap`. - pub fn new() -> Self { - MiniMap::Array(ArrayVec::new()) - } - - /// Inserts or updates value in the map. - pub fn insert(&mut self, key: K, value: V) { - match self { - MiniMap::Array(array) => { - for pair in array.iter_mut() { - if pair.0 == key { - pair.1 = value; - return; - } - } - if let Err(error) = array.try_push((key, value)) { - let mut map: FxHashMap = array.drain(..).collect(); - let (key, value) = error.element(); - map.insert(key, value); - *self = MiniMap::Map(map); - } - } - MiniMap::Map(map) => { - map.insert(key, value); - } - } - } - - /// Return value by key if any. - pub fn get(&self, key: &K) -> Option<&V> { - match self { - MiniMap::Array(array) => { - for pair in array { - if pair.0 == *key { - return Some(&pair.1); - } - } - return None; - } - MiniMap::Map(map) => { - return map.get(key); - } - } - } -} - #[derive(Clone)] pub struct CombineFields<'infcx, 'tcx> { pub infcx: &'infcx InferCtxt<'infcx, 'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 323063b958447..3dcebbcc24482 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -7,6 +7,7 @@ use crate::infer::canonical::OriginalQueryValues; use crate::infer::{InferCtxt, InferOk}; use crate::traits::error_reporting::InferCtxtExt; use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; +use rustc_data_structures::mini_map::MiniMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::traits::Normalized; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; @@ -57,6 +58,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { param_env: self.param_env, obligations: vec![], error: false, + cache: MiniMap::new(), anon_depth: 0, }; @@ -85,6 +87,7 @@ struct QueryNormalizer<'cx, 'tcx> { cause: &'cx ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, obligations: Vec>, + cache: MiniMap, Ty<'tcx>>, error: bool, anon_depth: usize, } @@ -99,8 +102,12 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { return ty; } + if let Some(ty) = self.cache.get(&ty) { + return ty; + } + let ty = ty.super_fold_with(self); - match *ty.kind() { + let res = (|| match *ty.kind() { ty::Opaque(def_id, substs) => { // Only normalize `impl Trait` after type-checking, usually in codegen. match self.param_env.reveal() { @@ -197,7 +204,9 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { } _ => ty, - } + })(); + self.cache.insert(ty, res); + res } fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { From 26d6081f1d1a2005be87bbe47f6fcda270cfd016 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 19 Sep 2020 18:48:39 +0200 Subject: [PATCH 0675/1052] Relax promises about condition variable. This allows for futex or thread parking based implementations in the future. --- library/std/src/sync/condvar.rs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/library/std/src/sync/condvar.rs b/library/std/src/sync/condvar.rs index bc01c26a86ace..7e2155dae6fce 100644 --- a/library/std/src/sync/condvar.rs +++ b/library/std/src/sync/condvar.rs @@ -78,13 +78,9 @@ impl WaitTimeoutResult { /// and a mutex. The predicate is always verified inside of the mutex before /// determining that a thread must block. /// -/// Functions in this module will block the current **thread** of execution and -/// are bindings to system-provided condition variables where possible. Note -/// that this module places one additional restriction over the system condition -/// variables: each condvar can be used with precisely one mutex at runtime. Any -/// attempt to use multiple mutexes on the same condition variable will result -/// in a runtime panic. If this is not desired, then the unsafe primitives in -/// `sys` do not have this restriction but may result in undefined behavior. +/// Functions in this module will block the current **thread** of execution. +/// Note that any attempt to use multiple mutexes on the same condition +/// variable may result in a runtime panic. /// /// # Examples /// @@ -159,10 +155,8 @@ impl Condvar { /// /// # Panics /// - /// This function will [`panic!`] if it is used with more than one mutex - /// over time. Each condition variable is dynamically bound to exactly one - /// mutex to ensure defined behavior across platforms. If this functionality - /// is not desired, then unsafe primitives in `sys` are provided. + /// This function may [`panic!`] if it is used with more than one mutex + /// over time. /// /// [`notify_one`]: Self::notify_one /// [`notify_all`]: Self::notify_all From 0661b0a36d483dfb7041a3526b07eeec2b67b2d0 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Sat, 19 Sep 2020 16:47:03 +0200 Subject: [PATCH 0676/1052] BTreeMap: wrap node's raw parent pointer in NonNull --- library/alloc/src/collections/btree/node.rs | 42 +++++++++++---------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 8776a5efbe4f5..ae42701b36a53 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -12,7 +12,7 @@ // edges: if height > 0 { // [Box>; 2 * B] // } else { () }, -// parent: *const Node, +// parent: Option>>, // parent_idx: u16, // len: u16, // } @@ -50,9 +50,8 @@ const EDGE_IDX_RIGHT_OF_CENTER: usize = B; /// The underlying representation of leaf nodes. #[repr(C)] struct LeafNode { - /// We use `*const` as opposed to `*mut` so as to be covariant in `K` and `V`. - /// This either points to an actual node or is null. - parent: *const InternalNode, + /// We want to be covariant in `K` and `V`. + parent: Option>>, /// This node's index into the parent node's `edges` array. /// `*node.parent.edges[node.parent_idx]` should be the same thing as `node`. @@ -80,7 +79,7 @@ impl LeafNode { // be both slightly faster and easier to track in Valgrind. keys: MaybeUninit::uninit_array(), vals: MaybeUninit::uninit_array(), - parent: ptr::null(), + parent: None, parent_idx: MaybeUninit::uninit(), len: 0, } @@ -224,7 +223,7 @@ impl Root { ) }; self.height -= 1; - self.node_as_mut().as_leaf_mut().parent = ptr::null(); + self.node_as_mut().as_leaf_mut().parent = None; unsafe { Global.dealloc(NonNull::from(top).cast(), Layout::new::>()); @@ -309,7 +308,7 @@ impl NodeRef { pub fn len(&self) -> usize { // Crucially, we only access the `len` field here. If BorrowType is marker::ValMut, // there might be outstanding mutable references to values that we must not invalidate. - unsafe { (*self.as_leaf_ptr()).len as usize } + unsafe { usize::from((*self.as_leaf_ptr()).len) } } /// Returns the height of this node in the whole tree. Zero height denotes the @@ -365,16 +364,19 @@ impl NodeRef { ) -> Result, marker::Edge>, Self> { // We need to use raw pointers to nodes because, if BorrowType is marker::ValMut, // there might be outstanding mutable references to values that we must not invalidate. - let parent_as_leaf = unsafe { (*self.as_leaf_ptr()).parent as *const LeafNode }; - if let Some(non_zero) = NonNull::new(parent_as_leaf as *mut _) { - Ok(Handle { - node: NodeRef { height: self.height + 1, node: non_zero, _marker: PhantomData }, - idx: unsafe { usize::from(*(*self.as_leaf_ptr()).parent_idx.as_ptr()) }, + let leaf_ptr = self.as_leaf_ptr(); + unsafe { (*leaf_ptr).parent } + .as_ref() + .map(|parent| Handle { + node: NodeRef { + height: self.height + 1, + node: parent.cast(), + _marker: PhantomData, + }, + idx: unsafe { usize::from((*leaf_ptr).parent_idx.assume_init()) }, _marker: PhantomData, }) - } else { - Err(self) - } + .ok_or(self) } pub fn first_edge(self) -> Handle { @@ -572,7 +574,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Leaf> { /// Adds a key/value pair to the end of the node. pub fn push(&mut self, key: K, val: V) { let len = &mut self.as_leaf_mut().len; - let idx = *len as usize; + let idx = usize::from(*len); assert!(idx < CAPACITY); *len += 1; unsafe { @@ -617,7 +619,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { assert!(edge.height == self.height - 1); let len = &mut self.as_leaf_mut().len; - let idx = *len as usize; + let idx = usize::from(*len); assert!(idx < CAPACITY); *len += 1; unsafe { @@ -672,7 +674,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { let edge = ptr::read(internal.as_internal().edges.get_unchecked(idx + 1).as_ptr()); let mut new_root = Root { node: edge, height: internal.height - 1 }; - new_root.node_as_mut().as_leaf_mut().parent = ptr::null(); + new_root.node_as_mut().as_leaf_mut().parent = None; Some(new_root) } }; @@ -704,7 +706,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { ); let mut new_root = Root { node: edge, height: internal.height - 1 }; - new_root.node_as_mut().as_leaf_mut().parent = ptr::null(); + new_root.node_as_mut().as_leaf_mut().parent = None; for i in 0..old_len { Handle::new_edge(internal.reborrow_mut(), i).correct_parent_link(); @@ -956,7 +958,7 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: /// when the ordering of edges has been changed, such as in the various `insert` methods. fn correct_parent_link(mut self) { let idx = self.idx as u16; - let ptr = self.node.as_internal_mut() as *mut _; + let ptr = NonNull::new(self.node.as_internal_mut()); let mut child = self.descend(); child.as_leaf_mut().parent = ptr; child.as_leaf_mut().parent_idx.write(idx); From 4d1ef03c9ed28b6855c3f73535e21dc9cd6f6c5d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 6 Sep 2020 16:06:39 +0200 Subject: [PATCH 0677/1052] cleanup promotion const_kind checks in particular allow a few more promotions for consistency when they were already allowed in other contexts --- .../rustc_mir/src/transform/promote_consts.rs | 58 +++++++++---------- src/test/ui/consts/promote-no-mut.rs | 10 ---- src/test/ui/consts/promote-not.rs | 30 ++++++++++ ...omote-no-mut.stderr => promote-not.stderr} | 26 ++++++++- src/test/ui/consts/promotion.rs | 2 +- src/test/ui/statics/static-promotion.rs | 2 +- 6 files changed, 83 insertions(+), 45 deletions(-) delete mode 100644 src/test/ui/consts/promote-no-mut.rs create mode 100644 src/test/ui/consts/promote-not.rs rename src/test/ui/consts/{promote-no-mut.stderr => promote-not.stderr} (51%) diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index b6124049579fd..a4a6a7b03aba4 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -297,6 +297,17 @@ impl std::ops::Deref for Validator<'a, 'tcx> { struct Unpromotable; impl<'tcx> Validator<'_, 'tcx> { + //! Determines if this code could be executed at runtime and thus is subject to codegen. + //! That means even unused constants need to be evaluated. + //! + //! `const_kind` should not be used in this file other than through this method! + fn maybe_runtime(&self) -> bool { + match self.const_kind { + None | Some(hir::ConstContext::ConstFn) => true, + Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) => false, + } + } + fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> { match candidate { Candidate::Ref(loc) => { @@ -365,10 +376,8 @@ impl<'tcx> Validator<'_, 'tcx> { // mutably without consequences. However, only &mut [] // is allowed right now, and only in functions. if let ty::Array(_, len) = ty.kind() { - // FIXME(eddyb) the `self.is_non_const_fn` condition - // seems unnecessary, given that this is merely a ZST. match len.try_eval_usize(self.tcx, self.param_env) { - Some(0) if self.const_kind.is_none() => {} + Some(0) => {} _ => return Err(Unpromotable), } } else { @@ -495,9 +504,10 @@ impl<'tcx> Validator<'_, 'tcx> { match place { PlaceRef { local, projection: [] } => self.validate_local(local), PlaceRef { local, projection: [proj_base @ .., elem] } => { + // Validate topmost projection, then recurse. match *elem { ProjectionElem::Deref => { - let mut not_promotable = true; + let mut promotable = false; // This is a special treatment for cases like *&STATIC where STATIC is a // global static variable. // This pattern is generated only when global static variables are directly @@ -512,6 +522,9 @@ impl<'tcx> Validator<'_, 'tcx> { }) = def_stmt { if let Some(did) = c.check_static_ptr(self.tcx) { + // Evaluating a promoted may not read statics except if it got + // promoted from a static (this is a CTFE check). So we + // can only promoted static accesses inside statics. if let Some(hir::ConstContext::Static(..)) = self.const_kind { // The `is_empty` predicate is introduced to exclude the case // where the projection operations are [ .field, * ]. @@ -524,13 +537,13 @@ impl<'tcx> Validator<'_, 'tcx> { if proj_base.is_empty() && !self.tcx.is_thread_local_static(did) { - not_promotable = false; + promotable = true; } } } } } - if not_promotable { + if !promotable { return Err(Unpromotable); } } @@ -545,7 +558,7 @@ impl<'tcx> Validator<'_, 'tcx> { } ProjectionElem::Field(..) => { - if self.const_kind.is_none() { + if self.maybe_runtime() { let base_ty = Place::ty_from(place.local, proj_base, self.body, self.tcx).ty; if let Some(def) = base_ty.ty_adt_def() { @@ -571,13 +584,6 @@ impl<'tcx> Validator<'_, 'tcx> { // `validate_rvalue` upon access. Operand::Constant(c) => { if let Some(def_id) = c.check_static_ptr(self.tcx) { - // Only allow statics (not consts) to refer to other statics. - // FIXME(eddyb) does this matter at all for promotion? - let is_static = matches!(self.const_kind, Some(hir::ConstContext::Static(_))); - if !is_static { - return Err(Unpromotable); - } - let is_thread_local = self.tcx.is_thread_local_static(def_id); if is_thread_local { return Err(Unpromotable); @@ -591,20 +597,20 @@ impl<'tcx> Validator<'_, 'tcx> { fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> { match *rvalue { - Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) if self.const_kind.is_none() => { + Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) if self.maybe_runtime() => { let operand_ty = operand.ty(self.body, self.tcx); let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); match (cast_in, cast_out) { (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => { - // in normal functions, mark such casts as not promotable + // ptr-to-int casts are not promotable return Err(Unpromotable); } _ => {} } } - Rvalue::BinaryOp(op, ref lhs, _) if self.const_kind.is_none() => { + Rvalue::BinaryOp(op, ref lhs, _) if self.maybe_runtime() => { if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind() { assert!( op == BinOp::Eq @@ -623,6 +629,7 @@ impl<'tcx> Validator<'_, 'tcx> { Rvalue::NullaryOp(NullOp::Box, _) => return Err(Unpromotable), + // FIXME(RalfJung): the rest is *implicitly considered promotable*... that seems dangerous. _ => {} } @@ -644,8 +651,8 @@ impl<'tcx> Validator<'_, 'tcx> { } Rvalue::AddressOf(_, place) => { - // Raw reborrows can come from reference to pointer coercions, - // so are allowed. + // We accept `&raw *`, i.e., raw reborrows -- creating a raw pointer is + // no problem, only using it is. if let [proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() { let base_ty = Place::ty_from(place.local, proj_base, self.body, self.tcx).ty; if let ty::Ref(..) = base_ty.kind() { @@ -666,10 +673,8 @@ impl<'tcx> Validator<'_, 'tcx> { // mutably without consequences. However, only &mut [] // is allowed right now, and only in functions. if let ty::Array(_, len) = ty.kind() { - // FIXME(eddyb): We only return `Unpromotable` for `&mut []` inside a - // const context which seems unnecessary given that this is merely a ZST. match len.try_eval_usize(self.tcx, self.param_env) { - Some(0) if self.const_kind.is_none() => {} + Some(0) => {} _ => return Err(Unpromotable), } } else { @@ -734,14 +739,7 @@ impl<'tcx> Validator<'_, 'tcx> { ) -> Result<(), Unpromotable> { let fn_ty = callee.ty(self.body, self.tcx); - // `const` and `static` use the explicit rules for promotion regardless of the `Candidate`, - // meaning calls to `const fn` can be promoted. - let context_uses_explicit_promotion_rules = matches!( - self.const_kind, - Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) - ); - - if !self.explicit && !context_uses_explicit_promotion_rules { + if !self.explicit && self.maybe_runtime() { if let ty::FnDef(def_id, _) = *fn_ty.kind() { // Never promote runtime `const fn` calls of // functions without `#[rustc_promotable]`. diff --git a/src/test/ui/consts/promote-no-mut.rs b/src/test/ui/consts/promote-no-mut.rs deleted file mode 100644 index fb57c8bb93458..0000000000000 --- a/src/test/ui/consts/promote-no-mut.rs +++ /dev/null @@ -1,10 +0,0 @@ -// ignore-tidy-linelength -// We do not promote mutable references. -static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); //~ ERROR temporary value dropped while borrowed - -static mut TEST2: &'static mut [i32] = { - let x = &mut [1,2,3]; //~ ERROR temporary value dropped while borrowed - x -}; - -fn main() {} diff --git a/src/test/ui/consts/promote-not.rs b/src/test/ui/consts/promote-not.rs new file mode 100644 index 0000000000000..8daac75837734 --- /dev/null +++ b/src/test/ui/consts/promote-not.rs @@ -0,0 +1,30 @@ +// ignore-tidy-linelength +// Test various things that we do not want to promote. +#![allow(unconditional_panic, const_err)] +#![feature(const_fn, const_fn_union)] + +// We do not promote mutable references. +static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); //~ ERROR temporary value dropped while borrowed + +static mut TEST2: &'static mut [i32] = { + let x = &mut [1,2,3]; //~ ERROR temporary value dropped while borrowed + x +}; + +// We do not promote fn calls in `fn`, including `const fn`. +pub const fn promote_cal(b: bool) -> i32 { + const fn foo() { [()][42] } + + if b { + let _x: &'static () = &foo(); //~ ERROR temporary value dropped while borrowed + } + 13 +} + +// We do not promote union field accesses in `fn. +union U { x: i32, y: i32 } +pub const fn promote_union() { + let _x: &'static i32 = &unsafe { U { x: 0 }.x }; //~ ERROR temporary value dropped while borrowed +} + +fn main() {} diff --git a/src/test/ui/consts/promote-no-mut.stderr b/src/test/ui/consts/promote-not.stderr similarity index 51% rename from src/test/ui/consts/promote-no-mut.stderr rename to src/test/ui/consts/promote-not.stderr index 49d96546ada3f..efe921b601104 100644 --- a/src/test/ui/consts/promote-no-mut.stderr +++ b/src/test/ui/consts/promote-not.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-no-mut.rs:3:50 + --> $DIR/promote-not.rs:7:50 | LL | static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); | ----------^^^^^^^^^- @@ -9,7 +9,7 @@ LL | static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); | using this value as a static requires that borrow lasts for `'static` error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-no-mut.rs:6:18 + --> $DIR/promote-not.rs:10:18 | LL | let x = &mut [1,2,3]; | ^^^^^^^ creates a temporary which is freed while still in use @@ -18,6 +18,26 @@ LL | x LL | }; | - temporary value is freed at the end of this statement -error: aborting due to 2 previous errors +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:19:32 + | +LL | let _x: &'static () = &foo(); + | ----------- ^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:27:29 + | +LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x }; + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/promotion.rs b/src/test/ui/consts/promotion.rs index 3c5401e421216..5f84030a9e96b 100644 --- a/src/test/ui/consts/promotion.rs +++ b/src/test/ui/consts/promotion.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // compile-flags: -O diff --git a/src/test/ui/statics/static-promotion.rs b/src/test/ui/statics/static-promotion.rs index bd8910bdb3f3f..b9eff469177e6 100644 --- a/src/test/ui/statics/static-promotion.rs +++ b/src/test/ui/statics/static-promotion.rs @@ -1,4 +1,4 @@ -// check-pass +// run-pass // Use of global static variables in literal values should be allowed for // promotion. From 7febd5a25770cb20805f20e43ab0d773ed2834ed Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Sep 2020 13:22:59 +0200 Subject: [PATCH 0678/1052] fix doc comment --- compiler/rustc_mir/src/transform/promote_consts.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index a4a6a7b03aba4..e1d704cb6806c 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -297,10 +297,10 @@ impl std::ops::Deref for Validator<'a, 'tcx> { struct Unpromotable; impl<'tcx> Validator<'_, 'tcx> { - //! Determines if this code could be executed at runtime and thus is subject to codegen. - //! That means even unused constants need to be evaluated. - //! - //! `const_kind` should not be used in this file other than through this method! + /// Determines if this code could be executed at runtime and thus is subject to codegen. + /// That means even unused constants need to be evaluated. + /// + /// `const_kind` should not be used in this file other than through this method! fn maybe_runtime(&self) -> bool { match self.const_kind { None | Some(hir::ConstContext::ConstFn) => true, From 7b99c8e1cf096c1ba71ba3ee58b19527a5b69c1a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Sep 2020 10:00:23 +0200 Subject: [PATCH 0679/1052] never promote non-const operations; revert STATIC promotion change --- .../rustc_mir/src/transform/promote_consts.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index e1d704cb6806c..020857a95fbaa 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -584,6 +584,16 @@ impl<'tcx> Validator<'_, 'tcx> { // `validate_rvalue` upon access. Operand::Constant(c) => { if let Some(def_id) = c.check_static_ptr(self.tcx) { + // Only allow statics (not consts) to refer to other statics. + // FIXME(eddyb) does this matter at all for promotion? + // FIXME(RalfJung) it makes little sense to not promote this in `fn/`const fn`, + // and in `const` this cannot occur anyway. The concern is that we might promote + // even `let x = &STATIC` which would be useless. + let is_static = matches!(self.const_kind, Some(hir::ConstContext::Static(_))); + if !is_static { + return Err(Unpromotable); + } + let is_thread_local = self.tcx.is_thread_local_static(def_id); if is_thread_local { return Err(Unpromotable); @@ -597,20 +607,20 @@ impl<'tcx> Validator<'_, 'tcx> { fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> { match *rvalue { - Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) if self.maybe_runtime() => { + Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => { let operand_ty = operand.ty(self.body, self.tcx); let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); match (cast_in, cast_out) { (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => { - // ptr-to-int casts are not promotable + // ptr-to-int casts are not possible in consts and thus not promotable return Err(Unpromotable); } _ => {} } } - Rvalue::BinaryOp(op, ref lhs, _) if self.maybe_runtime() => { + Rvalue::BinaryOp(op, ref lhs, _) => { if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind() { assert!( op == BinOp::Eq @@ -622,7 +632,7 @@ impl<'tcx> Validator<'_, 'tcx> { || op == BinOp::Offset ); - // raw pointer operations are not allowed inside promoteds + // raw pointer operations are not allowed inside consts and thus not promotable return Err(Unpromotable); } } From 9216eb825839ecd17d67c2731537e5d6afffc54a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Sep 2020 12:57:36 +0200 Subject: [PATCH 0680/1052] fix some comments --- compiler/rustc_mir/src/transform/promote_consts.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index 020857a95fbaa..37202276161c7 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -374,7 +374,7 @@ impl<'tcx> Validator<'_, 'tcx> { // In theory, any zero-sized value could be borrowed // mutably without consequences. However, only &mut [] - // is allowed right now, and only in functions. + // is allowed right now. if let ty::Array(_, len) = ty.kind() { match len.try_eval_usize(self.tcx, self.param_env) { Some(0) => {} @@ -524,7 +524,7 @@ impl<'tcx> Validator<'_, 'tcx> { if let Some(did) = c.check_static_ptr(self.tcx) { // Evaluating a promoted may not read statics except if it got // promoted from a static (this is a CTFE check). So we - // can only promoted static accesses inside statics. + // can only promote static accesses inside statics. if let Some(hir::ConstContext::Static(..)) = self.const_kind { // The `is_empty` predicate is introduced to exclude the case // where the projection operations are [ .field, * ]. @@ -586,9 +586,10 @@ impl<'tcx> Validator<'_, 'tcx> { if let Some(def_id) = c.check_static_ptr(self.tcx) { // Only allow statics (not consts) to refer to other statics. // FIXME(eddyb) does this matter at all for promotion? - // FIXME(RalfJung) it makes little sense to not promote this in `fn/`const fn`, - // and in `const` this cannot occur anyway. The concern is that we might promote - // even `let x = &STATIC` which would be useless. + // FIXME(RalfJung) it makes little sense to not promote this in `fn`/`const fn`, + // and in `const` this cannot occur anyway. The only concern is that we might + // promote even `let x = &STATIC` which would be useless, but this applies to + // promotion inside statics as well. let is_static = matches!(self.const_kind, Some(hir::ConstContext::Static(_))); if !is_static { return Err(Unpromotable); @@ -681,7 +682,7 @@ impl<'tcx> Validator<'_, 'tcx> { // In theory, any zero-sized value could be borrowed // mutably without consequences. However, only &mut [] - // is allowed right now, and only in functions. + // is allowed right now. if let ty::Array(_, len) = ty.kind() { match len.try_eval_usize(self.tcx, self.param_env) { Some(0) => {} From d4039c55c9ef392261aeaba6c14ae81f5098139a Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 19 Sep 2020 22:17:52 +0200 Subject: [PATCH 0681/1052] wip emit errors during AbstractConst building --- compiler/rustc_metadata/src/rmeta/decoder.rs | 5 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 4 +- compiler/rustc_trait_selection/src/lib.rs | 1 + .../src/traits/const_evaluatable.rs | 193 +++++++++++------- 5 files changed, 125 insertions(+), 80 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index a2e2cf1ca0219..72d54a26b01d4 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -11,6 +11,7 @@ use rustc_data_structures::fingerprint::{Fingerprint, FingerprintDecoder}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{AtomicCell, Lock, LockGuard, Lrc, OnceCell}; +use rustc_errors::ErrorReported; use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind}; use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, ProcMacroDerive}; use rustc_hir as hir; @@ -1201,13 +1202,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { &self, tcx: TyCtxt<'tcx>, id: DefIndex, - ) -> Option<&'tcx [mir::abstract_const::Node<'tcx>]> { + ) -> Result]>, ErrorReported> { self.root .tables .mir_abstract_consts .get(self, id) .filter(|_| !self.is_proc_macro(id)) - .map_or(None, |v| Some(v.decode((self, tcx)))) + .map_or(Ok(None), |v| Ok(Some(v.decode((self, tcx))))) } fn get_unused_generic_params(&self, id: DefIndex) -> FiniteBitSet { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index eb091d86b82c6..3500ec7455429 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1117,7 +1117,7 @@ impl EncodeContext<'a, 'tcx> { } let abstract_const = self.tcx.mir_abstract_const(def_id); - if let Some(abstract_const) = abstract_const { + if let Ok(Some(abstract_const)) = abstract_const { record!(self.tables.mir_abstract_consts[def_id.to_def_id()] <- abstract_const); } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 44d906dada5f0..86fb0664a5c62 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -247,7 +247,7 @@ rustc_queries! { /// Try to build an abstract representation of the given constant. query mir_abstract_const( key: DefId - ) -> Option<&'tcx [mir::abstract_const::Node<'tcx>]> { + ) -> Result]>, ErrorReported> { desc { |tcx| "building an abstract representation for {}", tcx.def_path_str(key), } @@ -255,7 +255,7 @@ rustc_queries! { /// Try to build an abstract representation of the given constant. query mir_abstract_const_of_const_arg( key: (LocalDefId, DefId) - ) -> Option<&'tcx [mir::abstract_const::Node<'tcx>]> { + ) -> Result]>, ErrorReported> { desc { |tcx| "building an abstract representation for the const argument {}", diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index da1996b92a60b..a53075448eddc 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -15,6 +15,7 @@ #![feature(box_patterns)] #![feature(drain_filter)] #![feature(in_band_lifetimes)] +#![feature(never_type)] #![feature(crate_visibility_modifier)] #![feature(or_patterns)] #![recursion_limit = "512"] // For rustdoc diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 2642358dbc54c..6c0c1df1b530f 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -8,6 +8,7 @@ //! In this case we try to build an abstract representation of this constant using //! `mir_abstract_const` which can then be checked for structural equality with other //! generic constants mentioned in the `caller_bounds` of the current environment. +use rustc_errors::ErrorReported; use rustc_hir::def::DefKind; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; @@ -31,7 +32,9 @@ pub fn is_const_evaluatable<'cx, 'tcx>( ) -> Result<(), ErrorHandled> { debug!("is_const_evaluatable({:?}, {:?})", def, substs); if infcx.tcx.features().const_evaluatable_checked { - if let Some(ct) = AbstractConst::new(infcx.tcx, def, substs) { + if let Some(ct) = + AbstractConst::new(infcx.tcx, def, substs).map_err(ErrorHandled::Reported)? + { for pred in param_env.caller_bounds() { match pred.skip_binders() { ty::PredicateAtom::ConstEvaluatable(b_def, b_substs) => { @@ -40,6 +43,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( debug!("is_const_evaluatable: caller_bound ~~> ok"); return Ok(()); } else if AbstractConst::new(infcx.tcx, b_def, b_substs) + .map_err(ErrorHandled::Reported)? .map_or(false, |b_ct| try_unify(infcx.tcx, ct, b_ct)) { debug!("is_const_evaluatable: abstract_const ~~> ok"); @@ -114,7 +118,7 @@ impl AbstractConst<'tcx> { tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam, substs: SubstsRef<'tcx>, - ) -> Option> { + ) -> Result>, ErrorReported> { let inner = match (def.did.as_local(), def.const_param_did) { (Some(did), Some(param_did)) => { tcx.mir_abstract_const_of_const_arg((did, param_did))? @@ -122,7 +126,7 @@ impl AbstractConst<'tcx> { _ => tcx.mir_abstract_const(def.did)?, }; - Some(AbstractConst { inner, substs }) + Ok(inner.map(|inner| AbstractConst { inner, substs })) } #[inline] @@ -148,53 +152,85 @@ struct AbstractConstBuilder<'a, 'tcx> { } impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { - fn new(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>) -> Option> { - // We only allow consts without control flow, so - // we check for cycles here which simplifies the - // rest of this implementation. - if body.is_cfg_cyclic() { - return None; + fn error(&mut self, span: Option, msg: &str) -> Result { + let mut err = + self.tcx.sess.struct_span_err(self.body.span, "overly complex generic constant"); + if let Some(span) = span { + err.span_note(span, msg); + } else { + err.note(msg); } + err.help("consider moving this anonymous constant into a `const` function").emit(); - // We don't have to look at concrete constants, as we - // can just evaluate them. - if !body.is_polymorphic { - return None; - } + Err(ErrorReported) + } - Some(AbstractConstBuilder { + fn new( + tcx: TyCtxt<'tcx>, + body: &'a mir::Body<'tcx>, + ) -> Result>, ErrorReported> { + let mut builder = AbstractConstBuilder { tcx, body, nodes: IndexVec::new(), locals: IndexVec::from_elem(NodeId::MAX, &body.local_decls), checked_op_locals: BitSet::new_empty(body.local_decls.len()), - }) + }; + + // We don't have to look at concrete constants, as we + // can just evaluate them. + if !body.is_polymorphic { + return Ok(None); + } + + // We only allow consts without control flow, so + // we check for cycles here which simplifies the + // rest of this implementation. + if body.is_cfg_cyclic() { + builder.error(None, "cyclic anonymous constants are forbidden")?; + } + + Ok(Some(builder)) } - fn operand_to_node(&mut self, op: &mir::Operand<'tcx>) -> Option { - debug!("operand_to_node: op={:?}", op); + + fn place_to_local( + &mut self, + span: Span, + p: &mir::Place<'tcx>, + ) -> Result { const ZERO_FIELD: mir::Field = mir::Field::from_usize(0); + // Do not allow any projections. + // + // One exception are field accesses on the result of checked operations, + // which are required to support things like `1 + 2`. + if let Some(p) = p.as_local() { + debug_assert!(!self.checked_op_locals.contains(p)); + Ok(p) + } else if let &[mir::ProjectionElem::Field(ZERO_FIELD, _)] = p.projection.as_ref() { + // Only allow field accesses if the given local + // contains the result of a checked operation. + if self.checked_op_locals.contains(p.local) { + Ok(p.local) + } else { + self.error(Some(span), "unsupported projection")?; + } + } else { + self.error(Some(span), "unsupported projection")?; + } + } + + fn operand_to_node( + &mut self, + span: Span, + op: &mir::Operand<'tcx>, + ) -> Result { + debug!("operand_to_node: op={:?}", op); match op { mir::Operand::Copy(p) | mir::Operand::Move(p) => { - // Do not allow any projections. - // - // One exception are field accesses on the result of checked operations, - // which are required to support things like `1 + 2`. - if let Some(p) = p.as_local() { - debug_assert!(!self.checked_op_locals.contains(p)); - Some(self.locals[p]) - } else if let &[mir::ProjectionElem::Field(ZERO_FIELD, _)] = p.projection.as_ref() { - // Only allow field accesses if the given local - // contains the result of a checked operation. - if self.checked_op_locals.contains(p.local) { - Some(self.locals[p.local]) - } else { - None - } - } else { - None - } + let local = self.place_to_local(span, p)?; + Ok(self.locals[local]) } - mir::Operand::Constant(ct) => Some(self.nodes.push(Node::Leaf(ct.literal))), + mir::Operand::Constant(ct) => Ok(self.nodes.push(Node::Leaf(ct.literal))), } } @@ -217,44 +253,45 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { } } - fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Option<()> { + fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Result<(), ErrorReported> { debug!("AbstractConstBuilder: stmt={:?}", stmt); match stmt.kind { StatementKind::Assign(box (ref place, ref rvalue)) => { - let local = place.as_local()?; + let local = self.place_to_local(stmt.source_info.span, place)?; match *rvalue { Rvalue::Use(ref operand) => { - self.locals[local] = self.operand_to_node(operand)?; - Some(()) + self.locals[local] = + self.operand_to_node(stmt.source_info.span, operand)?; + Ok(()) } Rvalue::BinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => { - let lhs = self.operand_to_node(lhs)?; - let rhs = self.operand_to_node(rhs)?; + let lhs = self.operand_to_node(stmt.source_info.span, lhs)?; + let rhs = self.operand_to_node(stmt.source_info.span, rhs)?; self.locals[local] = self.nodes.push(Node::Binop(op, lhs, rhs)); if op.is_checkable() { bug!("unexpected unchecked checkable binary operation"); } else { - Some(()) + Ok(()) } } Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => { - let lhs = self.operand_to_node(lhs)?; - let rhs = self.operand_to_node(rhs)?; + let lhs = self.operand_to_node(stmt.source_info.span, lhs)?; + let rhs = self.operand_to_node(stmt.source_info.span, rhs)?; self.locals[local] = self.nodes.push(Node::Binop(op, lhs, rhs)); self.checked_op_locals.insert(local); - Some(()) + Ok(()) } Rvalue::UnaryOp(op, ref operand) if Self::check_unop(op) => { - let operand = self.operand_to_node(operand)?; + let operand = self.operand_to_node(stmt.source_info.span, operand)?; self.locals[local] = self.nodes.push(Node::UnaryOp(op, operand)); - Some(()) + Ok(()) } - _ => None, + _ => self.error(Some(stmt.source_info.span), "unsupported rvalue")?, } } // These are not actually relevant for us here, so we can ignore them. - StatementKind::StorageLive(_) | StatementKind::StorageDead(_) => Some(()), - _ => None, + StatementKind::StorageLive(_) | StatementKind::StorageDead(_) => Ok(()), + _ => self.error(Some(stmt.source_info.span), "unsupported statement")?, } } @@ -266,11 +303,11 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { fn build_terminator( &mut self, terminator: &mir::Terminator<'tcx>, - ) -> Option> { + ) -> Result, ErrorReported> { debug!("AbstractConstBuilder: terminator={:?}", terminator); match terminator.kind { - TerminatorKind::Goto { target } => Some(Some(target)), - TerminatorKind::Return => Some(None), + TerminatorKind::Goto { target } => Ok(Some(target)), + TerminatorKind::Return => Ok(None), TerminatorKind::Call { ref func, ref args, @@ -288,17 +325,17 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { // // This is currently fairly irrelevant as it requires `const Trait`s. from_hir_call: true, - fn_span: _, + fn_span, } => { - let local = place.as_local()?; - let func = self.operand_to_node(func)?; + let local = self.place_to_local(fn_span, place)?; + let func = self.operand_to_node(fn_span, func)?; let args = self.tcx.arena.alloc_from_iter( args.iter() - .map(|arg| self.operand_to_node(arg)) - .collect::>>()?, + .map(|arg| self.operand_to_node(terminator.source_info.span, arg)) + .collect::, _>>()?, ); self.locals[local] = self.nodes.push(Node::FunctionCall(func, args)); - Some(Some(target)) + Ok(Some(target)) } // We only allow asserts for checked operations. // @@ -315,19 +352,19 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { if let &[mir::ProjectionElem::Field(ONE_FIELD, _)] = p.projection.as_ref() { // Only allow asserts checking the result of a checked operation. if self.checked_op_locals.contains(p.local) { - return Some(Some(target)); + return Ok(Some(target)); } } - None + self.error(Some(terminator.source_info.span), "unsupported assertion")?; } - _ => None, + _ => self.error(Some(terminator.source_info.span), "unsupported terminator")?, } } /// Builds the abstract const by walking the mir from start to finish /// and bailing out when encountering an unsupported operation. - fn build(mut self) -> Option<&'tcx [Node<'tcx>]> { + fn build(mut self) -> Result<&'tcx [Node<'tcx>], ErrorReported> { let mut block = &self.body.basic_blocks()[mir::START_BLOCK]; // We checked for a cyclic cfg above, so this should terminate. loop { @@ -339,7 +376,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { if let Some(next) = self.build_terminator(block.terminator())? { block = &self.body.basic_blocks()[next]; } else { - return Some(self.tcx.arena.alloc_from_iter(self.nodes)); + return Ok(self.tcx.arena.alloc_from_iter(self.nodes)); } } } @@ -349,7 +386,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { pub(super) fn mir_abstract_const<'tcx>( tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam, -) -> Option<&'tcx [Node<'tcx>]> { +) -> Result]>, ErrorReported> { if tcx.features().const_evaluatable_checked { match tcx.def_kind(def.did) { // FIXME(const_evaluatable_checked): We currently only do this for anonymous constants, @@ -358,12 +395,12 @@ pub(super) fn mir_abstract_const<'tcx>( // // Right now we do neither of that and simply always fail to unify them. DefKind::AnonConst => (), - _ => return None, + _ => return Ok(None), } let body = tcx.mir_const(def).borrow(); - AbstractConstBuilder::new(tcx, &body)?.build() + AbstractConstBuilder::new(tcx, &body)?.map(AbstractConstBuilder::build).transpose() } else { - None + Ok(None) } } @@ -374,13 +411,19 @@ pub(super) fn try_unify_abstract_consts<'tcx>( (ty::WithOptConstParam, SubstsRef<'tcx>), ), ) -> bool { - if let Some(a) = AbstractConst::new(tcx, a, a_substs) { - if let Some(b) = AbstractConst::new(tcx, b, b_substs) { - return try_unify(tcx, a, b); + (|| { + if let Some(a) = AbstractConst::new(tcx, a, a_substs)? { + if let Some(b) = AbstractConst::new(tcx, b, b_substs)? { + return Ok(try_unify(tcx, a, b)); + } } - } - false + Ok(false) + })() + .unwrap_or_else(|ErrorReported| true) + // FIXME(const_evaluatable_checked): We should instead have this + // method return the resulting `ty::Const` and return `ConstKind::Error` + // on `Error`. } /// Tries to unify two abstract constants using structural equality. From 30cbc9729654c66b9f54779d18f023e47112cdf2 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 19 Sep 2020 22:27:52 +0200 Subject: [PATCH 0682/1052] words --- compiler/rustc_trait_selection/src/traits/const_evaluatable.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 6c0c1df1b530f..12082475c85d4 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -423,7 +423,7 @@ pub(super) fn try_unify_abstract_consts<'tcx>( .unwrap_or_else(|ErrorReported| true) // FIXME(const_evaluatable_checked): We should instead have this // method return the resulting `ty::Const` and return `ConstKind::Error` - // on `Error`. + // on `ErrorReported`. } /// Tries to unify two abstract constants using structural equality. From 367efa86d5df6c4aacbd0f1b28c4008527722d4c Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 19 Sep 2020 16:25:50 -0400 Subject: [PATCH 0683/1052] Don't allow implementing trait directly on type-alias-impl-trait This is specifically disallowed by the RFC, but we never added a check for it. Fixes #76202 --- compiler/rustc_typeck/src/coherence/orphan.rs | 8 +++++++ .../issue-76202-trait-impl-for-tait.rs | 23 +++++++++++++++++++ .../issue-76202-trait-impl-for-tait.stderr | 14 +++++++++++ 3 files changed, 45 insertions(+) create mode 100644 src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs create mode 100644 src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.stderr diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs index fa3137567ad08..917fc5631c4f5 100644 --- a/compiler/rustc_typeck/src/coherence/orphan.rs +++ b/compiler/rustc_typeck/src/coherence/orphan.rs @@ -230,6 +230,14 @@ impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> { return; } } + + if let ty::Opaque(def_id, _) = *trait_ref.self_ty().kind() { + self.tcx + .sess + .struct_span_err(sp, "cannot implement trait on type alias impl trait") + .span_note(self.tcx.def_span(def_id), "type alias impl trait defined here") + .emit(); + } } } diff --git a/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs b/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs new file mode 100644 index 0000000000000..9ce19536e7949 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs @@ -0,0 +1,23 @@ +// Regression test for issue #76202 +// Tests that we don't ICE when we have a trait impl on a TAIT. + +#![feature(type_alias_impl_trait)] + +trait Dummy {} +impl Dummy for () {} + +type F = impl Dummy; +fn f() -> F {} + +trait Test { + fn test(self); +} + +impl Test for F { //~ ERROR cannot implement trait + fn test(self) {} +} + +fn main() { + let x: F = f(); + x.test(); +} diff --git a/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.stderr b/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.stderr new file mode 100644 index 0000000000000..8689ee53660f6 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.stderr @@ -0,0 +1,14 @@ +error: cannot implement trait on type alias impl trait + --> $DIR/issue-76202-trait-impl-for-tait.rs:16:1 + | +LL | impl Test for F { + | ^^^^^^^^^^^^^^^ + | +note: type alias impl trait defined here + --> $DIR/issue-76202-trait-impl-for-tait.rs:9:10 + | +LL | type F = impl Dummy; + | ^^^^^^^^^^ + +error: aborting due to previous error + From a875c7a1ea31f86d4a796209f50303564ce15a16 Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Sat, 19 Sep 2020 23:22:54 +0200 Subject: [PATCH 0684/1052] Add assertion for len of vecs --- compiler/rustc_mir/src/transform/simplify_try.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir/src/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs index bf6fdebb3d3c7..4935997eb82a5 100644 --- a/compiler/rustc_mir/src/transform/simplify_try.rs +++ b/compiler/rustc_mir/src/transform/simplify_try.rs @@ -568,14 +568,15 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { .basic_blocks() .iter_enumerated() .filter_map(|(bb_idx, bb)| { - let (discr_switched_on, targets_and_values):(_, Vec<_>) = match &bb.terminator().kind { + let (discr_switched_on, targets_and_values) = match &bb.terminator().kind { TerminatorKind::SwitchInt { targets, discr, values, .. } => { // if values.len() == targets.len() - 1, we need to include None where no value is present // such that the zip does not throw away targets. If no `otherwise` case is in targets, the zip will simply throw away the added None let values_extended = values.iter().map(|x|Some(*x)).chain(once(None)); - let targets_and_values = targets.iter().zip(values_extended) - .map(|(target, value)| SwitchTargetAndValue{target:*target, value:value}) + let targets_and_values:Vec<_> = targets.iter().zip(values_extended) + .map(|(target, value)| SwitchTargetAndValue{target:*target, value}) .collect(); + assert_eq!(targets.len(), targets_and_values.len()); (discr, targets_and_values)}, _ => return None, }; From f9fa649545bcf16ffbfc47a24fa7c6001d4eea2c Mon Sep 17 00:00:00 2001 From: Denis Vasilik Date: Fri, 18 Sep 2020 11:05:26 +0200 Subject: [PATCH 0685/1052] Use intra-doc links --- library/alloc/src/collections/btree/map.rs | 18 +++++++----------- library/alloc/src/collections/linked_list.rs | 2 +- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index aed898be08fb6..3e6a4e4ead6e8 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -47,7 +47,6 @@ use UnderflowResult::*; /// any other key, as determined by the [`Ord`] trait, changes while it is in the map. This is /// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. /// -/// [`Ord`]: core::cmp::Ord /// [`Cell`]: core::cell::Cell /// [`RefCell`]: core::cell::RefCell /// @@ -93,9 +92,10 @@ use UnderflowResult::*; /// } /// ``` /// -/// `BTreeMap` also implements an [`Entry API`](#method.entry), which allows -/// for more complex methods of getting, setting, updating and removing keys and -/// their values: +/// `BTreeMap` also implements an [`Entry API`], which allows for more complex +/// methods of getting, setting, updating and removing keys and their values: +/// +/// [`Entry API`]: BTreeMap::entry /// /// ``` /// use std::collections::BTreeMap; @@ -453,8 +453,6 @@ impl Debug for Entry<'_, K, V> { /// A view into a vacant entry in a `BTreeMap`. /// It is part of the [`Entry`] enum. -/// -/// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] pub struct VacantEntry<'a, K: 'a, V: 'a> { key: K, @@ -474,8 +472,6 @@ impl Debug for VacantEntry<'_, K, V> { /// A view into an occupied entry in a `BTreeMap`. /// It is part of the [`Entry`] enum. -/// -/// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] pub struct OccupiedEntry<'a, K: 'a, V: 'a> { handle: Handle, K, V, marker::LeafOrInternal>, marker::KV>, @@ -815,7 +811,7 @@ impl BTreeMap { /// types that can be `==` without being identical. See the [module-level /// documentation] for more. /// - /// [module-level documentation]: index.html#insert-and-complex-keys + /// [module-level documentation]: crate::collections#insert-and-complex-keys /// /// # Examples /// @@ -2554,7 +2550,7 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { /// If you need a reference to the `OccupiedEntry` that may outlive the /// destruction of the `Entry` value, see [`into_mut`]. /// - /// [`into_mut`]: #method.into_mut + /// [`into_mut`]: OccupiedEntry::into_mut /// /// # Examples /// @@ -2584,7 +2580,7 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { /// /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. /// - /// [`get_mut`]: #method.get_mut + /// [`get_mut`]: OccupiedEntry::get_mut /// /// # Examples /// diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 5390b57a1d98d..412c65681e684 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -102,7 +102,7 @@ impl fmt::Debug for IterMut<'_, T> { /// This `struct` is created by the [`into_iter`] method on [`LinkedList`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// -/// [`into_iter`]: struct.LinkedList.html#method.into_iter +/// [`into_iter`]: LinkedList::into_iter #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { From 389b7ff19074988a3855bbc5ba7b19eb903a6fb4 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Wed, 16 Sep 2020 17:57:20 -0400 Subject: [PATCH 0686/1052] Do not link LLVM tools to LLVM dylib unless rustc is Previously we would have some platforms where LLVM was linked to rustc statically, but to the LLVM tools dynamically. That meant we were distributing two copies of LLVM: one as a separate dylib and one statically linked in to librustc_driver. --- src/bootstrap/dist.rs | 13 +++++-------- src/bootstrap/native.rs | 11 ++++++++--- src/ci/run.sh | 7 ------- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index debe6e36a9b2e..044507c398f2f 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -2401,14 +2401,11 @@ fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir return; } - // On macOS for some reason the llvm-config binary behaves differently and - // and fails on missing .a files if run without --link-shared. If run with - // that option, it still fails, but because we only ship a libLLVM.dylib - // rather than libLLVM-11-rust-....dylib file. - // - // For now just don't use llvm-config here on macOS; that will fail to - // support CI-built LLVM, but until we work out the different behavior that - // is fine as it is off by default. + // On macOS, rustc (and LLVM tools) link to an unversioned libLLVM.dylib + // instead of libLLVM-11-rust-....dylib, as on linux. It's not entirely + // clear why this is the case, though. llvm-config will emit the versioned + // paths and we don't want those in the sysroot (as we're expecting + // unversioned paths). if target.contains("apple-darwin") { let src_libdir = builder.llvm_out(target).join("lib"); let llvm_dylib_path = src_libdir.join("libLLVM.dylib"); diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 3829d47da335f..71b35c0433a9c 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -129,8 +129,10 @@ impl Step for Llvm { Err(m) => m, }; - if builder.config.llvm_link_shared && target.contains("windows") { - panic!("shared linking to LLVM is not currently supported on Windows"); + if builder.config.llvm_link_shared + && (target.contains("windows") || target.contains("apple-darwin")) + { + panic!("shared linking to LLVM is not currently supported on {}", target.triple); } builder.info(&format!("Building LLVM for {}", target)); @@ -209,7 +211,10 @@ impl Step for Llvm { // which saves both memory during parallel links and overall disk space // for the tools. We don't do this on every platform as it doesn't work // equally well everywhere. - if builder.llvm_link_tools_dynamically(target) { + // + // If we're not linking rustc to a dynamic LLVM, though, then don't link + // tools to it. + if builder.llvm_link_tools_dynamically(target) && builder.config.llvm_link_shared { cfg.define("LLVM_LINK_LLVM_DYLIB", "ON"); } diff --git a/src/ci/run.sh b/src/ci/run.sh index c8faf1ec83179..5231aa2e76619 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -75,13 +75,6 @@ if [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.remap-debuginfo" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --debuginfo-level-std=1" - # If we're distributing binaries, we want a shared LLVM link. We're already - # going to link LLVM to the LLVM tools dynamically, so we need to ship a - # libLLVM library anyway. - if !isWindows; then - RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set llvm.link-shared=true" - fi - if [ "$NO_LLVM_ASSERTIONS" = "1" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-assertions" elif [ "$DEPLOY_ALT" != "" ]; then From 924cd135b6ab0fe48dae26d9ae30eaadebcd066d Mon Sep 17 00:00:00 2001 From: Giacomo Stevanato Date: Sat, 5 Sep 2020 23:16:56 +0200 Subject: [PATCH 0687/1052] Added benchmarks for BinaryHeap --- library/alloc/benches/binary_heap.rs | 91 ++++++++++++++++++++++++++++ library/alloc/benches/lib.rs | 1 + 2 files changed, 92 insertions(+) create mode 100644 library/alloc/benches/binary_heap.rs diff --git a/library/alloc/benches/binary_heap.rs b/library/alloc/benches/binary_heap.rs new file mode 100644 index 0000000000000..5b6538ea6c6b3 --- /dev/null +++ b/library/alloc/benches/binary_heap.rs @@ -0,0 +1,91 @@ +use std::collections::BinaryHeap; + +use rand::{seq::SliceRandom, thread_rng}; +use test::{black_box, Bencher}; + +#[bench] +fn bench_find_smallest_1000(b: &mut Bencher) { + let mut rng = thread_rng(); + let mut vec: Vec = (0..100_000).collect(); + vec.shuffle(&mut rng); + + b.iter(|| { + let mut iter = vec.iter().copied(); + let mut heap: BinaryHeap<_> = iter.by_ref().take(1000).collect(); + + for x in iter { + let mut max = heap.peek_mut().unwrap(); + // This comparison should be true only 1% of the time. + // Unnecessary `sift_down`s will degrade performance + if x < *max { + *max = x; + } + } + + heap + }) +} + +#[bench] +fn bench_peek_mut_deref_mut(b: &mut Bencher) { + let mut bheap = BinaryHeap::from(vec![42]); + let vec: Vec = (0..1_000_000).collect(); + + b.iter(|| { + let vec = black_box(&vec); + let mut peek_mut = bheap.peek_mut().unwrap(); + // The compiler shouldn't be able to optimize away the `sift_down` + // assignment in `PeekMut`'s `DerefMut` implementation since + // the loop may not run. + for &i in vec.iter() { + *peek_mut = i; + } + // Remove the already minimal overhead of the sift_down + std::mem::forget(peek_mut); + }) +} + +#[bench] +fn bench_from_vec(b: &mut Bencher) { + let mut rng = thread_rng(); + let mut vec: Vec = (0..100_000).collect(); + vec.shuffle(&mut rng); + + b.iter(|| BinaryHeap::from(vec.clone())) +} + +#[bench] +fn bench_into_sorted_vec(b: &mut Bencher) { + let bheap: BinaryHeap = (0..10_000).collect(); + + b.iter(|| bheap.clone().into_sorted_vec()) +} + +#[bench] +fn bench_push(b: &mut Bencher) { + let mut bheap = BinaryHeap::with_capacity(50_000); + let mut rng = thread_rng(); + let mut vec: Vec = (0..50_000).collect(); + vec.shuffle(&mut rng); + + b.iter(|| { + for &i in vec.iter() { + bheap.push(i); + } + black_box(&mut bheap); + bheap.clear(); + }) +} + +#[bench] +fn bench_pop(b: &mut Bencher) { + let mut bheap = BinaryHeap::with_capacity(10_000); + + b.iter(|| { + bheap.extend((0..10_000).rev()); + black_box(&mut bheap); + while let Some(elem) = bheap.pop() { + black_box(elem); + } + }) +} diff --git a/library/alloc/benches/lib.rs b/library/alloc/benches/lib.rs index 608eafc88d2a6..32edb86d10119 100644 --- a/library/alloc/benches/lib.rs +++ b/library/alloc/benches/lib.rs @@ -8,6 +8,7 @@ extern crate test; +mod binary_heap; mod btree; mod linked_list; mod slice; From af1e3633f734930a50000cc424fbcdc6629885c3 Mon Sep 17 00:00:00 2001 From: Giacomo Stevanato Date: Wed, 26 Aug 2020 23:52:20 +0200 Subject: [PATCH 0688/1052] Set sift=true only when PeekMut yields a mutable reference --- library/alloc/src/collections/binary_heap.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index 477a598ff5b00..e3b738a70c888 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -293,6 +293,7 @@ impl Deref for PeekMut<'_, T> { impl DerefMut for PeekMut<'_, T> { fn deref_mut(&mut self) -> &mut T { debug_assert!(!self.heap.is_empty()); + self.sift = true; // SAFE: PeekMut is only instantiated for non-empty heaps unsafe { self.heap.data.get_unchecked_mut(0) } } @@ -401,7 +402,7 @@ impl BinaryHeap { /// Cost is *O*(1) in the worst case. #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] pub fn peek_mut(&mut self) -> Option> { - if self.is_empty() { None } else { Some(PeekMut { heap: self, sift: true }) } + if self.is_empty() { None } else { Some(PeekMut { heap: self, sift: false }) } } /// Removes the greatest item from the binary heap and returns it, or `None` if it From ca15e9d8a11e7c25eb85930d1da3009647c1680e Mon Sep 17 00:00:00 2001 From: Giacomo Stevanato Date: Sun, 20 Sep 2020 01:07:34 +0200 Subject: [PATCH 0689/1052] Fix time complexity in BinaryHeap::peek_mut docs --- library/alloc/src/collections/binary_heap.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index e3b738a70c888..06e5ac037ca79 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -399,7 +399,8 @@ impl BinaryHeap { /// /// # Time complexity /// - /// Cost is *O*(1) in the worst case. + /// If the item is modified then the worst case time complexity is *O*(log(*n*)), + /// otherwise it's *O*(1). #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] pub fn peek_mut(&mut self) -> Option> { if self.is_empty() { None } else { Some(PeekMut { heap: self, sift: false }) } From 65edf54c256e5369fdf9c0a972cd83d2414d5bb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sun, 20 Sep 2020 00:00:00 +0000 Subject: [PATCH 0690/1052] Add a regression test for copy propagation miscompilation --- .../ui/mir/issue-76740-copy-propagation.rs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/test/ui/mir/issue-76740-copy-propagation.rs diff --git a/src/test/ui/mir/issue-76740-copy-propagation.rs b/src/test/ui/mir/issue-76740-copy-propagation.rs new file mode 100644 index 0000000000000..e3283949b2688 --- /dev/null +++ b/src/test/ui/mir/issue-76740-copy-propagation.rs @@ -0,0 +1,30 @@ +// Regression test for issue #76740. +// run-fail FIXME: change to run-pass once #76899 lands +// compile-flags: -Zmir-opt-level=3 + +#[derive(Copy, Clone)] +pub struct V([usize; 4]); + +impl V { + fn new() -> Self { + V([0; 4]) + } + + #[inline(never)] + fn check(mut self) { + assert_eq!(self.0[0], 0); + self.0[0] = 1; + } +} + +fn main() { + let v = V::new(); + let mut i = 0; + while i != 10 { + // Copy propagation incorrectly assumed that Operand::Move does not + // mutate the local, and used the same v for each V::check call, + // rather than a copy. + v.check(); + i += 1; + } +} From ab4fa215b91491be0a7d2c3630efce7a6edb971d Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Sun, 20 Sep 2020 03:32:36 +0200 Subject: [PATCH 0691/1052] Update Clippy testcases Update the test `redundant_pattern_matching`: check if `is_ok` and `is_err` are suggested within const contexts. Also removes the `redundant_pattern_matching_const_result` test, as it is no longer needed. --- .../tests/ui/redundant_pattern_matching.fixed | 35 +++++------ .../tests/ui/redundant_pattern_matching.rs | 41 +++++++------ .../ui/redundant_pattern_matching.stderr | 60 ++++++++++++++++--- ...undant_pattern_matching_const_result.fixed | 44 -------------- ...redundant_pattern_matching_const_result.rs | 50 ---------------- ...ndant_pattern_matching_const_result.stderr | 46 -------------- 6 files changed, 93 insertions(+), 183 deletions(-) delete mode 100644 src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.fixed delete mode 100644 src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.rs delete mode 100644 src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.stderr diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching.fixed index adbff8af8d9ca..08bfe7c78d38b 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching.fixed +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching.fixed @@ -77,6 +77,7 @@ fn main() { issue5504(); issue5697(); + issue6067(); let _ = if gen_opt().is_some() { 1 @@ -131,31 +132,14 @@ fn issue5504() { // None of these should be linted because none of the suggested methods // are `const fn` without toggling a feature. const fn issue5697() { - if let Ok(_) = Ok::(42) {} - - if let Err(_) = Err::(42) {} - if let Some(_) = Some(42) {} if let None = None::<()> {} - while let Ok(_) = Ok::(10) {} - - while let Err(_) = Ok::(10) {} - while let Some(_) = Some(42) {} while let None = None::<()> {} - match Ok::(42) { - Ok(_) => true, - Err(_) => false, - }; - - match Err::(42) { - Ok(_) => false, - Err(_) => true, - }; match Some(42) { Some(_) => true, None => false, @@ -166,3 +150,20 @@ const fn issue5697() { None => true, }; } + +// Methods that are unstable const should not be suggested within a const context, see issue #5697. +// However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result` were stabilized as const, +// so the following should be linted. +const fn issue6067() { + if Ok::(42).is_ok() {} + + if Err::(42).is_err() {} + + while Ok::(10).is_ok() {} + + while Ok::(10).is_err() {} + + Ok::(42).is_ok(); + + Err::(42).is_err(); +} diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching.rs index 4c2870e7803cb..c0660c6ac3947 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching.rs +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching.rs @@ -98,6 +98,7 @@ fn main() { issue5504(); issue5697(); + issue6067(); let _ = if let Some(_) = gen_opt() { 1 @@ -152,31 +153,14 @@ fn issue5504() { // None of these should be linted because none of the suggested methods // are `const fn` without toggling a feature. const fn issue5697() { - if let Ok(_) = Ok::(42) {} - - if let Err(_) = Err::(42) {} - if let Some(_) = Some(42) {} if let None = None::<()> {} - while let Ok(_) = Ok::(10) {} - - while let Err(_) = Ok::(10) {} - while let Some(_) = Some(42) {} while let None = None::<()> {} - match Ok::(42) { - Ok(_) => true, - Err(_) => false, - }; - - match Err::(42) { - Ok(_) => false, - Err(_) => true, - }; match Some(42) { Some(_) => true, None => false, @@ -187,3 +171,26 @@ const fn issue5697() { None => true, }; } + +// Methods that are unstable const should not be suggested within a const context, see issue #5697. +// However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result` were stabilized as const, +// so the following should be linted. +const fn issue6067() { + if let Ok(_) = Ok::(42) {} + + if let Err(_) = Err::(42) {} + + while let Ok(_) = Ok::(10) {} + + while let Err(_) = Ok::(10) {} + + match Ok::(42) { + Ok(_) => true, + Err(_) => false, + }; + + match Err::(42) { + Ok(_) => false, + Err(_) => true, + }; +} diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching.stderr index d3c9ceaa3d7c1..efd2f9903ec9c 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching.stderr +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching.stderr @@ -149,52 +149,94 @@ LL | let x = if let Some(_) = opt { true } else { false }; | -------^^^^^^^------ help: try this: `if opt.is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:102:20 + --> $DIR/redundant_pattern_matching.rs:103:20 | LL | let _ = if let Some(_) = gen_opt() { | -------^^^^^^^------------ help: try this: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:104:19 + --> $DIR/redundant_pattern_matching.rs:105:19 | LL | } else if let None = gen_opt() { | -------^^^^------------ help: try this: `if gen_opt().is_none()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:106:19 + --> $DIR/redundant_pattern_matching.rs:107:19 | LL | } else if let Ok(_) = gen_res() { | -------^^^^^------------ help: try this: `if gen_res().is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:108:19 + --> $DIR/redundant_pattern_matching.rs:109: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:141:19 + --> $DIR/redundant_pattern_matching.rs:142: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:142:16 + --> $DIR/redundant_pattern_matching.rs:143: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:148:12 + --> $DIR/redundant_pattern_matching.rs:149: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:149:15 + --> $DIR/redundant_pattern_matching.rs:150:15 | LL | while let Some(_) = m!() {} | ----------^^^^^^^------- help: try this: `while m!().is_some()` -error: aborting due to 29 previous errors +error: redundant pattern matching, consider using `is_ok()` + --> $DIR/redundant_pattern_matching.rs:179:12 + | +LL | if let Ok(_) = Ok::(42) {} + | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` + +error: redundant pattern matching, consider using `is_err()` + --> $DIR/redundant_pattern_matching.rs:181:12 + | +LL | if let Err(_) = Err::(42) {} + | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` + +error: redundant pattern matching, consider using `is_ok()` + --> $DIR/redundant_pattern_matching.rs:183:15 + | +LL | while let Ok(_) = Ok::(10) {} + | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` + +error: redundant pattern matching, consider using `is_err()` + --> $DIR/redundant_pattern_matching.rs:185:15 + | +LL | while let Err(_) = Ok::(10) {} + | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` + +error: redundant pattern matching, consider using `is_ok()` + --> $DIR/redundant_pattern_matching.rs:187:5 + | +LL | / match Ok::(42) { +LL | | Ok(_) => true, +LL | | Err(_) => false, +LL | | }; + | |_____^ help: try this: `Ok::(42).is_ok()` + +error: redundant pattern matching, consider using `is_err()` + --> $DIR/redundant_pattern_matching.rs:192:5 + | +LL | / match Err::(42) { +LL | | Ok(_) => false, +LL | | Err(_) => true, +LL | | }; + | |_____^ help: try this: `Err::(42).is_err()` + +error: aborting due to 35 previous errors diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.fixed deleted file mode 100644 index de3fe00d5fa68..0000000000000 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.fixed +++ /dev/null @@ -1,44 +0,0 @@ -// run-rustfix - -#![feature(const_result)] -#![warn(clippy::redundant_pattern_matching)] -#![allow(clippy::match_like_matches_macro, unused)] - -// Test that results are linted with the feature enabled. - -const fn issue_5697() { - if Ok::(42).is_ok() {} - - if Err::(42).is_err() {} - - while Ok::(10).is_ok() {} - - while Ok::(10).is_err() {} - - Ok::(42).is_ok(); - - Err::(42).is_err(); - - // These should not be linted until `const_option` is implemented. - // See https://github.com/rust-lang/rust/issues/67441 - - if let Some(_) = Some(42) {} - - if let None = None::<()> {} - - while let Some(_) = Some(42) {} - - while let None = None::<()> {} - - match Some(42) { - Some(_) => true, - None => false, - }; - - match None::<()> { - Some(_) => false, - None => true, - }; -} - -fn main() {} diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.rs deleted file mode 100644 index b77969d53d92d..0000000000000 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.rs +++ /dev/null @@ -1,50 +0,0 @@ -// run-rustfix - -#![feature(const_result)] -#![warn(clippy::redundant_pattern_matching)] -#![allow(clippy::match_like_matches_macro, unused)] - -// Test that results are linted with the feature enabled. - -const fn issue_5697() { - if let Ok(_) = Ok::(42) {} - - if let Err(_) = Err::(42) {} - - while let Ok(_) = Ok::(10) {} - - while let Err(_) = Ok::(10) {} - - match Ok::(42) { - Ok(_) => true, - Err(_) => false, - }; - - match Err::(42) { - Ok(_) => false, - Err(_) => true, - }; - - // These should not be linted until `const_option` is implemented. - // See https://github.com/rust-lang/rust/issues/67441 - - if let Some(_) = Some(42) {} - - if let None = None::<()> {} - - while let Some(_) = Some(42) {} - - while let None = None::<()> {} - - match Some(42) { - Some(_) => true, - None => false, - }; - - match None::<()> { - Some(_) => false, - None => true, - }; -} - -fn main() {} diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.stderr deleted file mode 100644 index 8ecd72158d33c..0000000000000 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.stderr +++ /dev/null @@ -1,46 +0,0 @@ -error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_const_result.rs:10:12 - | -LL | if let Ok(_) = Ok::(42) {} - | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` - | - = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` - -error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_const_result.rs:12:12 - | -LL | if let Err(_) = Err::(42) {} - | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` - -error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_const_result.rs:14:15 - | -LL | while let Ok(_) = Ok::(10) {} - | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` - -error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_const_result.rs:16:15 - | -LL | while let Err(_) = Ok::(10) {} - | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` - -error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_const_result.rs:18:5 - | -LL | / match Ok::(42) { -LL | | Ok(_) => true, -LL | | Err(_) => false, -LL | | }; - | |_____^ help: try this: `Ok::(42).is_ok()` - -error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_const_result.rs:23:5 - | -LL | / match Err::(42) { -LL | | Ok(_) => false, -LL | | Err(_) => true, -LL | | }; - | |_____^ help: try this: `Err::(42).is_err()` - -error: aborting due to 6 previous errors - From 10d272b2e2678544f108d6ce573333cd11c27234 Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Sun, 20 Sep 2020 03:32:36 +0200 Subject: [PATCH 0692/1052] Update Clippy testcases Update the test `redundant_pattern_matching`: check if `is_ok` and `is_err` are suggested within const contexts. Also removes the `redundant_pattern_matching_const_result` test, as it is no longer needed. --- tests/ui/redundant_pattern_matching.fixed | 35 +++++------ tests/ui/redundant_pattern_matching.rs | 41 +++++++------ tests/ui/redundant_pattern_matching.stderr | 60 ++++++++++++++++--- ...undant_pattern_matching_const_result.fixed | 44 -------------- ...redundant_pattern_matching_const_result.rs | 50 ---------------- ...ndant_pattern_matching_const_result.stderr | 46 -------------- 6 files changed, 93 insertions(+), 183 deletions(-) delete mode 100644 tests/ui/redundant_pattern_matching_const_result.fixed delete mode 100644 tests/ui/redundant_pattern_matching_const_result.rs delete mode 100644 tests/ui/redundant_pattern_matching_const_result.stderr diff --git a/tests/ui/redundant_pattern_matching.fixed b/tests/ui/redundant_pattern_matching.fixed index adbff8af8d9ca..08bfe7c78d38b 100644 --- a/tests/ui/redundant_pattern_matching.fixed +++ b/tests/ui/redundant_pattern_matching.fixed @@ -77,6 +77,7 @@ fn main() { issue5504(); issue5697(); + issue6067(); let _ = if gen_opt().is_some() { 1 @@ -131,31 +132,14 @@ fn issue5504() { // None of these should be linted because none of the suggested methods // are `const fn` without toggling a feature. const fn issue5697() { - if let Ok(_) = Ok::(42) {} - - if let Err(_) = Err::(42) {} - if let Some(_) = Some(42) {} if let None = None::<()> {} - while let Ok(_) = Ok::(10) {} - - while let Err(_) = Ok::(10) {} - while let Some(_) = Some(42) {} while let None = None::<()> {} - match Ok::(42) { - Ok(_) => true, - Err(_) => false, - }; - - match Err::(42) { - Ok(_) => false, - Err(_) => true, - }; match Some(42) { Some(_) => true, None => false, @@ -166,3 +150,20 @@ const fn issue5697() { None => true, }; } + +// Methods that are unstable const should not be suggested within a const context, see issue #5697. +// However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result` were stabilized as const, +// so the following should be linted. +const fn issue6067() { + if Ok::(42).is_ok() {} + + if Err::(42).is_err() {} + + while Ok::(10).is_ok() {} + + while Ok::(10).is_err() {} + + Ok::(42).is_ok(); + + Err::(42).is_err(); +} diff --git a/tests/ui/redundant_pattern_matching.rs b/tests/ui/redundant_pattern_matching.rs index 4c2870e7803cb..c0660c6ac3947 100644 --- a/tests/ui/redundant_pattern_matching.rs +++ b/tests/ui/redundant_pattern_matching.rs @@ -98,6 +98,7 @@ fn main() { issue5504(); issue5697(); + issue6067(); let _ = if let Some(_) = gen_opt() { 1 @@ -152,31 +153,14 @@ fn issue5504() { // None of these should be linted because none of the suggested methods // are `const fn` without toggling a feature. const fn issue5697() { - if let Ok(_) = Ok::(42) {} - - if let Err(_) = Err::(42) {} - if let Some(_) = Some(42) {} if let None = None::<()> {} - while let Ok(_) = Ok::(10) {} - - while let Err(_) = Ok::(10) {} - while let Some(_) = Some(42) {} while let None = None::<()> {} - match Ok::(42) { - Ok(_) => true, - Err(_) => false, - }; - - match Err::(42) { - Ok(_) => false, - Err(_) => true, - }; match Some(42) { Some(_) => true, None => false, @@ -187,3 +171,26 @@ const fn issue5697() { None => true, }; } + +// Methods that are unstable const should not be suggested within a const context, see issue #5697. +// However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result` were stabilized as const, +// so the following should be linted. +const fn issue6067() { + if let Ok(_) = Ok::(42) {} + + if let Err(_) = Err::(42) {} + + while let Ok(_) = Ok::(10) {} + + while let Err(_) = Ok::(10) {} + + match Ok::(42) { + Ok(_) => true, + Err(_) => false, + }; + + match Err::(42) { + Ok(_) => false, + Err(_) => true, + }; +} diff --git a/tests/ui/redundant_pattern_matching.stderr b/tests/ui/redundant_pattern_matching.stderr index d3c9ceaa3d7c1..efd2f9903ec9c 100644 --- a/tests/ui/redundant_pattern_matching.stderr +++ b/tests/ui/redundant_pattern_matching.stderr @@ -149,52 +149,94 @@ LL | let x = if let Some(_) = opt { true } else { false }; | -------^^^^^^^------ help: try this: `if opt.is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:102:20 + --> $DIR/redundant_pattern_matching.rs:103:20 | LL | let _ = if let Some(_) = gen_opt() { | -------^^^^^^^------------ help: try this: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:104:19 + --> $DIR/redundant_pattern_matching.rs:105:19 | LL | } else if let None = gen_opt() { | -------^^^^------------ help: try this: `if gen_opt().is_none()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:106:19 + --> $DIR/redundant_pattern_matching.rs:107:19 | LL | } else if let Ok(_) = gen_res() { | -------^^^^^------------ help: try this: `if gen_res().is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:108:19 + --> $DIR/redundant_pattern_matching.rs:109: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:141:19 + --> $DIR/redundant_pattern_matching.rs:142: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:142:16 + --> $DIR/redundant_pattern_matching.rs:143: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:148:12 + --> $DIR/redundant_pattern_matching.rs:149: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:149:15 + --> $DIR/redundant_pattern_matching.rs:150:15 | LL | while let Some(_) = m!() {} | ----------^^^^^^^------- help: try this: `while m!().is_some()` -error: aborting due to 29 previous errors +error: redundant pattern matching, consider using `is_ok()` + --> $DIR/redundant_pattern_matching.rs:179:12 + | +LL | if let Ok(_) = Ok::(42) {} + | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` + +error: redundant pattern matching, consider using `is_err()` + --> $DIR/redundant_pattern_matching.rs:181:12 + | +LL | if let Err(_) = Err::(42) {} + | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` + +error: redundant pattern matching, consider using `is_ok()` + --> $DIR/redundant_pattern_matching.rs:183:15 + | +LL | while let Ok(_) = Ok::(10) {} + | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` + +error: redundant pattern matching, consider using `is_err()` + --> $DIR/redundant_pattern_matching.rs:185:15 + | +LL | while let Err(_) = Ok::(10) {} + | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` + +error: redundant pattern matching, consider using `is_ok()` + --> $DIR/redundant_pattern_matching.rs:187:5 + | +LL | / match Ok::(42) { +LL | | Ok(_) => true, +LL | | Err(_) => false, +LL | | }; + | |_____^ help: try this: `Ok::(42).is_ok()` + +error: redundant pattern matching, consider using `is_err()` + --> $DIR/redundant_pattern_matching.rs:192:5 + | +LL | / match Err::(42) { +LL | | Ok(_) => false, +LL | | Err(_) => true, +LL | | }; + | |_____^ help: try this: `Err::(42).is_err()` + +error: aborting due to 35 previous errors diff --git a/tests/ui/redundant_pattern_matching_const_result.fixed b/tests/ui/redundant_pattern_matching_const_result.fixed deleted file mode 100644 index de3fe00d5fa68..0000000000000 --- a/tests/ui/redundant_pattern_matching_const_result.fixed +++ /dev/null @@ -1,44 +0,0 @@ -// run-rustfix - -#![feature(const_result)] -#![warn(clippy::redundant_pattern_matching)] -#![allow(clippy::match_like_matches_macro, unused)] - -// Test that results are linted with the feature enabled. - -const fn issue_5697() { - if Ok::(42).is_ok() {} - - if Err::(42).is_err() {} - - while Ok::(10).is_ok() {} - - while Ok::(10).is_err() {} - - Ok::(42).is_ok(); - - Err::(42).is_err(); - - // These should not be linted until `const_option` is implemented. - // See https://github.com/rust-lang/rust/issues/67441 - - if let Some(_) = Some(42) {} - - if let None = None::<()> {} - - while let Some(_) = Some(42) {} - - while let None = None::<()> {} - - match Some(42) { - Some(_) => true, - None => false, - }; - - match None::<()> { - Some(_) => false, - None => true, - }; -} - -fn main() {} diff --git a/tests/ui/redundant_pattern_matching_const_result.rs b/tests/ui/redundant_pattern_matching_const_result.rs deleted file mode 100644 index b77969d53d92d..0000000000000 --- a/tests/ui/redundant_pattern_matching_const_result.rs +++ /dev/null @@ -1,50 +0,0 @@ -// run-rustfix - -#![feature(const_result)] -#![warn(clippy::redundant_pattern_matching)] -#![allow(clippy::match_like_matches_macro, unused)] - -// Test that results are linted with the feature enabled. - -const fn issue_5697() { - if let Ok(_) = Ok::(42) {} - - if let Err(_) = Err::(42) {} - - while let Ok(_) = Ok::(10) {} - - while let Err(_) = Ok::(10) {} - - match Ok::(42) { - Ok(_) => true, - Err(_) => false, - }; - - match Err::(42) { - Ok(_) => false, - Err(_) => true, - }; - - // These should not be linted until `const_option` is implemented. - // See https://github.com/rust-lang/rust/issues/67441 - - if let Some(_) = Some(42) {} - - if let None = None::<()> {} - - while let Some(_) = Some(42) {} - - while let None = None::<()> {} - - match Some(42) { - Some(_) => true, - None => false, - }; - - match None::<()> { - Some(_) => false, - None => true, - }; -} - -fn main() {} diff --git a/tests/ui/redundant_pattern_matching_const_result.stderr b/tests/ui/redundant_pattern_matching_const_result.stderr deleted file mode 100644 index 8ecd72158d33c..0000000000000 --- a/tests/ui/redundant_pattern_matching_const_result.stderr +++ /dev/null @@ -1,46 +0,0 @@ -error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_const_result.rs:10:12 - | -LL | if let Ok(_) = Ok::(42) {} - | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` - | - = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` - -error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_const_result.rs:12:12 - | -LL | if let Err(_) = Err::(42) {} - | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` - -error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_const_result.rs:14:15 - | -LL | while let Ok(_) = Ok::(10) {} - | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` - -error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_const_result.rs:16:15 - | -LL | while let Err(_) = Ok::(10) {} - | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` - -error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_const_result.rs:18:5 - | -LL | / match Ok::(42) { -LL | | Ok(_) => true, -LL | | Err(_) => false, -LL | | }; - | |_____^ help: try this: `Ok::(42).is_ok()` - -error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_const_result.rs:23:5 - | -LL | / match Err::(42) { -LL | | Ok(_) => false, -LL | | Err(_) => true, -LL | | }; - | |_____^ help: try this: `Err::(42).is_err()` - -error: aborting due to 6 previous errors - From 562422ecf7fd8b34a337e6a99cc86e21c60dcf99 Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 18 Sep 2020 09:35:37 +0200 Subject: [PATCH 0693/1052] Remove some unused features from alloc core and std --- library/alloc/src/lib.rs | 9 +-------- library/core/src/lib.rs | 7 ------- library/std/src/lib.rs | 2 -- 3 files changed, 1 insertion(+), 17 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 3061ab8ee5369..0f67c57ff0946 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -74,6 +74,7 @@ #![deny(unsafe_op_in_unsafe_fn)] #![cfg_attr(not(test), feature(generator_trait))] #![cfg_attr(test, feature(test))] +#![cfg_attr(test, feature(new_uninit))] #![feature(allocator_api)] #![feature(array_chunks)] #![feature(array_windows)] @@ -81,7 +82,6 @@ #![feature(arbitrary_self_types)] #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(btree_drain_filter)] #![feature(cfg_sanitize)] #![feature(cfg_target_has_atomic)] #![feature(coerce_unsized)] @@ -89,10 +89,8 @@ #![feature(const_generics)] #![feature(const_in_array_repeat_expressions)] #![feature(cow_is_borrowed)] -#![feature(deque_range)] #![feature(dispatch_from_dyn)] #![feature(core_intrinsics)] -#![feature(container_error_extra)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] #![feature(exclusive_range_pattern)] @@ -103,12 +101,9 @@ #![feature(inplace_iteration)] #![feature(lang_items)] #![feature(layout_for_ptr)] -#![feature(map_first_last)] -#![feature(map_into_keys_values)] #![feature(maybe_uninit_ref)] #![feature(negative_impls)] #![feature(never_type)] -#![feature(new_uninit)] #![feature(nll)] #![feature(nonnull_slice_from_raw_parts)] #![feature(optin_builtin_traits)] @@ -123,10 +118,8 @@ #![feature(slice_ptr_get)] #![feature(slice_ptr_len)] #![feature(staged_api)] -#![feature(std_internals)] #![feature(str_internals)] #![feature(trusted_len)] -#![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(unicode_internals)] #![feature(unsafe_block_in_unsafe_fn)] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 3bddc3772e600..92f1f4be9560e 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -66,9 +66,7 @@ #![feature(allow_internal_unstable)] #![feature(arbitrary_self_types)] #![feature(asm)] -#![feature(bound_cloned)] #![feature(cfg_target_has_atomic)] -#![feature(concat_idents)] #![feature(const_alloc_layout)] #![feature(const_discriminant)] #![feature(const_checked_int_methods)] @@ -104,8 +102,6 @@ #![feature(extern_types)] #![feature(fundamental)] #![feature(intrinsics)] -#![feature(try_find)] -#![feature(is_sorted)] #![feature(lang_items)] #![feature(link_llvm_intrinsics)] #![feature(llvm_asm)] @@ -117,7 +113,6 @@ #![feature(optin_builtin_traits)] #![feature(or_patterns)] #![feature(prelude_import)] -#![feature(ptr_as_uninit)] #![feature(repr_simd, platform_intrinsics)] #![feature(rustc_attrs)] #![feature(simd_ffi)] @@ -148,8 +143,6 @@ #![feature(const_fn_transmute)] #![feature(abi_unadjusted)] #![feature(adx_target_feature)] -#![feature(maybe_uninit_slice)] -#![feature(maybe_uninit_extra)] #![feature(external_doc)] #![feature(associated_type_bounds)] #![feature(const_caller_location)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 34230629fb0be..c63c3c34a88a5 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -228,7 +228,6 @@ #![feature(atomic_mut_ptr)] #![feature(box_syntax)] #![feature(c_variadic)] -#![feature(can_vector)] #![feature(cfg_accessible)] #![feature(cfg_target_has_atomic)] #![feature(cfg_target_thread_local)] @@ -261,7 +260,6 @@ #![feature(gen_future)] #![feature(generator_trait)] #![feature(global_asm)] -#![feature(hash_raw_entry)] #![feature(hashmap_internals)] #![feature(int_error_internals)] #![feature(int_error_matching)] From 3435683fd5930676b5a7ccd40dc08e4758e8b90a Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 17 Sep 2020 09:28:14 +0200 Subject: [PATCH 0694/1052] use `array_windows` instead of `windows` in the compiler --- compiler/rustc_data_structures/src/lib.rs | 1 + compiler/rustc_data_structures/src/sorted_map.rs | 4 ++-- compiler/rustc_lint/src/lib.rs | 1 + compiler/rustc_lint/src/nonstandard_style.rs | 4 ++-- compiler/rustc_middle/src/lib.rs | 1 + compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_mir/src/lib.rs | 1 + .../rustc_mir/src/monomorphize/partitioning/mod.rs | 8 +------- compiler/rustc_mir_build/src/lib.rs | 2 +- compiler/rustc_mir_build/src/thir/pattern/_match.rs | 4 ++-- compiler/rustc_span/src/lib.rs | 10 ++++++++-- 11 files changed, 21 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 06718cc980312..3322edd18ccbd 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -8,6 +8,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![allow(incomplete_features)] +#![feature(array_windows)] #![feature(control_flow_enum)] #![feature(in_band_lifetimes)] #![feature(unboxed_closures)] diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs index 856eb73e6297a..4807380595db7 100644 --- a/compiler/rustc_data_structures/src/sorted_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map.rs @@ -34,7 +34,7 @@ impl SortedMap { /// and that there are no duplicates. #[inline] pub fn from_presorted_elements(elements: Vec<(K, V)>) -> SortedMap { - debug_assert!(elements.windows(2).all(|w| w[0].0 < w[1].0)); + debug_assert!(elements.array_windows().all(|[fst, snd]| fst.0 < snd.0)); SortedMap { data: elements } } @@ -159,7 +159,7 @@ impl SortedMap { return; } - debug_assert!(elements.windows(2).all(|w| w[0].0 < w[1].0)); + debug_assert!(elements.array_windows().all(|[fst, snd]| fst.0 < snd.0)); let start_index = self.lookup_index_for(&elements[0].0); diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 0a14b16e274c8..b48592c103ca2 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -27,6 +27,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![cfg_attr(test, feature(test))] +#![feature(array_windows)] #![feature(bool_to_option)] #![feature(box_syntax)] #![feature(crate_visibility_modifier)] diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 24467f811726a..b3125f55d4d6e 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -70,9 +70,9 @@ fn is_camel_case(name: &str) -> bool { // ones (some scripts don't have a concept of upper/lowercase) !name.chars().next().unwrap().is_lowercase() && !name.contains("__") - && !name.chars().collect::>().windows(2).any(|pair| { + && !name.chars().collect::>().array_windows().any(|&[fst, snd]| { // contains a capitalisable character followed by, or preceded by, an underscore - char_has_case(pair[0]) && pair[1] == '_' || char_has_case(pair[1]) && pair[0] == '_' + char_has_case(fst) && snd == '_' || char_has_case(snd) && fst == '_' }) } diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index a675aae5b17d4..ac931028c010d 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -23,6 +23,7 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![feature(array_windows)] #![feature(backtrace)] #![feature(bool_to_option)] #![feature(box_patterns)] diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 56746666e2f1f..38c0441990b25 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2419,7 +2419,7 @@ impl<'tcx> TyCtxt<'tcx> { eps: &[ExistentialPredicate<'tcx>], ) -> &'tcx List> { assert!(!eps.is_empty()); - assert!(eps.windows(2).all(|w| w[0].stable_cmp(self, &w[1]) != Ordering::Greater)); + assert!(eps.array_windows().all(|[a, b]| a.stable_cmp(self, b) != Ordering::Greater)); self._intern_existential_predicates(eps) } diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index 251037792c917..52b0a7e706769 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -6,6 +6,7 @@ Rust MIR: a lowered representation of Rust. #![feature(nll)] #![feature(in_band_lifetimes)] +#![feature(array_windows)] #![feature(bindings_after_at)] #![feature(bool_to_option)] #![feature(box_patterns)] diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs index b60beca688068..db6d3b2d912d6 100644 --- a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs @@ -277,14 +277,8 @@ where symbols.sort_by_key(|sym| sym.1); - for pair in symbols.windows(2) { - let sym1 = &pair[0].1; - let sym2 = &pair[1].1; - + for &[(mono_item1, ref sym1), (mono_item2, ref sym2)] in symbols.array_windows() { if sym1 == sym2 { - let mono_item1 = pair[0].0; - let mono_item2 = pair[1].0; - let span1 = mono_item1.local_span(tcx); let span2 = mono_item2.local_span(tcx); diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index e55180ff4be52..714041ad4e874 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -1,7 +1,7 @@ //! Construction of MIR from HIR. //! //! This crate also contains the match exhaustiveness and usefulness checking. - +#![feature(array_windows)] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(const_fn)] diff --git a/compiler/rustc_mir_build/src/thir/pattern/_match.rs b/compiler/rustc_mir_build/src/thir/pattern/_match.rs index ad94740c16066..e71e1abd680b3 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/_match.rs @@ -2299,8 +2299,8 @@ fn split_grouped_constructors<'p, 'tcx>( // interval into a constructor. split_ctors.extend( borders - .windows(2) - .filter_map(|window| match (window[0], window[1]) { + .array_windows() + .filter_map(|&[fst, snd]| match (fst, snd) { (Border::JustBefore(n), Border::JustBefore(m)) => { if n < m { Some(IntRange { range: n..=(m - 1), ty, span }) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index e38cd516b91ac..e817fa56c55eb 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -5,6 +5,7 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![feature(array_windows)] #![feature(crate_visibility_modifier)] #![feature(const_fn)] #![feature(const_panic)] @@ -1158,7 +1159,12 @@ impl Encodable for SourceFile { let max_line_length = if lines.len() == 1 { 0 } else { - lines.windows(2).map(|w| w[1] - w[0]).map(|bp| bp.to_usize()).max().unwrap() + lines + .array_windows() + .map(|&[fst, snd]| snd - fst) + .map(|bp| bp.to_usize()) + .max() + .unwrap() }; let bytes_per_diff: u8 = match max_line_length { @@ -1173,7 +1179,7 @@ impl Encodable for SourceFile { // Encode the first element. lines[0].encode(s)?; - let diff_iter = (&lines[..]).windows(2).map(|w| (w[1] - w[0])); + let diff_iter = lines[..].array_windows().map(|&[fst, snd]| snd - fst); match bytes_per_diff { 1 => { From bfb221b21e13e8fd71a8fc3a2df23e7f0e775df3 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 17 Sep 2020 10:01:24 +0200 Subject: [PATCH 0695/1052] array pattern --- compiler/rustc_mir_build/src/thir/pattern/_match.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/_match.rs b/compiler/rustc_mir_build/src/thir/pattern/_match.rs index e71e1abd680b3..eddd2882406ba 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/_match.rs @@ -2300,18 +2300,18 @@ fn split_grouped_constructors<'p, 'tcx>( split_ctors.extend( borders .array_windows() - .filter_map(|&[fst, snd]| match (fst, snd) { - (Border::JustBefore(n), Border::JustBefore(m)) => { + .filter_map(|&pair| match pair { + [Border::JustBefore(n), Border::JustBefore(m)] => { if n < m { Some(IntRange { range: n..=(m - 1), ty, span }) } else { None } } - (Border::JustBefore(n), Border::AfterMax) => { + [Border::JustBefore(n), Border::AfterMax] => { Some(IntRange { range: n..=u128::MAX, ty, span }) } - (Border::AfterMax, _) => None, + [Border::AfterMax, _] => None, }) .map(IntRange), ); From 2a00dda90258576e3adf5ecae0437a8fe6fadbcf Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 10 Sep 2020 19:43:53 +0200 Subject: [PATCH 0696/1052] miri: correctly deal with `ConstKind::Bound` --- compiler/rustc_mir/src/interpret/operand.rs | 6 ++-- .../ui/const-generics/issues/issue-73260.rs | 20 +++++++++++++ .../const-generics/issues/issue-73260.stderr | 29 +++++++++++++++++++ .../ui/const-generics/issues/issue-74634.rs | 27 +++++++++++++++++ .../const-generics/issues/issue-74634.stderr | 10 +++++++ 5 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/const-generics/issues/issue-73260.rs create mode 100644 src/test/ui/const-generics/issues/issue-73260.stderr create mode 100644 src/test/ui/const-generics/issues/issue-74634.rs create mode 100644 src/test/ui/const-generics/issues/issue-74634.stderr diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs index 57245696e576e..136a2699d20b2 100644 --- a/compiler/rustc_mir/src/interpret/operand.rs +++ b/compiler/rustc_mir/src/interpret/operand.rs @@ -549,7 +549,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; // Early-return cases. let val_val = match val.val { - ty::ConstKind::Param(_) => throw_inval!(TooGeneric), + ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric), ty::ConstKind::Error(_) => throw_inval!(TypeckError(ErrorReported)), ty::ConstKind::Unevaluated(def, substs, promoted) => { let instance = self.resolve(def.did, substs)?; @@ -561,9 +561,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // happening. return Ok(self.const_eval(GlobalId { instance, promoted }, val.ty)?); } - ty::ConstKind::Infer(..) - | ty::ConstKind::Bound(..) - | ty::ConstKind::Placeholder(..) => { + ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => { span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", val) } ty::ConstKind::Value(val_val) => val_val, diff --git a/src/test/ui/const-generics/issues/issue-73260.rs b/src/test/ui/const-generics/issues/issue-73260.rs new file mode 100644 index 0000000000000..351d6849af5db --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-73260.rs @@ -0,0 +1,20 @@ +// compile-flags: -Zsave-analysis + +#![feature(const_generics)] +#![allow(incomplete_features)] +struct Arr +where Assert::<{N < usize::max_value() / 2}>: IsTrue, //~ ERROR constant expression +{ +} + +enum Assert {} + +trait IsTrue {} + +impl IsTrue for Assert {} + +fn main() { + let x: Arr<{usize::max_value()}> = Arr {}; + //~^ ERROR mismatched types + //~| ERROR mismatched types +} diff --git a/src/test/ui/const-generics/issues/issue-73260.stderr b/src/test/ui/const-generics/issues/issue-73260.stderr new file mode 100644 index 0000000000000..e22612ed5ea63 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-73260.stderr @@ -0,0 +1,29 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-73260.rs:6:47 + | +LL | where Assert::<{N < usize::max_value() / 2}>: IsTrue, + | ^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error[E0308]: mismatched types + --> $DIR/issue-73260.rs:17:12 + | +LL | let x: Arr<{usize::max_value()}> = Arr {}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `false`, found `true` + | + = note: expected type `false` + found type `true` + +error[E0308]: mismatched types + --> $DIR/issue-73260.rs:17:40 + | +LL | let x: Arr<{usize::max_value()}> = Arr {}; + | ^^^ expected `false`, found `true` + | + = note: expected type `false` + found type `true` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/issues/issue-74634.rs b/src/test/ui/const-generics/issues/issue-74634.rs new file mode 100644 index 0000000000000..0f23fa92c3679 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-74634.rs @@ -0,0 +1,27 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +trait If {} +impl If for () {} + +trait IsZero { + type Answer; +} + +struct True; +struct False; + +impl IsZero for () +where (): If<{N == 0}> { //~ERROR constant expression + type Answer = True; +} + +trait Foobar {} + +impl Foobar for () +where (): IsZero {} + +impl Foobar for () +where (): IsZero {} + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-74634.stderr b/src/test/ui/const-generics/issues/issue-74634.stderr new file mode 100644 index 0000000000000..091a1ac7b9981 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-74634.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-74634.rs:15:11 + | +LL | where (): If<{N == 0}> { + | ^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + From 67342304253d8af47fe4453fbe2396b627620431 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Fri, 11 Sep 2020 18:39:26 +0200 Subject: [PATCH 0697/1052] do not ICE on `ty::Bound` in Layout::compute --- compiler/rustc_middle/src/ty/layout.rs | 4 ++-- .../ui/const-generics/issues/issue-76595.rs | 18 ++++++++++++++++ .../const-generics/issues/issue-76595.stderr | 21 +++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/const-generics/issues/issue-76595.rs create mode 100644 src/test/ui/const-generics/issues/issue-76595.stderr diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index b0a1413a9d62f..cb79b089d94a0 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1259,11 +1259,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { tcx.layout_raw(param_env.and(normalized))? } - ty::Bound(..) | ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Infer(_) => { + ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Infer(_) => { bug!("Layout::compute: unexpected type `{}`", ty) } - ty::Param(_) | ty::Error(_) => { + ty::Bound(..) | ty::Param(_) | ty::Error(_) => { return Err(LayoutError::Unknown(ty)); } }) diff --git a/src/test/ui/const-generics/issues/issue-76595.rs b/src/test/ui/const-generics/issues/issue-76595.rs new file mode 100644 index 0000000000000..0a16ca181f557 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-76595.rs @@ -0,0 +1,18 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +struct Bool; + +trait True {} + +impl True for Bool {} + +fn test() where Bool<{core::mem::size_of::() > 4}>: True { + todo!() +} + +fn main() { + test::<2>(); + //~^ ERROR wrong number of type + //~| ERROR constant expression depends +} diff --git a/src/test/ui/const-generics/issues/issue-76595.stderr b/src/test/ui/const-generics/issues/issue-76595.stderr new file mode 100644 index 0000000000000..4235bdc9b893c --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-76595.stderr @@ -0,0 +1,21 @@ +error[E0107]: wrong number of type arguments: expected 1, found 0 + --> $DIR/issue-76595.rs:15:5 + | +LL | test::<2>(); + | ^^^^^^^^^ expected 1 type argument + +error: constant expression depends on a generic parameter + --> $DIR/issue-76595.rs:15:5 + | +LL | fn test() where Bool<{core::mem::size_of::() > 4}>: True { + | ---- required by a bound in this +... +LL | test::<2>(); + | ^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + = note: required by this bound in `test` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0107`. From 34785fcc4a56c4f705a1f5c9929689e5c46e1fbc Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 20 Sep 2020 09:09:56 +0200 Subject: [PATCH 0698/1052] Make codegen test bitwidth-independent --- src/test/codegen/consts.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/codegen/consts.rs b/src/test/codegen/consts.rs index a69a4885bb5df..fcb9002986a1c 100644 --- a/src/test/codegen/consts.rs +++ b/src/test/codegen/consts.rs @@ -43,7 +43,7 @@ pub fn inline_enum_const() -> E { #[no_mangle] pub fn low_align_const() -> E { // Check that low_align_const and high_align_const use the same constant - // CHECK: memcpy.p0i8.p0i8.i64(i8* align 2 %1, i8* align 2 getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), i64 8, i1 false) + // CHECK: memcpy.p0i8.p0i8.i{{(32|64)}}(i8* align 2 %1, i8* align 2 getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), i{{(32|64)}} 8, i1 false) *&E::A(0) } @@ -51,6 +51,6 @@ pub fn low_align_const() -> E { #[no_mangle] pub fn high_align_const() -> E { // Check that low_align_const and high_align_const use the same constant - // CHECK: memcpy.p0i8.p0i8.i64(i8* align 4 %1, i8* align 4 getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), i64 8, i1 false) + // CHECK: memcpy.p0i8.p0i8.i{{(32|64)}}(i8* align 4 %1, i8* align 4 getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), i{{(32|64)}} 8, i1 false) *&E::A(0) } From 65b3419ca04fdf921309e7fc03010d9d2cc9b8f0 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 20 Sep 2020 09:32:59 +0200 Subject: [PATCH 0699/1052] update stderr file --- src/test/ui/const-generics/issues/issue-76595.stderr | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/ui/const-generics/issues/issue-76595.stderr b/src/test/ui/const-generics/issues/issue-76595.stderr index 4235bdc9b893c..2e457595393ca 100644 --- a/src/test/ui/const-generics/issues/issue-76595.stderr +++ b/src/test/ui/const-generics/issues/issue-76595.stderr @@ -8,13 +8,12 @@ error: constant expression depends on a generic parameter --> $DIR/issue-76595.rs:15:5 | LL | fn test() where Bool<{core::mem::size_of::() > 4}>: True { - | ---- required by a bound in this + | ---- required by this bound in `test` ... LL | test::<2>(); | ^^^^^^^^^ | = note: this may fail depending on what value the parameter takes - = note: required by this bound in `test` error: aborting due to 2 previous errors From cebbd9fcd35a63569b8fb5c836b5a26089861c41 Mon Sep 17 00:00:00 2001 From: est31 Date: Sun, 20 Sep 2020 10:12:57 +0200 Subject: [PATCH 0700/1052] Use as_nanos in bench.rs and base.rs --- compiler/rustc_codegen_llvm/src/base.rs | 2 +- library/test/src/bench.rs | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index 6a1b373ef0711..f35708b1d0965 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -108,7 +108,7 @@ pub fn compile_codegen_unit( // We assume that the cost to run LLVM on a CGU is proportional to // the time we needed for codegenning it. - let cost = time_to_codegen.as_secs() * 1_000_000_000 + time_to_codegen.subsec_nanos() as u64; + let cost = time_to_codegen.as_nanos() as u64; fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen { let cgu = tcx.codegen_unit(cgu_name); diff --git a/library/test/src/bench.rs b/library/test/src/bench.rs index e92e5b9829ec2..b709c76329637 100644 --- a/library/test/src/bench.rs +++ b/library/test/src/bench.rs @@ -98,10 +98,6 @@ fn fmt_thousands_sep(mut n: usize, sep: char) -> String { output } -fn ns_from_dur(dur: Duration) -> u64 { - dur.as_secs() * 1_000_000_000 + (dur.subsec_nanos() as u64) -} - fn ns_iter_inner(inner: &mut F, k: u64) -> u64 where F: FnMut() -> T, @@ -110,7 +106,7 @@ where for _ in 0..k { black_box(inner()); } - ns_from_dur(start.elapsed()) + start.elapsed().as_nanos() as u64 } pub fn iter(inner: &mut F) -> stats::Summary From 43193dcb882466163436057e50c96bb74d9bf50f Mon Sep 17 00:00:00 2001 From: est31 Date: Sun, 20 Sep 2020 10:27:14 +0200 Subject: [PATCH 0701/1052] Use as_secs_f64 in profiling.rs --- compiler/rustc_data_structures/src/profiling.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index 07d16c6483ec7..363879cbb1d19 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -600,10 +600,7 @@ pub fn print_time_passes_entry(do_it: bool, what: &str, dur: Duration) { // Hack up our own formatting for the duration to make it easier for scripts // to parse (always use the same number of decimal places and the same unit). pub fn duration_to_secs_str(dur: std::time::Duration) -> String { - const NANOS_PER_SEC: f64 = 1_000_000_000.0; - let secs = dur.as_secs() as f64 + dur.subsec_nanos() as f64 / NANOS_PER_SEC; - - format!("{:.3}", secs) + format!("{:.3}", dur.as_secs_f64()) } // Memory reporting From 4bc0e55ac4280be80d8cd0f9bc26bd0949f75494 Mon Sep 17 00:00:00 2001 From: est31 Date: Sun, 20 Sep 2020 10:35:23 +0200 Subject: [PATCH 0702/1052] Replace write_fmt with write! Latter is simpler --- library/test/src/bench.rs | 20 ++++++++++---------- src/tools/unstable-book-gen/src/main.rs | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/library/test/src/bench.rs b/library/test/src/bench.rs index e92e5b9829ec2..83be1cce63d52 100644 --- a/library/test/src/bench.rs +++ b/library/test/src/bench.rs @@ -61,15 +61,15 @@ pub fn fmt_bench_samples(bs: &BenchSamples) -> String { let median = bs.ns_iter_summ.median as usize; let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize; - output - .write_fmt(format_args!( - "{:>11} ns/iter (+/- {})", - fmt_thousands_sep(median, ','), - fmt_thousands_sep(deviation, ',') - )) - .unwrap(); + write!( + output, + "{:>11} ns/iter (+/- {})", + fmt_thousands_sep(median, ','), + fmt_thousands_sep(deviation, ',') + ) + .unwrap(); if bs.mb_s != 0 { - output.write_fmt(format_args!(" = {} MB/s", bs.mb_s)).unwrap(); + write!(output, " = {} MB/s", bs.mb_s).unwrap(); } output } @@ -83,9 +83,9 @@ fn fmt_thousands_sep(mut n: usize, sep: char) -> String { let base = 10_usize.pow(pow); if pow == 0 || trailing || n / base != 0 { if !trailing { - output.write_fmt(format_args!("{}", n / base)).unwrap(); + write!(output, "{}", n / base).unwrap(); } else { - output.write_fmt(format_args!("{:03}", n / base)).unwrap(); + write!(output, "{:03}", n / base).unwrap(); } if pow != 0 { output.push(sep); diff --git a/src/tools/unstable-book-gen/src/main.rs b/src/tools/unstable-book-gen/src/main.rs index 387b2acd1069e..e10f72a47b2c4 100644 --- a/src/tools/unstable-book-gen/src/main.rs +++ b/src/tools/unstable-book-gen/src/main.rs @@ -27,12 +27,12 @@ macro_rules! t { fn generate_stub_issue(path: &Path, name: &str, issue: u32) { let mut file = t!(File::create(path)); - t!(file.write_fmt(format_args!(include_str!("stub-issue.md"), name = name, issue = issue))); + t!(write!(file, include_str!("stub-issue.md"), name = name, issue = issue)); } fn generate_stub_no_issue(path: &Path, name: &str) { let mut file = t!(File::create(path)); - t!(file.write_fmt(format_args!(include_str!("stub-no-issue.md"), name = name))); + t!(write!(file, include_str!("stub-no-issue.md"), name = name)); } fn set_to_summary_str(set: &BTreeSet, dir: &str) -> String { From a59d48064931ab860fb065e4ef3a2f5cc4276f96 Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Sun, 20 Sep 2020 10:46:30 +0200 Subject: [PATCH 0703/1052] Remove `can_suggest` check for `is_ok` and `is_err`. `is_ok` and `is_err` are stabilized as const and can thus always be suggested. --- src/tools/clippy/clippy_lints/src/matches.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs index be879dfe28d70..d20662f1ef948 100644 --- a/src/tools/clippy/clippy_lints/src/matches.rs +++ b/src/tools/clippy/clippy_lints/src/matches.rs @@ -1469,10 +1469,10 @@ mod redundant_pattern_match { keyword: &'static str, ) { fn find_suggestion(cx: &LateContext<'_>, hir_id: HirId, path: &QPath<'_>) -> Option<&'static str> { - if match_qpath(path, &paths::RESULT_OK) && can_suggest(cx, hir_id, sym!(result_type), "is_ok") { + if match_qpath(path, &paths::RESULT_OK) { return Some("is_ok()"); } - if match_qpath(path, &paths::RESULT_ERR) && can_suggest(cx, hir_id, sym!(result_type), "is_err") { + if match_qpath(path, &paths::RESULT_ERR) { return Some("is_err()"); } if match_qpath(path, &paths::OPTION_SOME) && can_suggest(cx, hir_id, sym!(option_type), "is_some") { @@ -1562,8 +1562,8 @@ mod redundant_pattern_match { &paths::RESULT_ERR, "is_ok()", "is_err()", - || can_suggest(cx, hir_id, sym!(result_type), "is_ok"), - || can_suggest(cx, hir_id, sym!(result_type), "is_err"), + || true, + || true ) } else { None From 292e2f71a76dd0b9ecb8a975e5e5564e7563d965 Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Sun, 20 Sep 2020 10:46:30 +0200 Subject: [PATCH 0704/1052] Remove `can_suggest` check for `is_ok` and `is_err`. `is_ok` and `is_err` are stabilized as const and can thus always be suggested. --- clippy_lints/src/matches.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index be879dfe28d70..d20662f1ef948 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1469,10 +1469,10 @@ mod redundant_pattern_match { keyword: &'static str, ) { fn find_suggestion(cx: &LateContext<'_>, hir_id: HirId, path: &QPath<'_>) -> Option<&'static str> { - if match_qpath(path, &paths::RESULT_OK) && can_suggest(cx, hir_id, sym!(result_type), "is_ok") { + if match_qpath(path, &paths::RESULT_OK) { return Some("is_ok()"); } - if match_qpath(path, &paths::RESULT_ERR) && can_suggest(cx, hir_id, sym!(result_type), "is_err") { + if match_qpath(path, &paths::RESULT_ERR) { return Some("is_err()"); } if match_qpath(path, &paths::OPTION_SOME) && can_suggest(cx, hir_id, sym!(option_type), "is_some") { @@ -1562,8 +1562,8 @@ mod redundant_pattern_match { &paths::RESULT_ERR, "is_ok()", "is_err()", - || can_suggest(cx, hir_id, sym!(result_type), "is_ok"), - || can_suggest(cx, hir_id, sym!(result_type), "is_err"), + || true, + || true ) } else { None From b2c5f99883bf7ba348c9e9c03e7592b18ef59665 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 20 Sep 2020 11:15:00 +0200 Subject: [PATCH 0705/1052] Add test for issue #34634 --- src/test/codegen/issue-34634.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/test/codegen/issue-34634.rs diff --git a/src/test/codegen/issue-34634.rs b/src/test/codegen/issue-34634.rs new file mode 100644 index 0000000000000..6c18adbcb3c92 --- /dev/null +++ b/src/test/codegen/issue-34634.rs @@ -0,0 +1,16 @@ +// Test that `wrapping_div` only checks divisor once. +// This test checks that there is only a single compare agains -1 and -1 is not present as a +// switch case (the second check present until rustc 1.12). +// This test also verifies that a single panic call is generated (for the division by zero case). + +// compile-flags: -O +#![crate_type = "lib"] + +// CHECK-LABEL: @f +#[no_mangle] +pub fn f(x: i32, y: i32) -> i32 { + // CHECK-COUNT-1: icmp eq i32 %y, -1 + // CHECK-COUNT-1: panic + // CHECK-NOT: i32 -1, label + x.wrapping_div(y) +} From 812ff668032e5feb8cd702ecd9f4b5be21513f10 Mon Sep 17 00:00:00 2001 From: est31 Date: Sun, 20 Sep 2020 11:34:34 +0200 Subject: [PATCH 0706/1052] Use const_cstr macro in consts.rs --- compiler/rustc_codegen_llvm/src/consts.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 2b2bcd979999f..c8bc7c2f14f08 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -7,6 +7,7 @@ use crate::type_of::LayoutLlvmExt; use crate::value::Value; use libc::c_uint; use rustc_codegen_ssa::traits::*; +use rustc_data_structures::const_cstr; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::Node; @@ -22,8 +23,6 @@ use rustc_span::Span; use rustc_target::abi::{AddressSpace, Align, HasDataLayout, LayoutOf, Primitive, Scalar, Size}; use tracing::debug; -use std::ffi::CStr; - pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll Value { let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1); let dl = cx.data_layout(); @@ -457,9 +456,9 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> { .all(|&byte| byte == 0); let sect_name = if all_bytes_are_zero { - CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_bss\0") + const_cstr!("__DATA,__thread_bss") } else { - CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_data\0") + const_cstr!("__DATA,__thread_data") }; llvm::LLVMSetSection(g, sect_name.as_ptr()); } From c2dad1c6b9f9636198d7c561b47a2974f5103f6d Mon Sep 17 00:00:00 2001 From: est31 Date: Sun, 20 Sep 2020 11:40:51 +0200 Subject: [PATCH 0707/1052] Remove unused static_assert macro --- compiler/rustc_data_structures/src/macros.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/compiler/rustc_data_structures/src/macros.rs b/compiler/rustc_data_structures/src/macros.rs index 67fbe3058cdb9..b918ed9458cda 100644 --- a/compiler/rustc_data_structures/src/macros.rs +++ b/compiler/rustc_data_structures/src/macros.rs @@ -1,15 +1,3 @@ -/// A simple static assertion macro. -#[macro_export] -#[allow_internal_unstable(type_ascription)] -macro_rules! static_assert { - ($test:expr) => { - // Use the bool to access an array such that if the bool is false, the access - // is out-of-bounds. - #[allow(dead_code)] - const _: () = [()][!($test: bool) as usize]; - }; -} - /// Type size assertion. The first argument is a type and the second argument is its expected size. #[macro_export] macro_rules! static_assert_size { From c690c82ad42a15417996a087ef072fd2d8c2fe3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Fri, 18 Sep 2020 18:33:37 +0200 Subject: [PATCH 0708/1052] use if let instead of single match arm expressions to compact code and reduce nesting (clippy::single_match) --- .../nice_region_error/static_impl_trait.rs | 18 ++++++++---------- compiler/rustc_middle/src/ty/error.rs | 11 ++++------- compiler/rustc_middle/src/ty/print/pretty.rs | 9 +-------- .../rustc_mir/src/transform/promote_consts.rs | 16 +++++----------- compiler/rustc_parse/src/lexer/tokentrees.rs | 9 +++------ compiler/rustc_parse_format/src/lib.rs | 9 +++------ compiler/rustc_resolve/src/lib.rs | 7 ++----- compiler/rustc_symbol_mangling/src/v0.rs | 7 ++----- 8 files changed, 28 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 975b9d4f08631..441cfeea20a48 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -488,18 +488,16 @@ impl<'tcx> Visitor<'tcx> for HirTraitObjectVisitor { } fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) { - match t.kind { - TyKind::TraitObject( - poly_trait_refs, - Lifetime { name: LifetimeName::ImplicitObjectLifetimeDefault, .. }, - ) => { - for ptr in poly_trait_refs { - if Some(self.1) == ptr.trait_ref.trait_def_id() { - self.0.push(ptr.span); - } + if let TyKind::TraitObject( + poly_trait_refs, + Lifetime { name: LifetimeName::ImplicitObjectLifetimeDefault, .. }, + ) = t.kind + { + for ptr in poly_trait_refs { + if Some(self.1) == ptr.trait_ref.trait_def_id() { + self.0.push(ptr.span); } } - _ => {} } walk_ty(self, t); } diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 7226a906e5c97..2a950dcdf23fe 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -832,14 +832,11 @@ fn foo(&self) -> Self::T { String::new() } kind: hir::ItemKind::Impl { items, .. }, .. })) => { for item in &items[..] { - match item.kind { - hir::AssocItemKind::Type => { - if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found { - db.span_label(item.span, "expected this associated type"); - return true; - } + if let hir::AssocItemKind::Type = item.kind { + if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found { + db.span_label(item.span, "expected this associated type"); + return true; } - _ => {} } } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index f0bae48cc1221..c9cc9bfc9fa26 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2125,17 +2125,10 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N // Iterate all local crate items no matter where they are defined. let hir = tcx.hir(); for item in hir.krate().items.values() { - if item.ident.name.as_str().is_empty() { + if item.ident.name.as_str().is_empty() || matches!(item.kind, ItemKind::Use(_, _)) { continue; } - match item.kind { - ItemKind::Use(_, _) => { - continue; - } - _ => {} - } - if let Some(local_def_id) = hir.definitions().opt_hir_id_to_local_def_id(item.hir_id) { let def_id = local_def_id.to_def_id(); let ns = tcx.def_kind(def_id).ns().unwrap_or(Namespace::TypeNS); diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index 37202276161c7..7510c43243b1d 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -242,11 +242,8 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { } TerminatorKind::InlineAsm { ref operands, .. } => { for (index, op) in operands.iter().enumerate() { - match op { - InlineAsmOperand::Const { .. } => { - self.candidates.push(Candidate::InlineAsm { bb: location.block, index }) - } - _ => {} + if let InlineAsmOperand::Const { .. } = op { + self.candidates.push(Candidate::InlineAsm { bb: location.block, index }) } } } @@ -612,12 +609,9 @@ impl<'tcx> Validator<'_, 'tcx> { let operand_ty = operand.ty(self.body, self.tcx); let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); - match (cast_in, cast_out) { - (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => { - // ptr-to-int casts are not possible in consts and thus not promotable - return Err(Unpromotable); - } - _ => {} + if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) { + // ptr-to-int casts are not possible in consts and thus not promotable + return Err(Unpromotable); } } diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index 0f364bffb134e..6233549dc8579 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -149,12 +149,9 @@ impl<'a> TokenTreesReader<'a> { } } - match (open_brace, delim) { - //only add braces - (DelimToken::Brace, DelimToken::Brace) => { - self.matching_block_spans.push((open_brace_span, close_brace_span)); - } - _ => {} + //only add braces + if let (DelimToken::Brace, DelimToken::Brace) = (open_brace, delim) { + self.matching_block_spans.push((open_brace_span, close_brace_span)); } if self.open_braces.is_empty() { diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index e07b8b86aef8e..556bf69c9315e 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -527,12 +527,9 @@ impl<'a> Parser<'a> { // fill character if let Some(&(_, c)) = self.cur.peek() { - match self.cur.clone().nth(1) { - Some((_, '>' | '<' | '^')) => { - spec.fill = Some(c); - self.cur.next(); - } - _ => {} + if let Some((_, '>' | '<' | '^')) = self.cur.clone().nth(1) { + spec.fill = Some(c); + self.cur.next(); } } // Alignment diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 85ddc5f55d110..677cf27cde71c 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -534,11 +534,8 @@ impl<'a> ModuleData<'a> { if ns != TypeNS { return; } - match binding.res() { - Res::Def(DefKind::Trait | DefKind::TraitAlias, _) => { - collected_traits.push((name, binding)) - } - _ => (), + if let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = binding.res() { + collected_traits.push((name, binding)) } }); *traits = Some(collected_traits.into_boxed_slice()); diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 619edf06aa6e6..091d488138e46 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -152,11 +152,8 @@ impl SymbolMangler<'tcx> { let _ = write!(self.out, "{}", ident.len()); // Write a separating `_` if necessary (leading digit or `_`). - match ident.chars().next() { - Some('_' | '0'..='9') => { - self.push("_"); - } - _ => {} + if let Some('_' | '0'..='9') = ident.chars().next() { + self.push("_"); } self.push(ident); From bf70e21a7e48008a8c1d82c3b0376e574f9bc91b Mon Sep 17 00:00:00 2001 From: CDirkx Date: Sun, 20 Sep 2020 12:21:23 +0200 Subject: [PATCH 0709/1052] Update src/tools/clippy/clippy_lints/src/matches.rs Co-authored-by: Ralf Jung --- src/tools/clippy/clippy_lints/src/matches.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs index d20662f1ef948..e88ff070fb58e 100644 --- a/src/tools/clippy/clippy_lints/src/matches.rs +++ b/src/tools/clippy/clippy_lints/src/matches.rs @@ -1563,7 +1563,7 @@ mod redundant_pattern_match { "is_ok()", "is_err()", || true, - || true + || true, ) } else { None From ac0d0696169d0e69504dface45544132525244b6 Mon Sep 17 00:00:00 2001 From: CDirkx Date: Sun, 20 Sep 2020 12:21:23 +0200 Subject: [PATCH 0710/1052] Update src/tools/clippy/clippy_lints/src/matches.rs Co-authored-by: Ralf Jung --- clippy_lints/src/matches.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index d20662f1ef948..e88ff070fb58e 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1563,7 +1563,7 @@ mod redundant_pattern_match { "is_ok()", "is_err()", || true, - || true + || true, ) } else { None From b54f122a1cb2593325501a2ed5b3fbfc47293615 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 3 Apr 2020 15:22:37 +0200 Subject: [PATCH 0711/1052] Merge tuple and struct pattern generation. --- compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 2816bad7eabc1..55b5838429810 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -279,11 +279,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { subpatterns: field_pats(destructured.fields), } } - ty::Adt(_, _) => { - let destructured = tcx.destructure_const(param_env.and(cv)); - PatKind::Leaf { subpatterns: field_pats(destructured.fields) } - } - ty::Tuple(_) => { + ty::Tuple(_) | ty::Adt(_, _) => { let destructured = tcx.destructure_const(param_env.and(cv)); PatKind::Leaf { subpatterns: field_pats(destructured.fields) } } From 34c62e0abc82b7302a3b0ee16dfe445e1330ce4c Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 1 Jul 2020 11:41:38 +0200 Subject: [PATCH 0712/1052] Add a query for dereferencing constants of reference type --- compiler/rustc_middle/src/query/mod.rs | 8 +++++ compiler/rustc_mir/src/const_eval/mod.rs | 42 +++++++++++++++++++++++- compiler/rustc_mir/src/lib.rs | 4 +++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 44d906dada5f0..68bad428ea25b 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -749,6 +749,14 @@ rustc_queries! { desc { "destructure constant" } } + /// Dereference a constant reference or raw pointer and turn the result into a constant + /// again. + query deref_const( + key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>> + ) -> &'tcx ty::Const<'tcx> { + desc { "deref constant" } + } + query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> { desc { "get a &core::panic::Location referring to a span" } } diff --git a/compiler/rustc_mir/src/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs index c93feb5096bf7..451fa1458fda8 100644 --- a/compiler/rustc_mir/src/const_eval/mod.rs +++ b/compiler/rustc_mir/src/const_eval/mod.rs @@ -2,11 +2,14 @@ use std::convert::TryFrom; +use rustc_hir::Mutability; use rustc_middle::mir; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{source_map::DUMMY_SP, symbol::Symbol}; -use crate::interpret::{intern_const_alloc_recursive, ConstValue, InternKind, InterpCx}; +use crate::interpret::{ + intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, MemPlaceMeta, Scalar, +}; mod error; mod eval_queries; @@ -67,3 +70,40 @@ pub(crate) fn destructure_const<'tcx>( mir::DestructuredConst { variant, fields } } + +pub(crate) fn deref_const<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + val: &'tcx ty::Const<'tcx>, +) -> &'tcx ty::Const<'tcx> { + trace!("deref_const: {:?}", val); + let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); + let op = ecx.const_to_op(val, None).unwrap(); + let mplace = ecx.deref_operand(op).unwrap(); + if let Scalar::Ptr(ptr) = mplace.ptr { + assert_eq!( + ecx.memory.get_raw(ptr.alloc_id).unwrap().mutability, + Mutability::Not, + "deref_const cannot be used with mutable allocations as \ + that could allow pattern matching to observe mutable statics", + ); + } + + let ty = match mplace.meta { + MemPlaceMeta::None => mplace.layout.ty, + MemPlaceMeta::Poison => bug!("poison metadata in `deref_const`: {:#?}", mplace), + // In case of unsized types, figure out the real type behind. + MemPlaceMeta::Meta(scalar) => match mplace.layout.ty.kind { + ty::Dynamic(..) => ecx.read_drop_type_from_vtable(scalar).unwrap().1, + ty::Str => bug!("there's no sized equivalent of a `str`"), + ty::Slice(elem_ty) => tcx.mk_array(elem_ty, scalar.to_machine_usize(&tcx).unwrap()), + _ => bug!( + "type {} should not have metadata, but had {:?}", + mplace.layout.ty, + mplace.meta + ), + }, + }; + + tcx.mk_const(ty::Const { val: ty::ConstKind::Value(op_to_const(&ecx, mplace.into())), ty }) +} diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index 251037792c917..504c4ecd85ce3 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -60,4 +60,8 @@ pub fn provide(providers: &mut Providers) { let (param_env, value) = param_env_and_value.into_parts(); const_eval::destructure_const(tcx, param_env, value) }; + providers.deref_const = |tcx, param_env_and_value| { + let (param_env, value) = param_env_and_value.into_parts(); + const_eval::deref_const(tcx, param_env, value) + }; } From 5ef1db3622c373883571868cbdafbfbd568cddcb Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 20 Sep 2020 12:50:13 +0200 Subject: [PATCH 0713/1052] Revert adding Atomic::from_mut. This made too many assumptions about platforms, breaking some things. Will need to be added later with a better way of gating on proper alignment, without hardcoding cfg(target_arch)s. --- library/core/src/sync/atomic.rs | 90 --------------------------------- 1 file changed, 90 deletions(-) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 9d74f537491b1..1d2880405a64d 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -110,7 +110,6 @@ use self::Ordering::*; use crate::cell::UnsafeCell; use crate::fmt; use crate::intrinsics; -use crate::mem::align_of; use crate::hint::spin_loop; @@ -328,27 +327,6 @@ impl AtomicBool { unsafe { &mut *(self.v.get() as *mut bool) } } - /// Get atomic access to a `&mut bool`. - /// - /// # Examples - /// - /// ``` - /// #![feature(atomic_from_mut)] - /// use std::sync::atomic::{AtomicBool, Ordering}; - /// - /// let mut some_bool = true; - /// let a = AtomicBool::from_mut(&mut some_bool); - /// a.store(false, Ordering::Relaxed); - /// assert_eq!(some_bool, false); - /// ``` - #[inline] - #[unstable(feature = "atomic_from_mut", issue = "76314")] - pub fn from_mut(v: &mut bool) -> &Self { - // SAFETY: the mutable reference guarantees unique ownership, and - // alignment of both `bool` and `Self` is 1. - unsafe { &*(v as *mut bool as *mut Self) } - } - /// Consumes the atomic and returns the contained value. /// /// This is safe because passing `self` by value guarantees that no other threads are @@ -842,30 +820,6 @@ impl AtomicPtr { unsafe { &mut *self.p.get() } } - /// Get atomic access to a pointer. - /// - /// # Examples - /// - /// ``` - /// #![feature(atomic_from_mut)] - /// use std::sync::atomic::{AtomicPtr, Ordering}; - /// - /// let mut some_ptr = &mut 123 as *mut i32; - /// let a = AtomicPtr::from_mut(&mut some_ptr); - /// a.store(&mut 456, Ordering::Relaxed); - /// assert_eq!(unsafe { *some_ptr }, 456); - /// ``` - #[inline] - #[unstable(feature = "atomic_from_mut", issue = "76314")] - pub fn from_mut(v: &mut *mut T) -> &Self { - let [] = [(); align_of::>() - align_of::<*mut ()>()]; - // SAFETY: - // - the mutable reference guarantees unique ownership. - // - the alignment of `*mut T` and `Self` is the same on all platforms - // supported by rust, as verified above. - unsafe { &*(v as *mut *mut T as *mut Self) } - } - /// Consumes the atomic and returns the contained value. /// /// This is safe because passing `self` by value guarantees that no other threads are @@ -1168,7 +1122,6 @@ macro_rules! atomic_int { $stable_nand:meta, $const_stable:meta, $stable_init_const:meta, - $(from_mut: cfg($from_mut_cfg:meta),)? $s_int_type:literal, $int_ref:expr, $extra_feature:expr, $min_fn:ident, $max_fn:ident, @@ -1280,45 +1233,6 @@ assert_eq!(some_var.load(Ordering::SeqCst), 5); } } - doc_comment! { - concat!("Get atomic access to a `&mut ", stringify!($int_type), "`. - -", -if_not_8_bit! { - $int_type, - concat!( - "**Note:** This function is only available on targets where `", - stringify!($int_type), "` has an alignment of ", $align, " bytes." - ) -}, -" - -# Examples - -``` -#![feature(atomic_from_mut)] -", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; - -let mut some_int = 123; -let a = ", stringify!($atomic_type), "::from_mut(&mut some_int); -a.store(100, Ordering::Relaxed); -assert_eq!(some_int, 100); -``` - "), - #[inline] - $(#[cfg($from_mut_cfg)])? - #[unstable(feature = "atomic_from_mut", issue = "76314")] - pub fn from_mut(v: &mut $int_type) -> &Self { - let [] = [(); align_of::() - align_of::<$int_type>()]; - // SAFETY: - // - the mutable reference guarantees unique ownership. - // - the alignment of `$int_type` and `Self` is the - // same on all platforms enabled by `$from_mut_cfg` - // as verified above. - unsafe { &*(v as *mut $int_type as *mut Self) } - } - } - doc_comment! { concat!("Consumes the atomic and returns the contained value. @@ -2077,7 +1991,6 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), - from_mut: cfg(not(target_arch = "x86")), "i64", "../../../std/primitive.i64.html", "", atomic_min, atomic_max, @@ -2096,7 +2009,6 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), - from_mut: cfg(not(target_arch = "x86")), "u64", "../../../std/primitive.u64.html", "", atomic_umin, atomic_umax, @@ -2115,7 +2027,6 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), - from_mut: cfg(not(target_arch = "x86_64")), "i128", "../../../std/primitive.i128.html", "#![feature(integer_atomics)]\n\n", atomic_min, atomic_max, @@ -2134,7 +2045,6 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), - from_mut: cfg(not(target_arch = "x86_64")), "u128", "../../../std/primitive.u128.html", "#![feature(integer_atomics)]\n\n", atomic_umin, atomic_umax, From b2532a87306fafd097241a80f92f68b10df0cba4 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 1 Jul 2020 15:10:51 +0200 Subject: [PATCH 0714/1052] Implement destructuring for all aggregates and for references --- compiler/rustc_mir/src/const_eval/mod.rs | 3 +- .../rustc_mir_build/src/build/matches/test.rs | 35 +++++- .../src/thir/pattern/const_to_pat.rs | 110 +++++++++++++----- library/std/src/ffi/os_str.rs | 2 +- src/test/ui/consts/consts-in-patterns.rs | 2 - src/test/ui/consts/match_ice.rs | 3 +- src/test/ui/consts/match_ice.stderr | 21 +--- src/test/ui/match/pattern-deref-miscompile.rs | 46 ++++++++ src/test/ui/pattern/const-pat-ice.rs | 8 +- src/test/ui/pattern/const-pat-ice.stderr | 13 --- .../usefulness/exhaustive_integer_patterns.rs | 2 +- .../exhaustive_integer_patterns.stderr | 8 +- .../usefulness/slice-pattern-const-2.rs | 6 +- .../usefulness/slice-pattern-const-2.stderr | 26 ++++- .../usefulness/slice-pattern-const-3.rs | 6 +- .../usefulness/slice-pattern-const-3.stderr | 26 ++++- .../slice-patterns-exhaustiveness.rs | 62 +++++++--- .../slice-patterns-exhaustiveness.stderr | 48 +++++++- 18 files changed, 312 insertions(+), 115 deletions(-) create mode 100644 src/test/ui/match/pattern-deref-miscompile.rs delete mode 100644 src/test/ui/pattern/const-pat-ice.stderr diff --git a/compiler/rustc_mir/src/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs index 451fa1458fda8..978d2fe000468 100644 --- a/compiler/rustc_mir/src/const_eval/mod.rs +++ b/compiler/rustc_mir/src/const_eval/mod.rs @@ -93,8 +93,7 @@ pub(crate) fn deref_const<'tcx>( MemPlaceMeta::None => mplace.layout.ty, MemPlaceMeta::Poison => bug!("poison metadata in `deref_const`: {:#?}", mplace), // In case of unsized types, figure out the real type behind. - MemPlaceMeta::Meta(scalar) => match mplace.layout.ty.kind { - ty::Dynamic(..) => ecx.read_drop_type_from_vtable(scalar).unwrap().1, + MemPlaceMeta::Meta(scalar) => match mplace.layout.ty.kind() { ty::Str => bug!("there's no sized equivalent of a `str`"), ty::Slice(elem_ty) => tcx.mk_array(elem_ty, scalar.to_machine_usize(&tcx).unwrap()), _ => bug!( diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index d81c3b68f4853..796815cf2168c 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -409,7 +409,40 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let deref_ty = match *ty.kind() { ty::Ref(_, deref_ty, _) => deref_ty, - _ => bug!("non_scalar_compare called on non-reference type: {}", ty), + _ => { + trace!("non_scalar_compare called on non-reference type: {}", ty); + // Backcompat hack: due to non-structural matches not being a hard error, we can + // reach this for types that have manual `Eq` or `PartialEq` impls. + assert!(!ty.is_structural_eq_shallow(self.hir.tcx())); + let ref_ty = self.hir.tcx().mk_imm_ref(self.hir.tcx().lifetimes.re_erased, ty); + // let y = &place; + let y = self.temp(ref_ty, source_info.span); + self.cfg.push_assign( + block, + source_info, + y, + Rvalue::Ref(self.hir.tcx().lifetimes.re_erased, BorrowKind::Shared, place), + ); + val = Operand::Move(y); + // let temp = expect; + let temp = self.temp(ty, source_info.span); + self.cfg.push_assign( + block, + source_info, + temp, + Rvalue::Use(expect), + ); + // reftemp = &temp; + let reftemp = self.temp(ref_ty, source_info.span); + self.cfg.push_assign( + block, + source_info, + reftemp, + Rvalue::Ref(self.hir.tcx().lifetimes.re_erased, BorrowKind::Shared, temp), + ); + expect = Operand::Move(reftemp); + ty + }, }; let eq_def_id = self.hir.tcx().require_lang_item(LangItem::PartialEq, None); diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 55b5838429810..d47c3e7e3aba1 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -28,10 +28,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { debug!("const_to_pat: cv={:#?} id={:?}", cv, id); debug!("const_to_pat: cv.ty={:?} span={:?}", cv.ty, span); - self.tcx.infer_ctxt().enter(|infcx| { + let pat = self.tcx.infer_ctxt().enter(|infcx| { let mut convert = ConstToPat::new(self, id, span, infcx); convert.to_pat(cv, mir_structural_match_violation) - }) + }); + + debug!("const_to_pat: pat={:?}", pat); + pat } } @@ -45,6 +48,10 @@ struct ConstToPat<'a, 'tcx> { // value. saw_const_match_error: Cell, + // For backcompat we need to keep allowing non-structurally-eq types behind references. + // See also all the `cant-hide-behind` tests. + behind_reference: Cell, + // inference context used for checking `T: Structural` bounds. infcx: InferCtxt<'a, 'tcx>, @@ -65,6 +72,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { param_env: pat_ctxt.param_env, include_lint_checks: pat_ctxt.include_lint_checks, saw_const_match_error: Cell::new(false), + behind_reference: Cell::new(false), } } @@ -233,7 +241,18 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { tcx.sess.span_err(span, "cannot use unions in constant patterns"); PatKind::Wild } - // keep old code until future-compat upgraded to errors. + // If the type is not structurally comparable, just emit the constant directly, + // causing the pattern match code to treat it opaquely. + // FIXME: This code doesn't emit errors itself, the caller emits the errors. + // So instead of specific errors, you just get blanket errors about the whole + // const type. See + // https://github.com/rust-lang/rust/pull/70743#discussion_r404701963 for + // details. + // Backwards compatibility hack because we can't cause hard errors on these + // types, so we compare them via `PartialEq::eq` at runtime. + ty::Adt(..) if !self.type_marked_structural(cv.ty) && self.behind_reference.get() => { + PatKind::Constant { value: cv } + } ty::Adt(adt_def, _) if !self.type_marked_structural(cv.ty) => { debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, cv.ty); let path = tcx.def_path_str(adt_def.did); @@ -246,28 +265,6 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { tcx.sess.span_err(span, &msg); PatKind::Wild } - // keep old code until future-compat upgraded to errors. - ty::Ref(_, adt_ty, _) if adt_ty.is_adt() && !self.type_marked_structural(adt_ty) => { - let adt_def = - if let ty::Adt(adt_def, _) = adt_ty.kind() { adt_def } else { unreachable!() }; - - debug!( - "adt_def {:?} has !type_marked_structural for adt_ty: {:?}", - adt_def, adt_ty - ); - - // HACK(estebank): Side-step ICE #53708, but anything other than erroring here - // would be wrong. Returnging `PatKind::Wild` is not technically correct. - let path = tcx.def_path_str(adt_def.did); - let msg = format!( - "to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - path, path, - ); - self.saw_const_match_error.set(true); - tcx.sess.span_err(span, &msg); - PatKind::Wild - } ty::Adt(adt_def, substs) if adt_def.is_enum() => { let destructured = tcx.destructure_const(param_env.and(cv)); PatKind::Variant { @@ -293,7 +290,68 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { slice: None, suffix: Vec::new(), }, - _ => PatKind::Constant { value: cv }, + ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() { + // These are not allowed and will error elsewhere anyway. + ty::Dynamic(..) => PatKind::Constant { value: cv }, + // `&str` and `&[u8]` are represented as `ConstValue::Slice`, let's keep using this + // optimization for now. + ty::Str => PatKind::Constant { value: cv }, + ty::Slice(elem_ty) if elem_ty == tcx.types.u8 => PatKind::Constant { value: cv }, + // `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when + // matching against references, you can only use byte string literals. + // FIXME: clean this up, likely by permitting array patterns when matching on slices + ty::Array(elem_ty, _) if elem_ty == tcx.types.u8 => PatKind::Constant { value: cv }, + // Cannot merge this with the catch all branch below, because the `const_deref` + // changes the type from slice to array, and slice patterns behave differently from + // array patterns. + ty::Slice(..) => { + let old = self.behind_reference.replace(true); + let array = tcx.deref_const(self.param_env.and(cv)); + let val = PatKind::Deref { + subpattern: Pat { + kind: Box::new(PatKind::Slice { + prefix: tcx + .destructure_const(param_env.and(array)) + .fields + .iter() + .map(|val| self.recur(val)) + .collect(), + slice: None, + suffix: vec![], + }), + span, + ty: pointee_ty, + }, + }; + self.behind_reference.set(old); + val + } + // Backwards compatibility hack. Don't take away the reference, since + // `PartialEq::eq` takes a reference, this makes the rest of the matching logic + // simpler. + ty::Adt(..) if !self.type_marked_structural(pointee_ty) => { + PatKind::Constant { value: cv } + } + _ => { + let old = self.behind_reference.replace(true); + let val = PatKind::Deref { + subpattern: self.recur(tcx.deref_const(self.param_env.and(cv))), + }; + self.behind_reference.set(old); + val + } + }, + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::FnDef(..) => { + PatKind::Constant { value: cv } + } + // FIXME: these can have very suprising behaviour where optimization levels or other + // compilation choices change the runtime behaviour of the match. + // See https://github.com/rust-lang/rust/issues/70861 for examples. + ty::FnPtr(..) | ty::RawPtr(..) => PatKind::Constant { value: cv }, + _ => { + tcx.sess.delay_span_bug(span, &format!("cannot make a pattern out of {}", cv.ty)); + PatKind::Wild + } }; Pat { span, ty: cv.ty, kind: Box::new(kind) } diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index c83e996634c8a..2663f682a1de8 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -94,7 +94,7 @@ pub struct OsString { // `OsStr::from_inner` current implementation relies // on `OsStr` being layout-compatible with `Slice`. // When attribute privacy is implemented, `OsStr` should be annotated as `#[repr(transparent)]`. -// Anyway, `OsStr` representation and layout are considered implementation detail, are +// Anyway, `OsStr` representation and layout are considered implementation details, are // not documented and must not be relied upon. pub struct OsStr { inner: Slice, diff --git a/src/test/ui/consts/consts-in-patterns.rs b/src/test/ui/consts/consts-in-patterns.rs index d51215447d6ca..0295204c879ca 100644 --- a/src/test/ui/consts/consts-in-patterns.rs +++ b/src/test/ui/consts/consts-in-patterns.rs @@ -19,8 +19,6 @@ pub fn main() { assert_eq!(y, 2); let z = match &() { ZST => 9, - // FIXME: this should not be required - _ => 42, }; assert_eq!(z, 9); let z = match b"" { diff --git a/src/test/ui/consts/match_ice.rs b/src/test/ui/consts/match_ice.rs index 1e495438e836c..008c03ecddcc6 100644 --- a/src/test/ui/consts/match_ice.rs +++ b/src/test/ui/consts/match_ice.rs @@ -10,10 +10,9 @@ fn main() { match C { C => {} //~^ ERROR to use a constant of type `S` in a pattern, `S` must be annotated with - //~| ERROR to use a constant of type `S` in a pattern, `S` must be annotated with } const K: &T = &T; - match K { //~ ERROR non-exhaustive patterns: `&T` not covered + match K { K => {} } } diff --git a/src/test/ui/consts/match_ice.stderr b/src/test/ui/consts/match_ice.stderr index 5477170fb1e41..699b4a5e200e4 100644 --- a/src/test/ui/consts/match_ice.stderr +++ b/src/test/ui/consts/match_ice.stderr @@ -4,24 +4,5 @@ error: to use a constant of type `S` in a pattern, `S` must be annotated with `# LL | C => {} | ^ -error[E0004]: non-exhaustive patterns: `&T` not covered - --> $DIR/match_ice.rs:16:11 - | -LL | struct T; - | --------- `T` defined here -... -LL | match K { - | ^ pattern `&T` 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` - -error: to use a constant of type `S` in a pattern, `S` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/match_ice.rs:11:9 - | -LL | C => {} - | ^ - -error: aborting due to 3 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/match/pattern-deref-miscompile.rs b/src/test/ui/match/pattern-deref-miscompile.rs new file mode 100644 index 0000000000000..caa6d184a92dd --- /dev/null +++ b/src/test/ui/match/pattern-deref-miscompile.rs @@ -0,0 +1,46 @@ +// run-pass + +fn main() { + match b"." as &[u8] { + b"." if true => {}, + b"." => panic!(), + b".." => panic!(), + b"" => panic!(), + _ => panic!(), + } + match b"." as &[u8] { + b"." if false => panic!(), + b"." => {}, + b".." => panic!(), + b"" => panic!(), + _ => panic!(), + } + match b".." as &[u8] { + b"." if true => panic!(), // the miscompile caused this arm to be reached + b"." => panic!(), + b".." => {}, + b"" => panic!(), + _ => panic!(), + } + match b".." as &[u8] { + b"." if false => panic!(), + b"." => panic!(), + b".." => {}, + b"" => panic!(), + _ => panic!(), + } + match b"" as &[u8] { + b"." if true => panic!(), + b"." => panic!(), + b".." => panic!(), + b"" => {}, + _ => panic!(), + } + match b"" as &[u8] { + b"." if false => panic!(), + b"." => panic!(), + b".." => panic!(), + b"" => {}, + _ => panic!(), + } +} diff --git a/src/test/ui/pattern/const-pat-ice.rs b/src/test/ui/pattern/const-pat-ice.rs index 0655876788214..abfacf3936b6d 100644 --- a/src/test/ui/pattern/const-pat-ice.rs +++ b/src/test/ui/pattern/const-pat-ice.rs @@ -1,10 +1,4 @@ -// failure-status: 101 -// rustc-env:RUST_BACKTRACE=0 -// normalize-stderr-test "note: rustc 1.* running on .*" -> "note: rustc VERSION running on TARGET" -// normalize-stderr-test "note: compiler flags: .*" -> "note: compiler flags: FLAGS" -// normalize-stderr-test "/_match.rs:[0-9]+:[0-9]+" -> "/_match.rs:LL:CC" - -// This is a repro test for an ICE in our pattern handling of constants. +// check-pass const FOO: &&&u32 = &&&42; diff --git a/src/test/ui/pattern/const-pat-ice.stderr b/src/test/ui/pattern/const-pat-ice.stderr deleted file mode 100644 index 6b42c0e0848e9..0000000000000 --- a/src/test/ui/pattern/const-pat-ice.stderr +++ /dev/null @@ -1,13 +0,0 @@ -thread 'rustc' panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', compiler/rustc_mir_build/src/thir/pattern/_match.rs:LL:CC -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace - -error: internal compiler error: unexpected panic - -note: the compiler unexpectedly panicked. this is a bug. - -note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md - -note: rustc VERSION running on TARGET - -note: compiler flags: FLAGS - diff --git a/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.rs b/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.rs index d379dc44bf10b..78cc0d28fb037 100644 --- a/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.rs +++ b/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.rs @@ -160,7 +160,7 @@ fn main() { match &0 { &42 => {} &FOO => {} //~ ERROR unreachable pattern - BAR => {} // Not detected as unreachable because `try_eval_bits` fails on `BAR`. + BAR => {} //~ ERROR unreachable pattern _ => {} } diff --git a/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr b/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr index de8315205980c..9f076c50a8f09 100644 --- a/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr +++ b/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr @@ -135,6 +135,12 @@ error: unreachable pattern LL | &FOO => {} | ^^^^ -error: aborting due to 15 previous errors +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`. diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const-2.rs b/src/test/ui/pattern/usefulness/slice-pattern-const-2.rs index a36c550f530a9..4bf8d0fd2d306 100644 --- a/src/test/ui/pattern/usefulness/slice-pattern-const-2.rs +++ b/src/test/ui/pattern/usefulness/slice-pattern-const-2.rs @@ -6,19 +6,19 @@ fn main() { match s { MAGIC_TEST => (), [0x00, 0x00, 0x00, 0x00] => (), - [4, 5, 6, 7] => (), // FIXME(oli-obk): this should warn, but currently does not + [4, 5, 6, 7] => (), //~ ERROR unreachable pattern _ => (), } match s { [0x00, 0x00, 0x00, 0x00] => (), MAGIC_TEST => (), - [4, 5, 6, 7] => (), // FIXME(oli-obk): this should warn, but currently does not + [4, 5, 6, 7] => (), //~ ERROR unreachable pattern _ => (), } match s { [0x00, 0x00, 0x00, 0x00] => (), [4, 5, 6, 7] => (), - MAGIC_TEST => (), // FIXME(oli-obk): this should warn, but currently does not + MAGIC_TEST => (), //~ ERROR unreachable pattern _ => (), } const FOO: [u32; 1] = [4]; diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const-2.stderr b/src/test/ui/pattern/usefulness/slice-pattern-const-2.stderr index cd0cb2e887691..dcad11a38a7eb 100644 --- a/src/test/ui/pattern/usefulness/slice-pattern-const-2.stderr +++ b/src/test/ui/pattern/usefulness/slice-pattern-const-2.stderr @@ -1,8 +1,8 @@ error: unreachable pattern - --> $DIR/slice-pattern-const-2.rs:28:9 + --> $DIR/slice-pattern-const-2.rs:9:9 | -LL | FOO => (), - | ^^^ +LL | [4, 5, 6, 7] => (), + | ^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/slice-pattern-const-2.rs:1:9 @@ -10,5 +10,23 @@ note: the lint level is defined here LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: unreachable pattern + --> $DIR/slice-pattern-const-2.rs:15:9 + | +LL | [4, 5, 6, 7] => (), + | ^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const-2.rs:21:9 + | +LL | MAGIC_TEST => (), + | ^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const-2.rs:28:9 + | +LL | FOO => (), + | ^^^ + +error: aborting due to 4 previous errors diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const-3.rs b/src/test/ui/pattern/usefulness/slice-pattern-const-3.rs index 8805c43ba0283..2ca8323f00295 100644 --- a/src/test/ui/pattern/usefulness/slice-pattern-const-3.rs +++ b/src/test/ui/pattern/usefulness/slice-pattern-const-3.rs @@ -6,19 +6,19 @@ fn main() { match s { MAGIC_TEST => (), ["0x00", "0x00", "0x00", "0x00"] => (), - ["4", "5", "6", "7"] => (), // FIXME(oli-obk): this should warn, but currently does not + ["4", "5", "6", "7"] => (), //~ ERROR unreachable pattern _ => (), } match s { ["0x00", "0x00", "0x00", "0x00"] => (), MAGIC_TEST => (), - ["4", "5", "6", "7"] => (), // FIXME(oli-obk): this should warn, but currently does not + ["4", "5", "6", "7"] => (), //~ ERROR unreachable pattern _ => (), } match s { ["0x00", "0x00", "0x00", "0x00"] => (), ["4", "5", "6", "7"] => (), - MAGIC_TEST => (), // FIXME(oli-obk): this should warn, but currently does not + MAGIC_TEST => (), //~ ERROR unreachable pattern _ => (), } const FOO: [&str; 1] = ["boo"]; diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const-3.stderr b/src/test/ui/pattern/usefulness/slice-pattern-const-3.stderr index 3ba01b9eba3ce..b90b3a88a1860 100644 --- a/src/test/ui/pattern/usefulness/slice-pattern-const-3.stderr +++ b/src/test/ui/pattern/usefulness/slice-pattern-const-3.stderr @@ -1,8 +1,8 @@ error: unreachable pattern - --> $DIR/slice-pattern-const-3.rs:28:9 + --> $DIR/slice-pattern-const-3.rs:9:9 | -LL | FOO => (), - | ^^^ +LL | ["4", "5", "6", "7"] => (), + | ^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/slice-pattern-const-3.rs:1:9 @@ -10,5 +10,23 @@ note: the lint level is defined here LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: unreachable pattern + --> $DIR/slice-pattern-const-3.rs:15:9 + | +LL | ["4", "5", "6", "7"] => (), + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const-3.rs:21:9 + | +LL | MAGIC_TEST => (), + | ^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const-3.rs:28:9 + | +LL | FOO => (), + | ^^^ + +error: aborting due to 4 previous errors diff --git a/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs index 52d1320dad153..46e0da5be9b4f 100644 --- a/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs +++ b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs @@ -6,15 +6,15 @@ fn main() { let s10: &[bool; 10] = &[false; 10]; match s2 { - //~^ ERROR `&[false, _]` not covered + //~^ ERROR `&[false, _]` not covered [true, .., true] => {} } match s3 { - //~^ ERROR `&[false, ..]` not covered + //~^ ERROR `&[false, ..]` not covered [true, .., true] => {} } match s10 { - //~^ ERROR `&[false, ..]` not covered + //~^ ERROR `&[false, ..]` not covered [true, .., true] => {} } @@ -23,58 +23,58 @@ fn main() { [.., false] => {} } match s2 { - //~^ ERROR `&[false, true]` not covered + //~^ ERROR `&[false, true]` not covered [true, ..] => {} [.., false] => {} } match s3 { - //~^ ERROR `&[false, .., true]` not covered + //~^ ERROR `&[false, .., true]` not covered [true, ..] => {} [.., false] => {} } match s { - //~^ ERROR `&[false, .., true]` not covered + //~^ ERROR `&[false, .., true]` not covered [] => {} [true, ..] => {} [.., false] => {} } match s { - //~^ ERROR `&[_, ..]` not covered + //~^ ERROR `&[_, ..]` not covered [] => {} } match s { - //~^ ERROR `&[_, _, ..]` not covered + //~^ ERROR `&[_, _, ..]` not covered [] => {} [_] => {} } match s { - //~^ ERROR `&[false, ..]` not covered + //~^ ERROR `&[false, ..]` not covered [] => {} [true, ..] => {} } match s { - //~^ ERROR `&[false, _, ..]` not covered + //~^ ERROR `&[false, _, ..]` not covered [] => {} [_] => {} [true, ..] => {} } match s { - //~^ ERROR `&[_, .., false]` not covered + //~^ ERROR `&[_, .., false]` not covered [] => {} [_] => {} [.., true] => {} } match s { - //~^ ERROR `&[_, _, .., true]` not covered + //~^ ERROR `&[_, _, .., true]` not covered [] => {} [_] => {} [_, _] => {} [.., false] => {} } match s { - //~^ ERROR `&[true, _, .., _]` not covered + //~^ ERROR `&[true, _, .., _]` not covered [] => {} [_] => {} [_, _] => {} @@ -83,19 +83,43 @@ fn main() { const CONST: &[bool] = &[true]; match s { - //~^ ERROR `&[..]` not covered + //~^ ERROR `&[]` and `&[_, _, ..]` not covered + &[true] => {} + } + match s { + //~^ ERROR `&[]` and `&[_, _, ..]` not covered + CONST => {} + } + match s { + //~^ ERROR `&[]` and `&[_, _, ..]` not covered CONST => {} + &[false] => {} } match s { - //~^ ERROR `&[true]` not covered - [] => {}, - [false] => {}, - CONST => {}, + //~^ ERROR `&[]` and `&[_, _, ..]` not covered + &[false] => {} + CONST => {} + } + match s { + //~^ ERROR `&[_, _, ..]` not covered + &[] => {} + CONST => {} + } + match s { + //~^ ERROR `&[false]` not covered + &[] => {} + CONST => {} + &[_, _, ..] => {} + } + match s { + [] => {} + [false] => {} + CONST => {} [_, _, ..] => {} } const CONST1: &[bool; 1] = &[true]; match s1 { - //~^ ERROR `&[false]` not covered + //~^ ERROR `&[false]` not covered CONST1 => {} } match s1 { diff --git a/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr index 8b85eaeda0acf..e34770fb912e7 100644 --- a/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr +++ b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr @@ -115,26 +115,62 @@ LL | match s { = 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]` -error[E0004]: non-exhaustive patterns: `&[..]` not covered +error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered --> $DIR/slice-patterns-exhaustiveness.rs:85:11 | LL | match s { - | ^ pattern `&[..]` not covered + | ^ patterns `&[]` and `&[_, _, ..]` 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]` -error[E0004]: non-exhaustive patterns: `&[true]` not covered +error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered --> $DIR/slice-patterns-exhaustiveness.rs:89:11 | LL | match s { - | ^ pattern `&[true]` not covered + | ^ patterns `&[]` and `&[_, _, ..]` 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]` + +error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:93:11 + | +LL | match s { + | ^ patterns `&[]` and `&[_, _, ..]` 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]` + +error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:98:11 + | +LL | match s { + | ^ patterns `&[]` and `&[_, _, ..]` 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]` + +error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:103:11 + | +LL | match s { + | ^ 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 `&[bool]` + +error[E0004]: non-exhaustive patterns: `&[false]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:108:11 + | +LL | match s { + | ^ pattern `&[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]` error[E0004]: non-exhaustive patterns: `&[false]` not covered - --> $DIR/slice-patterns-exhaustiveness.rs:97:11 + --> $DIR/slice-patterns-exhaustiveness.rs:121:11 | LL | match s1 { | ^^ pattern `&[false]` not covered @@ -142,6 +178,6 @@ LL | match s1 { = 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; 1]` -error: aborting due to 16 previous errors +error: aborting due to 20 previous errors For more information about this error, try `rustc --explain E0004`. From 5fb32c2e33fd102adb14d943355542d1a1d2e68e Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Sun, 2 Aug 2020 01:47:52 +0200 Subject: [PATCH 0715/1052] New MIR optimization pass to reduce branches on match of tuples of enums --- .../src/transform/early_otherwise_branch.rs | 313 ++++++++++++++++++ compiler/rustc_mir/src/transform/mod.rs | 2 + ...wise_branch.opt1.EarlyOtherwiseBranch.diff | 88 +++++ ...ranch.opt1.EarlyOtherwiseBranch.diff.32bit | 88 +++++ ...ranch.opt1.EarlyOtherwiseBranch.diff.64bit | 88 +++++ ...wise_branch.opt2.EarlyOtherwiseBranch.diff | 105 ++++++ ...ranch.opt2.EarlyOtherwiseBranch.diff.32bit | 105 ++++++ ...ranch.opt2.EarlyOtherwiseBranch.diff.64bit | 105 ++++++ src/test/mir-opt/early_otherwise_branch.rs | 23 ++ ...ement_tuple.opt1.EarlyOtherwiseBranch.diff | 117 +++++++ ...tuple.opt1.EarlyOtherwiseBranch.diff.32bit | 117 +++++++ ...tuple.opt1.EarlyOtherwiseBranch.diff.64bit | 117 +++++++ .../early_otherwise_branch_3_element_tuple.rs | 14 + .../mir-opt/early_otherwise_branch_68867.rs | 31 ++ ...ch_68867.try_sum.EarlyOtherwiseBranch.diff | 219 ++++++++++++ ...nch_noopt.noopt1.EarlyOtherwiseBranch.diff | 114 +++++++ ...opt.noopt1.EarlyOtherwiseBranch.diff.32bit | 114 +++++++ ...opt.noopt1.EarlyOtherwiseBranch.diff.64bit | 114 +++++++ ...nch_noopt.noopt2.EarlyOtherwiseBranch.diff | 72 ++++ ...opt.noopt2.EarlyOtherwiseBranch.diff.32bit | 72 ++++ ...opt.noopt2.EarlyOtherwiseBranch.diff.64bit | 72 ++++ .../mir-opt/early_otherwise_branch_noopt.rs | 29 ++ 22 files changed, 2119 insertions(+) create mode 100644 compiler/rustc_mir/src/transform/early_otherwise_branch.rs create mode 100644 src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff create mode 100644 src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff.32bit create mode 100644 src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff.64bit create mode 100644 src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff create mode 100644 src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff.32bit create mode 100644 src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff.64bit create mode 100644 src/test/mir-opt/early_otherwise_branch.rs create mode 100644 src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff create mode 100644 src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff.32bit create mode 100644 src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff.64bit create mode 100644 src/test/mir-opt/early_otherwise_branch_3_element_tuple.rs create mode 100644 src/test/mir-opt/early_otherwise_branch_68867.rs create mode 100644 src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff create mode 100644 src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff create mode 100644 src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff.32bit create mode 100644 src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff.64bit create mode 100644 src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff create mode 100644 src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff.32bit create mode 100644 src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff.64bit create mode 100644 src/test/mir-opt/early_otherwise_branch_noopt.rs diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs new file mode 100644 index 0000000000000..0dc311ebb8c1f --- /dev/null +++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs @@ -0,0 +1,313 @@ +use crate::{ + transform::{MirPass, MirSource}, + util::patch::MirPatch, +}; +use rustc_middle::mir::*; +use rustc_middle::ty::{Ty, TyCtxt}; +use std::{borrow::Cow, fmt::Debug}; + +/// This pass optimizes something like +/// ```text +/// let x: Option<()>; +/// let y: Option<()>; +/// match (x,y) { +/// (Some(_), Some(_)) => {0}, +/// _ => {1} +/// } +/// ``` +/// into something like +/// ```text +/// let x: Option<()>; +/// let y: Option<()>; +/// let discriminant_x = // get discriminant of x +/// let discriminant_y = // get discriminant of x +/// if discriminant_x != discriminant_y {1} else {0} +/// ``` +pub struct EarlyOtherwiseBranch; + +impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { + fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { + if tcx.sess.opts.debugging_opts.mir_opt_level < 3 { + return; + } + trace!("running EarlyOtherwiseBranch on {:?}", source); + // we are only interested in this bb if the terminator is a switchInt + let bbs_with_switch = + body.basic_blocks().iter_enumerated().filter(|(_, bb)| is_switch(bb.terminator())); + + let opts_to_apply: Vec> = bbs_with_switch + .flat_map(|(bb_idx, bb)| { + let switch = bb.terminator(); + let helper = Helper { body, tcx }; + let infos = helper.go(bb, switch)?; + Some(OptimizationToApply { infos, basic_block_first_switch: bb_idx }) + }) + .collect(); + + for opt_to_apply in opts_to_apply { + trace!("SUCCESS: found optimization possibility to apply: {:?}", &opt_to_apply); + // create the patch using MirPatch + let mut patch = MirPatch::new(body); + + // create temp to store second discriminant in + let discr_type = opt_to_apply.infos[0].second_switch_info.discr_ty; + let discr_span = opt_to_apply.infos[0].second_switch_info.discr_source_info.span; + let temp = patch.new_temp(discr_type, discr_span); + let statements_before = + body.basic_blocks()[opt_to_apply.basic_block_first_switch].statements.len(); + let end_of_block_location = Location { + block: opt_to_apply.basic_block_first_switch, + statement_index: statements_before, + }; + patch.add_statement(end_of_block_location, StatementKind::StorageLive(temp)); + + // create assignment of discriminant + let place_of_adt_to_get_discriminant_of = + opt_to_apply.infos[0].second_switch_info.place_of_adt_discr_read; + patch.add_assign( + end_of_block_location, + Place::from(temp), + Rvalue::Discriminant(place_of_adt_to_get_discriminant_of), + ); + + // create temp to store NotEqual comparison between the two discriminants + let not_equal = BinOp::Ne; + let not_equal_res_type = not_equal.ty(tcx, discr_type, discr_type); + let not_equal_temp = patch.new_temp(not_equal_res_type, discr_span); + patch.add_statement(end_of_block_location, StatementKind::StorageLive(not_equal_temp)); + + // create NotEqual comparison between the two discriminants + let first_descriminant_place = + opt_to_apply.infos[0].first_switch_info.discr_used_in_switch; + let not_equal_rvalue = Rvalue::BinaryOp( + not_equal, + Operand::Copy(Place::from(temp)), + Operand::Copy(Place::from(first_descriminant_place)), + ); + patch.add_statement( + end_of_block_location, + StatementKind::Assign(box (Place::from(not_equal_temp), not_equal_rvalue)), + ); + + let (mut targets_to_jump_to, values_to_jump_to): (Vec<_>, Vec<_>) = opt_to_apply + .infos + .iter() + .flat_map(|x| x.second_switch_info.targets_with_values.iter()) + .cloned() + .unzip(); + + // add otherwise case in the end + targets_to_jump_to.push(opt_to_apply.infos[0].first_switch_info.otherwise_bb); + // new block that jumps to the correct discriminant case. This block is switched to if the discriminants are equal + let new_switch_data = BasicBlockData::new(Some(Terminator { + source_info: opt_to_apply.infos[0].second_switch_info.discr_source_info, + kind: TerminatorKind::SwitchInt { + // the first and second discriminants are equal, so just pick one + discr: Operand::Copy(first_descriminant_place), + switch_ty: discr_type, + values: Cow::from(values_to_jump_to), + targets: targets_to_jump_to, + }, + })); + + let new_switch_bb = patch.new_block(new_switch_data); + + // switch on the NotEqual. If true, then jump to the `otherwise` case. + // If false, then jump to a basic block that then jumps to the correct disciminant case + let true_case = opt_to_apply.infos[0].first_switch_info.otherwise_bb; + let false_case = new_switch_bb; + patch.patch_terminator( + opt_to_apply.basic_block_first_switch, + TerminatorKind::if_( + tcx, + Operand::Move(Place::from(not_equal_temp)), + true_case, + false_case, + ), + ); + + // generate StorageDead for the temp not in use anymore. We use the not_equal_temp in the switch, so we can't mark that dead + patch.add_statement(end_of_block_location, StatementKind::StorageDead(temp)); + + patch.apply(body); + } + } +} + +fn is_switch<'tcx>(terminator: &Terminator<'tcx>) -> bool { + match terminator.kind { + TerminatorKind::SwitchInt { .. } => true, + _ => false, + } +} + +struct Helper<'a, 'tcx> { + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, +} + +#[derive(Debug, Clone)] +struct SwitchDiscriminantInfo<'tcx> { + /// Type of the discriminant being switched on + discr_ty: Ty<'tcx>, + /// The basic block that the otherwise branch points to + otherwise_bb: BasicBlock, + /// Target along with the value being branched from. Otherwise is not included + targets_with_values: Vec<(BasicBlock, u128)>, + discr_source_info: SourceInfo, + /// The place of the discriminant used in the switch + discr_used_in_switch: Place<'tcx>, + /// The place of the adt that has its discriminant read + place_of_adt_discr_read: Place<'tcx>, + /// The type of the adt that has its discriminant read + type_adt_matched_on: Ty<'tcx>, +} + +#[derive(Debug)] +struct OptimizationToApply<'tcx> { + infos: Vec>, + /// Basic block of the original first switch + basic_block_first_switch: BasicBlock, +} + +#[derive(Debug)] +struct OptimizationInfo<'tcx> { + /// Info about the first switch and discriminant + first_switch_info: SwitchDiscriminantInfo<'tcx>, + /// Info about the second switch and discriminant + second_switch_info: SwitchDiscriminantInfo<'tcx>, +} + +impl<'a, 'tcx> Helper<'a, 'tcx> { + pub fn go( + &self, + bb: &BasicBlockData<'tcx>, + switch: &Terminator<'tcx>, + ) -> Option>> { + // try to find the statement that defines the discriminant that is used for the switch + let discr = self.find_switch_discriminant_info(bb, switch)?; + + // go through each target, finding a discriminant read, and a switch + let results = discr.targets_with_values.iter().map(|(target, value)| { + self.find_discriminant_switch_pairing(&discr, target.clone(), value.clone()) + }); + + // if the optimization did not apply for one of the targets, then abort + if results.clone().any(|x| x.is_none()) || results.len() == 0 { + trace!("NO: not all of the targets matched the pattern for optimization"); + return None; + } + + Some(results.flatten().collect()) + } + + fn find_discriminant_switch_pairing( + &self, + discr_info: &SwitchDiscriminantInfo<'tcx>, + target: BasicBlock, + value: u128, + ) -> Option> { + let bb = &self.body.basic_blocks()[target]; + // find switch + let terminator = bb.terminator(); + if is_switch(terminator) { + let this_bb_discr_info = self.find_switch_discriminant_info(bb, terminator)?; + + // the types of the two adts matched on have to be equalfor this optimization to apply + if discr_info.type_adt_matched_on != this_bb_discr_info.type_adt_matched_on { + trace!( + "NO: types do not match. LHS: {:?}, RHS: {:?}", + discr_info.type_adt_matched_on, + this_bb_discr_info.type_adt_matched_on + ); + return None; + } + + // the otherwise branch of the two switches have to point to the same bb + if discr_info.otherwise_bb != this_bb_discr_info.otherwise_bb { + trace!("NO: otherwise target is not the same"); + return None; + } + + // check that the value being matched on is the same. The + if this_bb_discr_info.targets_with_values.iter().find(|x| x.1 == value).is_none() { + trace!("NO: values being matched on are not the same"); + return None; + } + + // only allow optimization if the left and right of the tuple being matched are the same variants. + // so the following should not optimize + // ```rust + // let x: Option<()>; + // let y: Option<()>; + // match (x,y) { + // (Some(_), None) => {}, + // _ => {} + // } + // ``` + // We check this by seeing that the value of the first discriminant is the only other discriminant value being used as a target in the second switch + if !(this_bb_discr_info.targets_with_values.len() == 1 + && this_bb_discr_info.targets_with_values[0].1 == value) + { + trace!( + "NO: The second switch did not have only 1 target (besides otherwise) that had the same value as the value from the first switch that got us here" + ); + return None; + } + + // if we reach this point, the optimization applies, and we should be able to optimize this case + // store the info that is needed to apply the optimization + + Some(OptimizationInfo { + first_switch_info: discr_info.clone(), + second_switch_info: this_bb_discr_info, + }) + } else { + None + } + } + + fn find_switch_discriminant_info( + &self, + bb: &BasicBlockData<'tcx>, + switch: &Terminator<'tcx>, + ) -> Option> { + match &switch.kind { + TerminatorKind::SwitchInt { discr, targets, values, .. } => { + let discr_local = discr.place()?.as_local()?; + // the declaration of the discriminant read. Place of this read is being used in the switch + let discr_decl = &self.body.local_decls()[discr_local]; + let discr_ty = discr_decl.ty; + // the otherwise target lies as the last element + let otherwise_bb = targets.get(values.len())?.clone(); + let targets_with_values = targets + .iter() + .zip(values.iter()) + .map(|(t, v)| (t.clone(), v.clone())) + .collect(); + + // find the place of the adt where the discriminant is being read from + // assume this is the last statement of the block + let place_of_adt_discr_read = match bb.statements.last()?.kind { + StatementKind::Assign(box (_, Rvalue::Discriminant(adt_place))) => { + Some(adt_place) + } + _ => None, + }?; + + let type_adt_matched_on = place_of_adt_discr_read.ty(self.body, self.tcx).ty; + + Some(SwitchDiscriminantInfo { + discr_used_in_switch: discr.place()?, + discr_ty, + otherwise_bb, + targets_with_values, + discr_source_info: discr_decl.source_info, + place_of_adt_discr_read, + type_adt_matched_on, + }) + } + _ => unreachable!("must only be passed terminator that is a switch"), + } + } +} diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index fc9854ba499f8..abe2dc496a630 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -26,6 +26,7 @@ pub mod copy_prop; pub mod deaggregator; pub mod dest_prop; pub mod dump_mir; +pub mod early_otherwise_branch; pub mod elaborate_drops; pub mod generator; pub mod inline; @@ -465,6 +466,7 @@ fn run_optimization_passes<'tcx>( &instcombine::InstCombine, &const_prop::ConstProp, &simplify_branches::SimplifyBranches::new("after-const-prop"), + &early_otherwise_branch::EarlyOtherwiseBranch, &simplify_comparison_integral::SimplifyComparisonIntegral, &simplify_try::SimplifyArmIdentity, &simplify_try::SimplifyBranchSame, diff --git a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff new file mode 100644 index 0000000000000..28c9d422a9f4f --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff @@ -0,0 +1,88 @@ +- // MIR for `opt1` before EarlyOtherwiseBranch ++ // MIR for `opt1` after EarlyOtherwiseBranch + + fn opt1(_1: std::option::Option, _2: std::option::Option) -> usize { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:5:9: 5:10 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:5:27: 5:28 + let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch.rs:5:47: 5:52 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch.rs:6:11: 6:16 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:6:12: 6:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:6:14: 6:15 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:7:19: 7:26 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:7:10: 7:17 + let _8: usize; // in scope 0 at $DIR/early_otherwise_branch.rs:7:15: 7:16 + let _9: usize; // in scope 0 at $DIR/early_otherwise_branch.rs:7:24: 7:25 ++ let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:7:19: 7:26 ++ let mut _11: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:7:19: 7:26 + scope 1 { + debug a => _8; // in scope 1 at $DIR/early_otherwise_branch.rs:7:15: 7:16 + debug b => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:7:24: 7:25 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:6:11: 6:16 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:6:12: 6:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch.rs:6:12: 6:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:6:14: 6:15 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch.rs:6:14: 6:15 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:6:11: 6:16 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:6:11: 6:16 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:6:15: 6:16 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:6:15: 6:16 + _7 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:7:10: 7:17 +- switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:7:10: 7:17 ++ StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:7:10: 7:17 ++ _10 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:7:10: 7:17 ++ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:7:10: 7:17 ++ _11 = Ne(_10, _7); // scope 0 at $DIR/early_otherwise_branch.rs:7:10: 7:17 ++ StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:7:10: 7:17 ++ switchInt(move _11) -> [false: bb6, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:7:10: 7:17 + } + + bb1: { + _0 = const 1_usize; // scope 0 at $DIR/early_otherwise_branch.rs:8:14: 8:15 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000001)) + // mir::Constant + // + span: $DIR/early_otherwise_branch.rs:8:14: 8:15 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) } + goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:6:5: 9:6 + } + + bb2: { + _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:7:19: 7:26 + switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:7:19: 7:26 + } + + bb3: { + StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch.rs:7:15: 7:16 + _8 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch.rs:7:15: 7:16 + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:7:24: 7:25 + _9 = (((_3.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch.rs:7:24: 7:25 + _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch.rs:7:31: 7:32 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000000)) + // mir::Constant + // + span: $DIR/early_otherwise_branch.rs:7:31: 7:32 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:7:31: 7:32 + StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch.rs:7:31: 7:32 + goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:6:5: 9:6 + } + + bb4: { + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:10:1: 10:2 + return; // scope 0 at $DIR/early_otherwise_branch.rs:10:2: 10:2 ++ } ++ ++ bb5 (cleanup): { ++ resume; // scope 0 at $DIR/early_otherwise_branch.rs:5:1: 10:2 ++ } ++ ++ bb6: { ++ switchInt(_7) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:7:19: 7:26 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff.32bit b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff.32bit new file mode 100644 index 0000000000000..dbeb09bf2bbc8 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff.32bit @@ -0,0 +1,88 @@ +- // MIR for `opt1` before EarlyOtherwiseBranch ++ // MIR for `opt1` after EarlyOtherwiseBranch + + fn opt1(_1: std::option::Option, _2: std::option::Option) -> usize { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:4:9: 4:10 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:4:27: 4:28 + let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch.rs:4:47: 4:52 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch.rs:5:11: 5:16 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:5:12: 5:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:5:14: 5:15 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:6:19: 6:26 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 + let _8: usize; // in scope 0 at $DIR/early_otherwise_branch.rs:6:15: 6:16 + let _9: usize; // in scope 0 at $DIR/early_otherwise_branch.rs:6:24: 6:25 ++ let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:6:19: 6:26 ++ let mut _11: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:6:19: 6:26 + scope 1 { + debug a => _8; // in scope 1 at $DIR/early_otherwise_branch.rs:6:15: 6:16 + debug b => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:6:24: 6:25 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:5:11: 5:16 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:5:12: 5:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch.rs:5:12: 5:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:5:14: 5:15 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch.rs:5:14: 5:15 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:5:11: 5:16 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:5:11: 5:16 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:5:15: 5:16 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:5:15: 5:16 + _7 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 +- switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 ++ StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 ++ _10 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 ++ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 ++ _11 = Ne(_10, _7); // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 ++ StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 ++ switchInt(move _11) -> [false: bb6, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 + } + + bb1: { + _0 = const 1_usize; // scope 0 at $DIR/early_otherwise_branch.rs:7:14: 7:15 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x00000001)) + // mir::Constant + // + span: $DIR/early_otherwise_branch.rs:7:14: 7:15 + // + literal: Const { ty: usize, val: Value(Scalar(0x00000001)) } + goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:5:5: 8:6 + } + + bb2: { + _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:6:19: 6:26 + switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:6:19: 6:26 + } + + bb3: { + StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch.rs:6:15: 6:16 + _8 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch.rs:6:15: 6:16 + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:6:24: 6:25 + _9 = (((_3.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch.rs:6:24: 6:25 + _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch.rs:6:31: 6:32 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x00000000)) + // mir::Constant + // + span: $DIR/early_otherwise_branch.rs:6:31: 6:32 + // + literal: Const { ty: usize, val: Value(Scalar(0x00000000)) } + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:6:31: 6:32 + StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch.rs:6:31: 6:32 + goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:5:5: 8:6 + } + + bb4: { + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:9:1: 9:2 + return; // scope 0 at $DIR/early_otherwise_branch.rs:9:2: 9:2 ++ } ++ ++ bb5 (cleanup): { ++ resume; // scope 0 at $DIR/early_otherwise_branch.rs:4:1: 9:2 ++ } ++ ++ bb6: { ++ switchInt(_7) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:6:19: 6:26 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff.64bit b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff.64bit new file mode 100644 index 0000000000000..62a40a440db16 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff.64bit @@ -0,0 +1,88 @@ +- // MIR for `opt1` before EarlyOtherwiseBranch ++ // MIR for `opt1` after EarlyOtherwiseBranch + + fn opt1(_1: std::option::Option, _2: std::option::Option) -> usize { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:4:9: 4:10 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:4:27: 4:28 + let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch.rs:4:47: 4:52 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch.rs:5:11: 5:16 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:5:12: 5:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:5:14: 5:15 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:6:19: 6:26 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 + let _8: usize; // in scope 0 at $DIR/early_otherwise_branch.rs:6:15: 6:16 + let _9: usize; // in scope 0 at $DIR/early_otherwise_branch.rs:6:24: 6:25 ++ let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:6:19: 6:26 ++ let mut _11: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:6:19: 6:26 + scope 1 { + debug a => _8; // in scope 1 at $DIR/early_otherwise_branch.rs:6:15: 6:16 + debug b => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:6:24: 6:25 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:5:11: 5:16 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:5:12: 5:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch.rs:5:12: 5:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:5:14: 5:15 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch.rs:5:14: 5:15 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:5:11: 5:16 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:5:11: 5:16 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:5:15: 5:16 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:5:15: 5:16 + _7 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 +- switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 ++ StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 ++ _10 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 ++ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 ++ _11 = Ne(_10, _7); // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 ++ StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 ++ switchInt(move _11) -> [false: bb6, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 + } + + bb1: { + _0 = const 1_usize; // scope 0 at $DIR/early_otherwise_branch.rs:7:14: 7:15 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000001)) + // mir::Constant + // + span: $DIR/early_otherwise_branch.rs:7:14: 7:15 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) } + goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:5:5: 8:6 + } + + bb2: { + _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:6:19: 6:26 + switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:6:19: 6:26 + } + + bb3: { + StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch.rs:6:15: 6:16 + _8 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch.rs:6:15: 6:16 + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:6:24: 6:25 + _9 = (((_3.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch.rs:6:24: 6:25 + _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch.rs:6:31: 6:32 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000000)) + // mir::Constant + // + span: $DIR/early_otherwise_branch.rs:6:31: 6:32 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:6:31: 6:32 + StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch.rs:6:31: 6:32 + goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:5:5: 8:6 + } + + bb4: { + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:9:1: 9:2 + return; // scope 0 at $DIR/early_otherwise_branch.rs:9:2: 9:2 ++ } ++ ++ bb5 (cleanup): { ++ resume; // scope 0 at $DIR/early_otherwise_branch.rs:4:1: 9:2 ++ } ++ ++ bb6: { ++ switchInt(_7) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:6:19: 6:26 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff new file mode 100644 index 0000000000000..1868f4f5be1b6 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff @@ -0,0 +1,105 @@ +- // MIR for `opt2` before EarlyOtherwiseBranch ++ // MIR for `opt2` after EarlyOtherwiseBranch + + fn opt2(_1: std::option::Option, _2: std::option::Option) -> usize { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:13:9: 13:10 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:13:27: 13:28 + let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch.rs:13:47: 13:52 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch.rs:14:11: 14:16 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:14:12: 14:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:14:14: 14:15 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:16:16: 16:20 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:15:19: 15:26 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:15:10: 15:17 + let _9: usize; // in scope 0 at $DIR/early_otherwise_branch.rs:15:15: 15:16 + let _10: usize; // in scope 0 at $DIR/early_otherwise_branch.rs:15:24: 15:25 ++ let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:16:16: 16:20 ++ let mut _12: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:16:16: 16:20 + scope 1 { + debug a => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:15:15: 15:16 + debug b => _10; // in scope 1 at $DIR/early_otherwise_branch.rs:15:24: 15:25 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:14:11: 14:16 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:14:12: 14:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch.rs:14:12: 14:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:14:14: 14:15 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch.rs:14:14: 14:15 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:14:11: 14:16 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:14:11: 14:16 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:14:15: 14:16 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:14:15: 14:16 + _8 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:15:10: 15:17 +- switchInt(move _8) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:15:10: 15:17 ++ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:15:10: 15:17 ++ _11 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:15:10: 15:17 ++ StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch.rs:15:10: 15:17 ++ _12 = Ne(_11, _8); // scope 0 at $DIR/early_otherwise_branch.rs:15:10: 15:17 ++ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:15:10: 15:17 ++ switchInt(move _12) -> [false: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:15:10: 15:17 + } + + bb1: { + _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:16:16: 16:20 + switchInt(move _6) -> [0_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:16:16: 16:20 + } + + bb2: { + _0 = const 1_usize; // scope 0 at $DIR/early_otherwise_branch.rs:17:14: 17:15 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000001)) + // mir::Constant + // + span: $DIR/early_otherwise_branch.rs:17:14: 17:15 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) } + goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:14:5: 18:6 + } + + bb3: { + _7 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:15:19: 15:26 + switchInt(move _7) -> [1_isize: bb4, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:15:19: 15:26 + } + + bb4: { + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:15:15: 15:16 + _9 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch.rs:15:15: 15:16 + StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:15:24: 15:25 + _10 = (((_3.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch.rs:15:24: 15:25 + _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch.rs:15:31: 15:32 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000000)) + // mir::Constant + // + span: $DIR/early_otherwise_branch.rs:15:31: 15:32 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } + StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:15:31: 15:32 + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:15:31: 15:32 + goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:14:5: 18:6 + } + + bb5: { + _0 = const 0_usize; // scope 0 at $DIR/early_otherwise_branch.rs:16:25: 16:26 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000000)) + // mir::Constant + // + span: $DIR/early_otherwise_branch.rs:16:25: 16:26 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } + goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:14:5: 18:6 + } + + bb6: { + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:19:1: 19:2 + return; // scope 0 at $DIR/early_otherwise_branch.rs:19:2: 19:2 ++ } ++ ++ bb7 (cleanup): { ++ resume; // scope 0 at $DIR/early_otherwise_branch.rs:13:1: 19:2 ++ } ++ ++ bb8: { ++ switchInt(_8) -> [0_isize: bb5, 1_isize: bb4, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:16:16: 16:20 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff.32bit b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff.32bit new file mode 100644 index 0000000000000..38c303dc81413 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff.32bit @@ -0,0 +1,105 @@ +- // MIR for `opt2` before EarlyOtherwiseBranch ++ // MIR for `opt2` after EarlyOtherwiseBranch + + fn opt2(_1: std::option::Option, _2: std::option::Option) -> usize { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:12:9: 12:10 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:12:27: 12:28 + let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch.rs:12:47: 12:52 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch.rs:13:11: 13:16 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:13:12: 13:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:13:14: 13:15 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:15:16: 15:20 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:14:19: 14:26 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 + let _9: usize; // in scope 0 at $DIR/early_otherwise_branch.rs:14:15: 14:16 + let _10: usize; // in scope 0 at $DIR/early_otherwise_branch.rs:14:24: 14:25 ++ let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:15:16: 15:20 ++ let mut _12: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:15:16: 15:20 + scope 1 { + debug a => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:14:15: 14:16 + debug b => _10; // in scope 1 at $DIR/early_otherwise_branch.rs:14:24: 14:25 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:13:11: 13:16 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:13:12: 13:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch.rs:13:12: 13:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:13:14: 13:15 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch.rs:13:14: 13:15 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:13:11: 13:16 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:13:11: 13:16 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:13:15: 13:16 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:13:15: 13:16 + _8 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 +- switchInt(move _8) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 ++ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 ++ _11 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 ++ StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 ++ _12 = Ne(_11, _8); // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 ++ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 ++ switchInt(move _12) -> [false: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 + } + + bb1: { + _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:15:16: 15:20 + switchInt(move _6) -> [0_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:15:16: 15:20 + } + + bb2: { + _0 = const 1_usize; // scope 0 at $DIR/early_otherwise_branch.rs:16:14: 16:15 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x00000001)) + // mir::Constant + // + span: $DIR/early_otherwise_branch.rs:16:14: 16:15 + // + literal: Const { ty: usize, val: Value(Scalar(0x00000001)) } + goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:13:5: 17:6 + } + + bb3: { + _7 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:14:19: 14:26 + switchInt(move _7) -> [1_isize: bb4, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:14:19: 14:26 + } + + bb4: { + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:14:15: 14:16 + _9 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch.rs:14:15: 14:16 + StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:14:24: 14:25 + _10 = (((_3.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch.rs:14:24: 14:25 + _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch.rs:14:31: 14:32 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x00000000)) + // mir::Constant + // + span: $DIR/early_otherwise_branch.rs:14:31: 14:32 + // + literal: Const { ty: usize, val: Value(Scalar(0x00000000)) } + StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:14:31: 14:32 + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:14:31: 14:32 + goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:13:5: 17:6 + } + + bb5: { + _0 = const 0_usize; // scope 0 at $DIR/early_otherwise_branch.rs:15:25: 15:26 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x00000000)) + // mir::Constant + // + span: $DIR/early_otherwise_branch.rs:15:25: 15:26 + // + literal: Const { ty: usize, val: Value(Scalar(0x00000000)) } + goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:13:5: 17:6 + } + + bb6: { + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:18:1: 18:2 + return; // scope 0 at $DIR/early_otherwise_branch.rs:18:2: 18:2 ++ } ++ ++ bb7 (cleanup): { ++ resume; // scope 0 at $DIR/early_otherwise_branch.rs:12:1: 18:2 ++ } ++ ++ bb8: { ++ switchInt(_8) -> [0_isize: bb5, 1_isize: bb4, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:15:16: 15:20 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff.64bit b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff.64bit new file mode 100644 index 0000000000000..5449158bff0e1 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff.64bit @@ -0,0 +1,105 @@ +- // MIR for `opt2` before EarlyOtherwiseBranch ++ // MIR for `opt2` after EarlyOtherwiseBranch + + fn opt2(_1: std::option::Option, _2: std::option::Option) -> usize { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:12:9: 12:10 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:12:27: 12:28 + let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch.rs:12:47: 12:52 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch.rs:13:11: 13:16 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:13:12: 13:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:13:14: 13:15 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:15:16: 15:20 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:14:19: 14:26 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 + let _9: usize; // in scope 0 at $DIR/early_otherwise_branch.rs:14:15: 14:16 + let _10: usize; // in scope 0 at $DIR/early_otherwise_branch.rs:14:24: 14:25 ++ let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:15:16: 15:20 ++ let mut _12: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:15:16: 15:20 + scope 1 { + debug a => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:14:15: 14:16 + debug b => _10; // in scope 1 at $DIR/early_otherwise_branch.rs:14:24: 14:25 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:13:11: 13:16 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:13:12: 13:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch.rs:13:12: 13:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:13:14: 13:15 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch.rs:13:14: 13:15 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:13:11: 13:16 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:13:11: 13:16 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:13:15: 13:16 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:13:15: 13:16 + _8 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 +- switchInt(move _8) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 ++ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 ++ _11 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 ++ StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 ++ _12 = Ne(_11, _8); // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 ++ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 ++ switchInt(move _12) -> [false: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 + } + + bb1: { + _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:15:16: 15:20 + switchInt(move _6) -> [0_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:15:16: 15:20 + } + + bb2: { + _0 = const 1_usize; // scope 0 at $DIR/early_otherwise_branch.rs:16:14: 16:15 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000001)) + // mir::Constant + // + span: $DIR/early_otherwise_branch.rs:16:14: 16:15 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) } + goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:13:5: 17:6 + } + + bb3: { + _7 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:14:19: 14:26 + switchInt(move _7) -> [1_isize: bb4, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:14:19: 14:26 + } + + bb4: { + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:14:15: 14:16 + _9 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch.rs:14:15: 14:16 + StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:14:24: 14:25 + _10 = (((_3.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch.rs:14:24: 14:25 + _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch.rs:14:31: 14:32 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000000)) + // mir::Constant + // + span: $DIR/early_otherwise_branch.rs:14:31: 14:32 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } + StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:14:31: 14:32 + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:14:31: 14:32 + goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:13:5: 17:6 + } + + bb5: { + _0 = const 0_usize; // scope 0 at $DIR/early_otherwise_branch.rs:15:25: 15:26 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000000)) + // mir::Constant + // + span: $DIR/early_otherwise_branch.rs:15:25: 15:26 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } + goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:13:5: 17:6 + } + + bb6: { + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:18:1: 18:2 + return; // scope 0 at $DIR/early_otherwise_branch.rs:18:2: 18:2 ++ } ++ ++ bb7 (cleanup): { ++ resume; // scope 0 at $DIR/early_otherwise_branch.rs:12:1: 18:2 ++ } ++ ++ bb8: { ++ switchInt(_8) -> [0_isize: bb5, 1_isize: bb4, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:15:16: 15:20 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch.rs b/src/test/mir-opt/early_otherwise_branch.rs new file mode 100644 index 0000000000000..a1ffcda746712 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch.rs @@ -0,0 +1,23 @@ +// compile-flags: -Z mir-opt-level=3 +// EMIT_MIR_FOR_EACH_BIT_WIDTH +// EMIT_MIR early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff +fn opt1(x: Option, y:Option) -> usize { + match (x,y) { + (Some(a), Some(b)) => 0, + _ => 1 + } +} + +// EMIT_MIR early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff +fn opt2(x: Option, y:Option) -> usize { + match (x,y) { + (Some(a), Some(b)) => 0, + (None, None) => 0, + _ => 1 + } +} + +fn main() { + opt1(None, Some(0)); + opt2(None, Some(0)); +} diff --git a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff new file mode 100644 index 0000000000000..9c326895d296b --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff @@ -0,0 +1,117 @@ +- // MIR for `opt1` before EarlyOtherwiseBranch ++ // MIR for `opt1` after EarlyOtherwiseBranch + + fn opt1(_1: std::option::Option, _2: std::option::Option, _3: std::option::Option) -> usize { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:9: 5:10 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:27: 5:28 + debug z => _3; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:44: 5:45 + let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:64: 5:69 + let mut _4: (std::option::Option, std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:12: 6:13 + let mut _6: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:14: 6:15 + let mut _7: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:16: 6:17 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 + let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 + let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 + let _11: usize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:15: 7:16 + let _12: usize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:24: 7:25 + let _13: usize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:33: 7:34 ++ let mut _14: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ let mut _15: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ let mut _16: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 ++ let mut _17: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 + scope 1 { + debug a => _11; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:15: 7:16 + debug b => _12; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:24: 7:25 + debug c => _13; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:33: 7:34 + } + + bb0: { + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:12: 6:13 + _5 = _1; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:12: 6:13 + StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:14: 6:15 + _6 = _2; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:14: 6:15 + StorageLive(_7); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:16: 6:17 + _7 = _3; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:16: 6:17 + (_4.0: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 + (_4.1: std::option::Option) = move _6; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 + (_4.2: std::option::Option) = move _7; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 + StorageDead(_7); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:17: 6:18 + StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:17: 6:18 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:17: 6:18 + _10 = discriminant((_4.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 +- switchInt(move _10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 ++ StorageLive(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 ++ _14 = discriminant((_4.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 ++ StorageLive(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 ++ _15 = Ne(_14, _10); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 ++ StorageDead(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 ++ switchInt(move _15) -> [false: bb7, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 + } + + bb1: { + _0 = const 1_usize; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:8:14: 8:15 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000001)) + // mir::Constant + // + span: $DIR/early_otherwise_branch_3_element_tuple.rs:8:14: 8:15 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) } + goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:5: 9:6 + } + + bb2: { + _9 = discriminant((_4.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 +- switchInt(move _9) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ StorageLive(_16); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ _16 = discriminant((_4.2: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ _17 = Ne(_16, _9); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ StorageDead(_16); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ switchInt(move _17) -> [false: bb8, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 + } + + bb3: { + _8 = discriminant((_4.2: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 + switchInt(move _8) -> [1_isize: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 + } + + bb4: { + StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:15: 7:16 + _11 = (((_4.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:15: 7:16 + StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:24: 7:25 + _12 = (((_4.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:24: 7:25 + StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:33: 7:34 + _13 = (((_4.2: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:33: 7:34 + _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000000)) + // mir::Constant + // + span: $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } + StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 + StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 + StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 + goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:5: 9:6 + } + + bb5: { + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:10:1: 10:2 + return; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:10:2: 10:2 ++ } ++ ++ bb6 (cleanup): { ++ resume; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:1: 10:2 ++ } ++ ++ bb7: { ++ switchInt(_10) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ } ++ ++ bb8: { ++ switchInt(_9) -> [1_isize: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff.32bit b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff.32bit new file mode 100644 index 0000000000000..9a3f7614ad088 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff.32bit @@ -0,0 +1,117 @@ +- // MIR for `opt1` before EarlyOtherwiseBranch ++ // MIR for `opt1` after EarlyOtherwiseBranch + + fn opt1(_1: std::option::Option, _2: std::option::Option, _3: std::option::Option) -> usize { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:9: 5:10 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:27: 5:28 + debug z => _3; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:44: 5:45 + let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:64: 5:69 + let mut _4: (std::option::Option, std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:12: 6:13 + let mut _6: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:14: 6:15 + let mut _7: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:16: 6:17 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 + let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 + let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 + let _11: usize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:15: 7:16 + let _12: usize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:24: 7:25 + let _13: usize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:33: 7:34 ++ let mut _14: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ let mut _15: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ let mut _16: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 ++ let mut _17: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 + scope 1 { + debug a => _11; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:15: 7:16 + debug b => _12; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:24: 7:25 + debug c => _13; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:33: 7:34 + } + + bb0: { + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:12: 6:13 + _5 = _1; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:12: 6:13 + StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:14: 6:15 + _6 = _2; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:14: 6:15 + StorageLive(_7); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:16: 6:17 + _7 = _3; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:16: 6:17 + (_4.0: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 + (_4.1: std::option::Option) = move _6; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 + (_4.2: std::option::Option) = move _7; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 + StorageDead(_7); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:17: 6:18 + StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:17: 6:18 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:17: 6:18 + _10 = discriminant((_4.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 +- switchInt(move _10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 ++ StorageLive(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 ++ _14 = discriminant((_4.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 ++ StorageLive(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 ++ _15 = Ne(_14, _10); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 ++ StorageDead(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 ++ switchInt(move _15) -> [false: bb7, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 + } + + bb1: { + _0 = const 1_usize; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:8:14: 8:15 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x00000001)) + // mir::Constant + // + span: $DIR/early_otherwise_branch_3_element_tuple.rs:8:14: 8:15 + // + literal: Const { ty: usize, val: Value(Scalar(0x00000001)) } + goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:5: 9:6 + } + + bb2: { + _9 = discriminant((_4.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 +- switchInt(move _9) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ StorageLive(_16); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ _16 = discriminant((_4.2: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ _17 = Ne(_16, _9); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ StorageDead(_16); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ switchInt(move _17) -> [false: bb8, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 + } + + bb3: { + _8 = discriminant((_4.2: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 + switchInt(move _8) -> [1_isize: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 + } + + bb4: { + StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:15: 7:16 + _11 = (((_4.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:15: 7:16 + StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:24: 7:25 + _12 = (((_4.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:24: 7:25 + StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:33: 7:34 + _13 = (((_4.2: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:33: 7:34 + _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x00000000)) + // mir::Constant + // + span: $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 + // + literal: Const { ty: usize, val: Value(Scalar(0x00000000)) } + StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 + StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 + StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 + goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:5: 9:6 + } + + bb5: { + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:10:1: 10:2 + return; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:10:2: 10:2 ++ } ++ ++ bb6 (cleanup): { ++ resume; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:1: 10:2 ++ } ++ ++ bb7: { ++ switchInt(_10) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ } ++ ++ bb8: { ++ switchInt(_9) -> [1_isize: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff.64bit b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff.64bit new file mode 100644 index 0000000000000..9c326895d296b --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff.64bit @@ -0,0 +1,117 @@ +- // MIR for `opt1` before EarlyOtherwiseBranch ++ // MIR for `opt1` after EarlyOtherwiseBranch + + fn opt1(_1: std::option::Option, _2: std::option::Option, _3: std::option::Option) -> usize { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:9: 5:10 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:27: 5:28 + debug z => _3; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:44: 5:45 + let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:64: 5:69 + let mut _4: (std::option::Option, std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:12: 6:13 + let mut _6: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:14: 6:15 + let mut _7: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:16: 6:17 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 + let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 + let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 + let _11: usize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:15: 7:16 + let _12: usize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:24: 7:25 + let _13: usize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:33: 7:34 ++ let mut _14: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ let mut _15: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ let mut _16: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 ++ let mut _17: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 + scope 1 { + debug a => _11; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:15: 7:16 + debug b => _12; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:24: 7:25 + debug c => _13; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:33: 7:34 + } + + bb0: { + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:12: 6:13 + _5 = _1; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:12: 6:13 + StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:14: 6:15 + _6 = _2; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:14: 6:15 + StorageLive(_7); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:16: 6:17 + _7 = _3; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:16: 6:17 + (_4.0: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 + (_4.1: std::option::Option) = move _6; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 + (_4.2: std::option::Option) = move _7; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 + StorageDead(_7); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:17: 6:18 + StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:17: 6:18 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:17: 6:18 + _10 = discriminant((_4.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 +- switchInt(move _10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 ++ StorageLive(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 ++ _14 = discriminant((_4.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 ++ StorageLive(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 ++ _15 = Ne(_14, _10); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 ++ StorageDead(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 ++ switchInt(move _15) -> [false: bb7, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 + } + + bb1: { + _0 = const 1_usize; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:8:14: 8:15 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000001)) + // mir::Constant + // + span: $DIR/early_otherwise_branch_3_element_tuple.rs:8:14: 8:15 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) } + goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:5: 9:6 + } + + bb2: { + _9 = discriminant((_4.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 +- switchInt(move _9) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ StorageLive(_16); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ _16 = discriminant((_4.2: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ _17 = Ne(_16, _9); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ StorageDead(_16); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ switchInt(move _17) -> [false: bb8, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 + } + + bb3: { + _8 = discriminant((_4.2: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 + switchInt(move _8) -> [1_isize: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 + } + + bb4: { + StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:15: 7:16 + _11 = (((_4.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:15: 7:16 + StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:24: 7:25 + _12 = (((_4.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:24: 7:25 + StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:33: 7:34 + _13 = (((_4.2: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:33: 7:34 + _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000000)) + // mir::Constant + // + span: $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } + StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 + StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 + StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 + goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:5: 9:6 + } + + bb5: { + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:10:1: 10:2 + return; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:10:2: 10:2 ++ } ++ ++ bb6 (cleanup): { ++ resume; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:1: 10:2 ++ } ++ ++ bb7: { ++ switchInt(_10) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ } ++ ++ bb8: { ++ switchInt(_9) -> [1_isize: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.rs b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.rs new file mode 100644 index 0000000000000..ffb5de096c35d --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.rs @@ -0,0 +1,14 @@ +// compile-flags: -Z mir-opt-level=3 + +// EMIT_MIR_FOR_EACH_BIT_WIDTH +// EMIT_MIR early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff +fn opt1(x: Option, y:Option, z:Option) -> usize { + match (x,y,z) { + (Some(a), Some(b), Some(c)) => 0, + _ => 1 + } +} + +fn main() { + opt1(None, Some(0), None); +} diff --git a/src/test/mir-opt/early_otherwise_branch_68867.rs b/src/test/mir-opt/early_otherwise_branch_68867.rs new file mode 100644 index 0000000000000..abe666f9ca4f9 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_68867.rs @@ -0,0 +1,31 @@ +// compile-flags: -Z mir-opt-level=3 + +// example from #68867 +type CSSFloat = f32; + +pub enum ViewportPercentageLength { + Vw(CSSFloat), + Vh(CSSFloat), + Vmin(CSSFloat), + Vmax(CSSFloat), +} + +// EMIT_MIR early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff +#[no_mangle] +pub extern "C" fn try_sum(x: &ViewportPercentageLength, + other: &ViewportPercentageLength) + -> Result { + use self::ViewportPercentageLength::*; + Ok(match (x, other) { + (&Vw(one), &Vw(other)) => Vw(one + other), + (&Vh(one), &Vh(other)) => Vh(one + other), + (&Vmin(one), &Vmin(other)) => Vmin(one + other), + (&Vmax(one), &Vmax(other)) => Vmax(one + other), + _ => return Err(()), + }) +} + + +fn main() { + try_sum(&ViewportPercentageLength::Vw(1.0), &ViewportPercentageLength::Vw(2.0)); +} diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff new file mode 100644 index 0000000000000..7a02a1c347069 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff @@ -0,0 +1,219 @@ +- // MIR for `try_sum` before EarlyOtherwiseBranch ++ // MIR for `try_sum` after EarlyOtherwiseBranch + + fn try_sum(_1: &ViewportPercentageLength, _2: &ViewportPercentageLength) -> std::result::Result { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:15:27: 15:28 + debug other => _2; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:16:27: 16:32 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/early_otherwise_branch_68867.rs:17:28: 17:64 + let mut _3: ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 + let mut _4: (&ViewportPercentageLength, &ViewportPercentageLength); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:19:14: 19:24 + let mut _5: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:19:15: 19:16 + let mut _6: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:19:18: 19:23 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:20:21: 20:30 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:21: 21:30 + let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:34 + let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:23: 23:34 + let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:20:11: 20:18 + let _12: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:20:14: 20:17 + let _13: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:20:24: 20:29 + let mut _14: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:20:38: 20:49 + let mut _15: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:20:38: 20:41 + let mut _16: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:20:44: 20:49 + let _17: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:17 + let _18: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:24: 21:29 + let mut _19: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:38: 21:49 + let mut _20: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:38: 21:41 + let mut _21: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:44: 21:49 + let _22: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:16: 22:19 + let _23: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:28: 22:33 + let mut _24: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:55 + let mut _25: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:47 + let mut _26: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:50: 22:55 + let _27: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:16: 23:19 + let _28: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:28: 23:33 + let mut _29: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:55 + let mut _30: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:47 + let mut _31: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:50: 23:55 + let mut _32: !; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:28 + let mut _33: (); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:25: 24:27 ++ let mut _34: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:20:21: 20:30 ++ let mut _35: bool; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:20:21: 20:30 + scope 1 { + debug one => _12; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:20:14: 20:17 + debug other => _13; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:20:24: 20:29 + } + scope 2 { + debug one => _17; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:17 + debug other => _18; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:21:24: 21:29 + } + scope 3 { + debug one => _22; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:22:16: 22:19 + debug other => _23; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:22:28: 22:33 + } + scope 4 { + debug one => _27; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:23:16: 23:19 + debug other => _28; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:23:28: 23:33 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:14: 19:24 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:15: 19:16 + _5 = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:15: 19:16 + StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:18: 19:23 + _6 = _2; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:18: 19:23 + (_4.0: &ViewportPercentageLength) = move _5; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:14: 19:24 + (_4.1: &ViewportPercentageLength) = move _6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:14: 19:24 + StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:23: 19:24 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:23: 19:24 + _11 = discriminant((*(_4.0: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:11: 20:18 +- switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:11: 20:18 ++ StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:11: 20:18 ++ _34 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:11: 20:18 ++ StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:11: 20:18 ++ _35 = Ne(_34, _11); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:11: 20:18 ++ StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:11: 20:18 ++ switchInt(move _35) -> [false: bb13, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:11: 20:18 + } + + bb1: { + _7 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:21: 20:30 + switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:21: 20:30 + } + + bb2: { + StorageLive(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:25: 24:27 + ((_0 as Err).0: ()) = const (); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:28 + // ty::Const + // + ty: () + // + val: Value(Scalar()) + // mir::Constant + // + span: $DIR/early_otherwise_branch_68867.rs:24:21: 24:28 + // + literal: Const { ty: (), val: Value(Scalar()) } + discriminant(_0) = 1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:28 + StorageDead(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:27: 24:28 + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:6: 25:7 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:1: 26:2 + goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:28 + } + + bb3: { + _8 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:21: 21:30 + switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:21: 21:30 + } + + bb4: { + _9 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:34 + switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:34 + } + + bb5: { + _10 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:23: 23:34 + switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:23: 23:34 + } + + bb6: { + StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:14: 20:17 + _12 = (((*(_4.0: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:14: 20:17 + StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:24: 20:29 + _13 = (((*(_4.1: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:24: 20:29 + StorageLive(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:20:38: 20:49 + StorageLive(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:20:38: 20:41 + _15 = _12; // scope 1 at $DIR/early_otherwise_branch_68867.rs:20:38: 20:41 + StorageLive(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:20:44: 20:49 + _16 = _13; // scope 1 at $DIR/early_otherwise_branch_68867.rs:20:44: 20:49 + _14 = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:20:38: 20:49 + StorageDead(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:20:48: 20:49 + StorageDead(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:20:48: 20:49 + ((_3 as Vw).0: f32) = move _14; // scope 1 at $DIR/early_otherwise_branch_68867.rs:20:35: 20:50 + discriminant(_3) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:20:35: 20:50 + StorageDead(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:20:49: 20:50 + StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:49: 20:50 + StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:49: 20:50 + goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 + } + + bb7: { + StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:17 + _17 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:17 + StorageLive(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:24: 21:29 + _18 = (((*(_4.1: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:24: 21:29 + StorageLive(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:21:38: 21:49 + StorageLive(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:21:38: 21:41 + _20 = _17; // scope 2 at $DIR/early_otherwise_branch_68867.rs:21:38: 21:41 + StorageLive(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:21:44: 21:49 + _21 = _18; // scope 2 at $DIR/early_otherwise_branch_68867.rs:21:44: 21:49 + _19 = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:21:38: 21:49 + StorageDead(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:21:48: 21:49 + StorageDead(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:21:48: 21:49 + ((_3 as Vh).0: f32) = move _19; // scope 2 at $DIR/early_otherwise_branch_68867.rs:21:35: 21:50 + discriminant(_3) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:21:35: 21:50 + StorageDead(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:21:49: 21:50 + StorageDead(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:49: 21:50 + StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:49: 21:50 + goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 + } + + bb8: { + StorageLive(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:16: 22:19 + _22 = (((*(_4.0: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:16: 22:19 + StorageLive(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:28: 22:33 + _23 = (((*(_4.1: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:28: 22:33 + StorageLive(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:55 + StorageLive(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:47 + _25 = _22; // scope 3 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:47 + StorageLive(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:22:50: 22:55 + _26 = _23; // scope 3 at $DIR/early_otherwise_branch_68867.rs:22:50: 22:55 + _24 = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:55 + StorageDead(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:22:54: 22:55 + StorageDead(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:22:54: 22:55 + ((_3 as Vmin).0: f32) = move _24; // scope 3 at $DIR/early_otherwise_branch_68867.rs:22:39: 22:56 + discriminant(_3) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:22:39: 22:56 + StorageDead(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:22:55: 22:56 + StorageDead(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:55: 22:56 + StorageDead(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:55: 22:56 + goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 + } + + bb9: { + StorageLive(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:16: 23:19 + _27 = (((*(_4.0: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:16: 23:19 + StorageLive(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:28: 23:33 + _28 = (((*(_4.1: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:28: 23:33 + StorageLive(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:55 + StorageLive(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:47 + _30 = _27; // scope 4 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:47 + StorageLive(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:23:50: 23:55 + _31 = _28; // scope 4 at $DIR/early_otherwise_branch_68867.rs:23:50: 23:55 + _29 = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:55 + StorageDead(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:23:54: 23:55 + StorageDead(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:23:54: 23:55 + ((_3 as Vmax).0: f32) = move _29; // scope 4 at $DIR/early_otherwise_branch_68867.rs:23:39: 23:56 + discriminant(_3) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:23:39: 23:56 + StorageDead(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:23:55: 23:56 + StorageDead(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:55: 23:56 + StorageDead(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:55: 23:56 + goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 + } + + bb10: { + return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:2: 26:2 + } + + bb11: { + ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:5: 25:7 + discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:5: 25:7 + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:6: 25:7 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:1: 26:2 + goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:2: 26:2 ++ } ++ ++ bb12 (cleanup): { ++ resume; // scope 0 at $DIR/early_otherwise_branch_68867.rs:15:1: 26:2 ++ } ++ ++ bb13: { ++ switchInt(_11) -> [0_isize: bb6, 1_isize: bb7, 2_isize: bb8, 3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:21: 20:30 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff new file mode 100644 index 0000000000000..9908843a2d864 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff @@ -0,0 +1,114 @@ +- // MIR for `noopt1` before EarlyOtherwiseBranch ++ // MIR for `noopt1` after EarlyOtherwiseBranch + + fn noopt1(_1: std::option::Option, _2: std::option::Option) -> usize { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:12 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:29: 8:30 + let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:49: 8:54 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:11: 9:16 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:12: 9:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:14: 9:15 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:16: 12:23 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:19: 10:26 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:10: 10:17 + let _9: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 + let _10: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:24: 10:25 + let _11: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:15: 11:16 + let _12: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:21: 12:22 + scope 1 { + debug a => _9; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 + debug b => _10; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:10:24: 10:25 + } + scope 2 { + debug a => _11; // in scope 2 at $DIR/early_otherwise_branch_noopt.rs:11:15: 11:16 + } + scope 3 { + debug b => _12; // in scope 3 at $DIR/early_otherwise_branch_noopt.rs:12:21: 12:22 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:11: 9:16 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:12: 9:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:12: 9:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:14: 9:15 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:14: 9:15 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:11: 9:16 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:11: 9:16 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 + _8 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:10: 10:17 + switchInt(move _8) -> [0_isize: bb1, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:10: 10:17 + } + + bb1: { + _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:16: 12:23 + switchInt(move _6) -> [0_isize: bb2, otherwise: bb6]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:16: 12:23 + } + + bb2: { + _0 = const 3_usize; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:13:25: 13:26 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000003)) + // mir::Constant + // + span: $DIR/early_otherwise_branch_noopt.rs:13:25: 13:26 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000003)) } + goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:5: 14:6 + } + + bb3: { + _7 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:19: 10:26 + switchInt(move _7) -> [0_isize: bb5, otherwise: bb4]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:19: 10:26 + } + + bb4: { + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 + _9 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 + StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:24: 10:25 + _10 = (((_3.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:24: 10:25 + _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch_noopt.rs:10:31: 10:32 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000000)) + // mir::Constant + // + span: $DIR/early_otherwise_branch_noopt.rs:10:31: 10:32 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } + StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:31: 10:32 + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:31: 10:32 + goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:5: 14:6 + } + + bb5: { + StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:15: 11:16 + _11 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:15: 11:16 + _0 = const 1_usize; // scope 2 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000001)) + // mir::Constant + // + span: $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) } + StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 + goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:5: 14:6 + } + + bb6: { + StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:21: 12:22 + _12 = (((_3.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:21: 12:22 + _0 = const 2_usize; // scope 3 at $DIR/early_otherwise_branch_noopt.rs:12:28: 12:29 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000002)) + // mir::Constant + // + span: $DIR/early_otherwise_branch_noopt.rs:12:28: 12:29 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000002)) } + StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:28: 12:29 + goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:5: 14:6 + } + + bb7: { + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:15:1: 15:2 + return; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:15:2: 15:2 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff.32bit b/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff.32bit new file mode 100644 index 0000000000000..26842c74e6fd2 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff.32bit @@ -0,0 +1,114 @@ +- // MIR for `noopt1` before EarlyOtherwiseBranch ++ // MIR for `noopt1` after EarlyOtherwiseBranch + + fn noopt1(_1: std::option::Option, _2: std::option::Option) -> usize { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:12 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:29: 8:30 + let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:49: 8:54 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:11: 9:16 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:12: 9:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:14: 9:15 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:16: 12:23 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:19: 10:26 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:10: 10:17 + let _9: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 + let _10: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:24: 10:25 + let _11: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:15: 11:16 + let _12: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:21: 12:22 + scope 1 { + debug a => _9; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 + debug b => _10; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:10:24: 10:25 + } + scope 2 { + debug a => _11; // in scope 2 at $DIR/early_otherwise_branch_noopt.rs:11:15: 11:16 + } + scope 3 { + debug b => _12; // in scope 3 at $DIR/early_otherwise_branch_noopt.rs:12:21: 12:22 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:11: 9:16 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:12: 9:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:12: 9:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:14: 9:15 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:14: 9:15 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:11: 9:16 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:11: 9:16 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 + _8 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:10: 10:17 + switchInt(move _8) -> [0_isize: bb1, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:10: 10:17 + } + + bb1: { + _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:16: 12:23 + switchInt(move _6) -> [0_isize: bb2, otherwise: bb6]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:16: 12:23 + } + + bb2: { + _0 = const 3_usize; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:13:25: 13:26 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x00000003)) + // mir::Constant + // + span: $DIR/early_otherwise_branch_noopt.rs:13:25: 13:26 + // + literal: Const { ty: usize, val: Value(Scalar(0x00000003)) } + goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:5: 14:6 + } + + bb3: { + _7 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:19: 10:26 + switchInt(move _7) -> [0_isize: bb5, otherwise: bb4]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:19: 10:26 + } + + bb4: { + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 + _9 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 + StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:24: 10:25 + _10 = (((_3.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:24: 10:25 + _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch_noopt.rs:10:31: 10:32 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x00000000)) + // mir::Constant + // + span: $DIR/early_otherwise_branch_noopt.rs:10:31: 10:32 + // + literal: Const { ty: usize, val: Value(Scalar(0x00000000)) } + StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:31: 10:32 + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:31: 10:32 + goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:5: 14:6 + } + + bb5: { + StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:15: 11:16 + _11 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:15: 11:16 + _0 = const 1_usize; // scope 2 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x00000001)) + // mir::Constant + // + span: $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 + // + literal: Const { ty: usize, val: Value(Scalar(0x00000001)) } + StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 + goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:5: 14:6 + } + + bb6: { + StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:21: 12:22 + _12 = (((_3.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:21: 12:22 + _0 = const 2_usize; // scope 3 at $DIR/early_otherwise_branch_noopt.rs:12:28: 12:29 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x00000002)) + // mir::Constant + // + span: $DIR/early_otherwise_branch_noopt.rs:12:28: 12:29 + // + literal: Const { ty: usize, val: Value(Scalar(0x00000002)) } + StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:28: 12:29 + goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:5: 14:6 + } + + bb7: { + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:15:1: 15:2 + return; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:15:2: 15:2 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff.64bit b/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff.64bit new file mode 100644 index 0000000000000..9908843a2d864 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff.64bit @@ -0,0 +1,114 @@ +- // MIR for `noopt1` before EarlyOtherwiseBranch ++ // MIR for `noopt1` after EarlyOtherwiseBranch + + fn noopt1(_1: std::option::Option, _2: std::option::Option) -> usize { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:12 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:29: 8:30 + let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:49: 8:54 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:11: 9:16 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:12: 9:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:14: 9:15 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:16: 12:23 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:19: 10:26 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:10: 10:17 + let _9: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 + let _10: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:24: 10:25 + let _11: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:15: 11:16 + let _12: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:21: 12:22 + scope 1 { + debug a => _9; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 + debug b => _10; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:10:24: 10:25 + } + scope 2 { + debug a => _11; // in scope 2 at $DIR/early_otherwise_branch_noopt.rs:11:15: 11:16 + } + scope 3 { + debug b => _12; // in scope 3 at $DIR/early_otherwise_branch_noopt.rs:12:21: 12:22 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:11: 9:16 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:12: 9:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:12: 9:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:14: 9:15 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:14: 9:15 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:11: 9:16 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:11: 9:16 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 + _8 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:10: 10:17 + switchInt(move _8) -> [0_isize: bb1, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:10: 10:17 + } + + bb1: { + _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:16: 12:23 + switchInt(move _6) -> [0_isize: bb2, otherwise: bb6]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:16: 12:23 + } + + bb2: { + _0 = const 3_usize; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:13:25: 13:26 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000003)) + // mir::Constant + // + span: $DIR/early_otherwise_branch_noopt.rs:13:25: 13:26 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000003)) } + goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:5: 14:6 + } + + bb3: { + _7 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:19: 10:26 + switchInt(move _7) -> [0_isize: bb5, otherwise: bb4]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:19: 10:26 + } + + bb4: { + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 + _9 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 + StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:24: 10:25 + _10 = (((_3.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:24: 10:25 + _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch_noopt.rs:10:31: 10:32 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000000)) + // mir::Constant + // + span: $DIR/early_otherwise_branch_noopt.rs:10:31: 10:32 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } + StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:31: 10:32 + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:31: 10:32 + goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:5: 14:6 + } + + bb5: { + StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:15: 11:16 + _11 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:15: 11:16 + _0 = const 1_usize; // scope 2 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000001)) + // mir::Constant + // + span: $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) } + StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 + goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:5: 14:6 + } + + bb6: { + StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:21: 12:22 + _12 = (((_3.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:21: 12:22 + _0 = const 2_usize; // scope 3 at $DIR/early_otherwise_branch_noopt.rs:12:28: 12:29 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000002)) + // mir::Constant + // + span: $DIR/early_otherwise_branch_noopt.rs:12:28: 12:29 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000002)) } + StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:28: 12:29 + goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:5: 14:6 + } + + bb7: { + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:15:1: 15:2 + return; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:15:2: 15:2 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff new file mode 100644 index 0000000000000..25391ab792013 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff @@ -0,0 +1,72 @@ +- // MIR for `noopt2` before EarlyOtherwiseBranch ++ // MIR for `noopt2` after EarlyOtherwiseBranch + + fn noopt2(_1: std::option::Option, _2: std::option::Option) -> usize { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:12 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:29: 19:30 + let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:48: 19:53 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:11: 20:16 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:12: 20:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:14: 20:15 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:19: 21:26 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:10: 21:17 + let _8: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:15: 21:16 + let _9: bool; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:24: 21:25 + scope 1 { + debug a => _8; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:21:15: 21:16 + debug b => _9; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:21:24: 21:25 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:11: 20:16 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:12: 20:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:12: 20:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:14: 20:15 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:14: 20:15 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:11: 20:16 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:11: 20:16 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 + _7 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:10: 21:17 + switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:10: 21:17 + } + + bb1: { + _0 = const 1_usize; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:22:14: 22:15 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000001)) + // mir::Constant + // + span: $DIR/early_otherwise_branch_noopt.rs:22:14: 22:15 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) } + goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:5: 23:6 + } + + bb2: { + _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:19: 21:26 + switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:19: 21:26 + } + + bb3: { + StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:15: 21:16 + _8 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:15: 21:16 + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:24: 21:25 + _9 = (((_3.1: std::option::Option) as Some).0: bool); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:24: 21:25 + _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch_noopt.rs:21:31: 21:32 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000000)) + // mir::Constant + // + span: $DIR/early_otherwise_branch_noopt.rs:21:31: 21:32 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:31: 21:32 + StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:31: 21:32 + goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:5: 23:6 + } + + bb4: { + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:24:1: 24:2 + return; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:24:2: 24:2 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff.32bit b/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff.32bit new file mode 100644 index 0000000000000..49dad4a02a404 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff.32bit @@ -0,0 +1,72 @@ +- // MIR for `noopt2` before EarlyOtherwiseBranch ++ // MIR for `noopt2` after EarlyOtherwiseBranch + + fn noopt2(_1: std::option::Option, _2: std::option::Option) -> usize { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:12 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:29: 19:30 + let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:48: 19:53 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:11: 20:16 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:12: 20:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:14: 20:15 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:19: 21:26 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:10: 21:17 + let _8: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:15: 21:16 + let _9: bool; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:24: 21:25 + scope 1 { + debug a => _8; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:21:15: 21:16 + debug b => _9; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:21:24: 21:25 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:11: 20:16 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:12: 20:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:12: 20:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:14: 20:15 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:14: 20:15 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:11: 20:16 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:11: 20:16 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 + _7 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:10: 21:17 + switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:10: 21:17 + } + + bb1: { + _0 = const 1_usize; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:22:14: 22:15 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x00000001)) + // mir::Constant + // + span: $DIR/early_otherwise_branch_noopt.rs:22:14: 22:15 + // + literal: Const { ty: usize, val: Value(Scalar(0x00000001)) } + goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:5: 23:6 + } + + bb2: { + _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:19: 21:26 + switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:19: 21:26 + } + + bb3: { + StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:15: 21:16 + _8 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:15: 21:16 + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:24: 21:25 + _9 = (((_3.1: std::option::Option) as Some).0: bool); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:24: 21:25 + _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch_noopt.rs:21:31: 21:32 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x00000000)) + // mir::Constant + // + span: $DIR/early_otherwise_branch_noopt.rs:21:31: 21:32 + // + literal: Const { ty: usize, val: Value(Scalar(0x00000000)) } + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:31: 21:32 + StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:31: 21:32 + goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:5: 23:6 + } + + bb4: { + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:24:1: 24:2 + return; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:24:2: 24:2 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff.64bit b/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff.64bit new file mode 100644 index 0000000000000..25391ab792013 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff.64bit @@ -0,0 +1,72 @@ +- // MIR for `noopt2` before EarlyOtherwiseBranch ++ // MIR for `noopt2` after EarlyOtherwiseBranch + + fn noopt2(_1: std::option::Option, _2: std::option::Option) -> usize { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:12 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:29: 19:30 + let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:48: 19:53 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:11: 20:16 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:12: 20:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:14: 20:15 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:19: 21:26 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:10: 21:17 + let _8: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:15: 21:16 + let _9: bool; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:24: 21:25 + scope 1 { + debug a => _8; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:21:15: 21:16 + debug b => _9; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:21:24: 21:25 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:11: 20:16 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:12: 20:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:12: 20:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:14: 20:15 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:14: 20:15 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:11: 20:16 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:11: 20:16 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 + _7 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:10: 21:17 + switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:10: 21:17 + } + + bb1: { + _0 = const 1_usize; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:22:14: 22:15 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000001)) + // mir::Constant + // + span: $DIR/early_otherwise_branch_noopt.rs:22:14: 22:15 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) } + goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:5: 23:6 + } + + bb2: { + _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:19: 21:26 + switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:19: 21:26 + } + + bb3: { + StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:15: 21:16 + _8 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:15: 21:16 + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:24: 21:25 + _9 = (((_3.1: std::option::Option) as Some).0: bool); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:24: 21:25 + _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch_noopt.rs:21:31: 21:32 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000000)) + // mir::Constant + // + span: $DIR/early_otherwise_branch_noopt.rs:21:31: 21:32 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:31: 21:32 + StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:31: 21:32 + goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:5: 23:6 + } + + bb4: { + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:24:1: 24:2 + return; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:24:2: 24:2 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.rs b/src/test/mir-opt/early_otherwise_branch_noopt.rs new file mode 100644 index 0000000000000..8c4b37ac7a81f --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_noopt.rs @@ -0,0 +1,29 @@ +// compile-flags: -Z mir-opt-level=3 + +// must not optimize as it does not follow the pattern of +// left and right hand side being the same variant + +// EMIT_MIR_FOR_EACH_BIT_WIDTH +// EMIT_MIR early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff +fn noopt1(x: Option, y:Option) -> usize { + match (x,y) { + (Some(a), Some(b)) => 0, + (Some(a), None) => 1, + (None, Some(b)) => 2, + (None, None) => 3 + } +} + +// must not optimize as the types being matched on are not identical +// EMIT_MIR early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff +fn noopt2(x: Option, y:Option) -> usize { + match (x,y) { + (Some(a), Some(b)) => 0, + _ => 1 + } +} + +fn main() { + noopt1(None, Some(0)); + noopt2(None, Some(true)); +} From 5cc93950acb18c5b0978583ea518940336e847af Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Sat, 19 Sep 2020 23:27:20 +0200 Subject: [PATCH 0716/1052] Update src/librustc_mir/transform/early_otherwise_branch.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Laurențiu Nicola --- compiler/rustc_mir/src/transform/early_otherwise_branch.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs index 0dc311ebb8c1f..e60cc8c1348d1 100644 --- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs +++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs @@ -20,7 +20,7 @@ use std::{borrow::Cow, fmt::Debug}; /// let x: Option<()>; /// let y: Option<()>; /// let discriminant_x = // get discriminant of x -/// let discriminant_y = // get discriminant of x +/// let discriminant_y = // get discriminant of y /// if discriminant_x != discriminant_y {1} else {0} /// ``` pub struct EarlyOtherwiseBranch; From 04834139c43761efd2b14e37e819774033241ba2 Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Sat, 19 Sep 2020 23:38:54 +0200 Subject: [PATCH 0717/1052] replace usize with u32 to make it easier to bless --- src/test/mir-opt/early_otherwise_branch.rs | 13 ++++++------- .../early_otherwise_branch_3_element_tuple.rs | 7 +++---- src/test/mir-opt/early_otherwise_branch_noopt.rs | 13 ++++++------- 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/test/mir-opt/early_otherwise_branch.rs b/src/test/mir-opt/early_otherwise_branch.rs index a1ffcda746712..77003442080f4 100644 --- a/src/test/mir-opt/early_otherwise_branch.rs +++ b/src/test/mir-opt/early_otherwise_branch.rs @@ -1,19 +1,18 @@ // compile-flags: -Z mir-opt-level=3 -// EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff -fn opt1(x: Option, y:Option) -> usize { - match (x,y) { +fn opt1(x: Option, y: Option) -> u32 { + match (x, y) { (Some(a), Some(b)) => 0, - _ => 1 + _ => 1, } } // EMIT_MIR early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff -fn opt2(x: Option, y:Option) -> usize { - match (x,y) { +fn opt2(x: Option, y: Option) -> u32 { + match (x, y) { (Some(a), Some(b)) => 0, (None, None) => 0, - _ => 1 + _ => 1, } } diff --git a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.rs b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.rs index ffb5de096c35d..1d6877d67df82 100644 --- a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.rs +++ b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.rs @@ -1,11 +1,10 @@ // compile-flags: -Z mir-opt-level=3 -// EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff -fn opt1(x: Option, y:Option, z:Option) -> usize { - match (x,y,z) { +fn opt1(x: Option, y: Option, z: Option) -> u32 { + match (x, y, z) { (Some(a), Some(b), Some(c)) => 0, - _ => 1 + _ => 1, } } diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.rs b/src/test/mir-opt/early_otherwise_branch_noopt.rs index 8c4b37ac7a81f..bd15f520dfcd4 100644 --- a/src/test/mir-opt/early_otherwise_branch_noopt.rs +++ b/src/test/mir-opt/early_otherwise_branch_noopt.rs @@ -3,23 +3,22 @@ // must not optimize as it does not follow the pattern of // left and right hand side being the same variant -// EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff -fn noopt1(x: Option, y:Option) -> usize { - match (x,y) { +fn noopt1(x: Option, y: Option) -> u32 { + match (x, y) { (Some(a), Some(b)) => 0, (Some(a), None) => 1, (None, Some(b)) => 2, - (None, None) => 3 + (None, None) => 3, } } // must not optimize as the types being matched on are not identical // EMIT_MIR early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff -fn noopt2(x: Option, y:Option) -> usize { - match (x,y) { +fn noopt2(x: Option, y: Option) -> u32 { + match (x, y) { (Some(a), Some(b)) => 0, - _ => 1 + _ => 1, } } From 0e06456ecbe244291f1feef7c24b7165f028e0d0 Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Sat, 19 Sep 2020 23:50:51 +0200 Subject: [PATCH 0718/1052] bless --- ...wise_branch.opt1.EarlyOtherwiseBranch.diff | 108 ++++++------ ...wise_branch.opt2.EarlyOtherwiseBranch.diff | 124 ++++++-------- ...ement_tuple.opt1.EarlyOtherwiseBranch.diff | 154 ++++++++---------- ...ch_68867.try_sum.EarlyOtherwiseBranch.diff | 6 - ...nch_noopt.noopt1.EarlyOtherwiseBranch.diff | 134 +++++++-------- ...nch_noopt.noopt2.EarlyOtherwiseBranch.diff | 88 +++++----- 6 files changed, 265 insertions(+), 349 deletions(-) diff --git a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff index 28c9d422a9f4f..9f9c28723f07b 100644 --- a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff @@ -1,88 +1,76 @@ - // MIR for `opt1` before EarlyOtherwiseBranch + // MIR for `opt1` after EarlyOtherwiseBranch - fn opt1(_1: std::option::Option, _2: std::option::Option) -> usize { - debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:5:9: 5:10 - debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:5:27: 5:28 - let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch.rs:5:47: 5:52 - let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch.rs:6:11: 6:16 - let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:6:12: 6:13 - let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:6:14: 6:15 - let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:7:19: 7:26 - let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:7:10: 7:17 - let _8: usize; // in scope 0 at $DIR/early_otherwise_branch.rs:7:15: 7:16 - let _9: usize; // in scope 0 at $DIR/early_otherwise_branch.rs:7:24: 7:25 -+ let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:7:19: 7:26 -+ let mut _11: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:7:19: 7:26 + fn opt1(_1: Option, _2: Option) -> u32 { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:3:9: 3:10 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:3:25: 3:26 + let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch.rs:3:44: 3:47 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch.rs:4:11: 4:17 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:4:12: 4:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:4:15: 4:16 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 + let _8: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:5:15: 5:16 + let _9: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:5:24: 5:25 ++ let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 ++ let mut _11: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 scope 1 { - debug a => _8; // in scope 1 at $DIR/early_otherwise_branch.rs:7:15: 7:16 - debug b => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:7:24: 7:25 + debug a => _8; // in scope 1 at $DIR/early_otherwise_branch.rs:5:15: 5:16 + debug b => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:5:24: 5:25 } bb0: { - StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:6:11: 6:16 - StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:6:12: 6:13 - _4 = _1; // scope 0 at $DIR/early_otherwise_branch.rs:6:12: 6:13 - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:6:14: 6:15 - _5 = _2; // scope 0 at $DIR/early_otherwise_branch.rs:6:14: 6:15 - (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:6:11: 6:16 - (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:6:11: 6:16 - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:6:15: 6:16 - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:6:15: 6:16 - _7 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:7:10: 7:17 -- switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:7:10: 7:17 -+ StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:7:10: 7:17 -+ _10 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:7:10: 7:17 -+ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:7:10: 7:17 -+ _11 = Ne(_10, _7); // scope 0 at $DIR/early_otherwise_branch.rs:7:10: 7:17 -+ StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:7:10: 7:17 -+ switchInt(move _11) -> [false: bb6, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:7:10: 7:17 + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:4:11: 4:17 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:4:12: 4:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch.rs:4:12: 4:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:4:15: 4:16 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch.rs:4:15: 4:16 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:4:11: 4:17 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:4:11: 4:17 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:4:16: 4:17 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:4:16: 4:17 + _7 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 +- switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 ++ StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 ++ _10 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 ++ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 ++ _11 = Ne(_10, _7); // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 ++ StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 ++ switchInt(move _11) -> [false: bb6, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 } bb1: { - _0 = const 1_usize; // scope 0 at $DIR/early_otherwise_branch.rs:8:14: 8:15 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x0000000000000001)) - // mir::Constant - // + span: $DIR/early_otherwise_branch.rs:8:14: 8:15 - // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) } - goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:6:5: 9:6 + _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch.rs:6:14: 6:15 + goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 7:6 } bb2: { - _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:7:19: 7:26 - switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:7:19: 7:26 + _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 + switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 } bb3: { - StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch.rs:7:15: 7:16 - _8 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch.rs:7:15: 7:16 - StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:7:24: 7:25 - _9 = (((_3.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch.rs:7:24: 7:25 - _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch.rs:7:31: 7:32 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x0000000000000000)) - // mir::Constant - // + span: $DIR/early_otherwise_branch.rs:7:31: 7:32 - // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } - StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:7:31: 7:32 - StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch.rs:7:31: 7:32 - goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:6:5: 9:6 + StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch.rs:5:15: 5:16 + _8 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:5:15: 5:16 + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:5:24: 5:25 + _9 = (((_3.1: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:5:24: 5:25 + _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch.rs:5:31: 5:32 + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:5:31: 5:32 + StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch.rs:5:31: 5:32 + goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 7:6 } bb4: { - StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:10:1: 10:2 - return; // scope 0 at $DIR/early_otherwise_branch.rs:10:2: 10:2 + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:8:1: 8:2 + return; // scope 0 at $DIR/early_otherwise_branch.rs:8:2: 8:2 + } + + bb5 (cleanup): { -+ resume; // scope 0 at $DIR/early_otherwise_branch.rs:5:1: 10:2 ++ resume; // scope 0 at $DIR/early_otherwise_branch.rs:3:1: 8:2 + } + + bb6: { -+ switchInt(_7) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:7:19: 7:26 ++ switchInt(_7) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 } } diff --git a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff index 1868f4f5be1b6..569dc6c5db61e 100644 --- a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff @@ -1,105 +1,87 @@ - // MIR for `opt2` before EarlyOtherwiseBranch + // MIR for `opt2` after EarlyOtherwiseBranch - fn opt2(_1: std::option::Option, _2: std::option::Option) -> usize { - debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:13:9: 13:10 - debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:13:27: 13:28 - let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch.rs:13:47: 13:52 - let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch.rs:14:11: 14:16 - let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:14:12: 14:13 - let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:14:14: 14:15 - let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:16:16: 16:20 - let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:15:19: 15:26 - let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:15:10: 15:17 - let _9: usize; // in scope 0 at $DIR/early_otherwise_branch.rs:15:15: 15:16 - let _10: usize; // in scope 0 at $DIR/early_otherwise_branch.rs:15:24: 15:25 -+ let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:16:16: 16:20 -+ let mut _12: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:16:16: 16:20 + fn opt2(_1: Option, _2: Option) -> u32 { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:11:9: 11:10 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:11:25: 11:26 + let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch.rs:11:44: 11:47 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:12:12: 12:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:12:15: 12:16 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:13:19: 13:26 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 + let _9: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:13:15: 13:16 + let _10: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:13:24: 13:25 ++ let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 ++ let mut _12: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 scope 1 { - debug a => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:15:15: 15:16 - debug b => _10; // in scope 1 at $DIR/early_otherwise_branch.rs:15:24: 15:25 + debug a => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:13:15: 13:16 + debug b => _10; // in scope 1 at $DIR/early_otherwise_branch.rs:13:24: 13:25 } bb0: { - StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:14:11: 14:16 - StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:14:12: 14:13 - _4 = _1; // scope 0 at $DIR/early_otherwise_branch.rs:14:12: 14:13 - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:14:14: 14:15 - _5 = _2; // scope 0 at $DIR/early_otherwise_branch.rs:14:14: 14:15 - (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:14:11: 14:16 - (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:14:11: 14:16 - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:14:15: 14:16 - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:14:15: 14:16 - _8 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:15:10: 15:17 -- switchInt(move _8) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:15:10: 15:17 -+ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:15:10: 15:17 -+ _11 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:15:10: 15:17 -+ StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch.rs:15:10: 15:17 -+ _12 = Ne(_11, _8); // scope 0 at $DIR/early_otherwise_branch.rs:15:10: 15:17 -+ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:15:10: 15:17 -+ switchInt(move _12) -> [false: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:15:10: 15:17 + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:12:12: 12:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch.rs:12:12: 12:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:12:15: 12:16 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch.rs:12:15: 12:16 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:12:16: 12:17 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:12:16: 12:17 + _8 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 +- switchInt(move _8) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 ++ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 ++ _11 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 ++ StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 ++ _12 = Ne(_11, _8); // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 ++ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 ++ switchInt(move _12) -> [false: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 } bb1: { - _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:16:16: 16:20 - switchInt(move _6) -> [0_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:16:16: 16:20 + _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 + switchInt(move _6) -> [0_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 } bb2: { - _0 = const 1_usize; // scope 0 at $DIR/early_otherwise_branch.rs:17:14: 17:15 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x0000000000000001)) - // mir::Constant - // + span: $DIR/early_otherwise_branch.rs:17:14: 17:15 - // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) } - goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:14:5: 18:6 + _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch.rs:15:14: 15:15 + goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 16:6 } bb3: { - _7 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:15:19: 15:26 - switchInt(move _7) -> [1_isize: bb4, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:15:19: 15:26 + _7 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:13:19: 13:26 + switchInt(move _7) -> [1_isize: bb4, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:13:19: 13:26 } bb4: { - StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:15:15: 15:16 - _9 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch.rs:15:15: 15:16 - StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:15:24: 15:25 - _10 = (((_3.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch.rs:15:24: 15:25 - _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch.rs:15:31: 15:32 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x0000000000000000)) - // mir::Constant - // + span: $DIR/early_otherwise_branch.rs:15:31: 15:32 - // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } - StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:15:31: 15:32 - StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:15:31: 15:32 - goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:14:5: 18:6 + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:13:15: 13:16 + _9 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:13:15: 13:16 + StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:13:24: 13:25 + _10 = (((_3.1: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:13:24: 13:25 + _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch.rs:13:31: 13:32 + StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:13:31: 13:32 + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:13:31: 13:32 + goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 16:6 } bb5: { - _0 = const 0_usize; // scope 0 at $DIR/early_otherwise_branch.rs:16:25: 16:26 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x0000000000000000)) - // mir::Constant - // + span: $DIR/early_otherwise_branch.rs:16:25: 16:26 - // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } - goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:14:5: 18:6 + _0 = const 0_u32; // scope 0 at $DIR/early_otherwise_branch.rs:14:25: 14:26 + goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 16:6 } bb6: { - StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:19:1: 19:2 - return; // scope 0 at $DIR/early_otherwise_branch.rs:19:2: 19:2 + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:17:1: 17:2 + return; // scope 0 at $DIR/early_otherwise_branch.rs:17:2: 17:2 + } + + bb7 (cleanup): { -+ resume; // scope 0 at $DIR/early_otherwise_branch.rs:13:1: 19:2 ++ resume; // scope 0 at $DIR/early_otherwise_branch.rs:11:1: 17:2 + } + + bb8: { -+ switchInt(_8) -> [0_isize: bb5, 1_isize: bb4, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:16:16: 16:20 ++ switchInt(_8) -> [0_isize: bb5, 1_isize: bb4, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 } } diff --git a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff index 9c326895d296b..9d45aa69f6336 100644 --- a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff @@ -1,117 +1,105 @@ - // MIR for `opt1` before EarlyOtherwiseBranch + // MIR for `opt1` after EarlyOtherwiseBranch - fn opt1(_1: std::option::Option, _2: std::option::Option, _3: std::option::Option) -> usize { - debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:9: 5:10 - debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:27: 5:28 - debug z => _3; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:44: 5:45 - let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:64: 5:69 - let mut _4: (std::option::Option, std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 - let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:12: 6:13 - let mut _6: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:14: 6:15 - let mut _7: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:16: 6:17 - let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 - let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 - let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 - let _11: usize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:15: 7:16 - let _12: usize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:24: 7:25 - let _13: usize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:33: 7:34 -+ let mut _14: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -+ let mut _15: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -+ let mut _16: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 -+ let mut _17: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 + fn opt1(_1: Option, _2: Option, _3: Option) -> u32 { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:4:9: 4:10 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:4:25: 4:26 + debug z => _3; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:4:41: 4:42 + let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:4:60: 4:63 + let mut _4: (std::option::Option, std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:12: 5:13 + let mut _6: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:15: 5:16 + let mut _7: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:18: 5:19 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 + let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 + let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 + let _11: u32; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:15: 6:16 + let _12: u32; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:24: 6:25 + let _13: u32; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:33: 6:34 ++ let mut _14: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 ++ let mut _15: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 ++ let mut _16: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 ++ let mut _17: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 scope 1 { - debug a => _11; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:15: 7:16 - debug b => _12; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:24: 7:25 - debug c => _13; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:33: 7:34 + debug a => _11; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:15: 6:16 + debug b => _12; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:24: 6:25 + debug c => _13; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:33: 6:34 } bb0: { - StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:12: 6:13 - _5 = _1; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:12: 6:13 - StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:14: 6:15 - _6 = _2; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:14: 6:15 - StorageLive(_7); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:16: 6:17 - _7 = _3; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:16: 6:17 - (_4.0: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 - (_4.1: std::option::Option) = move _6; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 - (_4.2: std::option::Option) = move _7; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 - StorageDead(_7); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:17: 6:18 - StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:17: 6:18 - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:17: 6:18 - _10 = discriminant((_4.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 -- switchInt(move _10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 -+ StorageLive(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 -+ _14 = discriminant((_4.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 -+ StorageLive(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 -+ _15 = Ne(_14, _10); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 -+ StorageDead(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 -+ switchInt(move _15) -> [false: bb7, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:12: 5:13 + _5 = _1; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:12: 5:13 + StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:15: 5:16 + _6 = _2; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:15: 5:16 + StorageLive(_7); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:18: 5:19 + _7 = _3; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:18: 5:19 + (_4.0: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20 + (_4.1: std::option::Option) = move _6; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20 + (_4.2: std::option::Option) = move _7; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20 + StorageDead(_7); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:19: 5:20 + StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:19: 5:20 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:19: 5:20 + _10 = discriminant((_4.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 +- switchInt(move _10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 ++ StorageLive(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 ++ _14 = discriminant((_4.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 ++ StorageLive(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 ++ _15 = Ne(_14, _10); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 ++ StorageDead(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 ++ switchInt(move _15) -> [false: bb7, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 } bb1: { - _0 = const 1_usize; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:8:14: 8:15 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x0000000000000001)) - // mir::Constant - // + span: $DIR/early_otherwise_branch_3_element_tuple.rs:8:14: 8:15 - // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) } - goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:5: 9:6 + _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:14: 7:15 + goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 8:6 } bb2: { - _9 = discriminant((_4.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -- switchInt(move _9) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -+ StorageLive(_16); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -+ _16 = discriminant((_4.2: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -+ StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -+ _17 = Ne(_16, _9); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -+ StorageDead(_16); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -+ switchInt(move _17) -> [false: bb8, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 + _9 = discriminant((_4.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 +- switchInt(move _9) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 ++ StorageLive(_16); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 ++ _16 = discriminant((_4.2: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 ++ StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 ++ _17 = Ne(_16, _9); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 ++ StorageDead(_16); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 ++ switchInt(move _17) -> [false: bb8, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 } bb3: { - _8 = discriminant((_4.2: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 - switchInt(move _8) -> [1_isize: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 + _8 = discriminant((_4.2: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 + switchInt(move _8) -> [1_isize: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 } bb4: { - StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:15: 7:16 - _11 = (((_4.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:15: 7:16 - StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:24: 7:25 - _12 = (((_4.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:24: 7:25 - StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:33: 7:34 - _13 = (((_4.2: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:33: 7:34 - _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x0000000000000000)) - // mir::Constant - // + span: $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 - // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } - StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 - StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 - StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 - goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:5: 9:6 + StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:15: 6:16 + _11 = (((_4.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:15: 6:16 + StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:24: 6:25 + _12 = (((_4.1: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:24: 6:25 + StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:33: 6:34 + _13 = (((_4.2: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:33: 6:34 + _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:40: 6:41 + StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:40: 6:41 + StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:40: 6:41 + StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:40: 6:41 + goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 8:6 } bb5: { - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:10:1: 10:2 - return; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:10:2: 10:2 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:9:1: 9:2 + return; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:9:2: 9:2 + } + + bb6 (cleanup): { -+ resume; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:1: 10:2 ++ resume; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:4:1: 9:2 + } + + bb7: { -+ switchInt(_10) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 ++ switchInt(_10) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 + } + + bb8: { -+ switchInt(_9) -> [1_isize: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 ++ switchInt(_9) -> [1_isize: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 } } diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff index 7a02a1c347069..f08920ef06de3 100644 --- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff @@ -84,12 +84,6 @@ bb2: { StorageLive(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:25: 24:27 ((_0 as Err).0: ()) = const (); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:28 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/early_otherwise_branch_68867.rs:24:21: 24:28 - // + literal: Const { ty: (), val: Value(Scalar()) } discriminant(_0) = 1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:28 StorageDead(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:27: 24:28 StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:6: 25:7 diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff index 9908843a2d864..9a6094f12dfb1 100644 --- a/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff @@ -1,114 +1,90 @@ - // MIR for `noopt1` before EarlyOtherwiseBranch + // MIR for `noopt1` after EarlyOtherwiseBranch - fn noopt1(_1: std::option::Option, _2: std::option::Option) -> usize { - debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:12 - debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:29: 8:30 - let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:49: 8:54 - let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:11: 9:16 - let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:12: 9:13 - let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:14: 9:15 - let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:16: 12:23 - let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:19: 10:26 - let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:10: 10:17 - let _9: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 - let _10: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:24: 10:25 - let _11: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:15: 11:16 - let _12: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:21: 12:22 + fn noopt1(_1: Option, _2: Option) -> u32 { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:7:11: 7:12 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:7:27: 7:28 + let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch_noopt.rs:7:46: 7:49 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:12: 8:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:15: 8:16 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:16: 11:23 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:19: 9:26 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:10: 9:17 + let _9: u32; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 + let _10: u32; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:24: 9:25 + let _11: u32; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 + let _12: u32; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:21: 11:22 scope 1 { - debug a => _9; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 - debug b => _10; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:10:24: 10:25 + debug a => _9; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 + debug b => _10; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:9:24: 9:25 } scope 2 { - debug a => _11; // in scope 2 at $DIR/early_otherwise_branch_noopt.rs:11:15: 11:16 + debug a => _11; // in scope 2 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 } scope 3 { - debug b => _12; // in scope 3 at $DIR/early_otherwise_branch_noopt.rs:12:21: 12:22 + debug b => _12; // in scope 3 at $DIR/early_otherwise_branch_noopt.rs:11:21: 11:22 } bb0: { - StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:11: 9:16 - StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:12: 9:13 - _4 = _1; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:12: 9:13 - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:14: 9:15 - _5 = _2; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:14: 9:15 - (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:11: 9:16 - (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:11: 9:16 - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 - _8 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:10: 10:17 - switchInt(move _8) -> [0_isize: bb1, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:10: 10:17 + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:12: 8:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:12: 8:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:15: 8:16 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:15: 8:16 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:16: 8:17 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:16: 8:17 + _8 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:10: 9:17 + switchInt(move _8) -> [0_isize: bb1, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:10: 9:17 } bb1: { - _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:16: 12:23 - switchInt(move _6) -> [0_isize: bb2, otherwise: bb6]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:16: 12:23 + _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:16: 11:23 + switchInt(move _6) -> [0_isize: bb2, otherwise: bb6]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:16: 11:23 } bb2: { - _0 = const 3_usize; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:13:25: 13:26 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x0000000000000003)) - // mir::Constant - // + span: $DIR/early_otherwise_branch_noopt.rs:13:25: 13:26 - // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000003)) } - goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:5: 14:6 + _0 = const 3_u32; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:25: 12:26 + goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 13:6 } bb3: { - _7 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:19: 10:26 - switchInt(move _7) -> [0_isize: bb5, otherwise: bb4]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:19: 10:26 + _7 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:19: 9:26 + switchInt(move _7) -> [0_isize: bb5, otherwise: bb4]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:19: 9:26 } bb4: { - StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 - _9 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 - StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:24: 10:25 - _10 = (((_3.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:24: 10:25 - _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch_noopt.rs:10:31: 10:32 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x0000000000000000)) - // mir::Constant - // + span: $DIR/early_otherwise_branch_noopt.rs:10:31: 10:32 - // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } - StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:31: 10:32 - StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:31: 10:32 - goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:5: 14:6 + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 + _9 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 + StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:24: 9:25 + _10 = (((_3.1: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:24: 9:25 + _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32 + StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32 + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32 + goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 13:6 } bb5: { - StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:15: 11:16 - _11 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:15: 11:16 - _0 = const 1_usize; // scope 2 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x0000000000000001)) - // mir::Constant - // + span: $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 - // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) } - StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 - goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:5: 14:6 + StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 + _11 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 + _0 = const 1_u32; // scope 2 at $DIR/early_otherwise_branch_noopt.rs:10:28: 10:29 + StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:28: 10:29 + goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 13:6 } bb6: { - StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:21: 12:22 - _12 = (((_3.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:21: 12:22 - _0 = const 2_usize; // scope 3 at $DIR/early_otherwise_branch_noopt.rs:12:28: 12:29 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x0000000000000002)) - // mir::Constant - // + span: $DIR/early_otherwise_branch_noopt.rs:12:28: 12:29 - // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000002)) } - StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:28: 12:29 - goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:5: 14:6 + StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:21: 11:22 + _12 = (((_3.1: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:21: 11:22 + _0 = const 2_u32; // scope 3 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 + StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 + goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 13:6 } bb7: { - StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:15:1: 15:2 - return; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:15:2: 15:2 + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:14:1: 14:2 + return; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:14:2: 14:2 } } diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff index 25391ab792013..c3aecb4529351 100644 --- a/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff @@ -1,72 +1,60 @@ - // MIR for `noopt2` before EarlyOtherwiseBranch + // MIR for `noopt2` after EarlyOtherwiseBranch - fn noopt2(_1: std::option::Option, _2: std::option::Option) -> usize { - debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:12 - debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:29: 19:30 - let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:48: 19:53 - let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:11: 20:16 - let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:12: 20:13 - let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:14: 20:15 - let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:19: 21:26 - let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:10: 21:17 - let _8: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:15: 21:16 - let _9: bool; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:24: 21:25 + fn noopt2(_1: Option, _2: Option) -> u32 { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:18:11: 18:12 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:18:27: 18:28 + let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch_noopt.rs:18:47: 18:50 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:12: 19:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:15: 19:16 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:19: 20:26 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:10: 20:17 + let _8: u32; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 + let _9: bool; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:24: 20:25 scope 1 { - debug a => _8; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:21:15: 21:16 - debug b => _9; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:21:24: 21:25 + debug a => _8; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 + debug b => _9; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:20:24: 20:25 } bb0: { - StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:11: 20:16 - StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:12: 20:13 - _4 = _1; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:12: 20:13 - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:14: 20:15 - _5 = _2; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:14: 20:15 - (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:11: 20:16 - (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:11: 20:16 - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 - _7 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:10: 21:17 - switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:10: 21:17 + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:12: 19:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:12: 19:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:15: 19:16 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:15: 19:16 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:16: 19:17 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:16: 19:17 + _7 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:10: 20:17 + switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:10: 20:17 } bb1: { - _0 = const 1_usize; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:22:14: 22:15 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x0000000000000001)) - // mir::Constant - // + span: $DIR/early_otherwise_branch_noopt.rs:22:14: 22:15 - // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) } - goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:5: 23:6 + _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:14: 21:15 + goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:5: 22:6 } bb2: { - _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:19: 21:26 - switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:19: 21:26 + _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:19: 20:26 + switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:19: 20:26 } bb3: { - StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:15: 21:16 - _8 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:15: 21:16 - StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:24: 21:25 - _9 = (((_3.1: std::option::Option) as Some).0: bool); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:24: 21:25 - _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch_noopt.rs:21:31: 21:32 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x0000000000000000)) - // mir::Constant - // + span: $DIR/early_otherwise_branch_noopt.rs:21:31: 21:32 - // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } - StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:31: 21:32 - StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:31: 21:32 - goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:5: 23:6 + StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 + _8 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:24: 20:25 + _9 = (((_3.1: std::option::Option) as Some).0: bool); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:24: 20:25 + _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch_noopt.rs:20:31: 20:32 + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:31: 20:32 + StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:31: 20:32 + goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:5: 22:6 } bb4: { - StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:24:1: 24:2 - return; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:24:2: 24:2 + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:23:1: 23:2 + return; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:23:2: 23:2 } } From 25302740231152bccebc391e893d48ef9f3ca50a Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Sat, 19 Sep 2020 23:53:18 +0200 Subject: [PATCH 0719/1052] correct comment --- .../src/transform/early_otherwise_branch.rs | 2 +- ...ranch.opt1.EarlyOtherwiseBranch.diff.32bit | 88 ------------- ...ranch.opt1.EarlyOtherwiseBranch.diff.64bit | 88 ------------- ...ranch.opt2.EarlyOtherwiseBranch.diff.32bit | 105 ---------------- ...ranch.opt2.EarlyOtherwiseBranch.diff.64bit | 105 ---------------- ...tuple.opt1.EarlyOtherwiseBranch.diff.32bit | 117 ------------------ ...tuple.opt1.EarlyOtherwiseBranch.diff.64bit | 117 ------------------ ...opt.noopt1.EarlyOtherwiseBranch.diff.32bit | 114 ----------------- ...opt.noopt1.EarlyOtherwiseBranch.diff.64bit | 114 ----------------- ...opt.noopt2.EarlyOtherwiseBranch.diff.32bit | 72 ----------- ...opt.noopt2.EarlyOtherwiseBranch.diff.64bit | 72 ----------- 11 files changed, 1 insertion(+), 993 deletions(-) delete mode 100644 src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff.32bit delete mode 100644 src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff.64bit delete mode 100644 src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff.32bit delete mode 100644 src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff.64bit delete mode 100644 src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff.32bit delete mode 100644 src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff.64bit delete mode 100644 src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff.32bit delete mode 100644 src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff.64bit delete mode 100644 src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff.32bit delete mode 100644 src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff.64bit diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs index e60cc8c1348d1..d44bd1e3495a3 100644 --- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs +++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs @@ -21,7 +21,7 @@ use std::{borrow::Cow, fmt::Debug}; /// let y: Option<()>; /// let discriminant_x = // get discriminant of x /// let discriminant_y = // get discriminant of y -/// if discriminant_x != discriminant_y {1} else {0} +/// if discriminant_x != discriminant_y || discriminant_x == None {1} else {0} /// ``` pub struct EarlyOtherwiseBranch; diff --git a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff.32bit b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff.32bit deleted file mode 100644 index dbeb09bf2bbc8..0000000000000 --- a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff.32bit +++ /dev/null @@ -1,88 +0,0 @@ -- // MIR for `opt1` before EarlyOtherwiseBranch -+ // MIR for `opt1` after EarlyOtherwiseBranch - - fn opt1(_1: std::option::Option, _2: std::option::Option) -> usize { - debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:4:9: 4:10 - debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:4:27: 4:28 - let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch.rs:4:47: 4:52 - let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch.rs:5:11: 5:16 - let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:5:12: 5:13 - let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:5:14: 5:15 - let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:6:19: 6:26 - let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 - let _8: usize; // in scope 0 at $DIR/early_otherwise_branch.rs:6:15: 6:16 - let _9: usize; // in scope 0 at $DIR/early_otherwise_branch.rs:6:24: 6:25 -+ let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:6:19: 6:26 -+ let mut _11: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:6:19: 6:26 - scope 1 { - debug a => _8; // in scope 1 at $DIR/early_otherwise_branch.rs:6:15: 6:16 - debug b => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:6:24: 6:25 - } - - bb0: { - StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:5:11: 5:16 - StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:5:12: 5:13 - _4 = _1; // scope 0 at $DIR/early_otherwise_branch.rs:5:12: 5:13 - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:5:14: 5:15 - _5 = _2; // scope 0 at $DIR/early_otherwise_branch.rs:5:14: 5:15 - (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:5:11: 5:16 - (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:5:11: 5:16 - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:5:15: 5:16 - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:5:15: 5:16 - _7 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 -- switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 -+ StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 -+ _10 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 -+ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 -+ _11 = Ne(_10, _7); // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 -+ StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 -+ switchInt(move _11) -> [false: bb6, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 - } - - bb1: { - _0 = const 1_usize; // scope 0 at $DIR/early_otherwise_branch.rs:7:14: 7:15 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x00000001)) - // mir::Constant - // + span: $DIR/early_otherwise_branch.rs:7:14: 7:15 - // + literal: Const { ty: usize, val: Value(Scalar(0x00000001)) } - goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:5:5: 8:6 - } - - bb2: { - _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:6:19: 6:26 - switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:6:19: 6:26 - } - - bb3: { - StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch.rs:6:15: 6:16 - _8 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch.rs:6:15: 6:16 - StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:6:24: 6:25 - _9 = (((_3.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch.rs:6:24: 6:25 - _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch.rs:6:31: 6:32 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x00000000)) - // mir::Constant - // + span: $DIR/early_otherwise_branch.rs:6:31: 6:32 - // + literal: Const { ty: usize, val: Value(Scalar(0x00000000)) } - StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:6:31: 6:32 - StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch.rs:6:31: 6:32 - goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:5:5: 8:6 - } - - bb4: { - StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:9:1: 9:2 - return; // scope 0 at $DIR/early_otherwise_branch.rs:9:2: 9:2 -+ } -+ -+ bb5 (cleanup): { -+ resume; // scope 0 at $DIR/early_otherwise_branch.rs:4:1: 9:2 -+ } -+ -+ bb6: { -+ switchInt(_7) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:6:19: 6:26 - } - } - diff --git a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff.64bit b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff.64bit deleted file mode 100644 index 62a40a440db16..0000000000000 --- a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff.64bit +++ /dev/null @@ -1,88 +0,0 @@ -- // MIR for `opt1` before EarlyOtherwiseBranch -+ // MIR for `opt1` after EarlyOtherwiseBranch - - fn opt1(_1: std::option::Option, _2: std::option::Option) -> usize { - debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:4:9: 4:10 - debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:4:27: 4:28 - let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch.rs:4:47: 4:52 - let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch.rs:5:11: 5:16 - let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:5:12: 5:13 - let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:5:14: 5:15 - let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:6:19: 6:26 - let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 - let _8: usize; // in scope 0 at $DIR/early_otherwise_branch.rs:6:15: 6:16 - let _9: usize; // in scope 0 at $DIR/early_otherwise_branch.rs:6:24: 6:25 -+ let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:6:19: 6:26 -+ let mut _11: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:6:19: 6:26 - scope 1 { - debug a => _8; // in scope 1 at $DIR/early_otherwise_branch.rs:6:15: 6:16 - debug b => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:6:24: 6:25 - } - - bb0: { - StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:5:11: 5:16 - StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:5:12: 5:13 - _4 = _1; // scope 0 at $DIR/early_otherwise_branch.rs:5:12: 5:13 - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:5:14: 5:15 - _5 = _2; // scope 0 at $DIR/early_otherwise_branch.rs:5:14: 5:15 - (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:5:11: 5:16 - (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:5:11: 5:16 - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:5:15: 5:16 - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:5:15: 5:16 - _7 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 -- switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 -+ StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 -+ _10 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 -+ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 -+ _11 = Ne(_10, _7); // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 -+ StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 -+ switchInt(move _11) -> [false: bb6, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:6:10: 6:17 - } - - bb1: { - _0 = const 1_usize; // scope 0 at $DIR/early_otherwise_branch.rs:7:14: 7:15 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x0000000000000001)) - // mir::Constant - // + span: $DIR/early_otherwise_branch.rs:7:14: 7:15 - // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) } - goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:5:5: 8:6 - } - - bb2: { - _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:6:19: 6:26 - switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:6:19: 6:26 - } - - bb3: { - StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch.rs:6:15: 6:16 - _8 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch.rs:6:15: 6:16 - StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:6:24: 6:25 - _9 = (((_3.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch.rs:6:24: 6:25 - _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch.rs:6:31: 6:32 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x0000000000000000)) - // mir::Constant - // + span: $DIR/early_otherwise_branch.rs:6:31: 6:32 - // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } - StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:6:31: 6:32 - StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch.rs:6:31: 6:32 - goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:5:5: 8:6 - } - - bb4: { - StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:9:1: 9:2 - return; // scope 0 at $DIR/early_otherwise_branch.rs:9:2: 9:2 -+ } -+ -+ bb5 (cleanup): { -+ resume; // scope 0 at $DIR/early_otherwise_branch.rs:4:1: 9:2 -+ } -+ -+ bb6: { -+ switchInt(_7) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:6:19: 6:26 - } - } - diff --git a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff.32bit b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff.32bit deleted file mode 100644 index 38c303dc81413..0000000000000 --- a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff.32bit +++ /dev/null @@ -1,105 +0,0 @@ -- // MIR for `opt2` before EarlyOtherwiseBranch -+ // MIR for `opt2` after EarlyOtherwiseBranch - - fn opt2(_1: std::option::Option, _2: std::option::Option) -> usize { - debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:12:9: 12:10 - debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:12:27: 12:28 - let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch.rs:12:47: 12:52 - let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch.rs:13:11: 13:16 - let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:13:12: 13:13 - let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:13:14: 13:15 - let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:15:16: 15:20 - let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:14:19: 14:26 - let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 - let _9: usize; // in scope 0 at $DIR/early_otherwise_branch.rs:14:15: 14:16 - let _10: usize; // in scope 0 at $DIR/early_otherwise_branch.rs:14:24: 14:25 -+ let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:15:16: 15:20 -+ let mut _12: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:15:16: 15:20 - scope 1 { - debug a => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:14:15: 14:16 - debug b => _10; // in scope 1 at $DIR/early_otherwise_branch.rs:14:24: 14:25 - } - - bb0: { - StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:13:11: 13:16 - StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:13:12: 13:13 - _4 = _1; // scope 0 at $DIR/early_otherwise_branch.rs:13:12: 13:13 - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:13:14: 13:15 - _5 = _2; // scope 0 at $DIR/early_otherwise_branch.rs:13:14: 13:15 - (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:13:11: 13:16 - (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:13:11: 13:16 - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:13:15: 13:16 - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:13:15: 13:16 - _8 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 -- switchInt(move _8) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 -+ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 -+ _11 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 -+ StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 -+ _12 = Ne(_11, _8); // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 -+ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 -+ switchInt(move _12) -> [false: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 - } - - bb1: { - _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:15:16: 15:20 - switchInt(move _6) -> [0_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:15:16: 15:20 - } - - bb2: { - _0 = const 1_usize; // scope 0 at $DIR/early_otherwise_branch.rs:16:14: 16:15 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x00000001)) - // mir::Constant - // + span: $DIR/early_otherwise_branch.rs:16:14: 16:15 - // + literal: Const { ty: usize, val: Value(Scalar(0x00000001)) } - goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:13:5: 17:6 - } - - bb3: { - _7 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:14:19: 14:26 - switchInt(move _7) -> [1_isize: bb4, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:14:19: 14:26 - } - - bb4: { - StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:14:15: 14:16 - _9 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch.rs:14:15: 14:16 - StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:14:24: 14:25 - _10 = (((_3.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch.rs:14:24: 14:25 - _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch.rs:14:31: 14:32 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x00000000)) - // mir::Constant - // + span: $DIR/early_otherwise_branch.rs:14:31: 14:32 - // + literal: Const { ty: usize, val: Value(Scalar(0x00000000)) } - StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:14:31: 14:32 - StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:14:31: 14:32 - goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:13:5: 17:6 - } - - bb5: { - _0 = const 0_usize; // scope 0 at $DIR/early_otherwise_branch.rs:15:25: 15:26 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x00000000)) - // mir::Constant - // + span: $DIR/early_otherwise_branch.rs:15:25: 15:26 - // + literal: Const { ty: usize, val: Value(Scalar(0x00000000)) } - goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:13:5: 17:6 - } - - bb6: { - StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:18:1: 18:2 - return; // scope 0 at $DIR/early_otherwise_branch.rs:18:2: 18:2 -+ } -+ -+ bb7 (cleanup): { -+ resume; // scope 0 at $DIR/early_otherwise_branch.rs:12:1: 18:2 -+ } -+ -+ bb8: { -+ switchInt(_8) -> [0_isize: bb5, 1_isize: bb4, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:15:16: 15:20 - } - } - diff --git a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff.64bit b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff.64bit deleted file mode 100644 index 5449158bff0e1..0000000000000 --- a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff.64bit +++ /dev/null @@ -1,105 +0,0 @@ -- // MIR for `opt2` before EarlyOtherwiseBranch -+ // MIR for `opt2` after EarlyOtherwiseBranch - - fn opt2(_1: std::option::Option, _2: std::option::Option) -> usize { - debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:12:9: 12:10 - debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:12:27: 12:28 - let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch.rs:12:47: 12:52 - let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch.rs:13:11: 13:16 - let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:13:12: 13:13 - let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:13:14: 13:15 - let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:15:16: 15:20 - let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:14:19: 14:26 - let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 - let _9: usize; // in scope 0 at $DIR/early_otherwise_branch.rs:14:15: 14:16 - let _10: usize; // in scope 0 at $DIR/early_otherwise_branch.rs:14:24: 14:25 -+ let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:15:16: 15:20 -+ let mut _12: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:15:16: 15:20 - scope 1 { - debug a => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:14:15: 14:16 - debug b => _10; // in scope 1 at $DIR/early_otherwise_branch.rs:14:24: 14:25 - } - - bb0: { - StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:13:11: 13:16 - StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:13:12: 13:13 - _4 = _1; // scope 0 at $DIR/early_otherwise_branch.rs:13:12: 13:13 - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:13:14: 13:15 - _5 = _2; // scope 0 at $DIR/early_otherwise_branch.rs:13:14: 13:15 - (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:13:11: 13:16 - (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:13:11: 13:16 - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:13:15: 13:16 - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:13:15: 13:16 - _8 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 -- switchInt(move _8) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 -+ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 -+ _11 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 -+ StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 -+ _12 = Ne(_11, _8); // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 -+ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 -+ switchInt(move _12) -> [false: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:14:10: 14:17 - } - - bb1: { - _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:15:16: 15:20 - switchInt(move _6) -> [0_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:15:16: 15:20 - } - - bb2: { - _0 = const 1_usize; // scope 0 at $DIR/early_otherwise_branch.rs:16:14: 16:15 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x0000000000000001)) - // mir::Constant - // + span: $DIR/early_otherwise_branch.rs:16:14: 16:15 - // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) } - goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:13:5: 17:6 - } - - bb3: { - _7 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:14:19: 14:26 - switchInt(move _7) -> [1_isize: bb4, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:14:19: 14:26 - } - - bb4: { - StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:14:15: 14:16 - _9 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch.rs:14:15: 14:16 - StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:14:24: 14:25 - _10 = (((_3.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch.rs:14:24: 14:25 - _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch.rs:14:31: 14:32 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x0000000000000000)) - // mir::Constant - // + span: $DIR/early_otherwise_branch.rs:14:31: 14:32 - // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } - StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:14:31: 14:32 - StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:14:31: 14:32 - goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:13:5: 17:6 - } - - bb5: { - _0 = const 0_usize; // scope 0 at $DIR/early_otherwise_branch.rs:15:25: 15:26 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x0000000000000000)) - // mir::Constant - // + span: $DIR/early_otherwise_branch.rs:15:25: 15:26 - // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } - goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:13:5: 17:6 - } - - bb6: { - StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:18:1: 18:2 - return; // scope 0 at $DIR/early_otherwise_branch.rs:18:2: 18:2 -+ } -+ -+ bb7 (cleanup): { -+ resume; // scope 0 at $DIR/early_otherwise_branch.rs:12:1: 18:2 -+ } -+ -+ bb8: { -+ switchInt(_8) -> [0_isize: bb5, 1_isize: bb4, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:15:16: 15:20 - } - } - diff --git a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff.32bit b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff.32bit deleted file mode 100644 index 9a3f7614ad088..0000000000000 --- a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff.32bit +++ /dev/null @@ -1,117 +0,0 @@ -- // MIR for `opt1` before EarlyOtherwiseBranch -+ // MIR for `opt1` after EarlyOtherwiseBranch - - fn opt1(_1: std::option::Option, _2: std::option::Option, _3: std::option::Option) -> usize { - debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:9: 5:10 - debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:27: 5:28 - debug z => _3; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:44: 5:45 - let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:64: 5:69 - let mut _4: (std::option::Option, std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 - let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:12: 6:13 - let mut _6: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:14: 6:15 - let mut _7: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:16: 6:17 - let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 - let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 - let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 - let _11: usize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:15: 7:16 - let _12: usize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:24: 7:25 - let _13: usize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:33: 7:34 -+ let mut _14: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -+ let mut _15: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -+ let mut _16: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 -+ let mut _17: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 - scope 1 { - debug a => _11; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:15: 7:16 - debug b => _12; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:24: 7:25 - debug c => _13; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:33: 7:34 - } - - bb0: { - StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:12: 6:13 - _5 = _1; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:12: 6:13 - StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:14: 6:15 - _6 = _2; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:14: 6:15 - StorageLive(_7); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:16: 6:17 - _7 = _3; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:16: 6:17 - (_4.0: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 - (_4.1: std::option::Option) = move _6; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 - (_4.2: std::option::Option) = move _7; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 - StorageDead(_7); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:17: 6:18 - StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:17: 6:18 - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:17: 6:18 - _10 = discriminant((_4.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 -- switchInt(move _10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 -+ StorageLive(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 -+ _14 = discriminant((_4.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 -+ StorageLive(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 -+ _15 = Ne(_14, _10); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 -+ StorageDead(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 -+ switchInt(move _15) -> [false: bb7, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 - } - - bb1: { - _0 = const 1_usize; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:8:14: 8:15 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x00000001)) - // mir::Constant - // + span: $DIR/early_otherwise_branch_3_element_tuple.rs:8:14: 8:15 - // + literal: Const { ty: usize, val: Value(Scalar(0x00000001)) } - goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:5: 9:6 - } - - bb2: { - _9 = discriminant((_4.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -- switchInt(move _9) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -+ StorageLive(_16); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -+ _16 = discriminant((_4.2: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -+ StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -+ _17 = Ne(_16, _9); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -+ StorageDead(_16); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -+ switchInt(move _17) -> [false: bb8, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 - } - - bb3: { - _8 = discriminant((_4.2: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 - switchInt(move _8) -> [1_isize: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 - } - - bb4: { - StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:15: 7:16 - _11 = (((_4.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:15: 7:16 - StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:24: 7:25 - _12 = (((_4.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:24: 7:25 - StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:33: 7:34 - _13 = (((_4.2: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:33: 7:34 - _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x00000000)) - // mir::Constant - // + span: $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 - // + literal: Const { ty: usize, val: Value(Scalar(0x00000000)) } - StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 - StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 - StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 - goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:5: 9:6 - } - - bb5: { - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:10:1: 10:2 - return; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:10:2: 10:2 -+ } -+ -+ bb6 (cleanup): { -+ resume; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:1: 10:2 -+ } -+ -+ bb7: { -+ switchInt(_10) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -+ } -+ -+ bb8: { -+ switchInt(_9) -> [1_isize: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 - } - } - diff --git a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff.64bit b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff.64bit deleted file mode 100644 index 9c326895d296b..0000000000000 --- a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff.64bit +++ /dev/null @@ -1,117 +0,0 @@ -- // MIR for `opt1` before EarlyOtherwiseBranch -+ // MIR for `opt1` after EarlyOtherwiseBranch - - fn opt1(_1: std::option::Option, _2: std::option::Option, _3: std::option::Option) -> usize { - debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:9: 5:10 - debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:27: 5:28 - debug z => _3; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:44: 5:45 - let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:64: 5:69 - let mut _4: (std::option::Option, std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 - let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:12: 6:13 - let mut _6: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:14: 6:15 - let mut _7: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:16: 6:17 - let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 - let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 - let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 - let _11: usize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:15: 7:16 - let _12: usize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:24: 7:25 - let _13: usize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:33: 7:34 -+ let mut _14: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -+ let mut _15: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -+ let mut _16: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 -+ let mut _17: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 - scope 1 { - debug a => _11; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:15: 7:16 - debug b => _12; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:24: 7:25 - debug c => _13; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:33: 7:34 - } - - bb0: { - StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:12: 6:13 - _5 = _1; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:12: 6:13 - StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:14: 6:15 - _6 = _2; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:14: 6:15 - StorageLive(_7); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:16: 6:17 - _7 = _3; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:16: 6:17 - (_4.0: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 - (_4.1: std::option::Option) = move _6; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 - (_4.2: std::option::Option) = move _7; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:11: 6:18 - StorageDead(_7); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:17: 6:18 - StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:17: 6:18 - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:17: 6:18 - _10 = discriminant((_4.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 -- switchInt(move _10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 -+ StorageLive(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 -+ _14 = discriminant((_4.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 -+ StorageLive(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 -+ _15 = Ne(_14, _10); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 -+ StorageDead(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 -+ switchInt(move _15) -> [false: bb7, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:10: 7:17 - } - - bb1: { - _0 = const 1_usize; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:8:14: 8:15 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x0000000000000001)) - // mir::Constant - // + span: $DIR/early_otherwise_branch_3_element_tuple.rs:8:14: 8:15 - // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) } - goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:5: 9:6 - } - - bb2: { - _9 = discriminant((_4.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -- switchInt(move _9) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -+ StorageLive(_16); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -+ _16 = discriminant((_4.2: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -+ StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -+ _17 = Ne(_16, _9); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -+ StorageDead(_16); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -+ switchInt(move _17) -> [false: bb8, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 - } - - bb3: { - _8 = discriminant((_4.2: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 - switchInt(move _8) -> [1_isize: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 - } - - bb4: { - StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:15: 7:16 - _11 = (((_4.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:15: 7:16 - StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:24: 7:25 - _12 = (((_4.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:24: 7:25 - StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:33: 7:34 - _13 = (((_4.2: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:33: 7:34 - _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x0000000000000000)) - // mir::Constant - // + span: $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 - // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } - StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 - StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 - StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:40: 7:41 - goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:5: 9:6 - } - - bb5: { - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:10:1: 10:2 - return; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:10:2: 10:2 -+ } -+ -+ bb6 (cleanup): { -+ resume; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:1: 10:2 -+ } -+ -+ bb7: { -+ switchInt(_10) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:19: 7:26 -+ } -+ -+ bb8: { -+ switchInt(_9) -> [1_isize: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:28: 7:35 - } - } - diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff.32bit b/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff.32bit deleted file mode 100644 index 26842c74e6fd2..0000000000000 --- a/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff.32bit +++ /dev/null @@ -1,114 +0,0 @@ -- // MIR for `noopt1` before EarlyOtherwiseBranch -+ // MIR for `noopt1` after EarlyOtherwiseBranch - - fn noopt1(_1: std::option::Option, _2: std::option::Option) -> usize { - debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:12 - debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:29: 8:30 - let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:49: 8:54 - let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:11: 9:16 - let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:12: 9:13 - let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:14: 9:15 - let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:16: 12:23 - let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:19: 10:26 - let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:10: 10:17 - let _9: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 - let _10: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:24: 10:25 - let _11: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:15: 11:16 - let _12: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:21: 12:22 - scope 1 { - debug a => _9; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 - debug b => _10; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:10:24: 10:25 - } - scope 2 { - debug a => _11; // in scope 2 at $DIR/early_otherwise_branch_noopt.rs:11:15: 11:16 - } - scope 3 { - debug b => _12; // in scope 3 at $DIR/early_otherwise_branch_noopt.rs:12:21: 12:22 - } - - bb0: { - StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:11: 9:16 - StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:12: 9:13 - _4 = _1; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:12: 9:13 - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:14: 9:15 - _5 = _2; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:14: 9:15 - (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:11: 9:16 - (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:11: 9:16 - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 - _8 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:10: 10:17 - switchInt(move _8) -> [0_isize: bb1, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:10: 10:17 - } - - bb1: { - _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:16: 12:23 - switchInt(move _6) -> [0_isize: bb2, otherwise: bb6]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:16: 12:23 - } - - bb2: { - _0 = const 3_usize; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:13:25: 13:26 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x00000003)) - // mir::Constant - // + span: $DIR/early_otherwise_branch_noopt.rs:13:25: 13:26 - // + literal: Const { ty: usize, val: Value(Scalar(0x00000003)) } - goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:5: 14:6 - } - - bb3: { - _7 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:19: 10:26 - switchInt(move _7) -> [0_isize: bb5, otherwise: bb4]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:19: 10:26 - } - - bb4: { - StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 - _9 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 - StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:24: 10:25 - _10 = (((_3.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:24: 10:25 - _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch_noopt.rs:10:31: 10:32 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x00000000)) - // mir::Constant - // + span: $DIR/early_otherwise_branch_noopt.rs:10:31: 10:32 - // + literal: Const { ty: usize, val: Value(Scalar(0x00000000)) } - StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:31: 10:32 - StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:31: 10:32 - goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:5: 14:6 - } - - bb5: { - StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:15: 11:16 - _11 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:15: 11:16 - _0 = const 1_usize; // scope 2 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x00000001)) - // mir::Constant - // + span: $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 - // + literal: Const { ty: usize, val: Value(Scalar(0x00000001)) } - StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 - goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:5: 14:6 - } - - bb6: { - StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:21: 12:22 - _12 = (((_3.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:21: 12:22 - _0 = const 2_usize; // scope 3 at $DIR/early_otherwise_branch_noopt.rs:12:28: 12:29 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x00000002)) - // mir::Constant - // + span: $DIR/early_otherwise_branch_noopt.rs:12:28: 12:29 - // + literal: Const { ty: usize, val: Value(Scalar(0x00000002)) } - StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:28: 12:29 - goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:5: 14:6 - } - - bb7: { - StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:15:1: 15:2 - return; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:15:2: 15:2 - } - } - diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff.64bit b/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff.64bit deleted file mode 100644 index 9908843a2d864..0000000000000 --- a/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff.64bit +++ /dev/null @@ -1,114 +0,0 @@ -- // MIR for `noopt1` before EarlyOtherwiseBranch -+ // MIR for `noopt1` after EarlyOtherwiseBranch - - fn noopt1(_1: std::option::Option, _2: std::option::Option) -> usize { - debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:12 - debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:29: 8:30 - let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:49: 8:54 - let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:11: 9:16 - let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:12: 9:13 - let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:14: 9:15 - let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:16: 12:23 - let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:19: 10:26 - let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:10: 10:17 - let _9: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 - let _10: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:24: 10:25 - let _11: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:15: 11:16 - let _12: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:21: 12:22 - scope 1 { - debug a => _9; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 - debug b => _10; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:10:24: 10:25 - } - scope 2 { - debug a => _11; // in scope 2 at $DIR/early_otherwise_branch_noopt.rs:11:15: 11:16 - } - scope 3 { - debug b => _12; // in scope 3 at $DIR/early_otherwise_branch_noopt.rs:12:21: 12:22 - } - - bb0: { - StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:11: 9:16 - StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:12: 9:13 - _4 = _1; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:12: 9:13 - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:14: 9:15 - _5 = _2; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:14: 9:15 - (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:11: 9:16 - (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:11: 9:16 - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 - _8 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:10: 10:17 - switchInt(move _8) -> [0_isize: bb1, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:10: 10:17 - } - - bb1: { - _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:16: 12:23 - switchInt(move _6) -> [0_isize: bb2, otherwise: bb6]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:16: 12:23 - } - - bb2: { - _0 = const 3_usize; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:13:25: 13:26 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x0000000000000003)) - // mir::Constant - // + span: $DIR/early_otherwise_branch_noopt.rs:13:25: 13:26 - // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000003)) } - goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:5: 14:6 - } - - bb3: { - _7 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:19: 10:26 - switchInt(move _7) -> [0_isize: bb5, otherwise: bb4]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:19: 10:26 - } - - bb4: { - StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 - _9 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 - StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:24: 10:25 - _10 = (((_3.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:24: 10:25 - _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch_noopt.rs:10:31: 10:32 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x0000000000000000)) - // mir::Constant - // + span: $DIR/early_otherwise_branch_noopt.rs:10:31: 10:32 - // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } - StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:31: 10:32 - StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:31: 10:32 - goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:5: 14:6 - } - - bb5: { - StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:15: 11:16 - _11 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:15: 11:16 - _0 = const 1_usize; // scope 2 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x0000000000000001)) - // mir::Constant - // + span: $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 - // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) } - StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 - goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:5: 14:6 - } - - bb6: { - StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:21: 12:22 - _12 = (((_3.1: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:21: 12:22 - _0 = const 2_usize; // scope 3 at $DIR/early_otherwise_branch_noopt.rs:12:28: 12:29 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x0000000000000002)) - // mir::Constant - // + span: $DIR/early_otherwise_branch_noopt.rs:12:28: 12:29 - // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000002)) } - StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:28: 12:29 - goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:5: 14:6 - } - - bb7: { - StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:15:1: 15:2 - return; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:15:2: 15:2 - } - } - diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff.32bit b/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff.32bit deleted file mode 100644 index 49dad4a02a404..0000000000000 --- a/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff.32bit +++ /dev/null @@ -1,72 +0,0 @@ -- // MIR for `noopt2` before EarlyOtherwiseBranch -+ // MIR for `noopt2` after EarlyOtherwiseBranch - - fn noopt2(_1: std::option::Option, _2: std::option::Option) -> usize { - debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:12 - debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:29: 19:30 - let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:48: 19:53 - let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:11: 20:16 - let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:12: 20:13 - let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:14: 20:15 - let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:19: 21:26 - let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:10: 21:17 - let _8: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:15: 21:16 - let _9: bool; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:24: 21:25 - scope 1 { - debug a => _8; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:21:15: 21:16 - debug b => _9; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:21:24: 21:25 - } - - bb0: { - StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:11: 20:16 - StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:12: 20:13 - _4 = _1; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:12: 20:13 - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:14: 20:15 - _5 = _2; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:14: 20:15 - (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:11: 20:16 - (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:11: 20:16 - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 - _7 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:10: 21:17 - switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:10: 21:17 - } - - bb1: { - _0 = const 1_usize; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:22:14: 22:15 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x00000001)) - // mir::Constant - // + span: $DIR/early_otherwise_branch_noopt.rs:22:14: 22:15 - // + literal: Const { ty: usize, val: Value(Scalar(0x00000001)) } - goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:5: 23:6 - } - - bb2: { - _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:19: 21:26 - switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:19: 21:26 - } - - bb3: { - StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:15: 21:16 - _8 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:15: 21:16 - StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:24: 21:25 - _9 = (((_3.1: std::option::Option) as Some).0: bool); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:24: 21:25 - _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch_noopt.rs:21:31: 21:32 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x00000000)) - // mir::Constant - // + span: $DIR/early_otherwise_branch_noopt.rs:21:31: 21:32 - // + literal: Const { ty: usize, val: Value(Scalar(0x00000000)) } - StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:31: 21:32 - StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:31: 21:32 - goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:5: 23:6 - } - - bb4: { - StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:24:1: 24:2 - return; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:24:2: 24:2 - } - } - diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff.64bit b/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff.64bit deleted file mode 100644 index 25391ab792013..0000000000000 --- a/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff.64bit +++ /dev/null @@ -1,72 +0,0 @@ -- // MIR for `noopt2` before EarlyOtherwiseBranch -+ // MIR for `noopt2` after EarlyOtherwiseBranch - - fn noopt2(_1: std::option::Option, _2: std::option::Option) -> usize { - debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:12 - debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:29: 19:30 - let mut _0: usize; // return place in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:48: 19:53 - let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:11: 20:16 - let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:12: 20:13 - let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:14: 20:15 - let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:19: 21:26 - let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:10: 21:17 - let _8: usize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:15: 21:16 - let _9: bool; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:24: 21:25 - scope 1 { - debug a => _8; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:21:15: 21:16 - debug b => _9; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:21:24: 21:25 - } - - bb0: { - StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:11: 20:16 - StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:12: 20:13 - _4 = _1; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:12: 20:13 - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:14: 20:15 - _5 = _2; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:14: 20:15 - (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:11: 20:16 - (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:11: 20:16 - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 - _7 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:10: 21:17 - switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:10: 21:17 - } - - bb1: { - _0 = const 1_usize; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:22:14: 22:15 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x0000000000000001)) - // mir::Constant - // + span: $DIR/early_otherwise_branch_noopt.rs:22:14: 22:15 - // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) } - goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:5: 23:6 - } - - bb2: { - _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:19: 21:26 - switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:19: 21:26 - } - - bb3: { - StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:15: 21:16 - _8 = (((_3.0: std::option::Option) as Some).0: usize); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:15: 21:16 - StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:24: 21:25 - _9 = (((_3.1: std::option::Option) as Some).0: bool); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:24: 21:25 - _0 = const 0_usize; // scope 1 at $DIR/early_otherwise_branch_noopt.rs:21:31: 21:32 - // ty::Const - // + ty: usize - // + val: Value(Scalar(0x0000000000000000)) - // mir::Constant - // + span: $DIR/early_otherwise_branch_noopt.rs:21:31: 21:32 - // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } - StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:31: 21:32 - StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:31: 21:32 - goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:5: 23:6 - } - - bb4: { - StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:24:1: 24:2 - return; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:24:2: 24:2 - } - } - From 118aae2af1a8dfa9500b26f2542825291c9ae1f8 Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Sun, 20 Sep 2020 01:09:18 +0200 Subject: [PATCH 0720/1052] insert storageDead for not equal temp --- .../src/transform/early_otherwise_branch.rs | 38 +++++++++++++------ ...wise_branch.opt1.EarlyOtherwiseBranch.diff | 2 + ...wise_branch.opt2.EarlyOtherwiseBranch.diff | 2 + ...ement_tuple.opt1.EarlyOtherwiseBranch.diff | 4 ++ ...ch_68867.try_sum.EarlyOtherwiseBranch.diff | 2 + 5 files changed, 37 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs index d44bd1e3495a3..b0b9d5a889561 100644 --- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs +++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs @@ -46,27 +46,32 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { for opt_to_apply in opts_to_apply { trace!("SUCCESS: found optimization possibility to apply: {:?}", &opt_to_apply); - // create the patch using MirPatch - let mut patch = MirPatch::new(body); - // create temp to store second discriminant in - let discr_type = opt_to_apply.infos[0].second_switch_info.discr_ty; - let discr_span = opt_to_apply.infos[0].second_switch_info.discr_source_info.span; - let temp = patch.new_temp(discr_type, discr_span); let statements_before = body.basic_blocks()[opt_to_apply.basic_block_first_switch].statements.len(); let end_of_block_location = Location { block: opt_to_apply.basic_block_first_switch, statement_index: statements_before, }; - patch.add_statement(end_of_block_location, StatementKind::StorageLive(temp)); + + let mut patch = MirPatch::new(body); + + // create temp to store second discriminant in + let discr_type = opt_to_apply.infos[0].second_switch_info.discr_ty; + let discr_span = opt_to_apply.infos[0].second_switch_info.discr_source_info.span; + let second_discriminant_temp = patch.new_temp(discr_type, discr_span); + + patch.add_statement( + end_of_block_location, + StatementKind::StorageLive(second_discriminant_temp), + ); // create assignment of discriminant let place_of_adt_to_get_discriminant_of = opt_to_apply.infos[0].second_switch_info.place_of_adt_discr_read; patch.add_assign( end_of_block_location, - Place::from(temp), + Place::from(second_discriminant_temp), Rvalue::Discriminant(place_of_adt_to_get_discriminant_of), ); @@ -81,7 +86,7 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { opt_to_apply.infos[0].first_switch_info.discr_used_in_switch; let not_equal_rvalue = Rvalue::BinaryOp( not_equal, - Operand::Copy(Place::from(temp)), + Operand::Copy(Place::from(second_discriminant_temp)), Operand::Copy(Place::from(first_descriminant_place)), ); patch.add_statement( @@ -126,8 +131,19 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { ), ); - // generate StorageDead for the temp not in use anymore. We use the not_equal_temp in the switch, so we can't mark that dead - patch.add_statement(end_of_block_location, StatementKind::StorageDead(temp)); + // generate StorageDead for the second_discriminant_temp not in use anymore + patch.add_statement( + end_of_block_location, + StatementKind::StorageDead(second_discriminant_temp), + ); + + // Generate a StorageDead for not_equal_temp in each of the targets, since we moved it into the switch + for bb in [false_case, true_case].iter() { + patch.add_statement( + Location { block: *bb, statement_index: 0 }, + StatementKind::StorageDead(not_equal_temp), + ); + } patch.apply(body); } diff --git a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff index 9f9c28723f07b..ce0f0cf0a30ef 100644 --- a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff @@ -40,6 +40,7 @@ } bb1: { ++ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:6:14: 6:15 _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch.rs:6:14: 6:15 goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 7:6 } @@ -70,6 +71,7 @@ + } + + bb6: { ++ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 + switchInt(_7) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 } } diff --git a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff index 569dc6c5db61e..e9361f895bf22 100644 --- a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff @@ -46,6 +46,7 @@ } bb2: { ++ StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch.rs:15:14: 15:15 _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch.rs:15:14: 15:15 goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 16:6 } @@ -81,6 +82,7 @@ + } + + bb8: { ++ StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 + switchInt(_8) -> [0_isize: bb5, 1_isize: bb4, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 } } diff --git a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff index 9d45aa69f6336..80bbc30124d9f 100644 --- a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff @@ -51,6 +51,8 @@ } bb1: { ++ StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:14: 7:15 ++ StorageDead(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:14: 7:15 _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:14: 7:15 goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 8:6 } @@ -95,10 +97,12 @@ + } + + bb7: { ++ StorageDead(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 + switchInt(_10) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 + } + + bb8: { ++ StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 + switchInt(_9) -> [1_isize: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 } } diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff index f08920ef06de3..9abbe767cae2b 100644 --- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff @@ -82,6 +82,7 @@ } bb2: { ++ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:25: 24:27 StorageLive(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:25: 24:27 ((_0 as Err).0: ()) = const (); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:28 discriminant(_0) = 1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:28 @@ -207,6 +208,7 @@ + } + + bb13: { ++ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:21: 20:30 + switchInt(_11) -> [0_isize: bb6, 1_isize: bb7, 2_isize: bb8, 3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:21: 20:30 } } From 27068cbfdc15445cefc6a650355ff5c6bfe992c3 Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Sun, 20 Sep 2020 01:18:05 +0200 Subject: [PATCH 0721/1052] add cleanup of cfg --- .../src/transform/early_otherwise_branch.rs | 10 +++ ...wise_branch.opt1.EarlyOtherwiseBranch.diff | 29 +++---- ...wise_branch.opt2.EarlyOtherwiseBranch.diff | 48 ++++++----- ...ement_tuple.opt1.EarlyOtherwiseBranch.diff | 44 ++++------ ...ch_68867.try_sum.EarlyOtherwiseBranch.diff | 86 ++++++++++--------- 5 files changed, 113 insertions(+), 104 deletions(-) diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs index b0b9d5a889561..bb77dd38f22fb 100644 --- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs +++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs @@ -6,6 +6,8 @@ use rustc_middle::mir::*; use rustc_middle::ty::{Ty, TyCtxt}; use std::{borrow::Cow, fmt::Debug}; +use super::simplify::simplify_cfg; + /// This pass optimizes something like /// ```text /// let x: Option<()>; @@ -44,6 +46,8 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { }) .collect(); + let should_cleanup = !opts_to_apply.is_empty(); + for opt_to_apply in opts_to_apply { trace!("SUCCESS: found optimization possibility to apply: {:?}", &opt_to_apply); @@ -147,6 +151,12 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { patch.apply(body); } + + // Since this optimization adds new basic blocks and invalidates others, + // clean up the cfg to make it nicer for other passes + if should_cleanup { + simplify_cfg(body); + } } } diff --git a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff index ce0f0cf0a30ef..386726bfddc74 100644 --- a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff @@ -36,21 +36,22 @@ + StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 + _11 = Ne(_10, _7); // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 + StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 -+ switchInt(move _11) -> [false: bb6, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 ++ switchInt(move _11) -> [false: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 } bb1: { + StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:6:14: 6:15 _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch.rs:6:14: 6:15 - goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 7:6 +- goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 7:6 ++ goto -> bb3; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 7:6 } bb2: { - _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 - switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 - } - - bb3: { +- _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 +- switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 +- } +- +- bb3: { StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch.rs:5:15: 5:16 _8 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:5:15: 5:16 StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:5:24: 5:25 @@ -58,21 +59,19 @@ _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch.rs:5:31: 5:32 StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:5:31: 5:32 StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch.rs:5:31: 5:32 - goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 7:6 +- goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 7:6 ++ goto -> bb3; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 7:6 } - bb4: { +- bb4: { ++ bb3: { StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:8:1: 8:2 return; // scope 0 at $DIR/early_otherwise_branch.rs:8:2: 8:2 + } + -+ bb5 (cleanup): { -+ resume; // scope 0 at $DIR/early_otherwise_branch.rs:3:1: 8:2 -+ } -+ -+ bb6: { ++ bb4: { + StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 -+ switchInt(_7) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 ++ switchInt(_7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 } } diff --git a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff index e9361f895bf22..bc5934dec84e4 100644 --- a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff @@ -37,26 +37,28 @@ + StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 + _12 = Ne(_11, _8); // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 + StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 -+ switchInt(move _12) -> [false: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 ++ switchInt(move _12) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 } bb1: { - _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 - switchInt(move _6) -> [0_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 - } - - bb2: { +- _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 +- switchInt(move _6) -> [0_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 +- } +- +- bb2: { + StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch.rs:15:14: 15:15 _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch.rs:15:14: 15:15 - goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 16:6 - } - - bb3: { - _7 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:13:19: 13:26 - switchInt(move _7) -> [1_isize: bb4, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:13:19: 13:26 +- goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 16:6 ++ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 16:6 } - bb4: { +- bb3: { +- _7 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:13:19: 13:26 +- switchInt(move _7) -> [1_isize: bb4, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:13:19: 13:26 +- } +- +- bb4: { ++ bb2: { StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:13:15: 13:16 _9 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:13:15: 13:16 StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:13:24: 13:25 @@ -64,26 +66,26 @@ _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch.rs:13:31: 13:32 StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:13:31: 13:32 StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:13:31: 13:32 - goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 16:6 +- goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 16:6 ++ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 16:6 } - bb5: { +- bb5: { ++ bb3: { _0 = const 0_u32; // scope 0 at $DIR/early_otherwise_branch.rs:14:25: 14:26 - goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 16:6 +- goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 16:6 ++ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 16:6 } - bb6: { +- bb6: { ++ bb4: { StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:17:1: 17:2 return; // scope 0 at $DIR/early_otherwise_branch.rs:17:2: 17:2 + } + -+ bb7 (cleanup): { -+ resume; // scope 0 at $DIR/early_otherwise_branch.rs:11:1: 17:2 -+ } -+ -+ bb8: { ++ bb5: { + StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 -+ switchInt(_8) -> [0_isize: bb5, 1_isize: bb4, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 ++ switchInt(_8) -> [0_isize: bb3, 1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 } } diff --git a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff index 80bbc30124d9f..b0357f1aecd61 100644 --- a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff @@ -47,33 +47,30 @@ + StorageLive(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 + _15 = Ne(_14, _10); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 + StorageDead(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 -+ switchInt(move _15) -> [false: bb7, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 ++ switchInt(move _15) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 } bb1: { + StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:14: 7:15 + StorageDead(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:14: 7:15 _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:14: 7:15 - goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 8:6 +- goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 8:6 ++ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 8:6 } bb2: { - _9 = discriminant((_4.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 +- _9 = discriminant((_4.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 - switchInt(move _9) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 -+ StorageLive(_16); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 -+ _16 = discriminant((_4.2: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 -+ StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 -+ _17 = Ne(_16, _9); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 -+ StorageDead(_16); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 -+ switchInt(move _17) -> [false: bb8, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 - } - - bb3: { +- } +- +- bb3: { _8 = discriminant((_4.2: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 - switchInt(move _8) -> [1_isize: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 +- switchInt(move _8) -> [1_isize: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 ++ switchInt(move _8) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 } - bb4: { +- bb4: { ++ bb3: { StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:15: 6:16 _11 = (((_4.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:15: 6:16 StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:24: 6:25 @@ -84,26 +81,19 @@ StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:40: 6:41 StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:40: 6:41 StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:40: 6:41 - goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 8:6 +- goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 8:6 ++ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 8:6 } - bb5: { +- bb5: { ++ bb4: { StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:9:1: 9:2 return; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:9:2: 9:2 + } + -+ bb6 (cleanup): { -+ resume; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:4:1: 9:2 -+ } -+ -+ bb7: { ++ bb5: { + StorageDead(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 -+ switchInt(_10) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 -+ } -+ -+ bb8: { -+ StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 -+ switchInt(_9) -> [1_isize: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 ++ switchInt(_10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 } } diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff index 9abbe767cae2b..57f9b1dd3ca98 100644 --- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff @@ -73,15 +73,15 @@ + StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:11: 20:18 + _35 = Ne(_34, _11); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:11: 20:18 + StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:11: 20:18 -+ switchInt(move _35) -> [false: bb13, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:11: 20:18 ++ switchInt(move _35) -> [false: bb8, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:11: 20:18 } bb1: { - _7 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:21: 20:30 - switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:21: 20:30 - } - - bb2: { +- _7 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:21: 20:30 +- switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:21: 20:30 +- } +- +- bb2: { + StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:25: 24:27 StorageLive(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:25: 24:27 ((_0 as Err).0: ()) = const (); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:28 @@ -89,25 +89,27 @@ StorageDead(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:27: 24:28 StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:6: 25:7 StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:1: 26:2 - goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:28 - } - - bb3: { - _8 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:21: 21:30 - switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:21: 21:30 - } - - bb4: { - _9 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:34 - switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:34 - } - - bb5: { - _10 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:23: 23:34 - switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:23: 23:34 +- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:28 ++ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:28 } - bb6: { +- bb3: { +- _8 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:21: 21:30 +- switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:21: 21:30 +- } +- +- bb4: { +- _9 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:34 +- switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:34 +- } +- +- bb5: { +- _10 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:23: 23:34 +- switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:23: 23:34 +- } +- +- bb6: { ++ bb2: { StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:14: 20:17 _12 = (((*(_4.0: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:14: 20:17 StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:24: 20:29 @@ -125,10 +127,12 @@ StorageDead(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:20:49: 20:50 StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:49: 20:50 StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:49: 20:50 - goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 +- goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 ++ goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 } - bb7: { +- bb7: { ++ bb3: { StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:17 _17 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:17 StorageLive(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:24: 21:29 @@ -146,10 +150,12 @@ StorageDead(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:21:49: 21:50 StorageDead(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:49: 21:50 StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:49: 21:50 - goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 +- goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 ++ goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 } - bb8: { +- bb8: { ++ bb4: { StorageLive(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:16: 22:19 _22 = (((*(_4.0: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:16: 22:19 StorageLive(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:28: 22:33 @@ -167,10 +173,12 @@ StorageDead(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:22:55: 22:56 StorageDead(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:55: 22:56 StorageDead(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:55: 22:56 - goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 +- goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 ++ goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 } - bb9: { +- bb9: { ++ bb5: { StorageLive(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:16: 23:19 _27 = (((*(_4.0: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:16: 23:19 StorageLive(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:28: 23:33 @@ -188,28 +196,28 @@ StorageDead(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:23:55: 23:56 StorageDead(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:55: 23:56 StorageDead(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:55: 23:56 - goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 +- goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 ++ goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 } - bb10: { +- bb10: { ++ bb6: { return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:2: 26:2 } - bb11: { +- bb11: { ++ bb7: { ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:5: 25:7 discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:5: 25:7 StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:6: 25:7 StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:1: 26:2 - goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:2: 26:2 -+ } -+ -+ bb12 (cleanup): { -+ resume; // scope 0 at $DIR/early_otherwise_branch_68867.rs:15:1: 26:2 +- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:2: 26:2 ++ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:2: 26:2 + } + -+ bb13: { ++ bb8: { + StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:21: 20:30 -+ switchInt(_11) -> [0_isize: bb6, 1_isize: bb7, 2_isize: bb8, 3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:21: 20:30 ++ switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:21: 20:30 } } From e25738f529b431d5b824eb8b7510fbe86cf0c9fa Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Sun, 20 Sep 2020 01:40:58 +0200 Subject: [PATCH 0722/1052] enable on mir-opt-level=1 to test perf --- compiler/rustc_mir/src/transform/early_otherwise_branch.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs index bb77dd38f22fb..67e679a8b08d0 100644 --- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs +++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs @@ -29,7 +29,7 @@ pub struct EarlyOtherwiseBranch; impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.opts.debugging_opts.mir_opt_level < 3 { + if tcx.sess.opts.debugging_opts.mir_opt_level < 1 { return; } trace!("running EarlyOtherwiseBranch on {:?}", source); From 5de2c95e6e8352d2e45111025a57bd1e67a43a79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Thu, 3 Sep 2020 20:14:15 +0200 Subject: [PATCH 0723/1052] Remove MMX from Rust --- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 - compiler/rustc_codegen_llvm/src/llvm_util.rs | 1 - compiler/rustc_codegen_llvm/src/type_.rs | 4 --- compiler/rustc_codegen_llvm/src/type_of.rs | 19 ++----------- compiler/rustc_feature/src/active.rs | 1 - compiler/rustc_span/src/symbol.rs | 1 - compiler/rustc_typeck/src/collect.rs | 1 - library/core/src/lib.rs | 1 - src/test/codegen/x86_mmx.rs | 27 ------------------- .../using-target-feature-unstable.rs | 4 +-- src/test/ui/target-feature/gate.rs | 4 +-- src/test/ui/target-feature/gate.stderr | 2 +- 12 files changed, 6 insertions(+), 60 deletions(-) delete mode 100644 src/test/codegen/x86_mmx.rs diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 4942c997682d8..45c5f56f44793 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -948,7 +948,6 @@ extern "C" { // Operations on other types pub fn LLVMVoidTypeInContext(C: &Context) -> &Type; - pub fn LLVMX86MMXTypeInContext(C: &Context) -> &Type; pub fn LLVMRustMetadataTypeInContext(C: &Context) -> &Type; // Operations on all values diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index f0b50459837e9..900f2df383a06 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -203,7 +203,6 @@ const X86_ALLOWED_FEATURES: &[(&str, Option)] = &[ ("fma", None), ("fxsr", None), ("lzcnt", None), - ("mmx", Some(sym::mmx_target_feature)), ("movbe", Some(sym::movbe_target_feature)), ("pclmulqdq", None), ("popcnt", None), diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 3b53b4fe77be7..a43724fd49599 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -62,10 +62,6 @@ impl CodegenCx<'ll, 'tcx> { unsafe { llvm::LLVMIntTypeInContext(self.llcx, num_bits as c_uint) } } - crate fn type_x86_mmx(&self) -> &'ll Type { - unsafe { llvm::LLVMX86MMXTypeInContext(self.llcx) } - } - crate fn type_vector(&self, ty: &'ll Type, len: u64) -> &'ll Type { unsafe { llvm::LLVMVectorType(ty, len as c_uint) } } diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 12901de6048ac..e0754d21df1f0 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -21,23 +21,8 @@ fn uncached_llvm_type<'a, 'tcx>( match layout.abi { Abi::Scalar(_) => bug!("handled elsewhere"), Abi::Vector { ref element, count } => { - // LLVM has a separate type for 64-bit SIMD vectors on X86 called - // `x86_mmx` which is needed for some SIMD operations. As a bit of a - // hack (all SIMD definitions are super unstable anyway) we - // recognize any one-element SIMD vector as "this should be an - // x86_mmx" type. In general there shouldn't be a need for other - // one-element SIMD vectors, so it's assumed this won't clash with - // much else. - let use_x86_mmx = count == 1 - && layout.size.bits() == 64 - && (cx.sess().target.target.arch == "x86" - || cx.sess().target.target.arch == "x86_64"); - if use_x86_mmx { - return cx.type_x86_mmx(); - } else { - let element = layout.scalar_llvm_type_at(cx, element, Size::ZERO); - return cx.type_vector(element, count); - } + let element = layout.scalar_llvm_type_at(cx, element, Size::ZERO); + return cx.type_vector(element, count); } Abi::ScalarPair(..) => { return cx.type_struct( diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index d4664292a0cbd..6452bda293ef5 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -229,7 +229,6 @@ declare_features! ( (active, powerpc_target_feature, "1.27.0", Some(44839), None), (active, mips_target_feature, "1.27.0", Some(44839), None), (active, avx512_target_feature, "1.27.0", Some(44839), None), - (active, mmx_target_feature, "1.27.0", Some(44839), None), (active, sse4a_target_feature, "1.27.0", Some(44839), None), (active, tbm_target_feature, "1.27.0", Some(44839), None), (active, wasm_target_feature, "1.30.0", Some(44839), None), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 407663e57577a..ce6cc4ab035f3 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -677,7 +677,6 @@ symbols! { minnumf32, minnumf64, mips_target_feature, - mmx_target_feature, module, module_path, more_struct_aliases, diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 9b8427a46955c..ad2389a434d89 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2361,7 +2361,6 @@ fn from_target_feature( Some(sym::mips_target_feature) => rust_features.mips_target_feature, Some(sym::riscv_target_feature) => rust_features.riscv_target_feature, Some(sym::avx512_target_feature) => rust_features.avx512_target_feature, - Some(sym::mmx_target_feature) => rust_features.mmx_target_feature, Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature, Some(sym::tbm_target_feature) => rust_features.tbm_target_feature, Some(sym::wasm_target_feature) => rust_features.wasm_target_feature, diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 3bddc3772e600..dd247e49234e7 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -132,7 +132,6 @@ #![feature(unwind_attributes)] #![feature(variant_count)] #![cfg_attr(bootstrap, feature(doc_alias))] -#![feature(mmx_target_feature)] #![feature(tbm_target_feature)] #![feature(sse4a_target_feature)] #![feature(arm_target_feature)] diff --git a/src/test/codegen/x86_mmx.rs b/src/test/codegen/x86_mmx.rs deleted file mode 100644 index 9a58ef1c37a80..0000000000000 --- a/src/test/codegen/x86_mmx.rs +++ /dev/null @@ -1,27 +0,0 @@ -// ignore-arm -// ignore-aarch64 -// ignore-emscripten -// ignore-mips -// ignore-mips64 -// ignore-powerpc -// ignore-powerpc64 -// ignore-powerpc64le -// ignore-riscv64 -// ignore-sparc -// ignore-sparc64 -// ignore-s390x -// compile-flags: -O - -#![feature(repr_simd)] -#![crate_type="lib"] - -#[repr(simd)] -#[derive(Clone, Copy)] -pub struct i8x8(u64); - -#[no_mangle] -pub fn a(a: &mut i8x8, b: i8x8) -> i8x8 { - // CHECK-LABEL: define void @a(x86_mmx*{{.*}}, x86_mmx*{{.*}}, x86_mmx*{{.*}}) - *a = b; - return b -} diff --git a/src/test/ui/auxiliary/using-target-feature-unstable.rs b/src/test/ui/auxiliary/using-target-feature-unstable.rs index 78645c284f116..2682028936c19 100644 --- a/src/test/ui/auxiliary/using-target-feature-unstable.rs +++ b/src/test/ui/auxiliary/using-target-feature-unstable.rs @@ -1,5 +1,5 @@ -#![feature(mmx_target_feature)] +#![feature(avx512_target_feature)] #[inline] -#[target_feature(enable = "mmx")] +#[target_feature(enable = "avx512ifma")] pub unsafe fn foo() {} diff --git a/src/test/ui/target-feature/gate.rs b/src/test/ui/target-feature/gate.rs index 10fbba36d3f9d..e4b78c76e1699 100644 --- a/src/test/ui/target-feature/gate.rs +++ b/src/test/ui/target-feature/gate.rs @@ -19,7 +19,6 @@ // gate-test-aarch64_target_feature // gate-test-hexagon_target_feature // gate-test-mips_target_feature -// gate-test-mmx_target_feature // gate-test-wasm_target_feature // gate-test-adx_target_feature // gate-test-cmpxchg16b_target_feature @@ -30,7 +29,6 @@ #[target_feature(enable = "avx512bw")] //~^ ERROR: currently unstable -unsafe fn foo() { -} +unsafe fn foo() {} fn main() {} diff --git a/src/test/ui/target-feature/gate.stderr b/src/test/ui/target-feature/gate.stderr index 2d6abcc0a0150..2384a00aa47aa 100644 --- a/src/test/ui/target-feature/gate.stderr +++ b/src/test/ui/target-feature/gate.stderr @@ -1,5 +1,5 @@ error[E0658]: the target feature `avx512bw` is currently unstable - --> $DIR/gate.rs:31:18 + --> $DIR/gate.rs:30:18 | LL | #[target_feature(enable = "avx512bw")] | ^^^^^^^^^^^^^^^^^^^ From 3e08354fb0dc7a5f7733da9b308d483b9c1d2514 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 20 Sep 2020 12:46:06 +0000 Subject: [PATCH 0724/1052] Correct file path after some restructures in compiler --- compiler/rustc_codegen_ssa/src/traits/intrinsic.rs | 6 +++--- compiler/rustc_error_codes/src/error_codes/E0092.md | 4 ++-- compiler/rustc_error_codes/src/error_codes/E0093.md | 4 ++-- compiler/rustc_mir/src/interpret/terminator.rs | 4 ++-- compiler/rustc_typeck/src/check/intrinsic.rs | 4 ++-- library/core/src/intrinsics.rs | 6 +++--- library/panic_unwind/src/seh.rs | 2 +- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs index 9d48e233de655..ccd294d92b2f4 100644 --- a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs @@ -5,9 +5,9 @@ use rustc_span::Span; use rustc_target::abi::call::FnAbi; pub trait IntrinsicCallMethods<'tcx>: BackendTypes { - /// Remember to add all intrinsics here, in librustc_typeck/check/mod.rs, - /// and in libcore/intrinsics.rs; if you need access to any llvm intrinsics, - /// add them to librustc_codegen_llvm/context.rs + /// Remember to add all intrinsics here, in `compiler/rustc_typeck/src/check/mod.rs`, + /// and in `library/core/src/intrinsics.rs`; if you need access to any LLVM intrinsics, + /// add them to `compiler/rustc_codegen_llvm/src/context.rs`. fn codegen_intrinsic_call( &mut self, instance: ty::Instance<'tcx>, diff --git a/compiler/rustc_error_codes/src/error_codes/E0092.md b/compiler/rustc_error_codes/src/error_codes/E0092.md index e289534bf7abd..496174b28efac 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0092.md +++ b/compiler/rustc_error_codes/src/error_codes/E0092.md @@ -12,8 +12,8 @@ extern "rust-intrinsic" { ``` Please check you didn't make a mistake in the function's name. All intrinsic -functions are defined in `librustc_codegen_llvm/intrinsic.rs` and in -`libcore/intrinsics.rs` in the Rust source code. Example: +functions are defined in `compiler/rustc_codegen_llvm/src/intrinsic.rs` and in +`library/core/src/intrinsics.rs` in the Rust source code. Example: ``` #![feature(intrinsics)] diff --git a/compiler/rustc_error_codes/src/error_codes/E0093.md b/compiler/rustc_error_codes/src/error_codes/E0093.md index 8e7de1a9d37b3..6d58e50ec8813 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0093.md +++ b/compiler/rustc_error_codes/src/error_codes/E0093.md @@ -17,8 +17,8 @@ fn main() { ``` Please check you didn't make a mistake in the function's name. All intrinsic -functions are defined in `librustc_codegen_llvm/intrinsic.rs` and in -`libcore/intrinsics.rs` in the Rust source code. Example: +functions are defined in `compiler/rustc_codegen_llvm/src/intrinsic.rs` and in +`library/core/src/intrinsics.rs` in the Rust source code. Example: ``` #![feature(intrinsics)] diff --git a/compiler/rustc_mir/src/interpret/terminator.rs b/compiler/rustc_mir/src/interpret/terminator.rs index d3c0b497a1675..00271f227d871 100644 --- a/compiler/rustc_mir/src/interpret/terminator.rs +++ b/compiler/rustc_mir/src/interpret/terminator.rs @@ -385,9 +385,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::InstanceDef::Virtual(_, idx) => { let mut args = args.to_vec(); // We have to implement all "object safe receivers". Currently we - // support built-in pointers (&, &mut, Box) as well as unsized-self. We do + // support built-in pointers `(&, &mut, Box)` as well as unsized-self. We do // not yet support custom self types. - // Also see librustc_codegen_llvm/abi.rs and librustc_codegen_llvm/mir/block.rs. + // Also see `compiler/rustc_codegen_llvm/src/abi.rs` and `compiler/rustc_codegen_ssa/src/mir/block.rs`. let receiver_place = match args[0].layout.ty.builtin_deref(true) { Some(_) => { // Built-in pointer. diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index b8230f524446a..2ee867c2dd648 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -106,8 +106,8 @@ pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety { } } -/// Remember to add all intrinsics here, in librustc_codegen_llvm/intrinsic.rs, -/// and in libcore/intrinsics.rs +/// Remember to add all intrinsics here, in `compiler/rustc_codegen_llvm/src/intrinsic.rs`, +/// and in `library/core/src/intrinsics.rs`. pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n))); let def_id = tcx.hir().local_def_id(it.hir_id).to_def_id(); diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index dd9af2d07e770..de4d2efe29461 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1,7 +1,7 @@ //! Compiler intrinsics. //! -//! The corresponding definitions are in `librustc_codegen_llvm/intrinsic.rs`. -//! The corresponding const implementations are in `librustc_mir/interpret/intrinsics.rs` +//! The corresponding definitions are in `compiler/rustc_codegen_llvm/src/intrinsic.rs`. +//! The corresponding const implementations are in `compiler/rustc_mir/src/interpret/intrinsics.rs` //! //! # Const intrinsics //! @@ -10,7 +10,7 @@ //! //! In order to make an intrinsic usable at compile-time, one needs to copy the implementation //! from https://github.com/rust-lang/miri/blob/master/src/shims/intrinsics.rs to -//! `librustc_mir/interpret/intrinsics.rs` and add a +//! `compiler/rustc_mir/src/interpret/intrinsics.rs` and add a //! `#[rustc_const_unstable(feature = "foo", issue = "01234")]` to the intrinsic. //! //! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute, diff --git a/library/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs index eca169373f39f..5597bbb93d236 100644 --- a/library/panic_unwind/src/seh.rs +++ b/library/panic_unwind/src/seh.rs @@ -175,7 +175,7 @@ pub struct _TypeDescriptor { // to be able to catch Rust panics by simply declaring a `struct rust_panic`. // // When modifying, make sure that the type name string exactly matches -// the one used in src/librustc_codegen_llvm/intrinsic.rs. +// the one used in `compiler/rustc_codegen_llvm/src/intrinsic.rs`. const TYPE_NAME: [u8; 11] = *b"rust_panic\0"; static mut THROW_INFO: _ThrowInfo = _ThrowInfo { From 3f0f40904c18bce9915b5fe2a1d017f3906c0d26 Mon Sep 17 00:00:00 2001 From: Erik Hofmayer Date: Sun, 20 Sep 2020 15:50:44 +0200 Subject: [PATCH 0725/1052] Documented From impls in std/sync/mpsc/mod.rs --- library/std/src/sync/mpsc/mod.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs index 073f969bbe25b..d23a8161a229c 100644 --- a/library/std/src/sync/mpsc/mod.rs +++ b/library/std/src/sync/mpsc/mod.rs @@ -1531,6 +1531,9 @@ impl error::Error for TrySendError { #[stable(feature = "mpsc_error_conversions", since = "1.24.0")] impl From> for TrySendError { + /// Converts a `SendError` into a `TrySendError`. + /// This conversion always returns a `TrySendError::Disconnected` containing the data in the `SendError`. + /// No data is allocated on the heap. fn from(err: SendError) -> TrySendError { match err { SendError(t) => TrySendError::Disconnected(t), @@ -1576,6 +1579,9 @@ impl error::Error for TryRecvError { #[stable(feature = "mpsc_error_conversions", since = "1.24.0")] impl From for TryRecvError { + /// Converts a `RecvError` into a `TryRecvError`. + /// This conversion always returns `TryRecvError::Disconnected`. + /// No data is allocated on the heap. fn from(err: RecvError) -> TryRecvError { match err { RecvError => TryRecvError::Disconnected, @@ -1606,6 +1612,9 @@ impl error::Error for RecvTimeoutError { #[stable(feature = "mpsc_error_conversions", since = "1.24.0")] impl From for RecvTimeoutError { + /// Converts a `RecvError` into a `RecvTimeoutError`. + /// This conversion always returns `RecvTimeoutError::Disconnected`. + /// No data is allocated on the heap. fn from(err: RecvError) -> RecvTimeoutError { match err { RecvError => RecvTimeoutError::Disconnected, From 4387480dea6e2611483d431857f0f85b65e3c00c Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 20 Sep 2020 13:30:32 +0000 Subject: [PATCH 0726/1052] Add unstably const support for assume intrinsic --- compiler/rustc_mir/src/interpret/intrinsics.rs | 6 ++++++ library/core/src/intrinsics.rs | 1 + src/test/ui/consts/const-eval/const_assume.rs | 17 +++++++++++++++++ 3 files changed, 24 insertions(+) create mode 100644 src/test/ui/consts/const-eval/const_assume.rs diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index 0664f25e409dc..d3b6d706337ed 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -435,6 +435,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // These just return their argument self.copy_op(args[0], dest)?; } + sym::assume => { + let cond = self.read_scalar(args[0])?.check_init()?.to_bool()?; + if !cond { + throw_ub_format!("`assume` intrinsic called with `false`"); + } + } _ => return Ok(false), } diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index de4d2efe29461..c68200c90d8d0 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -733,6 +733,7 @@ extern "rust-intrinsic" { /// own, or if it does not enable any significant optimizations. /// /// This intrinsic does not have a stable counterpart. + #[rustc_const_unstable(feature = "const_assume", issue = "76972")] pub fn assume(b: bool); /// Hints to the compiler that branch condition is likely to be true. diff --git a/src/test/ui/consts/const-eval/const_assume.rs b/src/test/ui/consts/const-eval/const_assume.rs new file mode 100644 index 0000000000000..f72f151824bed --- /dev/null +++ b/src/test/ui/consts/const-eval/const_assume.rs @@ -0,0 +1,17 @@ +// check-pass + +// Check that `const_assume` feature allow `assume` intrinsic +// to be used in const contexts. + +#![feature(core_intrinsics, const_assume)] + +extern crate core; + +use core::intrinsics::assume; + +pub const unsafe fn foo(x: usize, y: usize) -> usize { + assume(y != 0); + x / y +} + +fn main() {} From 0363694c7ff72d0a4b1c52ebf2320930c3b60da8 Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Sun, 20 Sep 2020 14:45:08 +0200 Subject: [PATCH 0727/1052] emit diff after SimplifyBranches-after-copy-prop --- .../mir-opt/early_otherwise_branch_68867.rs | 10 +- ...implifyBranches-after-copy-prop.after.diff | 310 +++++++++++++++++ ...ch_68867.try_sum.EarlyOtherwiseBranch.diff | 328 +++++++++--------- 3 files changed, 480 insertions(+), 168 deletions(-) create mode 100644 src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-after-copy-prop.after.diff diff --git a/src/test/mir-opt/early_otherwise_branch_68867.rs b/src/test/mir-opt/early_otherwise_branch_68867.rs index abe666f9ca4f9..5922e73e5d205 100644 --- a/src/test/mir-opt/early_otherwise_branch_68867.rs +++ b/src/test/mir-opt/early_otherwise_branch_68867.rs @@ -1,3 +1,4 @@ +// ignore-tidy-linelength // compile-flags: -Z mir-opt-level=3 // example from #68867 @@ -11,10 +12,12 @@ pub enum ViewportPercentageLength { } // EMIT_MIR early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff +// EMIT_MIR early_otherwise_branch_68867.try_sum EarlyOtherwiseBranch.before SimplifyBranches-after-copy-prop.after #[no_mangle] -pub extern "C" fn try_sum(x: &ViewportPercentageLength, - other: &ViewportPercentageLength) - -> Result { +pub extern "C" fn try_sum( + x: &ViewportPercentageLength, + other: &ViewportPercentageLength, +) -> Result { use self::ViewportPercentageLength::*; Ok(match (x, other) { (&Vw(one), &Vw(other)) => Vw(one + other), @@ -25,7 +28,6 @@ pub extern "C" fn try_sum(x: &ViewportPercentageLength, }) } - fn main() { try_sum(&ViewportPercentageLength::Vw(1.0), &ViewportPercentageLength::Vw(2.0)); } diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-after-copy-prop.after.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-after-copy-prop.after.diff new file mode 100644 index 0000000000000..fbc46c9d196c1 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-after-copy-prop.after.diff @@ -0,0 +1,310 @@ +- // MIR for `try_sum` before EarlyOtherwiseBranch ++ // MIR for `try_sum` after SimplifyBranches-after-copy-prop + + fn try_sum(_1: &ViewportPercentageLength, _2: &ViewportPercentageLength) -> std::result::Result { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:18:5: 18:6 + debug other => _2; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:19:5: 19:10 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/early_otherwise_branch_68867.rs:20:6: 20:42 + let mut _3: ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + let mut _4: (&ViewportPercentageLength, &ViewportPercentageLength); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 + let mut _5: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 + let mut _6: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:30 + let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34 + let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:23: 26:34 + let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 + let _12: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + let _13: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + let mut _14: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 + let mut _15: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 + let mut _16: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 + let _17: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 + let _18: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 + let mut _19: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49 + let mut _20: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41 + let mut _21: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49 + let _22: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + let _23: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + let mut _24: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 + let mut _25: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 + let mut _26: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 + let _27: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 + let _28: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 + let mut _29: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55 + let mut _30: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47 + let mut _31: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55 + let mut _32: !; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:27:14: 27:28 + let mut _33: (); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:27:25: 27:27 ++ let mut _34: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 ++ let mut _35: bool; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 + scope 1 { +- debug one => _12; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 +- debug other => _13; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 ++ debug one => _15; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 ++ debug other => _16; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + } + scope 2 { +- debug one => _17; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 +- debug other => _18; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 ++ debug one => _20; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 ++ debug other => _21; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 + } + scope 3 { +- debug one => _22; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 +- debug other => _23; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 ++ debug one => _25; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 ++ debug other => _26; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + } + scope 4 { +- debug one => _27; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 +- debug other => _28; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 ++ debug one => _30; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 ++ debug other => _31; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 + } + + bb0: { +- StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 +- StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 +- StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 +- _5 = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 +- StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 +- _6 = _2; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 +- (_4.0: &ViewportPercentageLength) = move _5; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 +- (_4.1: &ViewportPercentageLength) = move _6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 +- StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24 +- StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 ++ (_4.0: &ViewportPercentageLength) = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 ++ (_4.1: &ViewportPercentageLength) = move _2; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24 + _11 = discriminant((*(_4.0: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 +- switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ _34 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ _35 = Ne(_34, _11); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ switchInt(move _35) -> [false: bb8, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 + } + + bb1: { +- _7 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 +- switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 +- } +- +- bb2: { ++ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:25: 27:27 + StorageLive(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:25: 27:27 + ((_0 as Err).0: ()) = const (); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:21: 27:28 + discriminant(_0) = 1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:21: 27:28 + StorageDead(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:27: 27:28 +- StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7 +- StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2 +- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:14: 27:28 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2 ++ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:14: 27:28 + } + ++ bb2: { ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 ++ _15 = (((*(_4.0: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 ++ _16 = (((*(_4.1: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 ++ ((((_0 as Ok).0: ViewportPercentageLength) as Vw).0: f32) = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 ++ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 ++ goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 ++ } ++ + bb3: { +- _8 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:30 +- switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:30 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 ++ _20 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 ++ _21 = (((*(_4.1: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49 ++ ((((_0 as Ok).0: ViewportPercentageLength) as Vh).0: f32) = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:48: 24:49 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:48: 24:49 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:35: 24:50 ++ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:35: 24:50 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 ++ goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + } + + bb4: { +- _9 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34 +- switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 ++ _25 = (((*(_4.0: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 ++ _26 = (((*(_4.1: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 ++ ((((_0 as Ok).0: ViewportPercentageLength) as Vmin).0: f32) = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 ++ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 ++ goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + } + + bb5: { +- _10 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:23: 26:34 +- switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:23: 26:34 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 ++ _30 = (((*(_4.0: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 ++ _31 = (((*(_4.1: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55 ++ ((((_0 as Ok).0: ViewportPercentageLength) as Vmax).0: f32) = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:54: 26:55 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:54: 26:55 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:39: 26:56 ++ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:39: 26:56 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 ++ goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + } + + bb6: { +- StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 +- _12 = (((*(_4.0: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 +- StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 +- _13 = (((*(_4.1: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 +- StorageLive(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 +- StorageLive(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 +- _15 = _12; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 +- StorageLive(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 +- _16 = _13; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 +- _14 = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 +- StorageDead(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49 +- StorageDead(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49 +- ((_3 as Vw).0: f32) = move _14; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 +- discriminant(_3) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 +- StorageDead(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 +- StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 +- StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 +- goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 ++ return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:2: 29:2 + } + + bb7: { +- StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 +- _17 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 +- StorageLive(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 +- _18 = (((*(_4.1: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 +- StorageLive(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49 +- StorageLive(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41 +- _20 = _17; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41 +- StorageLive(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49 +- _21 = _18; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49 +- _19 = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49 +- StorageDead(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:48: 24:49 +- StorageDead(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:48: 24:49 +- ((_3 as Vh).0: f32) = move _19; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:35: 24:50 +- discriminant(_3) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:35: 24:50 +- StorageDead(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 +- StorageDead(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 +- StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 +- goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7 ++ discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2 ++ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:2: 29:2 + } + + bb8: { +- StorageLive(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 +- _22 = (((*(_4.0: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 +- StorageLive(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 +- _23 = (((*(_4.1: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 +- StorageLive(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 +- StorageLive(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 +- _25 = _22; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 +- StorageLive(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 +- _26 = _23; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 +- _24 = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 +- StorageDead(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55 +- StorageDead(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55 +- ((_3 as Vmin).0: f32) = move _24; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 +- discriminant(_3) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 +- StorageDead(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 +- StorageDead(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 +- StorageDead(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 +- goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 +- } +- +- bb9: { +- StorageLive(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 +- _27 = (((*(_4.0: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 +- StorageLive(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 +- _28 = (((*(_4.1: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 +- StorageLive(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55 +- StorageLive(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47 +- _30 = _27; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47 +- StorageLive(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55 +- _31 = _28; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55 +- _29 = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55 +- StorageDead(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:54: 26:55 +- StorageDead(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:54: 26:55 +- ((_3 as Vmax).0: f32) = move _29; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:39: 26:56 +- discriminant(_3) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:39: 26:56 +- StorageDead(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 +- StorageDead(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 +- StorageDead(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 +- goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 +- } +- +- bb10: { +- return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:2: 29:2 +- } +- +- bb11: { +- ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7 +- discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7 +- StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7 +- StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2 +- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:2: 29:2 ++ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 ++ switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff index 57f9b1dd3ca98..54e4b08262616 100644 --- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff @@ -2,222 +2,222 @@ + // MIR for `try_sum` after EarlyOtherwiseBranch fn try_sum(_1: &ViewportPercentageLength, _2: &ViewportPercentageLength) -> std::result::Result { - debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:15:27: 15:28 - debug other => _2; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:16:27: 16:32 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/early_otherwise_branch_68867.rs:17:28: 17:64 - let mut _3: ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 - let mut _4: (&ViewportPercentageLength, &ViewportPercentageLength); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:19:14: 19:24 - let mut _5: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:19:15: 19:16 - let mut _6: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:19:18: 19:23 - let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:20:21: 20:30 - let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:21: 21:30 - let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:34 - let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:23: 23:34 - let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:20:11: 20:18 - let _12: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:20:14: 20:17 - let _13: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:20:24: 20:29 - let mut _14: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:20:38: 20:49 - let mut _15: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:20:38: 20:41 - let mut _16: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:20:44: 20:49 - let _17: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:17 - let _18: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:24: 21:29 - let mut _19: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:38: 21:49 - let mut _20: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:38: 21:41 - let mut _21: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:44: 21:49 - let _22: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:16: 22:19 - let _23: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:28: 22:33 - let mut _24: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:55 - let mut _25: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:47 - let mut _26: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:50: 22:55 - let _27: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:16: 23:19 - let _28: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:28: 23:33 - let mut _29: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:55 - let mut _30: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:47 - let mut _31: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:50: 23:55 - let mut _32: !; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:28 - let mut _33: (); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:25: 24:27 -+ let mut _34: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:20:21: 20:30 -+ let mut _35: bool; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:20:21: 20:30 + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:18:5: 18:6 + debug other => _2; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:19:5: 19:10 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/early_otherwise_branch_68867.rs:20:6: 20:42 + let mut _3: ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + let mut _4: (&ViewportPercentageLength, &ViewportPercentageLength); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 + let mut _5: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 + let mut _6: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:30 + let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34 + let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:23: 26:34 + let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 + let _12: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + let _13: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + let mut _14: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 + let mut _15: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 + let mut _16: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 + let _17: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 + let _18: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 + let mut _19: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49 + let mut _20: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41 + let mut _21: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49 + let _22: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + let _23: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + let mut _24: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 + let mut _25: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 + let mut _26: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 + let _27: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 + let _28: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 + let mut _29: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55 + let mut _30: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47 + let mut _31: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55 + let mut _32: !; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:27:14: 27:28 + let mut _33: (); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:27:25: 27:27 ++ let mut _34: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 ++ let mut _35: bool; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 scope 1 { - debug one => _12; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:20:14: 20:17 - debug other => _13; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:20:24: 20:29 + debug one => _12; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + debug other => _13; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 } scope 2 { - debug one => _17; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:17 - debug other => _18; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:21:24: 21:29 + debug one => _17; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 + debug other => _18; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 } scope 3 { - debug one => _22; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:22:16: 22:19 - debug other => _23; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:22:28: 22:33 + debug one => _22; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + debug other => _23; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 } scope 4 { - debug one => _27; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:23:16: 23:19 - debug other => _28; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:23:28: 23:33 + debug one => _27; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 + debug other => _28; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 } bb0: { - StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 - StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:14: 19:24 - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:15: 19:16 - _5 = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:15: 19:16 - StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:18: 19:23 - _6 = _2; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:18: 19:23 - (_4.0: &ViewportPercentageLength) = move _5; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:14: 19:24 - (_4.1: &ViewportPercentageLength) = move _6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:14: 19:24 - StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:23: 19:24 - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:23: 19:24 - _11 = discriminant((*(_4.0: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:11: 20:18 -- switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:11: 20:18 -+ StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:11: 20:18 -+ _34 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:11: 20:18 -+ StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:11: 20:18 -+ _35 = Ne(_34, _11); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:11: 20:18 -+ StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:11: 20:18 -+ switchInt(move _35) -> [false: bb8, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:11: 20:18 + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 + _5 = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 + StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 + _6 = _2; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 + (_4.0: &ViewportPercentageLength) = move _5; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 + (_4.1: &ViewportPercentageLength) = move _6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 + StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24 + _11 = discriminant((*(_4.0: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 +- switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ _34 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ _35 = Ne(_34, _11); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ switchInt(move _35) -> [false: bb8, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 } bb1: { -- _7 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:21: 20:30 -- switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:21: 20:30 +- _7 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 +- switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 - } - - bb2: { -+ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:25: 24:27 - StorageLive(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:25: 24:27 - ((_0 as Err).0: ()) = const (); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:28 - discriminant(_0) = 1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:28 - StorageDead(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:27: 24:28 - StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:6: 25:7 - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:1: 26:2 -- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:28 -+ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:28 ++ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:25: 27:27 + StorageLive(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:25: 27:27 + ((_0 as Err).0: ()) = const (); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:21: 27:28 + discriminant(_0) = 1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:21: 27:28 + StorageDead(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:27: 27:28 + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2 +- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:14: 27:28 ++ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:14: 27:28 } - bb3: { -- _8 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:21: 21:30 -- switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:21: 21:30 +- _8 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:30 +- switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:30 - } - - bb4: { -- _9 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:34 -- switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:34 +- _9 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34 +- switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34 - } - - bb5: { -- _10 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:23: 23:34 -- switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:23: 23:34 +- _10 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:23: 26:34 +- switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:23: 26:34 - } - - bb6: { + bb2: { - StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:14: 20:17 - _12 = (((*(_4.0: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:14: 20:17 - StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:24: 20:29 - _13 = (((*(_4.1: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:24: 20:29 - StorageLive(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:20:38: 20:49 - StorageLive(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:20:38: 20:41 - _15 = _12; // scope 1 at $DIR/early_otherwise_branch_68867.rs:20:38: 20:41 - StorageLive(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:20:44: 20:49 - _16 = _13; // scope 1 at $DIR/early_otherwise_branch_68867.rs:20:44: 20:49 - _14 = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:20:38: 20:49 - StorageDead(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:20:48: 20:49 - StorageDead(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:20:48: 20:49 - ((_3 as Vw).0: f32) = move _14; // scope 1 at $DIR/early_otherwise_branch_68867.rs:20:35: 20:50 - discriminant(_3) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:20:35: 20:50 - StorageDead(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:20:49: 20:50 - StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:49: 20:50 - StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:49: 20:50 -- goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 -+ goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 + StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + _12 = (((*(_4.0: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + _13 = (((*(_4.1: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + StorageLive(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 + StorageLive(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 + _15 = _12; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 + StorageLive(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 + _16 = _13; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 + _14 = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 + StorageDead(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49 + StorageDead(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49 + ((_3 as Vw).0: f32) = move _14; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 + discriminant(_3) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 + StorageDead(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 + StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 + StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 +- goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 ++ goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 } - bb7: { + bb3: { - StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:17 - _17 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:17 - StorageLive(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:24: 21:29 - _18 = (((*(_4.1: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:24: 21:29 - StorageLive(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:21:38: 21:49 - StorageLive(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:21:38: 21:41 - _20 = _17; // scope 2 at $DIR/early_otherwise_branch_68867.rs:21:38: 21:41 - StorageLive(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:21:44: 21:49 - _21 = _18; // scope 2 at $DIR/early_otherwise_branch_68867.rs:21:44: 21:49 - _19 = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:21:38: 21:49 - StorageDead(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:21:48: 21:49 - StorageDead(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:21:48: 21:49 - ((_3 as Vh).0: f32) = move _19; // scope 2 at $DIR/early_otherwise_branch_68867.rs:21:35: 21:50 - discriminant(_3) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:21:35: 21:50 - StorageDead(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:21:49: 21:50 - StorageDead(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:49: 21:50 - StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:49: 21:50 -- goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 -+ goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 + StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 + _17 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 + StorageLive(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 + _18 = (((*(_4.1: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 + StorageLive(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49 + StorageLive(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41 + _20 = _17; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41 + StorageLive(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49 + _21 = _18; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49 + _19 = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49 + StorageDead(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:48: 24:49 + StorageDead(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:48: 24:49 + ((_3 as Vh).0: f32) = move _19; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:35: 24:50 + discriminant(_3) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:35: 24:50 + StorageDead(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 + StorageDead(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 + StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 +- goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 ++ goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 } - bb8: { + bb4: { - StorageLive(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:16: 22:19 - _22 = (((*(_4.0: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:16: 22:19 - StorageLive(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:28: 22:33 - _23 = (((*(_4.1: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:28: 22:33 - StorageLive(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:55 - StorageLive(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:47 - _25 = _22; // scope 3 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:47 - StorageLive(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:22:50: 22:55 - _26 = _23; // scope 3 at $DIR/early_otherwise_branch_68867.rs:22:50: 22:55 - _24 = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:55 - StorageDead(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:22:54: 22:55 - StorageDead(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:22:54: 22:55 - ((_3 as Vmin).0: f32) = move _24; // scope 3 at $DIR/early_otherwise_branch_68867.rs:22:39: 22:56 - discriminant(_3) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:22:39: 22:56 - StorageDead(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:22:55: 22:56 - StorageDead(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:55: 22:56 - StorageDead(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:55: 22:56 -- goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 -+ goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 + StorageLive(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + _22 = (((*(_4.0: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + StorageLive(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + _23 = (((*(_4.1: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + StorageLive(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 + StorageLive(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 + _25 = _22; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 + StorageLive(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 + _26 = _23; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 + _24 = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 + StorageDead(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55 + StorageDead(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55 + ((_3 as Vmin).0: f32) = move _24; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 + discriminant(_3) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 + StorageDead(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 + StorageDead(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 + StorageDead(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 +- goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 ++ goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 } - bb9: { + bb5: { - StorageLive(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:16: 23:19 - _27 = (((*(_4.0: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:16: 23:19 - StorageLive(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:28: 23:33 - _28 = (((*(_4.1: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:28: 23:33 - StorageLive(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:55 - StorageLive(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:47 - _30 = _27; // scope 4 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:47 - StorageLive(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:23:50: 23:55 - _31 = _28; // scope 4 at $DIR/early_otherwise_branch_68867.rs:23:50: 23:55 - _29 = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:55 - StorageDead(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:23:54: 23:55 - StorageDead(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:23:54: 23:55 - ((_3 as Vmax).0: f32) = move _29; // scope 4 at $DIR/early_otherwise_branch_68867.rs:23:39: 23:56 - discriminant(_3) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:23:39: 23:56 - StorageDead(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:23:55: 23:56 - StorageDead(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:55: 23:56 - StorageDead(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:55: 23:56 -- goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 -+ goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:8: 25:6 + StorageLive(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 + _27 = (((*(_4.0: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 + StorageLive(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 + _28 = (((*(_4.1: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 + StorageLive(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55 + StorageLive(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47 + _30 = _27; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47 + StorageLive(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55 + _31 = _28; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55 + _29 = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55 + StorageDead(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:54: 26:55 + StorageDead(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:54: 26:55 + ((_3 as Vmax).0: f32) = move _29; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:39: 26:56 + discriminant(_3) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:39: 26:56 + StorageDead(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 + StorageDead(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 + StorageDead(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 +- goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 ++ goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 } - bb10: { + bb6: { - return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:2: 26:2 + return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:2: 29:2 } - bb11: { + bb7: { - ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:5: 25:7 - discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:19:5: 25:7 - StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:6: 25:7 - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:1: 26:2 -- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:2: 26:2 -+ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:2: 26:2 + ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7 + discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7 + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2 +- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:2: 29:2 ++ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:2: 29:2 + } + + bb8: { -+ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:21: 20:30 -+ switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:20:21: 20:30 ++ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 ++ switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 } } From 3795886f7e1f3dc5f5dd207ba4a7c092fe929486 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 20 Sep 2020 16:59:15 +0200 Subject: [PATCH 0728/1052] Split check for `PartialEq` impl into a method --- .../src/thir/pattern/const_to_pat.rs | 63 ++++++++++--------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index d47c3e7e3aba1..ebb71ea24ecc0 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -159,34 +159,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { } }); - // double-check there even *is* a semantic `PartialEq` to dispatch to. - // - // (If there isn't, then we can safely issue a hard - // error, because that's never worked, due to compiler - // using `PartialEq::eq` in this scenario in the past.) - // - // Note: To fix rust-lang/rust#65466, one could lift this check - // *before* any structural-match checking, and unconditionally error - // if `PartialEq` is not implemented. However, that breaks stable - // code at the moment, because types like `for <'a> fn(&'a ())` do - // not *yet* implement `PartialEq`. So for now we leave this here. - let ty_is_partial_eq: bool = { - let partial_eq_trait_id = - self.tcx().require_lang_item(hir::LangItem::PartialEq, Some(self.span)); - let obligation: PredicateObligation<'_> = predicate_for_trait_def( - self.tcx(), - self.param_env, - ObligationCause::misc(self.span, self.id), - partial_eq_trait_id, - 0, - cv.ty, - &[], - ); - // FIXME: should this call a `predicate_must_hold` variant instead? - self.infcx.predicate_may_hold(&obligation) - }; - - if !ty_is_partial_eq { + if !self.type_has_partial_eq_impl(cv.ty) { // span_fatal avoids ICE from resolution of non-existent method (rare case). self.tcx().sess.span_fatal(self.span, &msg); } else if mir_structural_match_violation { @@ -208,6 +181,40 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { inlined_const_as_pat } + fn type_has_partial_eq_impl(&self, ty: Ty<'tcx>) -> bool { + // double-check there even *is* a semantic `PartialEq` to dispatch to. + // + // (If there isn't, then we can safely issue a hard + // error, because that's never worked, due to compiler + // using `PartialEq::eq` in this scenario in the past.) + let partial_eq_trait_id = + self.tcx().require_lang_item(hir::LangItem::PartialEq, Some(self.span)); + let obligation: PredicateObligation<'_> = predicate_for_trait_def( + self.tcx(), + self.param_env, + ObligationCause::misc(self.span, self.id), + partial_eq_trait_id, + 0, + ty, + &[], + ); + // FIXME: should this call a `predicate_must_hold` variant instead? + + let has_impl = self.infcx.predicate_may_hold(&obligation); + + // Note: To fix rust-lang/rust#65466, we could just remove this type + // walk hack for function pointers, and unconditionally error + // if `PartialEq` is not implemented. However, that breaks stable + // code at the moment, because types like `for <'a> fn(&'a ())` do + // not *yet* implement `PartialEq`. So for now we leave this here. + has_impl + || ty.walk().any(|t| match t.unpack() { + ty::subst::GenericArgKind::Lifetime(_) => false, + ty::subst::GenericArgKind::Type(t) => t.is_fn_ptr(), + ty::subst::GenericArgKind::Const(_) => false, + }) + } + // Recursive helper for `to_pat`; invoke that (instead of calling this directly). fn recur(&self, cv: &'tcx ty::Const<'tcx>) -> Pat<'tcx> { let id = self.id; From 0e908759681d30bbc072170bad7eee68f5d7db05 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 17 Sep 2020 20:04:20 +0200 Subject: [PATCH 0729/1052] update Miri --- Cargo.lock | 29 +++++++++++++++++++---------- src/tools/miri | 2 +- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4ec750f7b4226..b232bc321d62a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -342,7 +342,6 @@ dependencies = [ name = "cargo-miri" version = "0.1.0" dependencies = [ - "cargo_metadata 0.11.1", "directories", "rustc-workspace-hack", "rustc_version", @@ -576,9 +575,9 @@ dependencies = [ [[package]] name = "colored" -version = "1.9.3" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" dependencies = [ "atty", "lazy_static", @@ -886,11 +885,10 @@ dependencies = [ [[package]] name = "directories" -version = "2.0.2" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c" +checksum = "f8fed639d60b58d0f53498ab13d26f621fd77569cc6edb031f4cc36a2ad9da0f" dependencies = [ - "cfg-if", "dirs-sys", ] @@ -1186,6 +1184,17 @@ dependencies = [ "wasi", ] +[[package]] +name = "getrandom" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "gimli" version = "0.22.0" @@ -1992,7 +2001,7 @@ dependencies = [ "colored", "compiletest_rs", "env_logger 0.7.1", - "getrandom", + "getrandom 0.2.0", "hex 0.4.2", "libc", "log", @@ -2584,7 +2593,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom", + "getrandom 0.1.14", "libc", "rand_chacha", "rand_core", @@ -2608,7 +2617,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom", + "getrandom 0.1.14", ] [[package]] @@ -2684,7 +2693,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" dependencies = [ - "getrandom", + "getrandom 0.1.14", "redox_syscall", "rust-argon2", ] diff --git a/src/tools/miri b/src/tools/miri index 604a674ea37b3..5a15c8a6dd620 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit 604a674ea37b302fd605df67be10a24ce94ad0a6 +Subproject commit 5a15c8a6dd62033f69688f9d1c6eacd674158539 From 08b85a6fc88b4c7b5e02742b5df825b62e168f81 Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Sun, 20 Sep 2020 18:04:12 +0200 Subject: [PATCH 0730/1052] use iter:: before free functions --- library/core/src/iter/sources.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/core/src/iter/sources.rs b/library/core/src/iter/sources.rs index c28538ef027c0..97562cf73b869 100644 --- a/library/core/src/iter/sources.rs +++ b/library/core/src/iter/sources.rs @@ -531,8 +531,10 @@ where /// An iterator where each iteration calls the provided closure `F: FnMut() -> Option`. /// -/// This `struct` is created by the [`from_fn()`] function. +/// 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); @@ -581,8 +583,10 @@ where /// An new iterator where each successive item is computed based on the preceding one. /// -/// This `struct` is created by the [`successors()`] function. +/// This `struct` is created by the [`iter::successors()`] function. /// See its documentation for more. +/// +/// [`iter::successors()`]: successors #[derive(Clone)] #[stable(feature = "iter_successors", since = "1.34.0")] pub struct Successors { From 81699895073162cd6731413711a4357dde67d661 Mon Sep 17 00:00:00 2001 From: Daniel Henry-Mantilla Date: Sat, 19 Sep 2020 21:32:33 +0200 Subject: [PATCH 0731/1052] Add non-`unsafe` `.get_mut()` for `UnsafeCell` Update the tracking issue number Updated the documentation for `UnsafeCell` Address review comments Address more review comments + minor changes --- library/core/src/cell.rs | 93 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 84 insertions(+), 9 deletions(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index cbbfcb4611321..44b863b220051 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1543,8 +1543,11 @@ impl fmt::Display for RefMut<'_, T> { /// allow internal mutability, such as `Cell` and `RefCell`, use `UnsafeCell` to wrap their /// internal data. There is *no* legal way to obtain aliasing `&mut`, not even with `UnsafeCell`. /// -/// The `UnsafeCell` API itself is technically very simple: it gives you a raw pointer `*mut T` to -/// its contents. It is up to _you_ as the abstraction designer to use that raw pointer correctly. +/// The `UnsafeCell` API itself is technically very simple: [`.get()`] gives you a raw pointer +/// `*mut T` to its contents. It is up to _you_ as the abstraction designer to use that raw pointer +/// correctly. +/// +/// [`.get()`]: `UnsafeCell::get` /// /// The precise Rust aliasing rules are somewhat in flux, but the main points are not contentious: /// @@ -1571,21 +1574,70 @@ impl fmt::Display for RefMut<'_, T> { /// 2. A `&mut T` reference may be released to safe code provided neither other `&mut T` nor `&T` /// co-exist with it. A `&mut T` must always be unique. /// -/// Note that while mutating or mutably aliasing the contents of an `&UnsafeCell` is -/// ok (provided you enforce the invariants some other way), it is still undefined behavior -/// to have multiple `&mut UnsafeCell` aliases. +/// Note that whilst mutating the contents of an `&UnsafeCell` (even while other +/// `&UnsafeCell` references alias the cell) is +/// ok (provided you enforce the above invariants some other way), it is still undefined behavior +/// to have multiple `&mut UnsafeCell` aliases. That is, `UnsafeCell` is a wrapper +/// designed to have a special interaction with _shared_ accesses (_i.e._, through an +/// `&UnsafeCell<_>` reference); there is no magic whatsoever when dealing with _exclusive_ +/// accesses (_e.g._, through an `&mut UnsafeCell<_>`): neither the cell nor the wrapped value +/// may be aliased for the duration of that `&mut` borrow. +/// This is showcased by the [`.get_mut()`] accessor, which is a non-`unsafe` getter that yields +/// a `&mut T`. +/// +/// [`.get_mut()`]: `UnsafeCell::get_mut` /// /// # Examples /// +/// Here is an example showcasing how to soundly mutate the contents of an `UnsafeCell<_>` despite +/// there being multiple references aliasing the cell: +/// /// ``` /// use std::cell::UnsafeCell; /// -/// # #[allow(dead_code)] -/// struct NotThreadSafe { -/// value: UnsafeCell, +/// let x: UnsafeCell = 42.into(); +/// // Get multiple / concurrent / shared references to the same `x`. +/// let (p1, p2): (&UnsafeCell, &UnsafeCell) = (&x, &x); +/// +/// unsafe { +/// // SAFETY: within this scope there are no other references to `x`'s contents, +/// // so ours is effectively unique. +/// let p1_exclusive: &mut i32 = &mut *p1.get(); // -- borrow --+ +/// *p1_exclusive += 27; // | +/// } // <---------- cannot go beyond this point -------------------+ +/// +/// unsafe { +/// // SAFETY: within this scope nobody expects to have exclusive access to `x`'s contents, +/// // so we can have multiple shared accesses concurrently. +/// let p2_shared: &i32 = &*p2.get(); +/// assert_eq!(*p2_shared, 42 + 27); +/// let p1_shared: &i32 = &*p1.get(); +/// assert_eq!(*p1_shared, *p2_shared); /// } +/// ``` +/// +/// The following example showcases the fact that exclusive access to an `UnsafeCell` +/// implies exclusive access to its `T`: /// -/// unsafe impl Sync for NotThreadSafe {} +/// ```rust +/// #![feature(unsafe_cell_get_mut)] +/// #![forbid(unsafe_code)] // with exclusive accesses, +/// // `UnsafeCell` is a transparent no-op wrapper, +/// // so no need for `unsafe` here. +/// use std::cell::UnsafeCell; +/// +/// let mut x: UnsafeCell = 42.into(); +/// +/// // Get a compile-time-checked unique reference to `x`. +/// let p_unique: &mut UnsafeCell = &mut x; +/// // With an exclusive reference, we can mutate the contents for free. +/// *p_unique.get_mut() = 0; +/// // Or, equivalently: +/// x = UnsafeCell::new(0); +/// +/// // When we own the value, we can extract the contents for free. +/// let contents: i32 = x.into_inner(); +/// assert_eq!(contents, 0); /// ``` #[lang = "unsafe_cell"] #[stable(feature = "rust1", since = "1.0.0")] @@ -1663,6 +1715,29 @@ impl UnsafeCell { self as *const UnsafeCell as *const T as *mut T } + /// Returns a mutable reference to the underlying data. + /// + /// This call borrows the `UnsafeCell` mutably (at compile-time) which + /// guarantees that we possess the only reference. + /// + /// # Examples + /// + /// ``` + /// #![feature(unsafe_cell_get_mut)] + /// use std::cell::UnsafeCell; + /// + /// let mut c = UnsafeCell::new(5); + /// *c.get_mut() += 1; + /// + /// assert_eq!(*c.get_mut(), 6); + /// ``` + #[inline] + #[unstable(feature = "unsafe_cell_get_mut", issue = "76943")] + pub fn get_mut(&mut self) -> &mut T { + // SAFETY: (outer) `&mut` guarantees unique access. + unsafe { &mut *self.get() } + } + /// Gets a mutable pointer to the wrapped value. /// The difference to [`get`] is that this function accepts a raw pointer, /// which is useful to avoid the creation of temporary references. From 5886c38112c8bb347b1cbd46c28b1ca6f8bac88d Mon Sep 17 00:00:00 2001 From: Daniel Henry-Mantilla Date: Sat, 19 Sep 2020 21:33:40 +0200 Subject: [PATCH 0732/1052] Replace unneeded `unsafe` calls to `.get()` with calls to `.get_mut()` --- library/core/src/cell.rs | 8 ++------ library/core/src/sync/atomic.rs | 6 ++---- library/std/src/lib.rs | 1 + library/std/src/sync/mutex.rs | 4 +--- library/std/src/sync/rwlock.rs | 4 +--- 5 files changed, 7 insertions(+), 16 deletions(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 44b863b220051..f60aa2d24c5ca 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -496,10 +496,7 @@ impl Cell { #[inline] #[stable(feature = "cell_get_mut", since = "1.11.0")] pub fn get_mut(&mut self) -> &mut T { - // SAFETY: This can cause data races if called from a separate thread, - // but `Cell` is `!Sync` so this won't happen, and `&mut` guarantees - // unique access. - unsafe { &mut *self.value.get() } + self.value.get_mut() } /// Returns a `&Cell` from a `&mut T` @@ -945,8 +942,7 @@ impl RefCell { #[inline] #[stable(feature = "cell_get_mut", since = "1.11.0")] pub fn get_mut(&mut self) -> &mut T { - // SAFETY: `&mut` guarantees unique access. - unsafe { &mut *self.value.get() } + self.value.get_mut() } /// Undo the effect of leaked guards on the borrow state of the `RefCell`. diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 9d74f537491b1..c67d6422c01ec 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -838,8 +838,7 @@ impl AtomicPtr { #[inline] #[stable(feature = "atomic_access", since = "1.15.0")] pub fn get_mut(&mut self) -> &mut *mut T { - // SAFETY: the mutable reference guarantees unique ownership. - unsafe { &mut *self.p.get() } + self.p.get_mut() } /// Get atomic access to a pointer. @@ -1275,8 +1274,7 @@ assert_eq!(some_var.load(Ordering::SeqCst), 5); #[inline] #[$stable_access] pub fn get_mut(&mut self) -> &mut $int_type { - // SAFETY: the mutable reference guarantees unique ownership. - unsafe { &mut *self.v.get() } + self.v.get_mut() } } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 5333d75ec1bc5..71b29cf5af99b 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -315,6 +315,7 @@ #![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(unsafe_block_in_unsafe_fn)] +#![feature(unsafe_cell_get_mut)] #![feature(unsafe_cell_raw_get)] #![feature(untagged_unions)] #![feature(unwind_attributes)] diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs index 240155b06b411..a1703c731d44d 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.rs @@ -406,9 +406,7 @@ impl Mutex { /// ``` #[stable(feature = "mutex_get_mut", since = "1.6.0")] pub fn get_mut(&mut self) -> LockResult<&mut T> { - // We know statically that there are no other references to `self`, so - // there's no need to lock the inner mutex. - let data = unsafe { &mut *self.data.get() }; + let data = self.data.get_mut(); poison::map_result(self.poison.borrow(), |_| data) } } diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index f38d6101da0d3..d967779ce361d 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -404,9 +404,7 @@ impl RwLock { /// ``` #[stable(feature = "rwlock_get_mut", since = "1.6.0")] pub fn get_mut(&mut self) -> LockResult<&mut T> { - // We know statically that there are no other references to `self`, so - // there's no need to lock the inner lock. - let data = unsafe { &mut *self.data.get() }; + let data = self.data.get_mut(); poison::map_result(self.poison.borrow(), |_| data) } } From aaddcdb0d097de1fee14be16479aeaeea41e8810 Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Sun, 20 Sep 2020 18:37:05 +0200 Subject: [PATCH 0733/1052] Fix nits --- library/std/src/sync/barrier.rs | 4 ++-- library/std/src/sync/once.rs | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/library/std/src/sync/barrier.rs b/library/std/src/sync/barrier.rs index 8d3e30dbd4545..eab26b6c7150c 100644 --- a/library/std/src/sync/barrier.rs +++ b/library/std/src/sync/barrier.rs @@ -150,8 +150,8 @@ impl fmt::Debug for BarrierWaitResult { } impl BarrierWaitResult { - /// Returns `true` if this thread from [`Barrier::wait()`] is the - /// "leader thread". + /// Returns `true` if this thread is the "leader thread" for the call to + /// [`Barrier::wait()`]. /// /// Only one thread will have `true` returned from their result, all other /// threads will have `false` returned. diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs index ee8902bf764bf..de5ddf1daf27b 100644 --- a/library/std/src/sync/once.rs +++ b/library/std/src/sync/once.rs @@ -95,8 +95,7 @@ use crate::thread::{self, Thread}; /// A synchronization primitive which can be used to run a one-time global /// initialization. Useful for one-time initialization for FFI or related -/// functionality. This type can only be constructed with the [`Once::new()`] -/// constructor. +/// functionality. This type can only be constructed with [`Once::new()`]. /// /// # Examples /// From aba5ea1430df393eddc90068e838de6b1707c0d8 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 20 Sep 2020 17:11:00 +0200 Subject: [PATCH 0734/1052] Lint on function pointers used in patterns --- .../src/thir/pattern/const_to_pat.rs | 19 ++++++++++++- compiler/rustc_session/src/lint/builtin.rs | 27 +++++++++++++++++++ src/test/ui/issues/issue-44333.rs | 9 +++++-- src/test/ui/issues/issue-44333.stderr | 25 +++++++++++++++++ .../ui/rfc1445/issue-63479-match-fnptr.rs | 4 +++ .../ui/rfc1445/issue-63479-match-fnptr.stderr | 16 +++++++++++ 6 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/issues/issue-44333.stderr create mode 100644 src/test/ui/rfc1445/issue-63479-match-fnptr.stderr diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index ebb71ea24ecc0..6ca1ff2c5f2e7 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -351,10 +351,27 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::FnDef(..) => { PatKind::Constant { value: cv } } + ty::RawPtr(pointee) if pointee.ty.is_sized(tcx.at(span), param_env) => { + PatKind::Constant { value: cv } + } // FIXME: these can have very suprising behaviour where optimization levels or other // compilation choices change the runtime behaviour of the match. // See https://github.com/rust-lang/rust/issues/70861 for examples. - ty::FnPtr(..) | ty::RawPtr(..) => PatKind::Constant { value: cv }, + ty::FnPtr(..) | ty::RawPtr(..) => { + if self.include_lint_checks && !self.saw_const_match_error.get() { + self.saw_const_match_error.set(true); + let msg = "function pointers and unsized pointers in patterns do not behave \ + deterministically. \ + See https://github.com/rust-lang/rust/issues/70861 for details."; + tcx.struct_span_lint_hir( + lint::builtin::POINTER_STRUCTURAL_MATCH, + id, + span, + |lint| lint.build(&msg).emit(), + ); + } + PatKind::Constant { value: cv } + } _ => { tcx.sess.delay_span_bug(span, &format!("cannot make a pattern out of {}", cv.ty)); PatKind::Wild diff --git a/compiler/rustc_session/src/lint/builtin.rs b/compiler/rustc_session/src/lint/builtin.rs index 562df176b14a7..c72b97fa1cabc 100644 --- a/compiler/rustc_session/src/lint/builtin.rs +++ b/compiler/rustc_session/src/lint/builtin.rs @@ -2197,6 +2197,32 @@ declare_lint! { report_in_external_macro } +declare_lint! { + /// The `pointer_structural_match` lint detects pointers used in patterns that do not + /// behave deterministically across optimizations. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(pointer_structural_match)] + /// fn foo(a: usize, b: usize) -> usize { a + b } + /// const FOO: fn(usize, usize) -> usize = foo; + /// fn main() { + /// match FOO { + /// FOO => {}, + /// _ => {}, + /// } + /// } + /// ``` + pub POINTER_STRUCTURAL_MATCH, + Allow, + "pointers are not structural-match", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #62411 ", + edition: None, + }; +} + declare_lint! { /// The `ambiguous_associated_items` lint detects ambiguity between /// [associated items] and [enum variants]. @@ -2630,6 +2656,7 @@ declare_lint_pass! { AMBIGUOUS_ASSOCIATED_ITEMS, MUTABLE_BORROW_RESERVATION_CONFLICT, INDIRECT_STRUCTURAL_MATCH, + POINTER_STRUCTURAL_MATCH, SOFT_UNSTABLE, INLINE_NO_SANITIZE, ASM_SUB_REGISTER, diff --git a/src/test/ui/issues/issue-44333.rs b/src/test/ui/issues/issue-44333.rs index fffef975043da..85f5ccbdb6561 100644 --- a/src/test/ui/issues/issue-44333.rs +++ b/src/test/ui/issues/issue-44333.rs @@ -1,4 +1,7 @@ // run-pass + +#![warn(pointer_structural_match)] + type Func = fn(usize, usize) -> usize; fn foo(a: usize, b: usize) -> usize { a + b } @@ -13,8 +16,10 @@ const BAR: Func = bar; fn main() { match test(std::env::consts::ARCH.len()) { - FOO => println!("foo"), - BAR => println!("bar"), + FOO => println!("foo"), //~ WARN pointers in patterns do not behave deterministically + //~^ WARN will become a hard error + BAR => println!("bar"), //~ WARN pointers in patterns do not behave deterministically + //~^ WARN will become a hard error _ => unreachable!(), } } diff --git a/src/test/ui/issues/issue-44333.stderr b/src/test/ui/issues/issue-44333.stderr new file mode 100644 index 0000000000000..a9ee5fc4dd7b1 --- /dev/null +++ b/src/test/ui/issues/issue-44333.stderr @@ -0,0 +1,25 @@ +warning: function pointers and unsized pointers in patterns do not behave deterministically. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-44333.rs:19:9 + | +LL | FOO => println!("foo"), + | ^^^ + | +note: the lint level is defined here + --> $DIR/issue-44333.rs:3:9 + | +LL | #![warn(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + = 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 #62411 + +warning: function pointers and unsized pointers in patterns do not behave deterministically. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-44333.rs:21:9 + | +LL | BAR => println!("bar"), + | ^^^ + | + = 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 #62411 + +warning: 2 warnings emitted + diff --git a/src/test/ui/rfc1445/issue-63479-match-fnptr.rs b/src/test/ui/rfc1445/issue-63479-match-fnptr.rs index b3c91cec580bf..0984b1d480ecb 100644 --- a/src/test/ui/rfc1445/issue-63479-match-fnptr.rs +++ b/src/test/ui/rfc1445/issue-63479-match-fnptr.rs @@ -5,6 +5,8 @@ // cover the case this hit; I've since expanded it accordingly, but the // experience left me wary of leaving this regression test out.) +#![warn(pointer_structural_match)] + #[derive(Eq)] struct A { a: i64 @@ -31,6 +33,8 @@ fn main() { let s = B(my_fn); match s { B(TEST) => println!("matched"), + //~^ WARN pointers in patterns do not behave deterministically + //~| WARN this was previously accepted by the compiler but is being phased out _ => panic!("didn't match") }; } diff --git a/src/test/ui/rfc1445/issue-63479-match-fnptr.stderr b/src/test/ui/rfc1445/issue-63479-match-fnptr.stderr new file mode 100644 index 0000000000000..34b9c359ca856 --- /dev/null +++ b/src/test/ui/rfc1445/issue-63479-match-fnptr.stderr @@ -0,0 +1,16 @@ +warning: function pointers and unsized pointers in patterns do not behave deterministically. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-63479-match-fnptr.rs:35:7 + | +LL | B(TEST) => println!("matched"), + | ^^^^ + | +note: the lint level is defined here + --> $DIR/issue-63479-match-fnptr.rs:8:9 + | +LL | #![warn(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + = 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 #62411 + +warning: 1 warning emitted + From adf98ab2dc6b3d8332873d41f3371a839b4e9df1 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 20 Sep 2020 17:22:33 +0200 Subject: [PATCH 0735/1052] Use precise errors during const to pat conversion instead of a catch-all on the main constant --- .../src/thir/pattern/const_to_pat.rs | 85 ++++++++++++++++--- compiler/rustc_session/src/lint/builtin.rs | 70 +++++++++++---- .../const_in_pattern/custom-eq-branch-warn.rs | 6 +- .../custom-eq-branch-warn.stderr | 12 +-- .../ui/consts/const_in_pattern/issue-65466.rs | 6 +- .../const_in_pattern/issue-65466.stderr | 15 ---- .../const_in_pattern/reject_non_partial_eq.rs | 1 + .../reject_non_partial_eq.stderr | 10 ++- .../const_in_pattern/warn_corner_cases.stderr | 18 ++-- src/test/ui/consts/match_ice.rs | 4 +- src/test/ui/consts/match_ice.stderr | 23 ++++- src/test/ui/issues/issue-34784.rs | 2 + src/test/ui/match/issue-70972-dyn-trait.rs | 3 +- .../ui/match/issue-70972-dyn-trait.stderr | 10 ++- ...opaquely-typed-constant-used-in-pattern.rs | 4 +- ...uely-typed-constant-used-in-pattern.stderr | 12 ++- ...-hide-behind-direct-unsafe-ptr-embedded.rs | 2 + ...low-hide-behind-direct-unsafe-ptr-param.rs | 2 + ...ide-behind-indirect-unsafe-ptr-embedded.rs | 2 + ...w-hide-behind-indirect-unsafe-ptr-param.rs | 2 + ...ide-behind-doubly-indirect-embedded.stderr | 10 +-- ...t-hide-behind-doubly-indirect-param.stderr | 10 +-- ...2307-match-ref-ref-forbidden-without-eq.rs | 2 +- ...-match-ref-ref-forbidden-without-eq.stderr | 14 +-- .../structural-match-no-leak.rs | 5 +- .../structural-match-no-leak.stderr | 10 ++- .../type-alias-impl-trait/structural-match.rs | 5 +- .../structural-match.stderr | 10 ++- 28 files changed, 240 insertions(+), 115 deletions(-) delete mode 100644 src/test/ui/consts/const_in_pattern/issue-65466.stderr diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 6ca1ff2c5f2e7..ad0bcfeb367f9 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -43,7 +43,7 @@ struct ConstToPat<'a, 'tcx> { span: Span, param_env: ty::ParamEnv<'tcx>, - // This tracks if we signal some hard error for a given const value, so that + // This tracks if we saw some error or lint for a given const value, so that // we will not subsequently issue an irrelevant lint for the same const // value. saw_const_match_error: Cell, @@ -103,7 +103,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // once indirect_structural_match is a full fledged error, this // level of indirection can be eliminated - let inlined_const_as_pat = self.recur(cv); + let inlined_const_as_pat = self.recur(cv, mir_structural_match_violation); if self.include_lint_checks && !self.saw_const_match_error.get() { // If we were able to successfully convert the const to some pat, @@ -216,7 +216,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { } // Recursive helper for `to_pat`; invoke that (instead of calling this directly). - fn recur(&self, cv: &'tcx ty::Const<'tcx>) -> Pat<'tcx> { + fn recur(&self, cv: &'tcx ty::Const<'tcx>, mir_structural_match_violation: bool) -> Pat<'tcx> { let id = self.id; let span = self.span; let tcx = self.tcx(); @@ -227,7 +227,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { .enumerate() .map(|(idx, val)| { let field = Field::new(idx); - FieldPat { field, pattern: self.recur(val) } + FieldPat { field, pattern: self.recur(val, false) } }) .collect() }; @@ -248,6 +248,21 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { tcx.sess.span_err(span, "cannot use unions in constant patterns"); PatKind::Wild } + ty::Adt(..) + if !self.type_has_partial_eq_impl(cv.ty) + // FIXME(#73448): Find a way to bring const qualification into parity with + // `search_for_structural_match_violation` and then remove this condition. + && self.search_for_structural_match_violation(cv.ty).is_some() => + { + let msg = format!( + "to use a constant of type `{}` in a pattern, \ + `{}` must be annotated with `#[derive(PartialEq, Eq)]`", + cv.ty, cv.ty, + ); + self.saw_const_match_error.set(true); + self.tcx().sess.span_err(self.span, &msg); + PatKind::Wild + } // If the type is not structurally comparable, just emit the constant directly, // causing the pattern match code to treat it opaquely. // FIXME: This code doesn't emit errors itself, the caller emits the errors. @@ -258,6 +273,20 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // Backwards compatibility hack because we can't cause hard errors on these // types, so we compare them via `PartialEq::eq` at runtime. ty::Adt(..) if !self.type_marked_structural(cv.ty) && self.behind_reference.get() => { + if self.include_lint_checks && !self.saw_const_match_error.get() { + self.saw_const_match_error.set(true); + let msg = format!( + "to use a constant of type `{}` in a pattern, \ + `{}` must be annotated with `#[derive(PartialEq, Eq)]`", + cv.ty, cv.ty, + ); + tcx.struct_span_lint_hir( + lint::builtin::INDIRECT_STRUCTURAL_MATCH, + id, + span, + |lint| lint.build(&msg).emit(), + ); + } PatKind::Constant { value: cv } } ty::Adt(adt_def, _) if !self.type_marked_structural(cv.ty) => { @@ -292,14 +321,18 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { .destructure_const(param_env.and(cv)) .fields .iter() - .map(|val| self.recur(val)) + .map(|val| self.recur(val, false)) .collect(), slice: None, suffix: Vec::new(), }, ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() { // These are not allowed and will error elsewhere anyway. - ty::Dynamic(..) => PatKind::Constant { value: cv }, + ty::Dynamic(..) => { + self.saw_const_match_error.set(true); + tcx.sess.span_err(span, &format!("`{}` cannot be used in patterns", cv.ty)); + PatKind::Wild + } // `&str` and `&[u8]` are represented as `ConstValue::Slice`, let's keep using this // optimization for now. ty::Str => PatKind::Constant { value: cv }, @@ -321,7 +354,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { .destructure_const(param_env.and(array)) .fields .iter() - .map(|val| self.recur(val)) + .map(|val| self.recur(val, false)) .collect(), slice: None, suffix: vec![], @@ -333,16 +366,21 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { self.behind_reference.set(old); val } - // Backwards compatibility hack. Don't take away the reference, since - // `PartialEq::eq` takes a reference, this makes the rest of the matching logic - // simpler. + // Backwards compatibility hack: support references to non-structural types. + // We'll lower + // this pattern to a `PartialEq::eq` comparison and `PartialEq::eq` takes a + // reference. This makes the rest of the matching logic simpler as it doesn't have + // to figure out how to get a reference again. ty::Adt(..) if !self.type_marked_structural(pointee_ty) => { PatKind::Constant { value: cv } } + // All other references are converted into deref patterns and then recursively + // convert the dereferenced constant to a pattern that is the sub-pattern of the + // deref pattern. _ => { let old = self.behind_reference.replace(true); let val = PatKind::Deref { - subpattern: self.recur(tcx.deref_const(self.param_env.and(cv))), + subpattern: self.recur(tcx.deref_const(self.param_env.and(cv)), false), }; self.behind_reference.set(old); val @@ -373,11 +411,34 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { PatKind::Constant { value: cv } } _ => { - tcx.sess.delay_span_bug(span, &format!("cannot make a pattern out of {}", cv.ty)); + self.saw_const_match_error.set(true); + tcx.sess.span_err(span, &format!("`{}` cannot be used in patterns", cv.ty)); PatKind::Wild } }; + if self.include_lint_checks + && !self.saw_const_match_error.get() + && mir_structural_match_violation + // FIXME(#73448): Find a way to bring const qualification into parity with + // `search_for_structural_match_violation` and then remove this condition. + && self.search_for_structural_match_violation(cv.ty).is_some() + { + self.saw_const_match_error.set(true); + let msg = format!( + "to use a constant of type `{}` in a pattern, \ + the constant's initializer must be trivial or all types \ + in the constant must be annotated with `#[derive(PartialEq, Eq)]`", + cv.ty, + ); + tcx.struct_span_lint_hir( + lint::builtin::NONTRIVIAL_STRUCTURAL_MATCH, + id, + span, + |lint| lint.build(&msg).emit(), + ); + } + Pat { span, ty: cv.ty, kind: Box::new(kind) } } } diff --git a/compiler/rustc_session/src/lint/builtin.rs b/compiler/rustc_session/src/lint/builtin.rs index c72b97fa1cabc..919aaf81ed207 100644 --- a/compiler/rustc_session/src/lint/builtin.rs +++ b/compiler/rustc_session/src/lint/builtin.rs @@ -2138,22 +2138,16 @@ declare_lint! { /// ```rust,compile_fail /// #![deny(indirect_structural_match)] /// - /// struct Plus(i32, i32); - /// const ONE_PLUS_TWO: &&Plus = &&Plus(1, 2); - /// - /// impl PartialEq for Plus { - /// fn eq(&self, other: &Self) -> bool { - /// self.0 + self.1 == other.0 + other.1 - /// } - /// } - /// - /// impl Eq for Plus {} - /// + /// struct NoDerive(i32); + /// impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + /// impl Eq for NoDerive { } + /// #[derive(PartialEq, Eq)] + /// struct WrapParam(T); + /// const WRAP_INDIRECT_PARAM: & &WrapParam = & &WrapParam(NoDerive(0)); /// fn main() { - /// if let ONE_PLUS_TWO = &&Plus(3, 0) { - /// println!("semantic!"); - /// } else { - /// println!("structural!"); + /// match WRAP_INDIRECT_PARAM { + /// WRAP_INDIRECT_PARAM => { } + /// _ => { } /// } /// } /// ``` @@ -2170,9 +2164,8 @@ declare_lint! { /// [issue #62411]: https://github.com/rust-lang/rust/issues/62411 /// [future-incompatible]: ../index.md#future-incompatible-lints pub INDIRECT_STRUCTURAL_MATCH, - // defaulting to allow until rust-lang/rust#62614 is fixed. - Allow, - "pattern with const indirectly referencing non-structural-match type", + Warn, + "constant used in pattern contains value of non-structural-match type in a field or a variant", @future_incompatible = FutureIncompatibleInfo { reference: "issue #62411 ", edition: None, @@ -2223,6 +2216,46 @@ declare_lint! { }; } +declare_lint! { + /// The `nontrivial_structural_match` lint detects constants that are used in patterns, + /// whose type is not structural-match and whose initializer body actually uses values + /// that are not structural-match. So `Option` is ok if the constant + /// is just `None`. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(nontrivial_structural_match)] + /// + /// struct Plus(i32, i32); + /// const ONE_PLUS_TWO: &&Plus = &&Plus(1, 2); + /// + /// impl PartialEq for Plus { + /// fn eq(&self, other: &Self) -> bool { + /// self.0 + self.1 == other.0 + other.1 + /// } + /// } + /// + /// impl Eq for Plus {} + /// + /// fn main() { + /// if let ONE_PLUS_TWO = &&Plus(3, 0) { + /// println!("semantic!"); + /// } else { + /// println!("structural!"); + /// } + /// } + /// ``` + pub NONTRIVIAL_STRUCTURAL_MATCH, + Warn, + "constant used in pattern of non-structural-match type and the constant's initializer \ + expression contains values of non-structural-match types", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #73448 ", + edition: None, + }; +} + declare_lint! { /// The `ambiguous_associated_items` lint detects ambiguity between /// [associated items] and [enum variants]. @@ -2657,6 +2690,7 @@ declare_lint_pass! { MUTABLE_BORROW_RESERVATION_CONFLICT, INDIRECT_STRUCTURAL_MATCH, POINTER_STRUCTURAL_MATCH, + NONTRIVIAL_STRUCTURAL_MATCH, SOFT_UNSTABLE, INLINE_NO_SANITIZE, ASM_SUB_REGISTER, diff --git a/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.rs b/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.rs index a1f9838ca0885..856d204178d42 100644 --- a/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.rs +++ b/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.rs @@ -1,8 +1,5 @@ // check-pass -#![warn(indirect_structural_match)] -//~^ NOTE lint level is defined here - struct CustomEq; impl Eq for CustomEq {} @@ -32,7 +29,8 @@ fn main() { BAR_BAZ => panic!(), //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` //~| WARN this was previously accepted - //~| NOTE see issue #62411 + //~| NOTE see issue #73448 + //~| NOTE `#[warn(nontrivial_structural_match)]` on by default _ => {} } } diff --git a/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr b/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr index 0be1cca806ed1..fd6732195e494 100644 --- a/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr +++ b/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr @@ -1,16 +1,12 @@ -warning: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/custom-eq-branch-warn.rs:32:9 +warning: to use a constant of type `Foo` in a pattern, the constant's initializer must be trivial or all types in the constant must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/custom-eq-branch-warn.rs:29:9 | LL | BAR_BAZ => panic!(), | ^^^^^^^ | -note: the lint level is defined here - --> $DIR/custom-eq-branch-warn.rs:3:9 - | -LL | #![warn(indirect_structural_match)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(nontrivial_structural_match)]` 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 #62411 + = note: for more information, see issue #73448 warning: 1 warning emitted diff --git a/src/test/ui/consts/const_in_pattern/issue-65466.rs b/src/test/ui/consts/const_in_pattern/issue-65466.rs index 0e3e0f6dd8834..2b421f4c705ec 100644 --- a/src/test/ui/consts/const_in_pattern/issue-65466.rs +++ b/src/test/ui/consts/const_in_pattern/issue-65466.rs @@ -1,9 +1,7 @@ -// FIXME: This still ICEs. -// -// ignore-test - #![deny(indirect_structural_match)] +// check-pass + #[derive(PartialEq, Eq)] enum O { Some(*const T), // Can also use PhantomData diff --git a/src/test/ui/consts/const_in_pattern/issue-65466.stderr b/src/test/ui/consts/const_in_pattern/issue-65466.stderr deleted file mode 100644 index 9fe3049d1d85f..0000000000000 --- a/src/test/ui/consts/const_in_pattern/issue-65466.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0601]: `main` function not found in crate `issue_65466` - --> $DIR/issue-65466.rs:1:1 - | -LL | / #![deny(indirect_structural_match)] -LL | | -LL | | #[derive(PartialEq, Eq)] -LL | | enum O { -... | -LL | | } -LL | | } - | |_^ consider adding a `main` function to `$DIR/issue-65466.rs` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0601`. diff --git a/src/test/ui/consts/const_in_pattern/reject_non_partial_eq.rs b/src/test/ui/consts/const_in_pattern/reject_non_partial_eq.rs index a8216901c027f..b2b2daa830f89 100644 --- a/src/test/ui/consts/const_in_pattern/reject_non_partial_eq.rs +++ b/src/test/ui/consts/const_in_pattern/reject_non_partial_eq.rs @@ -27,6 +27,7 @@ fn main() { match None { NO_PARTIAL_EQ_NONE => println!("NO_PARTIAL_EQ_NONE"), //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => panic!("whoops"), } } diff --git a/src/test/ui/consts/const_in_pattern/reject_non_partial_eq.stderr b/src/test/ui/consts/const_in_pattern/reject_non_partial_eq.stderr index 95cfa4a9ebe95..dc830d360031a 100644 --- a/src/test/ui/consts/const_in_pattern/reject_non_partial_eq.stderr +++ b/src/test/ui/consts/const_in_pattern/reject_non_partial_eq.stderr @@ -1,8 +1,14 @@ -error: to use a constant of type `NoPartialEq` in a pattern, `NoPartialEq` must be annotated with `#[derive(PartialEq, Eq)]` +error: to use a constant of type `Option` in a pattern, `Option` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/reject_non_partial_eq.rs:28:9 | LL | NO_PARTIAL_EQ_NONE => println!("NO_PARTIAL_EQ_NONE"), | ^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: to use a constant of type `Option` in a pattern, `Option` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/reject_non_partial_eq.rs:28:9 + | +LL | NO_PARTIAL_EQ_NONE => println!("NO_PARTIAL_EQ_NONE"), + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const_in_pattern/warn_corner_cases.stderr b/src/test/ui/consts/const_in_pattern/warn_corner_cases.stderr index 3e7ed573c74d7..a4feaff55b2e1 100644 --- a/src/test/ui/consts/const_in_pattern/warn_corner_cases.stderr +++ b/src/test/ui/consts/const_in_pattern/warn_corner_cases.stderr @@ -1,34 +1,30 @@ -warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `Option` in a pattern, the constant's initializer must be trivial or all types in the constant must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/warn_corner_cases.rs:26:47 | LL | match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), }; | ^^^^^ | -note: the lint level is defined here - --> $DIR/warn_corner_cases.rs:15:9 - | -LL | #![warn(indirect_structural_match)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(nontrivial_structural_match)]` 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 #62411 + = note: for more information, see issue #73448 -warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `Option` in a pattern, the constant's initializer must be trivial or all types in the constant must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/warn_corner_cases.rs:32:47 | LL | match None { Some(_) => panic!("whoops"), CALL => dbg!(CALL), }; | ^^^^ | = 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 #62411 + = note: for more information, see issue #73448 -warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `Option` in a pattern, the constant's initializer must be trivial or all types in the constant must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/warn_corner_cases.rs:38:47 | LL | match None { Some(_) => panic!("whoops"), METHOD_CALL => dbg!(METHOD_CALL), }; | ^^^^^^^^^^^ | = 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 #62411 + = note: for more information, see issue #73448 warning: 3 warnings emitted diff --git a/src/test/ui/consts/match_ice.rs b/src/test/ui/consts/match_ice.rs index 008c03ecddcc6..db76e23007089 100644 --- a/src/test/ui/consts/match_ice.rs +++ b/src/test/ui/consts/match_ice.rs @@ -8,8 +8,10 @@ struct T; fn main() { const C: &S = &S; match C { + //~^ non-exhaustive patterns: `&S` not covered C => {} - //~^ ERROR to use a constant of type `S` in a pattern, `S` must be annotated with + //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` + //~| WARN was previously accepted by the compiler } const K: &T = &T; match K { diff --git a/src/test/ui/consts/match_ice.stderr b/src/test/ui/consts/match_ice.stderr index 699b4a5e200e4..6cc79dbca7cc2 100644 --- a/src/test/ui/consts/match_ice.stderr +++ b/src/test/ui/consts/match_ice.stderr @@ -1,8 +1,25 @@ -error: to use a constant of type `S` in a pattern, `S` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/match_ice.rs:11:9 +warning: to use a constant of type `&S` in a pattern, the constant's initializer must be trivial or all types in the constant must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/match_ice.rs:12:9 | LL | C => {} | ^ + | + = note: `#[warn(nontrivial_structural_match)]` 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 #73448 + +error[E0004]: non-exhaustive patterns: `&S` not covered + --> $DIR/match_ice.rs:10:11 + | +LL | struct S; + | --------- `S` defined here +... +LL | match C { + | ^ pattern `&S` 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 `&S` -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/issues/issue-34784.rs b/src/test/ui/issues/issue-34784.rs index d3206e9943009..98d943470a7f9 100644 --- a/src/test/ui/issues/issue-34784.rs +++ b/src/test/ui/issues/issue-34784.rs @@ -1,4 +1,6 @@ // run-pass + +#![warn(pointer_structural_match)] #![allow(dead_code)] const C: *const u8 = &0; diff --git a/src/test/ui/match/issue-70972-dyn-trait.rs b/src/test/ui/match/issue-70972-dyn-trait.rs index a9b2699cafdc4..b69e2dab2650b 100644 --- a/src/test/ui/match/issue-70972-dyn-trait.rs +++ b/src/test/ui/match/issue-70972-dyn-trait.rs @@ -4,7 +4,8 @@ fn main() { let a: &dyn Send = &7u32; match a { F => panic!(), - //~^ ERROR trait objects cannot be used in patterns + //~^ ERROR `&dyn Send` cannot be used in patterns + //~| ERROR `&dyn Send` cannot be used in patterns _ => {} } } diff --git a/src/test/ui/match/issue-70972-dyn-trait.stderr b/src/test/ui/match/issue-70972-dyn-trait.stderr index a4e827357de6b..985799b3c8357 100644 --- a/src/test/ui/match/issue-70972-dyn-trait.stderr +++ b/src/test/ui/match/issue-70972-dyn-trait.stderr @@ -1,8 +1,14 @@ -error: trait objects cannot be used in patterns +error: `&dyn Send` cannot be used in patterns --> $DIR/issue-70972-dyn-trait.rs:6:9 | LL | F => panic!(), | ^ -error: aborting due to previous error +error: `&dyn Send` cannot be used in patterns + --> $DIR/issue-70972-dyn-trait.rs:6:9 + | +LL | F => panic!(), + | ^ + +error: aborting due to 2 previous errors diff --git a/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs index c5e4a72fb9ff1..0c38b533a16e6 100644 --- a/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs +++ b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs @@ -4,6 +4,8 @@ fn main() { const C: impl Copy = 0; match C { - C | _ => {} //~ ERROR: opaque types cannot be used in patterns + C => {} //~ ERROR: `impl Copy` cannot be used in patterns + //~^ ERROR: `impl Copy` cannot be used in patterns + _ => {} } } diff --git a/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr index 7695223f2cf98..ad6cc0aa3e3e9 100644 --- a/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr +++ b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr @@ -1,8 +1,14 @@ -error: opaque types cannot be used in patterns +error: `impl Copy` cannot be used in patterns --> $DIR/issue-71042-opaquely-typed-constant-used-in-pattern.rs:7:9 | -LL | C | _ => {} +LL | C => {} | ^ -error: aborting due to previous error +error: `impl Copy` cannot be used in patterns + --> $DIR/issue-71042-opaquely-typed-constant-used-in-pattern.rs:7:9 + | +LL | C => {} + | ^ + +error: aborting due to 2 previous errors diff --git a/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-embedded.rs b/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-embedded.rs index b90a750cc16c4..c6d7166e74065 100644 --- a/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-embedded.rs +++ b/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-embedded.rs @@ -3,6 +3,8 @@ // run-pass +#![warn(pointer_structural_match)] + struct NoDerive(i32); // This impl makes NoDerive irreflexive diff --git a/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-param.rs b/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-param.rs index 1076b9f25d89a..cc7ea6cde8d7f 100644 --- a/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-param.rs +++ b/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-param.rs @@ -3,6 +3,8 @@ // run-pass +#![warn(pointer_structural_match)] + struct NoDerive(i32); // This impl makes NoDerive irreflexive diff --git a/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-embedded.rs b/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-embedded.rs index a4b832d377d6f..86db09cc08fc8 100644 --- a/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-embedded.rs +++ b/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-embedded.rs @@ -3,6 +3,8 @@ // run-pass +#![warn(pointer_structural_match)] + struct NoDerive(i32); // This impl makes NoDerive irreflexive diff --git a/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-param.rs b/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-param.rs index 47b70e2e9cc56..99c574d078045 100644 --- a/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-param.rs +++ b/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-param.rs @@ -3,6 +3,8 @@ // run-pass +#![warn(pointer_structural_match)] + struct NoDerive(i32); // This impl makes NoDerive irreflexive diff --git a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.stderr b/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.stderr index 659a981267233..eb13eed6ec11b 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.stderr +++ b/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.stderr @@ -1,16 +1,12 @@ -warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `&&WrapInline` in a pattern, the constant's initializer must be trivial or all types in the constant must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/cant-hide-behind-doubly-indirect-embedded.rs:24:9 | LL | WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLINE matched itself"); } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the lint level is defined here - --> $DIR/cant-hide-behind-doubly-indirect-embedded.rs:7:9 - | -LL | #![warn(indirect_structural_match)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(nontrivial_structural_match)]` 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 #62411 + = note: for more information, see issue #73448 warning: 1 warning emitted diff --git a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.stderr b/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.stderr index c8c36510542a2..ddee99e76bbb9 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.stderr +++ b/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.stderr @@ -1,16 +1,12 @@ -warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `&&WrapParam` in a pattern, the constant's initializer must be trivial or all types in the constant must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/cant-hide-behind-doubly-indirect-param.rs:24:9 | LL | WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM matched itself"); } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the lint level is defined here - --> $DIR/cant-hide-behind-doubly-indirect-param.rs:7:9 - | -LL | #![warn(indirect_structural_match)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(nontrivial_structural_match)]` 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 #62411 + = note: for more information, see issue #73448 warning: 1 warning emitted diff --git a/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.rs b/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.rs index 6ebb948d736ec..b5e19611da83a 100644 --- a/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.rs +++ b/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.rs @@ -10,7 +10,7 @@ // Issue 62307 pointed out a case where the structural-match checking // was too shallow. -#![warn(indirect_structural_match)] +#![warn(indirect_structural_match, nontrivial_structural_match)] // run-pass #[derive(Debug)] diff --git a/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.stderr b/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.stderr index ae011dfcdba90..7f4b4923332a4 100644 --- a/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.stderr +++ b/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.stderr @@ -1,25 +1,25 @@ -warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `&&B` in a pattern, the constant's initializer must be trivial or all types in the constant must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:31:9 | LL | RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); } | ^^^^^ | note: the lint level is defined here - --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:13:9 + --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:13:36 | -LL | #![warn(indirect_structural_match)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(indirect_structural_match, nontrivial_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ = 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 #62411 + = note: for more information, see issue #73448 -warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `&&B` in a pattern, the constant's initializer must be trivial or all types in the constant must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:38:9 | LL | RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1); } | ^^^^^ | = 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 #62411 + = note: for more information, see issue #73448 warning: 2 warnings emitted diff --git a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs index 479d6cd9af765..54fc4956b9b28 100644 --- a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs +++ b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs @@ -12,9 +12,10 @@ const LEAK_FREE: Bar = leak_free(); fn leak_free_test() { match todo!() { LEAK_FREE => (), - //~^ opaque types cannot be used in patterns + //~^ `impl Send` cannot be used in patterns + //~| `impl Send` cannot be used in patterns _ => (), } } -fn main() { } +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr index ae0d8e8d4239c..90b44f6598df6 100644 --- a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr +++ b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr @@ -1,8 +1,14 @@ -error: opaque types cannot be used in patterns +error: `impl Send` cannot be used in patterns --> $DIR/structural-match-no-leak.rs:14:9 | LL | LEAK_FREE => (), | ^^^^^^^^^ -error: aborting due to previous error +error: `impl Send` cannot be used in patterns + --> $DIR/structural-match-no-leak.rs:14:9 + | +LL | LEAK_FREE => (), + | ^^^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/src/test/ui/type-alias-impl-trait/structural-match.rs b/src/test/ui/type-alias-impl-trait/structural-match.rs index 481448d64b1aa..5fe5bb4bdeaa8 100644 --- a/src/test/ui/type-alias-impl-trait/structural-match.rs +++ b/src/test/ui/type-alias-impl-trait/structural-match.rs @@ -13,9 +13,10 @@ const VALUE: Foo = value(); fn test() { match todo!() { VALUE => (), - //~^ opaque types cannot be used in patterns + //~^ `impl Send` cannot be used in patterns + //~| `impl Send` cannot be used in patterns _ => (), } } -fn main() { } +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/structural-match.stderr b/src/test/ui/type-alias-impl-trait/structural-match.stderr index ad9036a87d1d9..7aca3ba8640f1 100644 --- a/src/test/ui/type-alias-impl-trait/structural-match.stderr +++ b/src/test/ui/type-alias-impl-trait/structural-match.stderr @@ -1,8 +1,14 @@ -error: opaque types cannot be used in patterns +error: `impl Send` cannot be used in patterns --> $DIR/structural-match.rs:15:9 | LL | VALUE => (), | ^^^^^ -error: aborting due to previous error +error: `impl Send` cannot be used in patterns + --> $DIR/structural-match.rs:15:9 + | +LL | VALUE => (), + | ^^^^^ + +error: aborting due to 2 previous errors From d99bb9d31c9fb170c1f80c20511d18e433cc5e9c Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Mon, 21 Sep 2020 00:46:40 +0800 Subject: [PATCH 0736/1052] liballoc bench use imported path Bencher test is already in scope, no need to use the full path --- library/alloc/benches/vec.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/library/alloc/benches/vec.rs b/library/alloc/benches/vec.rs index 6703a99b15155..b295342f3610e 100644 --- a/library/alloc/benches/vec.rs +++ b/library/alloc/benches/vec.rs @@ -496,7 +496,7 @@ bench_in_place![ ]; #[bench] -fn bench_in_place_recycle(b: &mut test::Bencher) { +fn bench_in_place_recycle(b: &mut Bencher) { let mut data = vec![0; 1000]; b.iter(|| { @@ -513,7 +513,7 @@ fn bench_in_place_recycle(b: &mut test::Bencher) { } #[bench] -fn bench_in_place_zip_recycle(b: &mut test::Bencher) { +fn bench_in_place_zip_recycle(b: &mut Bencher) { let mut data = vec![0u8; 1000]; let mut rng = rand::thread_rng(); let mut subst = vec![0u8; 1000]; @@ -533,7 +533,7 @@ fn bench_in_place_zip_recycle(b: &mut test::Bencher) { } #[bench] -fn bench_in_place_zip_iter_mut(b: &mut test::Bencher) { +fn bench_in_place_zip_iter_mut(b: &mut Bencher) { let mut data = vec![0u8; 256]; let mut rng = rand::thread_rng(); let mut subst = vec![0u8; 1000]; @@ -558,7 +558,7 @@ impl Drop for Droppable { } #[bench] -fn bench_in_place_collect_droppable(b: &mut test::Bencher) { +fn bench_in_place_collect_droppable(b: &mut Bencher) { let v: Vec = std::iter::repeat_with(|| Droppable(0)).take(1000).collect(); b.iter(|| { v.clone() @@ -571,13 +571,13 @@ fn bench_in_place_collect_droppable(b: &mut test::Bencher) { } #[bench] -fn bench_chain_collect(b: &mut test::Bencher) { +fn bench_chain_collect(b: &mut Bencher) { let data = black_box([0; LEN]); b.iter(|| data.iter().cloned().chain([1].iter().cloned()).collect::>()); } #[bench] -fn bench_chain_chain_collect(b: &mut test::Bencher) { +fn bench_chain_chain_collect(b: &mut Bencher) { let data = black_box([0; LEN]); b.iter(|| { data.iter() @@ -589,7 +589,7 @@ fn bench_chain_chain_collect(b: &mut test::Bencher) { } #[bench] -fn bench_nest_chain_chain_collect(b: &mut test::Bencher) { +fn bench_nest_chain_chain_collect(b: &mut Bencher) { let data = black_box([0; LEN]); b.iter(|| { data.iter().cloned().chain([1].iter().chain([2].iter()).cloned()).collect::>() @@ -616,12 +616,12 @@ pub fn map_fast(l: &[(u32, u32)]) -> Vec { const LEN: usize = 16384; #[bench] -fn bench_range_map_collect(b: &mut test::Bencher) { +fn bench_range_map_collect(b: &mut Bencher) { b.iter(|| (0..LEN).map(|_| u32::default()).collect::>()); } #[bench] -fn bench_chain_extend_ref(b: &mut test::Bencher) { +fn bench_chain_extend_ref(b: &mut Bencher) { let data = black_box([0; LEN]); b.iter(|| { let mut v = Vec::::with_capacity(data.len() + 1); @@ -631,7 +631,7 @@ fn bench_chain_extend_ref(b: &mut test::Bencher) { } #[bench] -fn bench_chain_extend_value(b: &mut test::Bencher) { +fn bench_chain_extend_value(b: &mut Bencher) { let data = black_box([0; LEN]); b.iter(|| { let mut v = Vec::::with_capacity(data.len() + 1); @@ -641,7 +641,7 @@ fn bench_chain_extend_value(b: &mut test::Bencher) { } #[bench] -fn bench_rev_1(b: &mut test::Bencher) { +fn bench_rev_1(b: &mut Bencher) { let data = black_box([0; LEN]); b.iter(|| { let mut v = Vec::::new(); @@ -651,13 +651,13 @@ fn bench_rev_1(b: &mut test::Bencher) { } #[bench] -fn bench_rev_2(b: &mut test::Bencher) { +fn bench_rev_2(b: &mut Bencher) { let data = black_box([0; LEN]); b.iter(|| example_plain_slow(&data)); } #[bench] -fn bench_map_regular(b: &mut test::Bencher) { +fn bench_map_regular(b: &mut Bencher) { let data = black_box([(0, 0); LEN]); b.iter(|| { let mut v = Vec::::new(); @@ -667,7 +667,7 @@ fn bench_map_regular(b: &mut test::Bencher) { } #[bench] -fn bench_map_fast(b: &mut test::Bencher) { +fn bench_map_fast(b: &mut Bencher) { let data = black_box([(0, 0); LEN]); b.iter(|| map_fast(&data)); } From 53aaa1e532657390edfbe046a3f18d95e9543424 Mon Sep 17 00:00:00 2001 From: Julian Wollersberger Date: Sun, 20 Sep 2020 19:07:52 +0200 Subject: [PATCH 0737/1052] To avoid monomorphizing `psm::on_stack::with_on_stack` 1500 times, I made a change in `stacker` to wrap the callback in `dyn`. --- Cargo.lock | 4 ++-- compiler/rustc_data_structures/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4ec750f7b4226..21e65dd74580d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4436,9 +4436,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "stacker" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92bc346006ae78c539d6ab2cf1a1532bc657b8339c464877a990ec82073c66f" +checksum = "21ccb4c06ec57bc82d0f610f1a2963d7648700e43a6f513e564b9c89f7991786" dependencies = [ "cc", "cfg-if", diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 3dc55cab95a11..bf75fc96f1fab 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -26,7 +26,7 @@ rustc_index = { path = "../rustc_index", package = "rustc_index" } bitflags = "1.2.1" measureme = "0.7.1" libc = "0.2" -stacker = "0.1.11" +stacker = "0.1.12" tempfile = "3.0.5" [dependencies.parking_lot] From 37ec0458507447565f3abdba0fab182c0dcd0e14 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Sun, 20 Sep 2020 00:45:29 +0200 Subject: [PATCH 0738/1052] BTreeMap: extra testing unveiling mistakes in future PR --- .../alloc/src/collections/btree/map/tests.rs | 19 +++++++++++++++++++ library/alloc/src/collections/btree/node.rs | 12 ++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index d2cd6b8e5241a..8018514fa1776 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -88,6 +88,11 @@ impl<'a, K: 'a, V: 'a> BTreeMap { let min_len = if is_root { 1 } else { node::MIN_LEN }; assert!(node.len() >= min_len, "{} < {}", node.len(), min_len); + for idx in 0..=node.len() { + let edge = unsafe { node::Handle::new_edge(node, idx) }; + assert!(edge.descend().ascend().ok().unwrap() == edge); + } + internal_length += node.len(); } Position::InternalKV(kv) => { @@ -1846,3 +1851,17 @@ fn test_into_values() { assert!(values.contains(&'b')); assert!(values.contains(&'c')); } + +#[test] +fn test_insert_remove_intertwined() { + let loops = if cfg!(miri) { 100 } else { 1_000_000 }; + let mut map = BTreeMap::new(); + let mut i = 1; + for _ in 0..loops { + i = (i + 421) & 0xFF; + map.insert(i, i); + map.remove(&(0xFF - i)); + } + + map.check(); +} diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index f52d07c9b8c94..f1d66e973cb52 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -613,8 +613,8 @@ impl<'a, K, V> NodeRef, K, V, marker::Internal> { } impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { - /// Adds a key/value pair and an edge to go to the right of that pair to - /// the end of the node. + /// Adds a key/value pair, and an edge to go to the right of that pair, + /// to the end of the node. pub fn push(&mut self, key: K, val: V, edge: Root) { assert!(edge.height == self.height - 1); @@ -630,8 +630,8 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { } } - /// Adds a key/value pair and an edge to go to the left of that pair to - /// the beginning of the node. + /// Adds a key/value pair, and an edge to go to the left of that pair, + /// to the beginning of the node. pub fn push_front(&mut self, key: K, val: V, edge: Root) { assert!(edge.height == self.height - 1); assert!(self.len() < CAPACITY); @@ -1152,7 +1152,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, mark /// /// - The node is truncated to only contain the key/value pairs to the right of /// this handle. - /// - The key and value pointed to by this handle and extracted. + /// - 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, K, V, marker::Leaf>, K, V, Root) { @@ -1196,7 +1196,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, /// /// - The node is truncated to only contain the edges and key/value pairs to the /// right of this handle. - /// - The key and value pointed to by this handle and extracted. + /// - 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, K, V, marker::Internal>, K, V, Root) { From 6d195615872440798ac47ad7a4d8fd090fcbc24a Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sun, 6 Sep 2020 19:57:07 -0400 Subject: [PATCH 0739/1052] Set BUILD_TRIPLE via build script This moves build triple discovery for rustbuild from bootstrap.py into a build script, meaning it will "just work" if building rustbuild via Cargo rather than Python. --- src/bootstrap/Cargo.toml | 1 + src/bootstrap/bootstrap.py | 1 - src/bootstrap/build.rs | 3 +++ src/bootstrap/config.rs | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 src/bootstrap/build.rs diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index faec2c53742ec..890315a744e56 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -3,6 +3,7 @@ authors = ["The Rust Project Developers"] name = "bootstrap" version = "0.0.0" edition = "2018" +build = "build.rs" [lib] path = "lib.rs" diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 5f78031e1c7cb..c9a9a484ee338 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -1032,7 +1032,6 @@ def bootstrap(help_triggered): args = [build.bootstrap_binary()] args.extend(sys.argv[1:]) env = os.environ.copy() - env["BUILD"] = build.build env["SRC"] = build.rust_root env["BOOTSTRAP_PARENT_ID"] = str(os.getpid()) env["BOOTSTRAP_PYTHON"] = sys.executable diff --git a/src/bootstrap/build.rs b/src/bootstrap/build.rs new file mode 100644 index 0000000000000..5e5c31de5b6dc --- /dev/null +++ b/src/bootstrap/build.rs @@ -0,0 +1,3 @@ +fn main() { + println!("cargo:rustc-env=BUILD_TRIPLE={}", std::env::var("HOST").unwrap()); +} diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 6de4388495baf..1ec99ef30ffa5 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -487,7 +487,7 @@ impl Config { config.missing_tools = false; // set by bootstrap.py - config.build = TargetSelection::from_user(&env::var("BUILD").expect("'BUILD' to be set")); + config.build = TargetSelection::from_user(&env!("BUILD_TRIPLE")); config.src = Config::path_from_python("SRC"); config.out = Config::path_from_python("BUILD_DIR"); From e21eb613e09a0ecb4eaa141712a389d05c40ffad Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sun, 6 Sep 2020 21:32:55 -0400 Subject: [PATCH 0740/1052] Remove support for different src directory This requires that bootstrap is run from the same worktree as the sources it'll build, but this is basically required for the build to work anyway. You can still run it from a different directory, just that the files it builds must be beside it. --- src/bootstrap/bootstrap.py | 4 +--- src/bootstrap/config.rs | 4 +++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index c9a9a484ee338..c8cb2595d32f4 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -966,7 +966,6 @@ def bootstrap(help_triggered): parser = argparse.ArgumentParser(description='Build rust') parser.add_argument('--config') parser.add_argument('--build') - parser.add_argument('--src') parser.add_argument('--clean', action='store_true') parser.add_argument('-v', '--verbose', action='count', default=0) @@ -975,7 +974,7 @@ def bootstrap(help_triggered): # Configure initial bootstrap build = RustBuild() - build.rust_root = args.src or os.path.abspath(os.path.join(__file__, '../../..')) + build.rust_root = os.path.abspath(os.path.join(__file__, '../../..')) build.verbose = args.verbose build.clean = args.clean @@ -1032,7 +1031,6 @@ def bootstrap(help_triggered): args = [build.bootstrap_binary()] args.extend(sys.argv[1:]) env = os.environ.copy() - env["SRC"] = build.rust_root env["BOOTSTRAP_PARENT_ID"] = str(os.getpid()) env["BOOTSTRAP_PYTHON"] = sys.executable env["BUILD_DIR"] = build.build_dir diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 1ec99ef30ffa5..3ecfac835642f 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -488,7 +488,9 @@ impl Config { // set by bootstrap.py config.build = TargetSelection::from_user(&env!("BUILD_TRIPLE")); - config.src = Config::path_from_python("SRC"); + let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + // Undo `src/bootstrap` + config.src = manifest_dir.parent().unwrap().parent().unwrap().to_owned(); config.out = Config::path_from_python("BUILD_DIR"); config.initial_rustc = Config::path_from_python("RUSTC"); From a625ab77e87b31ac6689e97f2f10cb09773bed38 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 7 Sep 2020 12:02:50 -0400 Subject: [PATCH 0741/1052] Discover Rust toolchain without Python --- src/bootstrap/bootstrap.py | 4 ---- src/bootstrap/build.rs | 25 ++++++++++++++++++++++++- src/bootstrap/config.rs | 19 ++++++++++++------- 3 files changed, 36 insertions(+), 12 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index c8cb2595d32f4..e58cf0d164197 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -1035,12 +1035,8 @@ def bootstrap(help_triggered): env["BOOTSTRAP_PYTHON"] = sys.executable env["BUILD_DIR"] = build.build_dir env["RUSTC_BOOTSTRAP"] = '1' - env["CARGO"] = build.cargo() - env["RUSTC"] = build.rustc() if toml_path: env["BOOTSTRAP_CONFIG"] = toml_path - if build.rustfmt(): - env["RUSTFMT"] = build.rustfmt() run(args, env=env, verbose=build.verbose) diff --git a/src/bootstrap/build.rs b/src/bootstrap/build.rs index 5e5c31de5b6dc..d40b924e0ff5f 100644 --- a/src/bootstrap/build.rs +++ b/src/bootstrap/build.rs @@ -1,3 +1,26 @@ +use std::env; +use std::path::PathBuf; + fn main() { - println!("cargo:rustc-env=BUILD_TRIPLE={}", std::env::var("HOST").unwrap()); + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rustc-env=BUILD_TRIPLE={}", env::var("HOST").unwrap()); + + // This may not be a canonicalized path. + let mut rustc = PathBuf::from(env::var_os("RUSTC").unwrap()); + + if rustc.is_relative() { + for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) { + let absolute = dir.join(&rustc); + if absolute.exists() { + rustc = absolute; + break; + } + } + } + assert!(rustc.is_absolute()); + + // FIXME: if the path is not utf-8, this is going to break. Unfortunately + // Cargo doesn't have a way for us to specify non-utf-8 paths easily, so + // we'll need to invent some encoding scheme if this becomes a problem. + println!("cargo:rustc-env=RUSTC={}", rustc.to_str().unwrap()); } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 3ecfac835642f..d4f6ce64decc7 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -291,7 +291,7 @@ struct Build { build_dir: Option, cargo: Option, rustc: Option, - rustfmt: Option, /* allow bootstrap.py to use rustfmt key */ + rustfmt: Option, docs: Option, compiler_docs: Option, submodules: Option, @@ -493,9 +493,8 @@ impl Config { config.src = manifest_dir.parent().unwrap().parent().unwrap().to_owned(); config.out = Config::path_from_python("BUILD_DIR"); - config.initial_rustc = Config::path_from_python("RUSTC"); - config.initial_cargo = Config::path_from_python("CARGO"); - config.initial_rustfmt = env::var_os("RUSTFMT").map(Config::normalize_python_path); + config.initial_cargo = PathBuf::from(env!("CARGO")); + config.initial_rustc = PathBuf::from(env!("RUSTC")); config } @@ -584,6 +583,9 @@ impl Config { set(&mut config.full_bootstrap, build.full_bootstrap); set(&mut config.extended, build.extended); config.tools = build.tools; + if build.rustfmt.is_some() { + config.initial_rustfmt = build.rustfmt; + } set(&mut config.verbose, build.verbose); set(&mut config.sanitizers, build.sanitizers); set(&mut config.profiler, build.profiler); @@ -838,12 +840,15 @@ impl Config { set(&mut config.missing_tools, t.missing_tools); } + // Cargo does not provide a RUSTFMT environment variable, so we + // synthesize it manually. Note that we also later check the config.toml + // and set this to that path if necessary. + let rustfmt = config.initial_rustc.with_file_name(exe("rustfmt", config.build)); + config.initial_rustfmt = if rustfmt.exists() { Some(rustfmt) } else { None }; + // Now that we've reached the end of our configuration, infer the // default values for all options that we haven't otherwise stored yet. - set(&mut config.initial_rustc, build.rustc.map(PathBuf::from)); - set(&mut config.initial_cargo, build.cargo.map(PathBuf::from)); - config.llvm_skip_rebuild = llvm_skip_rebuild.unwrap_or(false); let default = false; From c9c8fb88cf1be7e0a6bd6fd049d8d28fb5d86135 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 12 Sep 2020 00:42:52 -0400 Subject: [PATCH 0742/1052] Add sample defaults for config.toml - Allow including defaults in `src/bootstrap/defaults` using `profile = "..."` - Add default config files - Combine config files using the merge dependency. - Add comments to default config files - Add a README asking to open an issue if the defaults are bad - Give a loud error if trying to merge `.target`, since it's not currently supported - Use an exhaustive match - Use `` in config.toml.example to avoid confusion - Fix bugs in `Merge` derives Previously, it would completely ignore the profile defaults if there were any settings in `config.toml`. I sent an email to the `merge` maintainer asking them to make the behavior in this commit the default. This introduces a new dependency on `merge` that hasn't yet been vetted. I want to improve the output when `include = "x"` isn't found: ``` thread 'main' panicked at 'fs::read_to_string(&file) failed with No such file or directory (os error 2) ("configuration file did not exist")', src/bootstrap/config.rs:522:28 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace failed to run: /home/joshua/rustc/build/bootstrap/debug/bootstrap test tidy Build completed unsuccessfully in 0:00:00 ``` However that seems like it could be fixed in a follow-up. --- Cargo.lock | 23 +++++++ config.toml.example | 10 +++ src/bootstrap/Cargo.toml | 1 + src/bootstrap/config.rs | 76 ++++++++++++++------- src/bootstrap/defaults/README.md | 11 +++ src/bootstrap/defaults/config.toml.codegen | 13 ++++ src/bootstrap/defaults/config.toml.compiler | 8 +++ src/bootstrap/defaults/config.toml.library | 10 +++ src/bootstrap/defaults/config.toml.user | 9 +++ 9 files changed, 136 insertions(+), 25 deletions(-) create mode 100644 src/bootstrap/defaults/README.md create mode 100644 src/bootstrap/defaults/config.toml.codegen create mode 100644 src/bootstrap/defaults/config.toml.compiler create mode 100644 src/bootstrap/defaults/config.toml.library create mode 100644 src/bootstrap/defaults/config.toml.user diff --git a/Cargo.lock b/Cargo.lock index d3f777bc663dd..4c55fea30e0e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -207,6 +207,7 @@ dependencies = [ "ignore", "lazy_static", "libc", + "merge", "num_cpus", "opener", "pretty_assertions", @@ -1900,6 +1901,28 @@ dependencies = [ "autocfg", ] +[[package]] +name = "merge" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10bbef93abb1da61525bbc45eeaff6473a41907d19f8f9aa5168d214e10693e9" +dependencies = [ + "merge_derive", + "num-traits", +] + +[[package]] +name = "merge_derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "209d075476da2e63b4b29e72a2ef627b840589588e71400a25e3565c4f849d07" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "minifier" version = "0.0.33" diff --git a/config.toml.example b/config.toml.example index 99e6f9dceb41c..8bf1b48ce830e 100644 --- a/config.toml.example +++ b/config.toml.example @@ -9,6 +9,16 @@ # a custom configuration file can also be specified with `--config` to the build # system. +# ============================================================================= +# Global Settings +# ============================================================================= + +# Use different pre-set defaults than the global defaults. +# +# See `src/bootstrap/defaults` for more information. +# Note that this has no default value (x.py uses the defaults in `config.toml.example`). +#profile = + # ============================================================================= # Tweaking how LLVM is compiled # ============================================================================= diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index faec2c53742ec..0177a9dab97e3 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -48,6 +48,7 @@ lazy_static = "1.3.0" time = "0.1" ignore = "0.4.10" opener = "0.4" +merge = "0.1.0" [target.'cfg(windows)'.dependencies.winapi] version = "0.3" diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 7e2cb7721865e..d925af19a8426 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -16,6 +16,7 @@ use crate::flags::Flags; pub use crate::flags::Subcommand; use crate::util::exe; use build_helper::t; +use merge::Merge; use serde::Deserialize; macro_rules! check_ci_llvm { @@ -278,10 +279,31 @@ struct TomlConfig { rust: Option, target: Option>, dist: Option, + profile: Option, +} + +impl Merge for TomlConfig { + fn merge(&mut self, TomlConfig { build, install, llvm, rust, dist, target, profile: _ }: Self) { + fn do_merge(x: &mut Option, y: Option) { + if let Some(new) = y { + if let Some(original) = x { + original.merge(new); + } else { + *x = Some(new); + } + } + }; + do_merge(&mut self.build, build); + do_merge(&mut self.install, install); + do_merge(&mut self.llvm, llvm); + do_merge(&mut self.rust, rust); + do_merge(&mut self.dist, dist); + assert!(target.is_none(), "merging target-specific config is not currently supported"); + } } /// TOML representation of various global build decisions. -#[derive(Deserialize, Default, Clone)] +#[derive(Deserialize, Default, Clone, Merge)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct Build { build: Option, @@ -321,7 +343,7 @@ struct Build { } /// TOML representation of various global install decisions. -#[derive(Deserialize, Default, Clone)] +#[derive(Deserialize, Default, Clone, Merge)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct Install { prefix: Option, @@ -338,7 +360,7 @@ struct Install { } /// TOML representation of how the LLVM build is configured. -#[derive(Deserialize, Default)] +#[derive(Deserialize, Default, Merge)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct Llvm { skip_rebuild: Option, @@ -365,7 +387,7 @@ struct Llvm { download_ci_llvm: Option, } -#[derive(Deserialize, Default, Clone)] +#[derive(Deserialize, Default, Clone, Merge)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct Dist { sign_folder: Option, @@ -389,7 +411,7 @@ impl Default for StringOrBool { } /// TOML representation of how the Rust build is configured. -#[derive(Deserialize, Default)] +#[derive(Deserialize, Default, Merge)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct Rust { optimize: Option, @@ -434,7 +456,7 @@ struct Rust { } /// TOML representation of how each build target is configured. -#[derive(Deserialize, Default)] +#[derive(Deserialize, Default, Merge)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct TomlTarget { cc: Option, @@ -523,27 +545,31 @@ impl Config { } #[cfg(test)] - let toml = TomlConfig::default(); + let get_toml = |_| TomlConfig::default(); #[cfg(not(test))] - let toml = flags - .config - .map(|file| { - use std::process; - - let contents = t!(fs::read_to_string(&file)); - match toml::from_str(&contents) { - Ok(table) => table, - Err(err) => { - println!( - "failed to parse TOML configuration '{}': {}", - file.display(), - err - ); - process::exit(2); - } + let get_toml = |file: PathBuf| { + use std::process; + + let contents = t!(fs::read_to_string(&file), "configuration file did not exist"); + match toml::from_str(&contents) { + Ok(table) => table, + Err(err) => { + println!("failed to parse TOML configuration '{}': {}", file.display(), err); + process::exit(2); } - }) - .unwrap_or_else(TomlConfig::default); + } + }; + + let mut toml = flags.config.map(get_toml).unwrap_or_else(TomlConfig::default); + if let Some(include) = &toml.profile { + let mut include_path = config.src.clone(); + include_path.push("src"); + include_path.push("bootstrap"); + include_path.push("defaults"); + include_path.push(format!("config.toml.{}", include)); + let included_toml = get_toml(include_path); + toml.merge(included_toml); + } let build = toml.build.unwrap_or_default(); diff --git a/src/bootstrap/defaults/README.md b/src/bootstrap/defaults/README.md new file mode 100644 index 0000000000000..a91fc3538eb55 --- /dev/null +++ b/src/bootstrap/defaults/README.md @@ -0,0 +1,11 @@ +# About bootstrap defaults + +These defaults are intended to be a good starting point for working with x.py, +with the understanding that no one set of defaults make sense for everyone. + +They are still experimental, and we'd appreciate your help improving them! +If you use a setting that's not in these defaults that you think others would benefit from, please [file an issue] or make a PR with the changes. +Similarly, if one of these defaults doesn't match what you use personally, +please open an issue to get it changed. + +[file an issue]: https://github.com/rust-lang/rust/issues/new/choose diff --git a/src/bootstrap/defaults/config.toml.codegen b/src/bootstrap/defaults/config.toml.codegen new file mode 100644 index 0000000000000..a9505922ca7fc --- /dev/null +++ b/src/bootstrap/defaults/config.toml.codegen @@ -0,0 +1,13 @@ +# These defaults are meant for contributors to the compiler who modify codegen or LLVM +[llvm] +# This enables debug-assertions in LLVM, +# catching logic errors in codegen much earlier in the process. +assertions = true + +[rust] +# This enables `RUSTC_LOG=debug`, avoiding confusing situations +# where adding `debug!()` appears to do nothing. +# However, it makes running the compiler slightly slower. +debug-logging = true +# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower. +incremental = true diff --git a/src/bootstrap/defaults/config.toml.compiler b/src/bootstrap/defaults/config.toml.compiler new file mode 100644 index 0000000000000..4772de8a2cb22 --- /dev/null +++ b/src/bootstrap/defaults/config.toml.compiler @@ -0,0 +1,8 @@ +# These defaults are meant for contributors to the compiler who do not modify codegen or LLVM +[rust] +# This enables `RUSTC_LOG=debug`, avoiding confusing situations +# where adding `debug!()` appears to do nothing. +# However, it makes running the compiler slightly slower. +debug-logging = true +# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower. +incremental = true diff --git a/src/bootstrap/defaults/config.toml.library b/src/bootstrap/defaults/config.toml.library new file mode 100644 index 0000000000000..e4316f4d86440 --- /dev/null +++ b/src/bootstrap/defaults/config.toml.library @@ -0,0 +1,10 @@ +# These defaults are meant for contributors to the standard library and documentation. +[build] +# When building the standard library, you almost never want to build the compiler itself. +build-stage = 0 +test-stage = 0 +bench-stage = 0 + +[rust] +# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower. +incremental = true diff --git a/src/bootstrap/defaults/config.toml.user b/src/bootstrap/defaults/config.toml.user new file mode 100644 index 0000000000000..6647061d88fcb --- /dev/null +++ b/src/bootstrap/defaults/config.toml.user @@ -0,0 +1,9 @@ +# These defaults are meant for users and distro maintainers building from source, without intending to make multiple changes. +[build] +# When compiling from source, you almost always want a full stage 2 build, +# which has all the latest optimizations from nightly. +build-stage = 2 +test-stage = 2 +doc-stage = 2 +# When compiling from source, you usually want all tools. +extended = true From 1aac99de25d3e28e4b2a16e8fbe6737d5202f27a Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 10 Sep 2020 10:17:32 -0400 Subject: [PATCH 0743/1052] Provide bootstrap tools with RUSTC in environment --- src/bootstrap/test.rs | 2 ++ src/bootstrap/tool.rs | 4 ++++ src/test/run-make/thumb-none-cortex-m/Makefile | 2 +- src/test/run-make/thumb-none-qemu/script.sh | 4 ++-- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index dc28b8ece2452..a9a8d3783fd1e 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1281,6 +1281,8 @@ impl Step for Compiletest { cmd.arg("--rustfix-coverage"); } + cmd.env("BOOTSTRAP_CARGO", &builder.initial_cargo); + builder.ci_env.force_coloring_in_ci(&mut cmd); builder.info(&format!( diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 5d66632d92ceb..460dffb5c8a57 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -700,6 +700,10 @@ impl<'a> Builder<'a> { } add_dylib_path(lib_paths, &mut cmd); + + // Provide a RUSTC for this command to use. + cmd.env("RUSTC", &self.initial_rustc); + cmd } } diff --git a/src/test/run-make/thumb-none-cortex-m/Makefile b/src/test/run-make/thumb-none-cortex-m/Makefile index 36e51bcab6de2..13385369e4451 100644 --- a/src/test/run-make/thumb-none-cortex-m/Makefile +++ b/src/test/run-make/thumb-none-cortex-m/Makefile @@ -35,4 +35,4 @@ all: # HACK(eddyb) sets `RUSTC_BOOTSTRAP=1` so Cargo can accept nightly features. # These come from the top-level Rust workspace, that this crate is not a # member of, but Cargo tries to load the workspace `Cargo.toml` anyway. - cd $(WORK_DIR) && cd $(CRATE) && env RUSTC_BOOTSTRAP=1 $(CARGO) build --target $(TARGET) -v + cd $(WORK_DIR) && cd $(CRATE) && env RUSTC_BOOTSTRAP=1 $(BOOTSTRAP_CARGO) build --target $(TARGET) -v diff --git a/src/test/run-make/thumb-none-qemu/script.sh b/src/test/run-make/thumb-none-qemu/script.sh index c5cbff5c3c36d..045d02a8ed25d 100644 --- a/src/test/run-make/thumb-none-qemu/script.sh +++ b/src/test/run-make/thumb-none-qemu/script.sh @@ -12,8 +12,8 @@ pushd $WORK_DIR # These come from the top-level Rust workspace, that this crate is not a # member of, but Cargo tries to load the workspace `Cargo.toml` anyway. env RUSTC_BOOTSTRAP=1 RUSTFLAGS="-C linker=arm-none-eabi-ld -C link-arg=-Tlink.x" \ - $CARGO run --target $TARGET | grep "x = 42" + $BOOTSTRAP_CARGO run --target $TARGET | grep "x = 42" env RUSTC_BOOTSTRAP=1 RUSTFLAGS="-C linker=arm-none-eabi-ld -C link-arg=-Tlink.x" \ - $CARGO run --target $TARGET --release | grep "x = 42" + $BOOTSTRAP_CARGO run --target $TARGET --release | grep "x = 42" popd popd From cf33aad8fdd3885fbc26518aaccff0788d1a21a7 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 10 Sep 2020 10:52:27 -0400 Subject: [PATCH 0744/1052] Specify output directory for bootstrap tests --- src/bootstrap/builder/tests.rs | 3 +++ src/bootstrap/test.rs | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index f96925f927086..cd90021507ec7 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -10,6 +10,9 @@ fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config { config.dry_run = true; config.ninja_in_file = false; // try to avoid spurious failures in dist where we create/delete each others file + config.out = PathBuf::from(env::var_os("BOOTSTRAP_OUTPUT_DIRECTORY").unwrap()); + config.initial_rustc = PathBuf::from(env::var_os("RUSTC").unwrap()); + config.initial_cargo = PathBuf::from(env::var_os("BOOTSTRAP_INITIAL_CARGO").unwrap()); let dir = config .out .join("tmp-rustbuild-tests") diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index a9a8d3783fd1e..00522ee6b673c 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -2024,6 +2024,8 @@ impl Step for Bootstrap { .current_dir(builder.src.join("src/bootstrap")) .env("RUSTFLAGS", "-Cdebuginfo=2") .env("CARGO_TARGET_DIR", builder.out.join("bootstrap")) + .env("BOOTSTRAP_OUTPUT_DIRECTORY", &builder.config.out) + .env("BOOTSTRAP_INITIAL_CARGO", &builder.config.initial_cargo) .env("RUSTC_BOOTSTRAP", "1") .env("RUSTC", &builder.initial_rustc); if let Some(flags) = option_env!("RUSTFLAGS") { From 9486f728790e1fb15bb88db672d2f164078a19eb Mon Sep 17 00:00:00 2001 From: CDirkx Date: Mon, 31 Aug 2020 02:11:48 +0200 Subject: [PATCH 0745/1052] Stabilize some Option methods as const Stabilize the following methods of `Option` as const: - `is_some` - `is_none` - `as_ref` Possible because of stabilization of #49146 (Allow if and match in constants). --- library/core/src/option.rs | 6 +++--- src/test/ui/consts/const-option.rs | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 7e560d63fe23b..b1589008be073 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -175,7 +175,7 @@ impl Option { /// ``` #[must_use = "if you intended to assert that this has a value, consider `.unwrap()` instead"] #[inline] - #[rustc_const_unstable(feature = "const_option", issue = "67441")] + #[rustc_const_stable(feature = "const_option", since = "1.48.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn is_some(&self) -> bool { matches!(*self, Some(_)) @@ -195,7 +195,7 @@ impl Option { #[must_use = "if you intended to assert that this doesn't have a value, consider \ `.and_then(|| panic!(\"`Option` had a value when expected `None`\"))` instead"] #[inline] - #[rustc_const_unstable(feature = "const_option", issue = "67441")] + #[rustc_const_stable(feature = "const_option", since = "1.48.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn is_none(&self) -> bool { !self.is_some() @@ -254,7 +254,7 @@ impl Option { /// println!("still can print text: {:?}", text); /// ``` #[inline] - #[rustc_const_unstable(feature = "const_option", issue = "67441")] + #[rustc_const_stable(feature = "const_option", since = "1.48.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn as_ref(&self) -> Option<&T> { match *self { diff --git a/src/test/ui/consts/const-option.rs b/src/test/ui/consts/const-option.rs index fbf20b9db6741..793f78c8d20fa 100644 --- a/src/test/ui/consts/const-option.rs +++ b/src/test/ui/consts/const-option.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(const_option)] - const X: Option = Some(32); const Y: Option<&i32> = X.as_ref(); From 4f859fbcfc9080687f4a52a96e0ec98290e02f19 Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Fri, 4 Sep 2020 00:13:25 +0200 Subject: [PATCH 0746/1052] Move const tests for `Option` to `library\core` Part of #76268 --- library/core/tests/option.rs | 16 ++++++++++++++++ src/test/ui/consts/const-option.rs | 12 ------------ 2 files changed, 16 insertions(+), 12 deletions(-) delete mode 100644 src/test/ui/consts/const-option.rs diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs index b46bcfd16d283..9e86e07dd91a3 100644 --- a/library/core/tests/option.rs +++ b/library/core/tests/option.rs @@ -356,3 +356,19 @@ fn test_replace() { assert_eq!(x, Some(3)); assert_eq!(old, None); } + +#[test] +fn option_const() { + // test that the methods of `Option` are usable in a const context + + const OPTION: Option = Some(32); + + const REF: Option<&usize> = OPTION.as_ref(); + assert_eq!(REF, Some(&32)); + + const IS_SOME: bool = OPTION.is_some(); + assert!(IS_SOME); + + const IS_NONE: bool = OPTION.is_none(); + assert!(!IS_NONE); +} diff --git a/src/test/ui/consts/const-option.rs b/src/test/ui/consts/const-option.rs deleted file mode 100644 index 793f78c8d20fa..0000000000000 --- a/src/test/ui/consts/const-option.rs +++ /dev/null @@ -1,12 +0,0 @@ -// run-pass - -const X: Option = Some(32); -const Y: Option<&i32> = X.as_ref(); - -const IS_SOME: bool = X.is_some(); -const IS_NONE: bool = Y.is_none(); - -fn main() { - assert!(IS_SOME); - assert!(!IS_NONE) -} From e58d0627b8e12644bdf4e915b5c5bc0d3c37be29 Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Sun, 20 Sep 2020 23:59:34 +0200 Subject: [PATCH 0747/1052] Update Clippy testcases Update the test `redundant_pattern_matching`: check if `is_some` and `is_none` are suggested within const contexts. --- .../tests/ui/redundant_pattern_matching.fixed | 39 ++++------ .../tests/ui/redundant_pattern_matching.rs | 45 ++++++------ .../ui/redundant_pattern_matching.stderr | 72 +++++++++++++++---- 3 files changed, 91 insertions(+), 65 deletions(-) diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching.fixed index 08bfe7c78d38b..8084fdefdc23e 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching.fixed +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching.fixed @@ -76,7 +76,6 @@ fn main() { takes_bool(x); issue5504(); - issue5697(); issue6067(); let _ = if gen_opt().is_some() { @@ -129,41 +128,31 @@ fn issue5504() { while m!().is_some() {} } -// None of these should be linted because none of the suggested methods -// are `const fn` without toggling a feature. -const fn issue5697() { - if let Some(_) = Some(42) {} - - if let None = None::<()> {} - - while let Some(_) = Some(42) {} - - while let None = None::<()> {} - - match Some(42) { - Some(_) => true, - None => false, - }; - - match None::<()> { - Some(_) => false, - None => true, - }; -} - // Methods that are unstable const should not be suggested within a const context, see issue #5697. -// However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result` were stabilized as const, -// so the following should be linted. +// However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result`, and `is_some` and `is_none` +// of `Option` were stabilized as const, so the following should be linted. const fn issue6067() { if Ok::(42).is_ok() {} if Err::(42).is_err() {} + if Some(42).is_some() {} + + if None::<()>.is_none() {} + while Ok::(10).is_ok() {} while Ok::(10).is_err() {} + while Some(42).is_some() {} + + while None::<()>.is_none() {} + Ok::(42).is_ok(); Err::(42).is_err(); + + Some(42).is_some(); + + None::<()>.is_none(); } diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching.rs index c0660c6ac3947..48a32cb1c7b7d 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching.rs +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching.rs @@ -97,7 +97,6 @@ fn main() { takes_bool(x); issue5504(); - issue5697(); issue6067(); let _ = if let Some(_) = gen_opt() { @@ -150,40 +149,26 @@ fn issue5504() { while let Some(_) = m!() {} } -// None of these should be linted because none of the suggested methods -// are `const fn` without toggling a feature. -const fn issue5697() { - if let Some(_) = Some(42) {} - - if let None = None::<()> {} - - while let Some(_) = Some(42) {} - - while let None = None::<()> {} - - match Some(42) { - Some(_) => true, - None => false, - }; - - match None::<()> { - Some(_) => false, - None => true, - }; -} - // Methods that are unstable const should not be suggested within a const context, see issue #5697. -// However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result` were stabilized as const, -// so the following should be linted. +// However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result`, and `is_some` and `is_none` +// of `Option` were stabilized as const, so the following should be linted. const fn issue6067() { if let Ok(_) = Ok::(42) {} if let Err(_) = Err::(42) {} + if let Some(_) = Some(42) {} + + if let None = None::<()> {} + while let Ok(_) = Ok::(10) {} while let Err(_) = Ok::(10) {} + while let Some(_) = Some(42) {} + + while let None = None::<()> {} + match Ok::(42) { Ok(_) => true, Err(_) => false, @@ -193,4 +178,14 @@ const fn issue6067() { Ok(_) => false, Err(_) => true, }; + + match Some(42) { + Some(_) => true, + None => false, + }; + + match None::<()> { + Some(_) => false, + None => true, + }; } diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching.stderr index efd2f9903ec9c..17185217e8950 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching.stderr +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching.stderr @@ -149,79 +149,103 @@ LL | let x = if let Some(_) = opt { true } else { false }; | -------^^^^^^^------ help: try this: `if opt.is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:103:20 + --> $DIR/redundant_pattern_matching.rs:102:20 | LL | let _ = if let Some(_) = gen_opt() { | -------^^^^^^^------------ help: try this: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:105:19 + --> $DIR/redundant_pattern_matching.rs:104:19 | LL | } else if let None = gen_opt() { | -------^^^^------------ help: try this: `if gen_opt().is_none()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:107:19 + --> $DIR/redundant_pattern_matching.rs:106:19 | LL | } else if let Ok(_) = gen_res() { | -------^^^^^------------ help: try this: `if gen_res().is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:109:19 + --> $DIR/redundant_pattern_matching.rs:108:19 | LL | } else if let Err(_) = gen_res() { | -------^^^^^^------------ help: try this: `if gen_res().is_err()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:142:19 + --> $DIR/redundant_pattern_matching.rs:141:19 | LL | while let Some(_) = r#try!(result_opt()) {} | ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:143:16 + --> $DIR/redundant_pattern_matching.rs:142:16 | LL | if let Some(_) = r#try!(result_opt()) {} | -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:149:12 + --> $DIR/redundant_pattern_matching.rs:148:12 | LL | if let Some(_) = m!() {} | -------^^^^^^^------- help: try this: `if m!().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:150:15 + --> $DIR/redundant_pattern_matching.rs:149:15 | LL | while let Some(_) = m!() {} | ----------^^^^^^^------- help: try this: `while m!().is_some()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:179:12 + --> $DIR/redundant_pattern_matching.rs:156:12 | LL | if let Ok(_) = Ok::(42) {} | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:181:12 + --> $DIR/redundant_pattern_matching.rs:158:12 | LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` +error: redundant pattern matching, consider using `is_some()` + --> $DIR/redundant_pattern_matching.rs:160:12 + | +LL | if let Some(_) = Some(42) {} + | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` + +error: redundant pattern matching, consider using `is_none()` + --> $DIR/redundant_pattern_matching.rs:162:12 + | +LL | if let None = None::<()> {} + | -------^^^^------------- help: try this: `if None::<()>.is_none()` + error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:183:15 + --> $DIR/redundant_pattern_matching.rs:164:15 | LL | while let Ok(_) = Ok::(10) {} | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:185:15 + --> $DIR/redundant_pattern_matching.rs:166:15 | LL | while let Err(_) = Ok::(10) {} | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` +error: redundant pattern matching, consider using `is_some()` + --> $DIR/redundant_pattern_matching.rs:168:15 + | +LL | while let Some(_) = Some(42) {} + | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` + +error: redundant pattern matching, consider using `is_none()` + --> $DIR/redundant_pattern_matching.rs:170:15 + | +LL | while let None = None::<()> {} + | ----------^^^^------------- help: try this: `while None::<()>.is_none()` + error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:187:5 + --> $DIR/redundant_pattern_matching.rs:172:5 | LL | / match Ok::(42) { LL | | Ok(_) => true, @@ -230,7 +254,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:192:5 + --> $DIR/redundant_pattern_matching.rs:177:5 | LL | / match Err::(42) { LL | | Ok(_) => false, @@ -238,5 +262,23 @@ LL | | Err(_) => true, LL | | }; | |_____^ help: try this: `Err::(42).is_err()` -error: aborting due to 35 previous errors +error: redundant pattern matching, consider using `is_some()` + --> $DIR/redundant_pattern_matching.rs:182:5 + | +LL | / match Some(42) { +LL | | Some(_) => true, +LL | | None => false, +LL | | }; + | |_____^ help: try this: `Some(42).is_some()` + +error: redundant pattern matching, consider using `is_none()` + --> $DIR/redundant_pattern_matching.rs:187:5 + | +LL | / match None::<()> { +LL | | Some(_) => false, +LL | | None => true, +LL | | }; + | |_____^ help: try this: `None::<()>.is_none()` + +error: aborting due to 41 previous errors From ed43385cab3285c008ff91d282eec2313aa607f0 Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Sun, 20 Sep 2020 23:59:34 +0200 Subject: [PATCH 0748/1052] Update Clippy testcases Update the test `redundant_pattern_matching`: check if `is_some` and `is_none` are suggested within const contexts. --- tests/ui/redundant_pattern_matching.fixed | 39 +++++------- tests/ui/redundant_pattern_matching.rs | 45 ++++++-------- tests/ui/redundant_pattern_matching.stderr | 72 +++++++++++++++++----- 3 files changed, 91 insertions(+), 65 deletions(-) diff --git a/tests/ui/redundant_pattern_matching.fixed b/tests/ui/redundant_pattern_matching.fixed index 08bfe7c78d38b..8084fdefdc23e 100644 --- a/tests/ui/redundant_pattern_matching.fixed +++ b/tests/ui/redundant_pattern_matching.fixed @@ -76,7 +76,6 @@ fn main() { takes_bool(x); issue5504(); - issue5697(); issue6067(); let _ = if gen_opt().is_some() { @@ -129,41 +128,31 @@ fn issue5504() { while m!().is_some() {} } -// None of these should be linted because none of the suggested methods -// are `const fn` without toggling a feature. -const fn issue5697() { - if let Some(_) = Some(42) {} - - if let None = None::<()> {} - - while let Some(_) = Some(42) {} - - while let None = None::<()> {} - - match Some(42) { - Some(_) => true, - None => false, - }; - - match None::<()> { - Some(_) => false, - None => true, - }; -} - // Methods that are unstable const should not be suggested within a const context, see issue #5697. -// However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result` were stabilized as const, -// so the following should be linted. +// However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result`, and `is_some` and `is_none` +// of `Option` were stabilized as const, so the following should be linted. const fn issue6067() { if Ok::(42).is_ok() {} if Err::(42).is_err() {} + if Some(42).is_some() {} + + if None::<()>.is_none() {} + while Ok::(10).is_ok() {} while Ok::(10).is_err() {} + while Some(42).is_some() {} + + while None::<()>.is_none() {} + Ok::(42).is_ok(); Err::(42).is_err(); + + Some(42).is_some(); + + None::<()>.is_none(); } diff --git a/tests/ui/redundant_pattern_matching.rs b/tests/ui/redundant_pattern_matching.rs index c0660c6ac3947..48a32cb1c7b7d 100644 --- a/tests/ui/redundant_pattern_matching.rs +++ b/tests/ui/redundant_pattern_matching.rs @@ -97,7 +97,6 @@ fn main() { takes_bool(x); issue5504(); - issue5697(); issue6067(); let _ = if let Some(_) = gen_opt() { @@ -150,40 +149,26 @@ fn issue5504() { while let Some(_) = m!() {} } -// None of these should be linted because none of the suggested methods -// are `const fn` without toggling a feature. -const fn issue5697() { - if let Some(_) = Some(42) {} - - if let None = None::<()> {} - - while let Some(_) = Some(42) {} - - while let None = None::<()> {} - - match Some(42) { - Some(_) => true, - None => false, - }; - - match None::<()> { - Some(_) => false, - None => true, - }; -} - // Methods that are unstable const should not be suggested within a const context, see issue #5697. -// However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result` were stabilized as const, -// so the following should be linted. +// However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result`, and `is_some` and `is_none` +// of `Option` were stabilized as const, so the following should be linted. const fn issue6067() { if let Ok(_) = Ok::(42) {} if let Err(_) = Err::(42) {} + if let Some(_) = Some(42) {} + + if let None = None::<()> {} + while let Ok(_) = Ok::(10) {} while let Err(_) = Ok::(10) {} + while let Some(_) = Some(42) {} + + while let None = None::<()> {} + match Ok::(42) { Ok(_) => true, Err(_) => false, @@ -193,4 +178,14 @@ const fn issue6067() { Ok(_) => false, Err(_) => true, }; + + match Some(42) { + Some(_) => true, + None => false, + }; + + match None::<()> { + Some(_) => false, + None => true, + }; } diff --git a/tests/ui/redundant_pattern_matching.stderr b/tests/ui/redundant_pattern_matching.stderr index efd2f9903ec9c..17185217e8950 100644 --- a/tests/ui/redundant_pattern_matching.stderr +++ b/tests/ui/redundant_pattern_matching.stderr @@ -149,79 +149,103 @@ LL | let x = if let Some(_) = opt { true } else { false }; | -------^^^^^^^------ help: try this: `if opt.is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:103:20 + --> $DIR/redundant_pattern_matching.rs:102:20 | LL | let _ = if let Some(_) = gen_opt() { | -------^^^^^^^------------ help: try this: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:105:19 + --> $DIR/redundant_pattern_matching.rs:104:19 | LL | } else if let None = gen_opt() { | -------^^^^------------ help: try this: `if gen_opt().is_none()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:107:19 + --> $DIR/redundant_pattern_matching.rs:106:19 | LL | } else if let Ok(_) = gen_res() { | -------^^^^^------------ help: try this: `if gen_res().is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:109:19 + --> $DIR/redundant_pattern_matching.rs:108:19 | LL | } else if let Err(_) = gen_res() { | -------^^^^^^------------ help: try this: `if gen_res().is_err()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:142:19 + --> $DIR/redundant_pattern_matching.rs:141:19 | LL | while let Some(_) = r#try!(result_opt()) {} | ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:143:16 + --> $DIR/redundant_pattern_matching.rs:142:16 | LL | if let Some(_) = r#try!(result_opt()) {} | -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:149:12 + --> $DIR/redundant_pattern_matching.rs:148:12 | LL | if let Some(_) = m!() {} | -------^^^^^^^------- help: try this: `if m!().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:150:15 + --> $DIR/redundant_pattern_matching.rs:149:15 | LL | while let Some(_) = m!() {} | ----------^^^^^^^------- help: try this: `while m!().is_some()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:179:12 + --> $DIR/redundant_pattern_matching.rs:156:12 | LL | if let Ok(_) = Ok::(42) {} | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:181:12 + --> $DIR/redundant_pattern_matching.rs:158:12 | LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` +error: redundant pattern matching, consider using `is_some()` + --> $DIR/redundant_pattern_matching.rs:160:12 + | +LL | if let Some(_) = Some(42) {} + | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` + +error: redundant pattern matching, consider using `is_none()` + --> $DIR/redundant_pattern_matching.rs:162:12 + | +LL | if let None = None::<()> {} + | -------^^^^------------- help: try this: `if None::<()>.is_none()` + error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:183:15 + --> $DIR/redundant_pattern_matching.rs:164:15 | LL | while let Ok(_) = Ok::(10) {} | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:185:15 + --> $DIR/redundant_pattern_matching.rs:166:15 | LL | while let Err(_) = Ok::(10) {} | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` +error: redundant pattern matching, consider using `is_some()` + --> $DIR/redundant_pattern_matching.rs:168:15 + | +LL | while let Some(_) = Some(42) {} + | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` + +error: redundant pattern matching, consider using `is_none()` + --> $DIR/redundant_pattern_matching.rs:170:15 + | +LL | while let None = None::<()> {} + | ----------^^^^------------- help: try this: `while None::<()>.is_none()` + error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:187:5 + --> $DIR/redundant_pattern_matching.rs:172:5 | LL | / match Ok::(42) { LL | | Ok(_) => true, @@ -230,7 +254,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:192:5 + --> $DIR/redundant_pattern_matching.rs:177:5 | LL | / match Err::(42) { LL | | Ok(_) => false, @@ -238,5 +262,23 @@ LL | | Err(_) => true, LL | | }; | |_____^ help: try this: `Err::(42).is_err()` -error: aborting due to 35 previous errors +error: redundant pattern matching, consider using `is_some()` + --> $DIR/redundant_pattern_matching.rs:182:5 + | +LL | / match Some(42) { +LL | | Some(_) => true, +LL | | None => false, +LL | | }; + | |_____^ help: try this: `Some(42).is_some()` + +error: redundant pattern matching, consider using `is_none()` + --> $DIR/redundant_pattern_matching.rs:187:5 + | +LL | / match None::<()> { +LL | | Some(_) => false, +LL | | None => true, +LL | | }; + | |_____^ help: try this: `None::<()>.is_none()` + +error: aborting due to 41 previous errors From 43cba349bdf9472eafccbff2542287a1f6580c5e Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Mon, 21 Sep 2020 00:00:33 +0200 Subject: [PATCH 0749/1052] Remove `can_suggest` from Clippy. Removes `can_suggest` from as it is no longer used. Reverts rust-clippy#5724. --- src/tools/clippy/clippy_lints/src/matches.rs | 78 ++++---------------- 1 file changed, 16 insertions(+), 62 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs index db52c97475fa7..819846ebc793b 100644 --- a/src/tools/clippy/clippy_lints/src/matches.rs +++ b/src/tools/clippy/clippy_lints/src/matches.rs @@ -1440,15 +1440,12 @@ where mod redundant_pattern_match { use super::REDUNDANT_PATTERN_MATCHING; - use crate::utils::{in_constant, match_qpath, match_trait_method, paths, snippet, span_lint_and_then}; + use crate::utils::{match_qpath, match_trait_method, paths, snippet, span_lint_and_then}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; - use rustc_hir::{Arm, Expr, ExprKind, HirId, MatchSource, PatKind, QPath}; + use rustc_hir::{Arm, Expr, ExprKind, MatchSource, PatKind, QPath}; use rustc_lint::LateContext; - use rustc_middle::ty; - use rustc_mir::const_eval::is_const_fn; - use rustc_span::source_map::Symbol; pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::Match(op, arms, ref match_source) = &expr.kind { @@ -1468,37 +1465,24 @@ mod redundant_pattern_match { arms: &[Arm<'_>], keyword: &'static str, ) { - fn find_suggestion(cx: &LateContext<'_>, hir_id: HirId, path: &QPath<'_>) -> Option<&'static str> { - if match_qpath(path, &paths::RESULT_OK) { - return Some("is_ok()"); - } - if match_qpath(path, &paths::RESULT_ERR) { - return Some("is_err()"); - } - if match_qpath(path, &paths::OPTION_SOME) && can_suggest(cx, hir_id, sym!(option_type), "is_some") { - return Some("is_some()"); - } - if match_qpath(path, &paths::OPTION_NONE) && can_suggest(cx, hir_id, sym!(option_type), "is_none") { - return Some("is_none()"); - } - None - } - - let hir_id = expr.hir_id; let good_method = match arms[0].pat.kind { PatKind::TupleStruct(ref path, ref patterns, _) if patterns.len() == 1 => { if let PatKind::Wild = patterns[0].kind { - find_suggestion(cx, hir_id, path) + if match_qpath(path, &paths::RESULT_OK) { + "is_ok()" + } else if match_qpath(path, &paths::RESULT_ERR) { + "is_err()" + } else if match_qpath(path, &paths::OPTION_SOME) { + "is_some()" + } else { + return; + } } else { - None + return; } }, - PatKind::Path(ref path) => find_suggestion(cx, hir_id, path), - _ => None, - }; - let good_method = match good_method { - Some(method) => method, - None => return, + PatKind::Path(ref path) if match_qpath(path, &paths::OPTION_NONE) => "is_none()", + _ => return, }; // check that `while_let_on_iterator` lint does not trigger @@ -1547,7 +1531,6 @@ mod redundant_pattern_match { if arms.len() == 2 { let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind); - let hir_id = expr.hir_id; let found_good_method = match node_pair { ( PatKind::TupleStruct(ref path_left, ref patterns_left, _), @@ -1562,8 +1545,6 @@ mod redundant_pattern_match { &paths::RESULT_ERR, "is_ok()", "is_err()", - || true, - || true, ) } else { None @@ -1582,8 +1563,6 @@ mod redundant_pattern_match { &paths::OPTION_NONE, "is_some()", "is_none()", - || can_suggest(cx, hir_id, sym!(option_type), "is_some"), - || can_suggest(cx, hir_id, sym!(option_type), "is_none"), ) } else { None @@ -1616,7 +1595,6 @@ mod redundant_pattern_match { } } - #[allow(clippy::too_many_arguments)] fn find_good_method_for_match<'a>( arms: &[Arm<'_>], path_left: &QPath<'_>, @@ -1625,8 +1603,6 @@ mod redundant_pattern_match { expected_right: &[&str], should_be_left: &'a str, should_be_right: &'a str, - can_suggest_left: impl Fn() -> bool, - can_suggest_right: impl Fn() -> bool, ) -> Option<&'a str> { let body_node_pair = if match_qpath(path_left, expected_left) && match_qpath(path_right, expected_right) { (&(*arms[0].body).kind, &(*arms[1].body).kind) @@ -1638,35 +1614,13 @@ mod redundant_pattern_match { match body_node_pair { (ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) { - (LitKind::Bool(true), LitKind::Bool(false)) if can_suggest_left() => Some(should_be_left), - (LitKind::Bool(false), LitKind::Bool(true)) if can_suggest_right() => Some(should_be_right), + (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left), + (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right), _ => None, }, _ => None, } } - - fn can_suggest(cx: &LateContext<'_>, hir_id: HirId, diag_item: Symbol, name: &str) -> bool { - if !in_constant(cx, hir_id) { - return true; - } - - // Avoid suggesting calls to non-`const fn`s in const contexts, see #5697. - cx.tcx - .get_diagnostic_item(diag_item) - .and_then(|def_id| { - cx.tcx.inherent_impls(def_id).iter().find_map(|imp| { - cx.tcx - .associated_items(*imp) - .in_definition_order() - .find_map(|item| match item.kind { - ty::AssocKind::Fn if item.ident.name.as_str() == name => Some(item.def_id), - _ => None, - }) - }) - }) - .map_or(false, |def_id| is_const_fn(cx.tcx, def_id)) - } } #[test] From 141b9c28901fd80da028a984eca2af4e7218a09a Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Mon, 21 Sep 2020 00:00:33 +0200 Subject: [PATCH 0750/1052] Remove `can_suggest` from Clippy. Removes `can_suggest` from as it is no longer used. Reverts rust-clippy#5724. --- clippy_lints/src/matches.rs | 78 ++++++++----------------------------- 1 file changed, 16 insertions(+), 62 deletions(-) diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index db52c97475fa7..819846ebc793b 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1440,15 +1440,12 @@ where mod redundant_pattern_match { use super::REDUNDANT_PATTERN_MATCHING; - use crate::utils::{in_constant, match_qpath, match_trait_method, paths, snippet, span_lint_and_then}; + use crate::utils::{match_qpath, match_trait_method, paths, snippet, span_lint_and_then}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; - use rustc_hir::{Arm, Expr, ExprKind, HirId, MatchSource, PatKind, QPath}; + use rustc_hir::{Arm, Expr, ExprKind, MatchSource, PatKind, QPath}; use rustc_lint::LateContext; - use rustc_middle::ty; - use rustc_mir::const_eval::is_const_fn; - use rustc_span::source_map::Symbol; pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::Match(op, arms, ref match_source) = &expr.kind { @@ -1468,37 +1465,24 @@ mod redundant_pattern_match { arms: &[Arm<'_>], keyword: &'static str, ) { - fn find_suggestion(cx: &LateContext<'_>, hir_id: HirId, path: &QPath<'_>) -> Option<&'static str> { - if match_qpath(path, &paths::RESULT_OK) { - return Some("is_ok()"); - } - if match_qpath(path, &paths::RESULT_ERR) { - return Some("is_err()"); - } - if match_qpath(path, &paths::OPTION_SOME) && can_suggest(cx, hir_id, sym!(option_type), "is_some") { - return Some("is_some()"); - } - if match_qpath(path, &paths::OPTION_NONE) && can_suggest(cx, hir_id, sym!(option_type), "is_none") { - return Some("is_none()"); - } - None - } - - let hir_id = expr.hir_id; let good_method = match arms[0].pat.kind { PatKind::TupleStruct(ref path, ref patterns, _) if patterns.len() == 1 => { if let PatKind::Wild = patterns[0].kind { - find_suggestion(cx, hir_id, path) + if match_qpath(path, &paths::RESULT_OK) { + "is_ok()" + } else if match_qpath(path, &paths::RESULT_ERR) { + "is_err()" + } else if match_qpath(path, &paths::OPTION_SOME) { + "is_some()" + } else { + return; + } } else { - None + return; } }, - PatKind::Path(ref path) => find_suggestion(cx, hir_id, path), - _ => None, - }; - let good_method = match good_method { - Some(method) => method, - None => return, + PatKind::Path(ref path) if match_qpath(path, &paths::OPTION_NONE) => "is_none()", + _ => return, }; // check that `while_let_on_iterator` lint does not trigger @@ -1547,7 +1531,6 @@ mod redundant_pattern_match { if arms.len() == 2 { let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind); - let hir_id = expr.hir_id; let found_good_method = match node_pair { ( PatKind::TupleStruct(ref path_left, ref patterns_left, _), @@ -1562,8 +1545,6 @@ mod redundant_pattern_match { &paths::RESULT_ERR, "is_ok()", "is_err()", - || true, - || true, ) } else { None @@ -1582,8 +1563,6 @@ mod redundant_pattern_match { &paths::OPTION_NONE, "is_some()", "is_none()", - || can_suggest(cx, hir_id, sym!(option_type), "is_some"), - || can_suggest(cx, hir_id, sym!(option_type), "is_none"), ) } else { None @@ -1616,7 +1595,6 @@ mod redundant_pattern_match { } } - #[allow(clippy::too_many_arguments)] fn find_good_method_for_match<'a>( arms: &[Arm<'_>], path_left: &QPath<'_>, @@ -1625,8 +1603,6 @@ mod redundant_pattern_match { expected_right: &[&str], should_be_left: &'a str, should_be_right: &'a str, - can_suggest_left: impl Fn() -> bool, - can_suggest_right: impl Fn() -> bool, ) -> Option<&'a str> { let body_node_pair = if match_qpath(path_left, expected_left) && match_qpath(path_right, expected_right) { (&(*arms[0].body).kind, &(*arms[1].body).kind) @@ -1638,35 +1614,13 @@ mod redundant_pattern_match { match body_node_pair { (ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) { - (LitKind::Bool(true), LitKind::Bool(false)) if can_suggest_left() => Some(should_be_left), - (LitKind::Bool(false), LitKind::Bool(true)) if can_suggest_right() => Some(should_be_right), + (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left), + (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right), _ => None, }, _ => None, } } - - fn can_suggest(cx: &LateContext<'_>, hir_id: HirId, diag_item: Symbol, name: &str) -> bool { - if !in_constant(cx, hir_id) { - return true; - } - - // Avoid suggesting calls to non-`const fn`s in const contexts, see #5697. - cx.tcx - .get_diagnostic_item(diag_item) - .and_then(|def_id| { - cx.tcx.inherent_impls(def_id).iter().find_map(|imp| { - cx.tcx - .associated_items(*imp) - .in_definition_order() - .find_map(|item| match item.kind { - ty::AssocKind::Fn if item.ident.name.as_str() == name => Some(item.def_id), - _ => None, - }) - }) - }) - .map_or(false, |def_id| is_const_fn(cx.tcx, def_id)) - } } #[test] From 34d3c7df80dc687e184d8bfa456e851cad9839de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kornel=20Lesi=C5=84ski?= Date: Wed, 16 Sep 2020 03:45:58 +0100 Subject: [PATCH 0751/1052] Let user see the full type of type-length limit error --- .../rustc_mir/src/monomorphize/collector.rs | 66 +++++++++++-------- .../ui/infinite/infinite-instantiation.rs | 1 + .../ui/infinite/infinite-instantiation.stderr | 5 +- src/test/ui/issues/issue-22638.rs | 1 + src/test/ui/issues/issue-22638.stderr | 5 +- .../issue-37311.rs | 1 + .../issue-37311.stderr | 5 +- src/test/ui/issues/issue-67552.rs | 1 + src/test/ui/issues/issue-67552.stderr | 5 +- src/test/ui/issues/issue-8727.rs | 1 + src/test/ui/issues/issue-8727.stderr | 7 +- ...ssue-38591-non-regular-dropck-recursion.rs | 2 + ...-38591-non-regular-dropck-recursion.stderr | 1 + src/test/ui/recursion/recursion.rs | 1 + src/test/ui/recursion/recursion.stderr | 5 +- src/test/ui/type_length_limit.rs | 1 + src/test/ui/type_length_limit.stderr | 3 +- 17 files changed, 71 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs index 4ef871b05f47f..7e12cc9176ee1 100644 --- a/compiler/rustc_mir/src/monomorphize/collector.rs +++ b/compiler/rustc_mir/src/monomorphize/collector.rs @@ -197,6 +197,7 @@ use rustc_session::config::EntryFnType; use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP}; use smallvec::SmallVec; use std::iter; +use std::path::PathBuf; #[derive(PartialEq)] pub enum MonoItemCollectionMode { @@ -420,27 +421,38 @@ fn record_accesses<'a, 'tcx: 'a>( inlining_map.lock_mut().record_accesses(caller, &accesses); } -// Shrinks string by keeping prefix and suffix of given sizes. -fn shrink(s: String, before: usize, after: usize) -> String { - // An iterator of all byte positions including the end of the string. - let positions = || s.char_indices().map(|(i, _)| i).chain(iter::once(s.len())); - - let shrunk = format!( - "{before}...{after}", - before = &s[..positions().nth(before).unwrap_or(s.len())], - after = &s[positions().rev().nth(after).unwrap_or(0)..], - ); +/// Format instance name that is already known to be too long for rustc. +/// Show only the first and last 32 characters to avoid blasting +/// the user's terminal with thousands of lines of type-name. +/// +/// If the type name is longer than before+after, it will be written to a file. +fn shrunk_instance_name( + tcx: TyCtxt<'tcx>, + instance: &Instance<'tcx>, + before: usize, + after: usize, +) -> (String, Option) { + let s = instance.to_string(); // Only use the shrunk version if it's really shorter. // This also avoids the case where before and after slices overlap. - if shrunk.len() < s.len() { shrunk } else { s } -} + if s.chars().nth(before + after + 1).is_some() { + // An iterator of all byte positions including the end of the string. + let positions = || s.char_indices().map(|(i, _)| i).chain(iter::once(s.len())); + + let shrunk = format!( + "{before}...{after}", + before = &s[..positions().nth(before).unwrap_or(s.len())], + after = &s[positions().rev().nth(after).unwrap_or(0)..], + ); + + let path = tcx.output_filenames(LOCAL_CRATE).temp_path_ext("long-type.txt", None); + let written_to_path = std::fs::write(&path, s).ok().map(|_| path); -// Format instance name that is already known to be too long for rustc. -// Show only the first and last 32 characters to avoid blasting -// the user's terminal with thousands of lines of type-name. -fn shrunk_instance_name(instance: &Instance<'tcx>) -> String { - shrink(instance.to_string(), 32, 32) + (shrunk, written_to_path) + } else { + (s, None) + } } fn check_recursion_limit<'tcx>( @@ -465,15 +477,16 @@ fn check_recursion_limit<'tcx>( // more than the recursion limit is assumed to be causing an // infinite expansion. if !tcx.sess.recursion_limit().value_within_limit(adjusted_recursion_depth) { - let error = format!( - "reached the recursion limit while instantiating `{}`", - shrunk_instance_name(&instance), - ); + let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32); + let error = format!("reached the recursion limit while instantiating `{}`", shrunk); let mut err = tcx.sess.struct_span_fatal(span, &error); err.span_note( tcx.def_span(def_id), &format!("`{}` defined here", tcx.def_path_str(def_id)), ); + if let Some(path) = written_to_path { + err.note(&format!("the full type name has been written to '{}'", path.display())); + } err.emit(); FatalError.raise(); } @@ -502,12 +515,13 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { // // Bail out in these cases to avoid that bad user experience. if !tcx.sess.type_length_limit().value_within_limit(type_length) { - let msg = format!( - "reached the type-length limit while instantiating `{}`", - shrunk_instance_name(&instance), - ); + let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32); + let msg = format!("reached the type-length limit while instantiating `{}`", shrunk); let mut diag = tcx.sess.struct_span_fatal(tcx.def_span(instance.def_id()), &msg); - diag.note(&format!( + if let Some(path) = written_to_path { + diag.note(&format!("the full type name has been written to '{}'", path.display())); + } + diag.help(&format!( "consider adding a `#![type_length_limit=\"{}\"]` attribute to your crate", type_length )); diff --git a/src/test/ui/infinite/infinite-instantiation.rs b/src/test/ui/infinite/infinite-instantiation.rs index cb3550cf66bed..9b9f332ca86de 100644 --- a/src/test/ui/infinite/infinite-instantiation.rs +++ b/src/test/ui/infinite/infinite-instantiation.rs @@ -1,4 +1,5 @@ // build-fail +// normalize-stderr-test: ".nll/" -> "/" trait ToOpt: Sized { fn to_option(&self) -> Option; diff --git a/src/test/ui/infinite/infinite-instantiation.stderr b/src/test/ui/infinite/infinite-instantiation.stderr index d27d14842ce99..52f5781349e16 100644 --- a/src/test/ui/infinite/infinite-instantiation.stderr +++ b/src/test/ui/infinite/infinite-instantiation.stderr @@ -1,14 +1,15 @@ error: reached the recursion limit while instantiating `function::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - --> $DIR/infinite-instantiation.rs:21:9 + --> $DIR/infinite-instantiation.rs:22:9 | LL | function(counter - 1, t.to_option()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `function` defined here - --> $DIR/infinite-instantiation.rs:19:1 + --> $DIR/infinite-instantiation.rs:20:1 | LL | fn function(counter: usize, t: T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the full type name has been written to '$TEST_BUILD_DIR/infinite/infinite-instantiation/infinite-instantiation.long-type.txt' error: aborting due to previous error diff --git a/src/test/ui/issues/issue-22638.rs b/src/test/ui/issues/issue-22638.rs index 89137538425bf..198ceccc2c33c 100644 --- a/src/test/ui/issues/issue-22638.rs +++ b/src/test/ui/issues/issue-22638.rs @@ -1,5 +1,6 @@ // build-fail // normalize-stderr-test: "<\[closure@.+`" -> "$$CLOSURE`" +// normalize-stderr-test: ".nll/" -> "/" #![allow(unused)] diff --git a/src/test/ui/issues/issue-22638.stderr b/src/test/ui/issues/issue-22638.stderr index c4255b95b704e..1354ec8e899c0 100644 --- a/src/test/ui/issues/issue-22638.stderr +++ b/src/test/ui/issues/issue-22638.stderr @@ -1,14 +1,15 @@ error: reached the recursion limit while instantiating `A::matches::$CLOSURE` - --> $DIR/issue-22638.rs:55:9 + --> $DIR/issue-22638.rs:56:9 | LL | a.matches(f) | ^^^^^^^^^^^^ | note: `A::matches` defined here - --> $DIR/issue-22638.rs:14:5 + --> $DIR/issue-22638.rs:15:5 | LL | pub fn matches(&self, f: &F) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-22638/issue-22638.long-type.txt' error: aborting due to previous error diff --git a/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.rs b/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.rs index d3d5863ddb3c9..50d1f166c9865 100644 --- a/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.rs +++ b/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.rs @@ -1,4 +1,5 @@ // build-fail +// normalize-stderr-test: ".nll/" -> "/" trait Mirror { type Image; diff --git a/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr b/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr index a94f190d6b25d..93aeb89469d4a 100644 --- a/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr +++ b/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr @@ -1,14 +1,15 @@ error: reached the recursion limit while instantiating `<(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(.....), ...), ...) as Foo>::recurse` - --> $DIR/issue-37311.rs:16:9 + --> $DIR/issue-37311.rs:17:9 | LL | (self, self).recurse(); | ^^^^^^^^^^^^^^^^^^^^^^ | note: `::recurse` defined here - --> $DIR/issue-37311.rs:15:5 + --> $DIR/issue-37311.rs:16:5 | LL | fn recurse(&self) { | ^^^^^^^^^^^^^^^^^ + = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-37311-type-length-limit/issue-37311/issue-37311.long-type.txt' error: aborting due to previous error diff --git a/src/test/ui/issues/issue-67552.rs b/src/test/ui/issues/issue-67552.rs index b0fcb74764b98..98192dae20da8 100644 --- a/src/test/ui/issues/issue-67552.rs +++ b/src/test/ui/issues/issue-67552.rs @@ -1,4 +1,5 @@ // build-fail +// normalize-stderr-test: ".nll/" -> "/" fn main() { rec(Empty); diff --git a/src/test/ui/issues/issue-67552.stderr b/src/test/ui/issues/issue-67552.stderr index f3e73399b57ce..cf05a72e921e0 100644 --- a/src/test/ui/issues/issue-67552.stderr +++ b/src/test/ui/issues/issue-67552.stderr @@ -1,16 +1,17 @@ error: reached the recursion limit while instantiating `rec::<&mut &mut &mut &mut &mut &... &mut &mut &mut &mut &mut Empty>` - --> $DIR/issue-67552.rs:27:9 + --> $DIR/issue-67552.rs:28:9 | LL | rec(identity(&mut it)) | ^^^^^^^^^^^^^^^^^^^^^^ | note: `rec` defined here - --> $DIR/issue-67552.rs:20:1 + --> $DIR/issue-67552.rs:21:1 | LL | / fn rec(mut it: T) LL | | where LL | | T: Iterator, | |________________^ + = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-67552/issue-67552.long-type.txt' error: aborting due to previous error diff --git a/src/test/ui/issues/issue-8727.rs b/src/test/ui/issues/issue-8727.rs index 01b3bc582f7e0..a9b8126618fe5 100644 --- a/src/test/ui/issues/issue-8727.rs +++ b/src/test/ui/issues/issue-8727.rs @@ -2,6 +2,7 @@ // recursions. // build-fail +// normalize-stderr-test: ".nll/" -> "/" fn generic() { //~ WARN function cannot return without recursing generic::>(); diff --git a/src/test/ui/issues/issue-8727.stderr b/src/test/ui/issues/issue-8727.stderr index 279e3ffbb4a41..10daba5ef3dd5 100644 --- a/src/test/ui/issues/issue-8727.stderr +++ b/src/test/ui/issues/issue-8727.stderr @@ -1,5 +1,5 @@ warning: function cannot return without recursing - --> $DIR/issue-8727.rs:6:1 + --> $DIR/issue-8727.rs:7:1 | LL | fn generic() { | ^^^^^^^^^^^^^^^ cannot return without recursing @@ -10,16 +10,17 @@ LL | generic::>(); = help: a `loop` may express intention better if this is on purpose error: reached the recursion limit while instantiating `generic::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - --> $DIR/issue-8727.rs:7:5 + --> $DIR/issue-8727.rs:8:5 | LL | generic::>(); | ^^^^^^^^^^^^^^^^^^^^^^ | note: `generic` defined here - --> $DIR/issue-8727.rs:6:1 + --> $DIR/issue-8727.rs:7:1 | LL | fn generic() { | ^^^^^^^^^^^^^^^ + = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-8727/issue-8727.long-type.txt' error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.rs b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.rs index d9996b80ac09d..658def0ad5a72 100644 --- a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.rs +++ b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.rs @@ -2,7 +2,9 @@ // no free regions or type parameters. // Codegen however, has to error for the infinitely many `drop_in_place` // functions it has been asked to create. + // build-fail +// normalize-stderr-test: ".nll/" -> "/" struct S { t: T, diff --git a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr index 4d77b3d295c00..3efe13b3de3d0 100644 --- a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr +++ b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr @@ -21,6 +21,7 @@ LL | | // SAFETY: see comment above LL | | unsafe { drop_in_place(to_drop) } LL | | } | |_^ + = note: the full type name has been written to '$TEST_BUILD_DIR/recursion/issue-38591-non-regular-dropck-recursion/issue-38591-non-regular-dropck-recursion.long-type.txt' error: aborting due to previous error diff --git a/src/test/ui/recursion/recursion.rs b/src/test/ui/recursion/recursion.rs index 373cc17d0e0fe..b3ba0ec3a2a01 100644 --- a/src/test/ui/recursion/recursion.rs +++ b/src/test/ui/recursion/recursion.rs @@ -1,5 +1,6 @@ // build-fail // compile-flags:-C overflow-checks=off +// normalize-stderr-test: ".nll/" -> "/" enum Nil {NilValue} struct Cons {head:isize, tail:T} diff --git a/src/test/ui/recursion/recursion.stderr b/src/test/ui/recursion/recursion.stderr index 085bf82ef8b93..d2844d0e6d9f0 100644 --- a/src/test/ui/recursion/recursion.stderr +++ b/src/test/ui/recursion/recursion.stderr @@ -1,14 +1,15 @@ error: reached the recursion limit while instantiating `test::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - --> $DIR/recursion.rs:17:11 + --> $DIR/recursion.rs:18:11 | LL | _ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `test` defined here - --> $DIR/recursion.rs:15:1 + --> $DIR/recursion.rs:16:1 | LL | fn test (n:isize, i:isize, first:T, second:T) ->isize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the full type name has been written to '$TEST_BUILD_DIR/recursion/recursion/recursion.long-type.txt' error: aborting due to previous error diff --git a/src/test/ui/type_length_limit.rs b/src/test/ui/type_length_limit.rs index 921cded5037b6..c1f3acbecf95f 100644 --- a/src/test/ui/type_length_limit.rs +++ b/src/test/ui/type_length_limit.rs @@ -1,5 +1,6 @@ // build-fail // error-pattern: reached the type-length limit while instantiating +// normalize-stderr-test: ".nll/" -> "/" // Test that the type length limit can be changed. diff --git a/src/test/ui/type_length_limit.stderr b/src/test/ui/type_length_limit.stderr index cf3d64d734ba0..1c0a596a64cb9 100644 --- a/src/test/ui/type_length_limit.stderr +++ b/src/test/ui/type_length_limit.stderr @@ -4,7 +4,8 @@ error: reached the type-length limit while instantiating `std::mem::drop::(_x: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: consider adding a `#![type_length_limit="8"]` attribute to your crate + = note: the full type name has been written to '$TEST_BUILD_DIR/type_length_limit/type_length_limit.long-type.txt' + = help: consider adding a `#![type_length_limit="8"]` attribute to your crate error: aborting due to previous error From 63dbfb3c30c96449eb1e0236b4f6fa5d60bdf609 Mon Sep 17 00:00:00 2001 From: Nicholas-Baron Date: Sat, 19 Sep 2020 00:42:15 -0700 Subject: [PATCH 0752/1052] Start of moving some functionality to separate files --- compiler/rustc_typeck/src/check/mod.rs | 32 +++++-------------------- compiler/rustc_typeck/src/check/util.rs | 28 ++++++++++++++++++++++ 2 files changed, 34 insertions(+), 26 deletions(-) create mode 100644 compiler/rustc_typeck/src/check/util.rs diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index e84cc3c9b8684..1b542818b6fb9 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -1,5 +1,3 @@ -// ignore-tidy-filelength - /*! # typeck: check phase @@ -82,6 +80,7 @@ mod pat; mod place_op; mod regionck; mod upvar; +mod util; mod wfcheck; pub mod writeback; @@ -97,7 +96,7 @@ use rustc_errors::ErrorReported; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::lang_items::LangItem; @@ -738,31 +737,12 @@ pub fn check_wf_new(tcx: TyCtxt<'_>) { tcx.hir().krate().par_visit_all_item_likes(&visit); } -fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { - tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx }); -} - -fn typeck_item_bodies(tcx: TyCtxt<'_>, crate_num: CrateNum) { - debug_assert!(crate_num == LOCAL_CRATE); - tcx.par_body_owners(|body_owner_def_id| { - tcx.ensure().typeck(body_owner_def_id); - }); -} - -fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { - wfcheck::check_item_well_formed(tcx, def_id); -} - -fn check_trait_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { - wfcheck::check_trait_item(tcx, def_id); -} - -fn check_impl_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { - wfcheck::check_impl_item(tcx, def_id); -} - pub fn provide(providers: &mut Providers) { method::provide(providers); + use util::{ + check_impl_item_well_formed, check_item_well_formed, check_mod_item_types, + check_trait_item_well_formed, typeck_item_bodies, + }; *providers = Providers { typeck_item_bodies, typeck_const_arg, diff --git a/compiler/rustc_typeck/src/check/util.rs b/compiler/rustc_typeck/src/check/util.rs new file mode 100644 index 0000000000000..c215a9c2f909d --- /dev/null +++ b/compiler/rustc_typeck/src/check/util.rs @@ -0,0 +1,28 @@ +use rustc_hir::def_id::{CrateNum, LocalDefId, LOCAL_CRATE}; + +use crate::TyCtxt; +use super::wfcheck; +use crate::check::CheckItemTypesVisitor; + +pub fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { + tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx }); +} + +pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { + wfcheck::check_item_well_formed(tcx, def_id); +} + +pub fn check_trait_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { + wfcheck::check_trait_item(tcx, def_id); +} + +pub fn check_impl_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { + wfcheck::check_impl_item(tcx, def_id); +} + +pub fn typeck_item_bodies(tcx: TyCtxt<'_>, crate_num: CrateNum) { + debug_assert!(crate_num == LOCAL_CRATE); + tcx.par_body_owners(|body_owner_def_id| { + tcx.ensure().typeck(body_owner_def_id); + }); +} From bfe5bc9cb93445c7e2818db684de2bf1d84a06c7 Mon Sep 17 00:00:00 2001 From: Nicholas-Baron Date: Sat, 19 Sep 2020 00:50:54 -0700 Subject: [PATCH 0753/1052] Formatter moved one use statement --- compiler/rustc_typeck/src/check/util.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_typeck/src/check/util.rs b/compiler/rustc_typeck/src/check/util.rs index c215a9c2f909d..973c9a2a26a18 100644 --- a/compiler/rustc_typeck/src/check/util.rs +++ b/compiler/rustc_typeck/src/check/util.rs @@ -1,8 +1,8 @@ use rustc_hir::def_id::{CrateNum, LocalDefId, LOCAL_CRATE}; -use crate::TyCtxt; use super::wfcheck; use crate::check::CheckItemTypesVisitor; +use crate::TyCtxt; pub fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx }); From 6fd80e35e03f0acf48c065d6682600d32b27915f Mon Sep 17 00:00:00 2001 From: Nicholas-Baron Date: Sat, 19 Sep 2020 01:09:45 -0700 Subject: [PATCH 0754/1052] Moved another struct and used pub(super) to be explicit --- compiler/rustc_typeck/src/check/mod.rs | 29 ++---------------- compiler/rustc_typeck/src/check/util.rs | 40 +++++++++++++++++++++---- 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 1b542818b6fb9..560248480cfe6 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -87,6 +87,7 @@ pub mod writeback; use crate::astconv::{ AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, PathSeg, }; +use crate::check::util::MaybeInProgressTables; use rustc_ast as ast; use rustc_ast::util::parser::ExprPrecedence; use rustc_attr as attr; @@ -141,7 +142,7 @@ use rustc_trait_selection::traits::{ self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt, }; -use std::cell::{Cell, Ref, RefCell, RefMut}; +use std::cell::{Cell, RefCell}; use std::cmp; use std::collections::hash_map::Entry; use std::iter; @@ -177,32 +178,6 @@ pub struct LocalTy<'tcx> { revealed_ty: Ty<'tcx>, } -/// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field. -#[derive(Copy, Clone)] -struct MaybeInProgressTables<'a, 'tcx> { - maybe_typeck_results: Option<&'a RefCell>>, -} - -impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> { - fn borrow(self) -> Ref<'a, ty::TypeckResults<'tcx>> { - match self.maybe_typeck_results { - Some(typeck_results) => typeck_results.borrow(), - None => bug!( - "MaybeInProgressTables: inh/fcx.typeck_results.borrow() with no typeck results" - ), - } - } - - fn borrow_mut(self) -> RefMut<'a, ty::TypeckResults<'tcx>> { - match self.maybe_typeck_results { - Some(typeck_results) => typeck_results.borrow_mut(), - None => bug!( - "MaybeInProgressTables: inh/fcx.typeck_results.borrow_mut() with no typeck results" - ), - } - } -} - /// Closures defined within the function. For example: /// /// fn foo() { diff --git a/compiler/rustc_typeck/src/check/util.rs b/compiler/rustc_typeck/src/check/util.rs index 973c9a2a26a18..9a948c949ece3 100644 --- a/compiler/rustc_typeck/src/check/util.rs +++ b/compiler/rustc_typeck/src/check/util.rs @@ -1,26 +1,54 @@ use rustc_hir::def_id::{CrateNum, LocalDefId, LOCAL_CRATE}; +use std::cell::{Ref, RefCell, RefMut}; + use super::wfcheck; use crate::check::CheckItemTypesVisitor; -use crate::TyCtxt; +use crate::{ty, TyCtxt}; + +/// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field. +#[derive(Copy, Clone)] +pub(super) struct MaybeInProgressTables<'a, 'tcx> { + pub(super) maybe_typeck_results: Option<&'a RefCell>>, +} + +impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> { + pub(super) fn borrow(self) -> Ref<'a, ty::TypeckResults<'tcx>> { + match self.maybe_typeck_results { + Some(typeck_results) => typeck_results.borrow(), + None => bug!( + "MaybeInProgressTables: inh/fcx.typeck_results.borrow() with no typeck results" + ), + } + } + + pub(super) fn borrow_mut(self) -> RefMut<'a, ty::TypeckResults<'tcx>> { + match self.maybe_typeck_results { + Some(typeck_results) => typeck_results.borrow_mut(), + None => bug!( + "MaybeInProgressTables: inh/fcx.typeck_results.borrow_mut() with no typeck results" + ), + } + } +} -pub fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { +pub(super) fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx }); } -pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { +pub(super) fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { wfcheck::check_item_well_formed(tcx, def_id); } -pub fn check_trait_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { +pub(super) fn check_trait_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { wfcheck::check_trait_item(tcx, def_id); } -pub fn check_impl_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { +pub(super) fn check_impl_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { wfcheck::check_impl_item(tcx, def_id); } -pub fn typeck_item_bodies(tcx: TyCtxt<'_>, crate_num: CrateNum) { +pub(super) fn typeck_item_bodies(tcx: TyCtxt<'_>, crate_num: CrateNum) { debug_assert!(crate_num == LOCAL_CRATE); tcx.par_body_owners(|body_owner_def_id| { tcx.ensure().typeck(body_owner_def_id); From 3e770645aade4b7e34898a9f102bd5e4d5589f32 Mon Sep 17 00:00:00 2001 From: Nicholas-Baron Date: Sat, 19 Sep 2020 01:20:05 -0700 Subject: [PATCH 0755/1052] Moved a struct only need by util into util --- compiler/rustc_typeck/src/check/mod.rs | 13 ------------- compiler/rustc_typeck/src/check/util.rs | 15 ++++++++++++++- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 560248480cfe6..c507393bc3140 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -99,7 +99,6 @@ use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, GenericArg, HirIdMap, ItemKind, Node, PatKind, QPath}; use rustc_index::bit_set::BitSet; @@ -695,18 +694,6 @@ impl Inherited<'a, 'tcx> { } } -struct CheckItemTypesVisitor<'tcx> { - tcx: TyCtxt<'tcx>, -} - -impl ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'tcx> { - fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) { - check_item_type(self.tcx, i); - } - fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {} - fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {} -} - pub fn check_wf_new(tcx: TyCtxt<'_>) { let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx); tcx.hir().krate().par_visit_all_item_likes(&visit); diff --git a/compiler/rustc_typeck/src/check/util.rs b/compiler/rustc_typeck/src/check/util.rs index 9a948c949ece3..62865accad4ad 100644 --- a/compiler/rustc_typeck/src/check/util.rs +++ b/compiler/rustc_typeck/src/check/util.rs @@ -1,9 +1,10 @@ +use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, LocalDefId, LOCAL_CRATE}; +use rustc_hir::itemlikevisit::ItemLikeVisitor; use std::cell::{Ref, RefCell, RefMut}; use super::wfcheck; -use crate::check::CheckItemTypesVisitor; use crate::{ty, TyCtxt}; /// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field. @@ -32,6 +33,18 @@ impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> { } } +struct CheckItemTypesVisitor<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'tcx> { + fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) { + super::check_item_type(self.tcx, i); + } + fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {} + fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {} +} + pub(super) fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx }); } From c190f66060ee3ae4aa84a1c291b3a95ce77e6dc8 Mon Sep 17 00:00:00 2001 From: Nicholas-Baron Date: Sat, 19 Sep 2020 01:45:28 -0700 Subject: [PATCH 0756/1052] Moved GatherLocalsVisitor to its own file --- .../rustc_typeck/src/check/gather_locals.rs | 120 ++++++++++++++++++ compiler/rustc_typeck/src/check/mod.rs | 118 +---------------- 2 files changed, 126 insertions(+), 112 deletions(-) create mode 100644 compiler/rustc_typeck/src/check/gather_locals.rs diff --git a/compiler/rustc_typeck/src/check/gather_locals.rs b/compiler/rustc_typeck/src/check/gather_locals.rs new file mode 100644 index 0000000000000..1d505cfa69804 --- /dev/null +++ b/compiler/rustc_typeck/src/check/gather_locals.rs @@ -0,0 +1,120 @@ +use crate::check::{FnCtxt, LocalTy, UserType}; +use rustc_hir as hir; +use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::PatKind; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_middle::ty::Ty; +use rustc_span::Span; +use rustc_trait_selection::traits; + +pub(super) struct GatherLocalsVisitor<'a, 'tcx> { + fcx: &'a FnCtxt<'a, 'tcx>, + parent_id: hir::HirId, +} + +impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { + pub(super) fn new(fcx: &'a FnCtxt<'a, 'tcx>, parent_id: hir::HirId) -> Self { + Self { fcx, parent_id } + } + + fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option>) -> Ty<'tcx> { + match ty_opt { + None => { + // Infer the variable's type. + let var_ty = self.fcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span, + }); + self.fcx + .locals + .borrow_mut() + .insert(nid, LocalTy { decl_ty: var_ty, revealed_ty: var_ty }); + var_ty + } + Some(typ) => { + // Take type that the user specified. + self.fcx.locals.borrow_mut().insert(nid, typ); + typ.revealed_ty + } + } + } +} + +impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { + type Map = intravisit::ErasedMap<'tcx>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } + + // Add explicitly-declared locals. + fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { + let local_ty = match local.ty { + Some(ref ty) => { + let o_ty = self.fcx.to_ty(&ty); + + let revealed_ty = if self.fcx.tcx.features().impl_trait_in_bindings { + self.fcx.instantiate_opaque_types_from_value(self.parent_id, &o_ty, ty.span) + } else { + o_ty + }; + + let c_ty = self + .fcx + .inh + .infcx + .canonicalize_user_type_annotation(&UserType::Ty(revealed_ty)); + debug!( + "visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}", + ty.hir_id, o_ty, revealed_ty, c_ty + ); + self.fcx + .typeck_results + .borrow_mut() + .user_provided_types_mut() + .insert(ty.hir_id, c_ty); + + Some(LocalTy { decl_ty: o_ty, revealed_ty }) + } + None => None, + }; + self.assign(local.span, local.hir_id, local_ty); + + debug!( + "local variable {:?} is assigned type {}", + local.pat, + self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&local.hir_id).unwrap().decl_ty) + ); + intravisit::walk_local(self, local); + } + + // Add pattern bindings. + fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) { + if let PatKind::Binding(_, _, ident, _) = p.kind { + let var_ty = self.assign(p.span, p.hir_id, None); + + if !self.fcx.tcx.features().unsized_locals { + self.fcx.require_type_is_sized(var_ty, p.span, traits::VariableType(p.hir_id)); + } + + debug!( + "pattern binding {} is assigned to {} with type {:?}", + ident, + self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&p.hir_id).unwrap().decl_ty), + var_ty + ); + } + intravisit::walk_pat(self, p); + } + + // Don't descend into the bodies of nested closures. + fn visit_fn( + &mut self, + _: intravisit::FnKind<'tcx>, + _: &'tcx hir::FnDecl<'tcx>, + _: hir::BodyId, + _: Span, + _: hir::HirId, + ) { + } +} diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index c507393bc3140..2b8940f1813d1 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -72,6 +72,7 @@ mod compare_method; pub mod demand; pub mod dropck; mod expr; +mod gather_locals; mod generator_interior; pub mod intrinsic; pub mod method; @@ -87,6 +88,7 @@ pub mod writeback; use crate::astconv::{ AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, PathSeg, }; +use crate::check::gather_locals::GatherLocalsVisitor; use crate::check::util::MaybeInProgressTables; use rustc_ast as ast; use rustc_ast::util::parser::ExprPrecedence; @@ -98,9 +100,9 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; -use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; -use rustc_hir::{ExprKind, GenericArg, HirIdMap, ItemKind, Node, PatKind, QPath}; +use rustc_hir::{ExprKind, GenericArg, HirIdMap, ItemKind, Node, QPath}; use rustc_index::bit_set::BitSet; use rustc_index::vec::Idx; use rustc_infer::infer; @@ -997,7 +999,7 @@ fn typeck_with_fallback<'tcx>( }; // Gather locals in statics (because of block expressions). - GatherLocalsVisitor { fcx: &fcx, parent_id: id }.visit_body(body); + GatherLocalsVisitor::new(&fcx, id).visit_body(body); fcx.check_expr_coercable_to_type(&body.value, revealed_ty, None); @@ -1097,114 +1099,6 @@ fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: Abi) { } } -struct GatherLocalsVisitor<'a, 'tcx> { - fcx: &'a FnCtxt<'a, 'tcx>, - parent_id: hir::HirId, -} - -impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { - fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option>) -> Ty<'tcx> { - match ty_opt { - None => { - // Infer the variable's type. - let var_ty = self.fcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, - span, - }); - self.fcx - .locals - .borrow_mut() - .insert(nid, LocalTy { decl_ty: var_ty, revealed_ty: var_ty }); - var_ty - } - Some(typ) => { - // Take type that the user specified. - self.fcx.locals.borrow_mut().insert(nid, typ); - typ.revealed_ty - } - } - } -} - -impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { - type Map = intravisit::ErasedMap<'tcx>; - - fn nested_visit_map(&mut self) -> NestedVisitorMap { - NestedVisitorMap::None - } - - // Add explicitly-declared locals. - fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { - let local_ty = match local.ty { - Some(ref ty) => { - let o_ty = self.fcx.to_ty(&ty); - - let revealed_ty = if self.fcx.tcx.features().impl_trait_in_bindings { - self.fcx.instantiate_opaque_types_from_value(self.parent_id, &o_ty, ty.span) - } else { - o_ty - }; - - let c_ty = self - .fcx - .inh - .infcx - .canonicalize_user_type_annotation(&UserType::Ty(revealed_ty)); - debug!( - "visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}", - ty.hir_id, o_ty, revealed_ty, c_ty - ); - self.fcx - .typeck_results - .borrow_mut() - .user_provided_types_mut() - .insert(ty.hir_id, c_ty); - - Some(LocalTy { decl_ty: o_ty, revealed_ty }) - } - None => None, - }; - self.assign(local.span, local.hir_id, local_ty); - - debug!( - "local variable {:?} is assigned type {}", - local.pat, - self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&local.hir_id).unwrap().decl_ty) - ); - intravisit::walk_local(self, local); - } - - // Add pattern bindings. - fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) { - if let PatKind::Binding(_, _, ident, _) = p.kind { - let var_ty = self.assign(p.span, p.hir_id, None); - - if !self.fcx.tcx.features().unsized_locals { - self.fcx.require_type_is_sized(var_ty, p.span, traits::VariableType(p.hir_id)); - } - - debug!( - "pattern binding {} is assigned to {} with type {:?}", - ident, - self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&p.hir_id).unwrap().decl_ty), - var_ty - ); - } - intravisit::walk_pat(self, p); - } - - // Don't descend into the bodies of nested closures. - fn visit_fn( - &mut self, - _: intravisit::FnKind<'tcx>, - _: &'tcx hir::FnDecl<'tcx>, - _: hir::BodyId, - _: Span, - _: hir::HirId, - ) { - } -} - /// When `check_fn` is invoked on a generator (i.e., a body that /// includes yield), it returns back some information about the yield /// points. @@ -1285,7 +1179,7 @@ fn check_fn<'a, 'tcx>( let outer_def_id = tcx.closure_base_def_id(hir.local_def_id(fn_id).to_def_id()).expect_local(); let outer_hir_id = hir.local_def_id_to_hir_id(outer_def_id); - GatherLocalsVisitor { fcx: &fcx, parent_id: outer_hir_id }.visit_body(body); + GatherLocalsVisitor::new(&fcx, outer_hir_id).visit_body(body); // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` // (as it's created inside the body itself, not passed in from outside). From c8162c22ebce04a7a70739cb09b913ee162c4d0a Mon Sep 17 00:00:00 2001 From: Nicholas-Baron Date: Sat, 19 Sep 2020 04:00:29 -0700 Subject: [PATCH 0757/1052] Moved the FnCtxt struct to its own file --- compiler/rustc_typeck/src/check/fn_ctxt.rs | 3198 ++++++++++++++++++++ compiler/rustc_typeck/src/check/mod.rs | 3182 +------------------ 2 files changed, 3213 insertions(+), 3167 deletions(-) create mode 100644 compiler/rustc_typeck/src/check/fn_ctxt.rs diff --git a/compiler/rustc_typeck/src/check/fn_ctxt.rs b/compiler/rustc_typeck/src/check/fn_ctxt.rs new file mode 100644 index 0000000000000..f7046468511c2 --- /dev/null +++ b/compiler/rustc_typeck/src/check/fn_ctxt.rs @@ -0,0 +1,3198 @@ +use super::callee::{self, DeferredCallResolution}; +use super::coercion::{CoerceMany, DynamicCoerceMany}; +use super::method::{MethodCallee, SelfSource}; +use super::Expectation::*; +use super::TupleArgumentsFlag::*; +use super::{ + method, potentially_plural_count, struct_span_err, BreakableCtxt, Diverges, + EnclosingBreakables, Expectation, FallbackMode, Inherited, LocalTy, Needs, TupleArgumentsFlag, + UnsafetyState, +}; +use crate::astconv::{ + AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, PathSeg, +}; + +use rustc_ast as ast; +use rustc_ast::util::parser::ExprPrecedence; +use rustc_data_structures::captures::Captures; +use rustc_data_structures::fx::FxHashSet; +use rustc_errors::ErrorReported; +use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId}; +use rustc_hir as hir; +use rustc_hir::def::{CtorOf, DefKind, Res}; +use rustc_hir::def_id::DefId; +use rustc_hir::lang_items::LangItem; +use rustc_hir::{ExprKind, GenericArg, ItemKind, Node, QPath}; +use rustc_infer::infer; +use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; +use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; +use rustc_infer::infer::{InferOk, InferResult}; +use rustc_middle::hir::map::blocks::FnLikeNode; +use rustc_middle::ty::adjustment::{ + Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, +}; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::subst::{ + self, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSelfTy, UserSubsts, +}; +use rustc_middle::ty::{ + self, AdtKind, CanonicalUserType, Const, DefIdTree, GenericParamDefKind, ToPolyTraitRef, + ToPredicate, Ty, TyCtxt, UserType, +}; +use rustc_session::lint; +use rustc_session::Session; +use rustc_span::hygiene::DesugaringKind; +use rustc_span::source_map::{original_sp, DUMMY_SP}; +use rustc_span::symbol::{kw, sym, Ident}; +use rustc_span::{self, BytePos, MultiSpan, Span}; +use rustc_trait_selection::infer::InferCtxtExt as _; +use rustc_trait_selection::opaque_types::InferCtxtExt as _; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; +use rustc_trait_selection::traits::{ + self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt, +}; + +use std::cell::{Cell, RefCell}; +use std::collections::hash_map::Entry; +use std::iter; +use std::mem::replace; +use std::ops::Deref; +use std::slice; + +pub struct FnCtxt<'a, 'tcx> { + pub(super) body_id: hir::HirId, + + /// The parameter environment used for proving trait obligations + /// in this function. This can change when we descend into + /// closures (as they bring new things into scope), hence it is + /// not part of `Inherited` (as of the time of this writing, + /// closures do not yet change the environment, but they will + /// eventually). + pub(super) param_env: ty::ParamEnv<'tcx>, + + /// Number of errors that had been reported when we started + /// checking this function. On exit, if we find that *more* errors + /// have been reported, we will skip regionck and other work that + /// expects the types within the function to be consistent. + // FIXME(matthewjasper) This should not exist, and it's not correct + // if type checking is run in parallel. + err_count_on_creation: usize, + + /// If `Some`, this stores coercion information for returned + /// expressions. If `None`, this is in a context where return is + /// inappropriate, such as a const expression. + /// + /// This is a `RefCell`, which means that we + /// can track all the return expressions and then use them to + /// compute a useful coercion from the set, similar to a match + /// expression or other branching context. You can use methods + /// like `expected_ty` to access the declared return type (if + /// any). + pub(super) ret_coercion: Option>>, + + pub(super) ret_coercion_impl_trait: Option>, + + pub(super) ret_type_span: Option, + + /// Used exclusively to reduce cost of advanced evaluation used for + /// more helpful diagnostics. + pub(super) in_tail_expr: bool, + + /// First span of a return site that we find. Used in error messages. + pub(super) ret_coercion_span: RefCell>, + + pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>, + + pub(super) ps: RefCell, + + /// Whether the last checked node generates a divergence (e.g., + /// `return` will set this to `Always`). In general, when entering + /// an expression or other node in the tree, the initial value + /// indicates whether prior parts of the containing expression may + /// have diverged. It is then typically set to `Maybe` (and the + /// old value remembered) for processing the subparts of the + /// current expression. As each subpart is processed, they may set + /// the flag to `Always`, etc. Finally, at the end, we take the + /// result and "union" it with the original value, so that when we + /// return the flag indicates if any subpart of the parent + /// expression (up to and including this part) has diverged. So, + /// if you read it after evaluating a subexpression `X`, the value + /// you get indicates whether any subexpression that was + /// evaluating up to and including `X` diverged. + /// + /// We currently use this flag only for diagnostic purposes: + /// + /// - To warn about unreachable code: if, after processing a + /// sub-expression but before we have applied the effects of the + /// current node, we see that the flag is set to `Always`, we + /// can issue a warning. This corresponds to something like + /// `foo(return)`; we warn on the `foo()` expression. (We then + /// update the flag to `WarnedAlways` to suppress duplicate + /// reports.) Similarly, if we traverse to a fresh statement (or + /// tail expression) from a `Always` setting, we will issue a + /// warning. This corresponds to something like `{return; + /// foo();}` or `{return; 22}`, where we would warn on the + /// `foo()` or `22`. + /// + /// An expression represents dead code if, after checking it, + /// the diverges flag is set to something other than `Maybe`. + pub(super) diverges: Cell, + + /// Whether any child nodes have any type errors. + pub(super) has_errors: Cell, + + pub(super) enclosing_breakables: RefCell>, + + pub(super) inh: &'a Inherited<'a, 'tcx>, +} + +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + pub fn new( + inh: &'a Inherited<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + ) -> FnCtxt<'a, 'tcx> { + FnCtxt { + body_id, + param_env, + err_count_on_creation: inh.tcx.sess.err_count(), + ret_coercion: None, + ret_coercion_impl_trait: None, + ret_type_span: None, + in_tail_expr: false, + ret_coercion_span: RefCell::new(None), + resume_yield_tys: None, + ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)), + diverges: Cell::new(Diverges::Maybe), + has_errors: Cell::new(false), + enclosing_breakables: RefCell::new(EnclosingBreakables { + stack: Vec::new(), + by_id: Default::default(), + }), + inh, + } + } + + pub fn sess(&self) -> &Session { + &self.tcx.sess + } + + pub fn errors_reported_since_creation(&self) -> bool { + self.tcx.sess.err_count() > self.err_count_on_creation + } + + /// Produces warning on the given node, if the current point in the + /// function is unreachable, and there hasn't been another warning. + pub(super) fn warn_if_unreachable(&self, id: hir::HirId, span: Span, kind: &str) { + // FIXME: Combine these two 'if' expressions into one once + // let chains are implemented + if let Diverges::Always { span: orig_span, custom_note } = self.diverges.get() { + // If span arose from a desugaring of `if` or `while`, then it is the condition itself, + // which diverges, that we are about to lint on. This gives suboptimal diagnostics. + // Instead, stop here so that the `if`- or `while`-expression's block is linted instead. + if !span.is_desugaring(DesugaringKind::CondTemporary) + && !span.is_desugaring(DesugaringKind::Async) + && !orig_span.is_desugaring(DesugaringKind::Await) + { + self.diverges.set(Diverges::WarnedAlways); + + debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind); + + self.tcx().struct_span_lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, |lint| { + let msg = format!("unreachable {}", kind); + lint.build(&msg) + .span_label(span, &msg) + .span_label( + orig_span, + custom_note + .unwrap_or("any code following this expression is unreachable"), + ) + .emit(); + }) + } + } + } + + pub fn cause(&self, span: Span, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> { + ObligationCause::new(span, self.body_id, code) + } + + pub fn misc(&self, span: Span) -> ObligationCause<'tcx> { + self.cause(span, ObligationCauseCode::MiscObligation) + } + + /// Resolves type and const variables in `ty` if possible. Unlike the infcx + /// version (resolve_vars_if_possible), this version will + /// also select obligations if it seems useful, in an effort + /// to get more type information. + pub(super) fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { + debug!("resolve_vars_with_obligations(ty={:?})", ty); + + // No Infer()? Nothing needs doing. + if !ty.has_infer_types_or_consts() { + debug!("resolve_vars_with_obligations: ty={:?}", ty); + return ty; + } + + // If `ty` is a type variable, see whether we already know what it is. + ty = self.resolve_vars_if_possible(&ty); + if !ty.has_infer_types_or_consts() { + debug!("resolve_vars_with_obligations: ty={:?}", ty); + return ty; + } + + // If not, try resolving pending obligations as much as + // possible. This can help substantially when there are + // indirect dependencies that don't seem worth tracking + // precisely. + self.select_obligations_where_possible(false, |_| {}); + ty = self.resolve_vars_if_possible(&ty); + + debug!("resolve_vars_with_obligations: ty={:?}", ty); + ty + } + + pub(super) fn record_deferred_call_resolution( + &self, + closure_def_id: DefId, + r: DeferredCallResolution<'tcx>, + ) { + let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut(); + deferred_call_resolutions.entry(closure_def_id).or_default().push(r); + } + + pub(super) fn remove_deferred_call_resolutions( + &self, + closure_def_id: DefId, + ) -> Vec> { + let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut(); + deferred_call_resolutions.remove(&closure_def_id).unwrap_or(vec![]) + } + + pub fn tag(&self) -> String { + format!("{:p}", self) + } + + pub fn local_ty(&self, span: Span, nid: hir::HirId) -> LocalTy<'tcx> { + self.locals.borrow().get(&nid).cloned().unwrap_or_else(|| { + span_bug!(span, "no type for local variable {}", self.tcx.hir().node_to_string(nid)) + }) + } + + #[inline] + pub fn write_ty(&self, id: hir::HirId, ty: Ty<'tcx>) { + debug!( + "write_ty({:?}, {:?}) in fcx {}", + id, + self.resolve_vars_if_possible(&ty), + self.tag() + ); + self.typeck_results.borrow_mut().node_types_mut().insert(id, ty); + + if ty.references_error() { + self.has_errors.set(true); + self.set_tainted_by_errors(); + } + } + + pub fn write_field_index(&self, hir_id: hir::HirId, index: usize) { + self.typeck_results.borrow_mut().field_indices_mut().insert(hir_id, index); + } + + fn write_resolution(&self, hir_id: hir::HirId, r: Result<(DefKind, DefId), ErrorReported>) { + self.typeck_results.borrow_mut().type_dependent_defs_mut().insert(hir_id, r); + } + + pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) { + debug!("write_method_call(hir_id={:?}, method={:?})", hir_id, method); + self.write_resolution(hir_id, Ok((DefKind::AssocFn, method.def_id))); + self.write_substs(hir_id, method.substs); + + // When the method is confirmed, the `method.substs` includes + // parameters from not just the method, but also the impl of + // the method -- in particular, the `Self` type will be fully + // resolved. However, those are not something that the "user + // specified" -- i.e., those types come from the inferred type + // of the receiver, not something the user wrote. So when we + // create the user-substs, we want to replace those earlier + // types with just the types that the user actually wrote -- + // that is, those that appear on the *method itself*. + // + // As an example, if the user wrote something like + // `foo.bar::(...)` -- the `Self` type here will be the + // type of `foo` (possibly adjusted), but we don't want to + // include that. We want just the `[_, u32]` part. + if !method.substs.is_noop() { + let method_generics = self.tcx.generics_of(method.def_id); + if !method_generics.params.is_empty() { + let user_type_annotation = self.infcx.probe(|_| { + let user_substs = UserSubsts { + substs: InternalSubsts::for_item(self.tcx, method.def_id, |param, _| { + let i = param.index as usize; + if i < method_generics.parent_count { + self.infcx.var_for_def(DUMMY_SP, param) + } else { + method.substs[i] + } + }), + user_self_ty: None, // not relevant here + }; + + self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf( + method.def_id, + user_substs, + )) + }); + + debug!("write_method_call: user_type_annotation={:?}", user_type_annotation); + self.write_user_type_annotation(hir_id, user_type_annotation); + } + } + } + + pub fn write_substs(&self, node_id: hir::HirId, substs: SubstsRef<'tcx>) { + if !substs.is_noop() { + debug!("write_substs({:?}, {:?}) in fcx {}", node_id, substs, self.tag()); + + self.typeck_results.borrow_mut().node_substs_mut().insert(node_id, substs); + } + } + + /// Given the substs that we just converted from the HIR, try to + /// canonicalize them and store them as user-given substitutions + /// (i.e., substitutions that must be respected by the NLL check). + /// + /// This should be invoked **before any unifications have + /// occurred**, so that annotations like `Vec<_>` are preserved + /// properly. + pub fn write_user_type_annotation_from_substs( + &self, + hir_id: hir::HirId, + def_id: DefId, + substs: SubstsRef<'tcx>, + user_self_ty: Option>, + ) { + debug!( + "write_user_type_annotation_from_substs: hir_id={:?} def_id={:?} substs={:?} \ + user_self_ty={:?} in fcx {}", + hir_id, + def_id, + substs, + user_self_ty, + self.tag(), + ); + + if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) { + let canonicalized = self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf( + def_id, + UserSubsts { substs, user_self_ty }, + )); + debug!("write_user_type_annotation_from_substs: canonicalized={:?}", canonicalized); + self.write_user_type_annotation(hir_id, canonicalized); + } + } + + pub fn write_user_type_annotation( + &self, + hir_id: hir::HirId, + canonical_user_type_annotation: CanonicalUserType<'tcx>, + ) { + debug!( + "write_user_type_annotation: hir_id={:?} canonical_user_type_annotation={:?} tag={}", + hir_id, + canonical_user_type_annotation, + self.tag(), + ); + + if !canonical_user_type_annotation.is_identity() { + self.typeck_results + .borrow_mut() + .user_provided_types_mut() + .insert(hir_id, canonical_user_type_annotation); + } else { + debug!("write_user_type_annotation: skipping identity substs"); + } + } + + pub fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec>) { + debug!("apply_adjustments(expr={:?}, adj={:?})", expr, adj); + + if adj.is_empty() { + return; + } + + let autoborrow_mut = adj.iter().any(|adj| { + matches!(adj, &Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. })), + .. + }) + }); + + match self.typeck_results.borrow_mut().adjustments_mut().entry(expr.hir_id) { + Entry::Vacant(entry) => { + entry.insert(adj); + } + Entry::Occupied(mut entry) => { + debug!(" - composing on top of {:?}", entry.get()); + match (&entry.get()[..], &adj[..]) { + // Applying any adjustment on top of a NeverToAny + // is a valid NeverToAny adjustment, because it can't + // be reached. + (&[Adjustment { kind: Adjust::NeverToAny, .. }], _) => return, + (&[ + Adjustment { kind: Adjust::Deref(_), .. }, + Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. }, + ], &[ + Adjustment { kind: Adjust::Deref(_), .. }, + .. // Any following adjustments are allowed. + ]) => { + // A reborrow has no effect before a dereference. + } + // FIXME: currently we never try to compose autoderefs + // and ReifyFnPointer/UnsafeFnPointer, but we could. + _ => + bug!("while adjusting {:?}, can't compose {:?} and {:?}", + expr, entry.get(), adj) + }; + *entry.get_mut() = adj; + } + } + + // If there is an mutable auto-borrow, it is equivalent to `&mut `. + // In this case implicit use of `Deref` and `Index` within `` should + // instead be `DerefMut` and `IndexMut`, so fix those up. + if autoborrow_mut { + self.convert_place_derefs_to_mutable(expr); + } + } + + /// Basically whenever we are converting from a type scheme into + /// the fn body space, we always want to normalize associated + /// types as well. This function combines the two. + fn instantiate_type_scheme(&self, span: Span, substs: SubstsRef<'tcx>, value: &T) -> T + where + T: TypeFoldable<'tcx>, + { + let value = value.subst(self.tcx, substs); + let result = self.normalize_associated_types_in(span, &value); + debug!("instantiate_type_scheme(value={:?}, substs={:?}) = {:?}", value, substs, result); + result + } + + /// As `instantiate_type_scheme`, but for the bounds found in a + /// generic type scheme. + fn instantiate_bounds( + &self, + span: Span, + def_id: DefId, + substs: SubstsRef<'tcx>, + ) -> (ty::InstantiatedPredicates<'tcx>, Vec) { + let bounds = self.tcx.predicates_of(def_id); + let spans: Vec = bounds.predicates.iter().map(|(_, span)| *span).collect(); + let result = bounds.instantiate(self.tcx, substs); + let result = self.normalize_associated_types_in(span, &result); + debug!( + "instantiate_bounds(bounds={:?}, substs={:?}) = {:?}, {:?}", + bounds, substs, result, spans, + ); + (result, spans) + } + + /// Replaces the opaque types from the given value with type variables, + /// and records the `OpaqueTypeMap` for later use during writeback. See + /// `InferCtxt::instantiate_opaque_types` for more details. + pub(super) fn instantiate_opaque_types_from_value>( + &self, + parent_id: hir::HirId, + value: &T, + value_span: Span, + ) -> T { + let parent_def_id = self.tcx.hir().local_def_id(parent_id); + debug!( + "instantiate_opaque_types_from_value(parent_def_id={:?}, value={:?})", + parent_def_id, value + ); + + let (value, opaque_type_map) = + self.register_infer_ok_obligations(self.instantiate_opaque_types( + parent_def_id, + self.body_id, + self.param_env, + value, + value_span, + )); + + let mut opaque_types = self.opaque_types.borrow_mut(); + let mut opaque_types_vars = self.opaque_types_vars.borrow_mut(); + for (ty, decl) in opaque_type_map { + let _ = opaque_types.insert(ty, decl); + let _ = opaque_types_vars.insert(decl.concrete_ty, decl.opaque_type); + } + + value + } + + pub(super) fn normalize_associated_types_in(&self, span: Span, value: &T) -> T + where + T: TypeFoldable<'tcx>, + { + self.inh.normalize_associated_types_in(span, self.body_id, self.param_env, value) + } + + pub(super) fn normalize_associated_types_in_as_infer_ok( + &self, + span: Span, + value: &T, + ) -> InferOk<'tcx, T> + where + T: TypeFoldable<'tcx>, + { + self.inh.partially_normalize_associated_types_in(span, self.body_id, self.param_env, value) + } + + pub fn require_type_meets( + &self, + ty: Ty<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>, + def_id: DefId, + ) { + self.register_bound(ty, def_id, traits::ObligationCause::new(span, self.body_id, code)); + } + + pub fn require_type_is_sized( + &self, + ty: Ty<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>, + ) { + if !ty.references_error() { + let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); + self.require_type_meets(ty, span, code, lang_item); + } + } + + pub fn require_type_is_sized_deferred( + &self, + ty: Ty<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>, + ) { + if !ty.references_error() { + self.deferred_sized_obligations.borrow_mut().push((ty, span, code)); + } + } + + pub fn register_bound( + &self, + ty: Ty<'tcx>, + def_id: DefId, + cause: traits::ObligationCause<'tcx>, + ) { + if !ty.references_error() { + self.fulfillment_cx.borrow_mut().register_bound( + self, + self.param_env, + ty, + def_id, + cause, + ); + } + } + + pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> Ty<'tcx> { + let t = AstConv::ast_ty_to_ty(self, ast_t); + self.register_wf_obligation(t.into(), ast_t.span, traits::MiscObligation); + t + } + + pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> { + let ty = self.to_ty(ast_ty); + debug!("to_ty_saving_user_provided_ty: ty={:?}", ty); + + if Self::can_contain_user_lifetime_bounds(ty) { + let c_ty = self.infcx.canonicalize_response(&UserType::Ty(ty)); + debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty); + self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty); + } + + ty + } + + pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> { + let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id); + let c = ty::Const::from_anon_const(self.tcx, const_def_id); + self.register_wf_obligation( + c.into(), + self.tcx.hir().span(ast_c.hir_id), + ObligationCauseCode::MiscObligation, + ); + c + } + + pub fn const_arg_to_const( + &self, + ast_c: &hir::AnonConst, + param_def_id: DefId, + ) -> &'tcx ty::Const<'tcx> { + let const_def = ty::WithOptConstParam { + did: self.tcx.hir().local_def_id(ast_c.hir_id), + const_param_did: Some(param_def_id), + }; + let c = ty::Const::from_opt_const_arg_anon_const(self.tcx, const_def); + self.register_wf_obligation( + c.into(), + self.tcx.hir().span(ast_c.hir_id), + ObligationCauseCode::MiscObligation, + ); + c + } + + // If the type given by the user has free regions, save it for later, since + // NLL would like to enforce those. Also pass in types that involve + // projections, since those can resolve to `'static` bounds (modulo #54940, + // which hopefully will be fixed by the time you see this comment, dear + // reader, although I have my doubts). Also pass in types with inference + // types, because they may be repeated. Other sorts of things are already + // sufficiently enforced with erased regions. =) + fn can_contain_user_lifetime_bounds(t: T) -> bool + where + T: TypeFoldable<'tcx>, + { + t.has_free_regions() || t.has_projections() || t.has_infer_types() + } + + pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> { + match self.typeck_results.borrow().node_types().get(id) { + Some(&t) => t, + None if self.is_tainted_by_errors() => self.tcx.ty_error(), + None => { + bug!( + "no type for node {}: {} in fcx {}", + id, + self.tcx.hir().node_to_string(id), + self.tag() + ); + } + } + } + + /// Registers an obligation for checking later, during regionck, that `arg` is well-formed. + pub fn register_wf_obligation( + &self, + arg: subst::GenericArg<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>, + ) { + // WF obligations never themselves fail, so no real need to give a detailed cause: + let cause = traits::ObligationCause::new(span, self.body_id, code); + self.register_predicate(traits::Obligation::new( + cause, + self.param_env, + ty::PredicateAtom::WellFormed(arg).to_predicate(self.tcx), + )); + } + + /// Registers obligations that all `substs` are well-formed. + pub fn add_wf_bounds(&self, substs: SubstsRef<'tcx>, expr: &hir::Expr<'_>) { + for arg in substs.iter().filter(|arg| { + matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..)) + }) { + self.register_wf_obligation(arg, expr.span, traits::MiscObligation); + } + } + + /// Given a fully substituted set of bounds (`generic_bounds`), and the values with which each + /// type/region parameter was instantiated (`substs`), creates and registers suitable + /// trait/region obligations. + /// + /// For example, if there is a function: + /// + /// ``` + /// fn foo<'a,T:'a>(...) + /// ``` + /// + /// and a reference: + /// + /// ``` + /// let f = foo; + /// ``` + /// + /// Then we will create a fresh region variable `'$0` and a fresh type variable `$1` for `'a` + /// and `T`. This routine will add a region obligation `$1:'$0` and register it locally. + pub fn add_obligations_for_parameters( + &self, + cause: traits::ObligationCause<'tcx>, + predicates: ty::InstantiatedPredicates<'tcx>, + ) { + assert!(!predicates.has_escaping_bound_vars()); + + debug!("add_obligations_for_parameters(predicates={:?})", predicates); + + for obligation in traits::predicates_for_generics(cause, self.param_env, predicates) { + self.register_predicate(obligation); + } + } + + // FIXME(arielb1): use this instead of field.ty everywhere + // Only for fields! Returns for methods> + // Indifferent to privacy flags + pub fn field_ty( + &self, + span: Span, + field: &'tcx ty::FieldDef, + substs: SubstsRef<'tcx>, + ) -> Ty<'tcx> { + self.normalize_associated_types_in(span, &field.ty(self.tcx, substs)) + } + + pub(super) fn check_casts(&self) { + let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); + for cast in deferred_cast_checks.drain(..) { + cast.check(self); + } + } + + pub(super) fn resolve_generator_interiors(&self, def_id: DefId) { + let mut generators = self.deferred_generator_interiors.borrow_mut(); + for (body_id, interior, kind) in generators.drain(..) { + self.select_obligations_where_possible(false, |_| {}); + super::generator_interior::resolve_interior(self, def_id, body_id, interior, kind); + } + } + + // Tries to apply a fallback to `ty` if it is an unsolved variable. + // + // - Unconstrained ints are replaced with `i32`. + // + // - Unconstrained floats are replaced with with `f64`. + // + // - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]` + // is enabled. Otherwise, they are replaced with `()`. + // + // Fallback becomes very dubious if we have encountered type-checking errors. + // In that case, fallback to Error. + // The return value indicates whether fallback has occurred. + pub(super) fn fallback_if_possible(&self, ty: Ty<'tcx>, mode: FallbackMode) -> bool { + use rustc_middle::ty::error::UnconstrainedNumeric::Neither; + use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt}; + + assert!(ty.is_ty_infer()); + let fallback = match self.type_is_unconstrained_numeric(ty) { + _ if self.is_tainted_by_errors() => self.tcx().ty_error(), + UnconstrainedInt => self.tcx.types.i32, + UnconstrainedFloat => self.tcx.types.f64, + Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(), + Neither => { + // This type variable was created from the instantiation of an opaque + // type. The fact that we're attempting to perform fallback for it + // means that the function neither constrained it to a concrete + // type, nor to the opaque type itself. + // + // For example, in this code: + // + //``` + // type MyType = impl Copy; + // fn defining_use() -> MyType { true } + // fn other_use() -> MyType { defining_use() } + // ``` + // + // `defining_use` will constrain the instantiated inference + // variable to `bool`, while `other_use` will constrain + // the instantiated inference variable to `MyType`. + // + // When we process opaque types during writeback, we + // will handle cases like `other_use`, and not count + // them as defining usages + // + // However, we also need to handle cases like this: + // + // ```rust + // pub type Foo = impl Copy; + // fn produce() -> Option { + // None + // } + // ``` + // + // In the above snippet, the inference variable created by + // instantiating `Option` will be completely unconstrained. + // We treat this as a non-defining use by making the inference + // variable fall back to the opaque type itself. + if let FallbackMode::All = mode { + if let Some(opaque_ty) = self.opaque_types_vars.borrow().get(ty) { + debug!( + "fallback_if_possible: falling back opaque type var {:?} to {:?}", + ty, opaque_ty + ); + *opaque_ty + } else { + return false; + } + } else { + return false; + } + } + }; + debug!("fallback_if_possible: defaulting `{:?}` to `{:?}`", ty, fallback); + self.demand_eqtype(rustc_span::DUMMY_SP, ty, fallback); + true + } + + pub(super) fn select_all_obligations_or_error(&self) { + debug!("select_all_obligations_or_error"); + if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) { + self.report_fulfillment_errors(&errors, self.inh.body_id, false); + } + } + + /// Select as many obligations as we can at present. + pub(super) fn select_obligations_where_possible( + &self, + fallback_has_occurred: bool, + mutate_fullfillment_errors: impl Fn(&mut Vec>), + ) { + let result = self.fulfillment_cx.borrow_mut().select_where_possible(self); + if let Err(mut errors) = result { + mutate_fullfillment_errors(&mut errors); + self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred); + } + } + + /// For the overloaded place expressions (`*x`, `x[3]`), the trait + /// returns a type of `&T`, but the actual type we assign to the + /// *expression* is `T`. So this function just peels off the return + /// type by one layer to yield `T`. + pub(super) fn make_overloaded_place_return_type( + &self, + method: MethodCallee<'tcx>, + ) -> ty::TypeAndMut<'tcx> { + // extract method return type, which will be &T; + let ret_ty = method.sig.output(); + + // method returns &T, but the type as visible to user is T, so deref + ret_ty.builtin_deref(true).unwrap() + } + + pub(super) fn check_method_argument_types( + &self, + sp: Span, + expr: &'tcx hir::Expr<'tcx>, + method: Result, ()>, + args_no_rcvr: &'tcx [hir::Expr<'tcx>], + tuple_arguments: TupleArgumentsFlag, + expected: Expectation<'tcx>, + ) -> Ty<'tcx> { + let has_error = match method { + Ok(method) => method.substs.references_error() || method.sig.references_error(), + Err(_) => true, + }; + if has_error { + let err_inputs = self.err_args(args_no_rcvr.len()); + + let err_inputs = match tuple_arguments { + DontTupleArguments => err_inputs, + TupleArguments => vec![self.tcx.intern_tup(&err_inputs[..])], + }; + + self.check_argument_types( + sp, + expr, + &err_inputs[..], + &[], + args_no_rcvr, + false, + tuple_arguments, + None, + ); + return self.tcx.ty_error(); + } + + let method = method.unwrap(); + // HACK(eddyb) ignore self in the definition (see above). + let expected_arg_tys = self.expected_inputs_for_expected_output( + sp, + expected, + method.sig.output(), + &method.sig.inputs()[1..], + ); + self.check_argument_types( + sp, + expr, + &method.sig.inputs()[1..], + &expected_arg_tys[..], + args_no_rcvr, + method.sig.c_variadic, + tuple_arguments, + self.tcx.hir().span_if_local(method.def_id), + ); + method.sig.output() + } + + fn self_type_matches_expected_vid( + &self, + trait_ref: ty::PolyTraitRef<'tcx>, + expected_vid: ty::TyVid, + ) -> bool { + let self_ty = self.shallow_resolve(trait_ref.skip_binder().self_ty()); + debug!( + "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?}, expected_vid={:?})", + trait_ref, self_ty, expected_vid + ); + match *self_ty.kind() { + ty::Infer(ty::TyVar(found_vid)) => { + // FIXME: consider using `sub_root_var` here so we + // can see through subtyping. + let found_vid = self.root_var(found_vid); + debug!("self_type_matches_expected_vid - found_vid={:?}", found_vid); + expected_vid == found_vid + } + _ => false, + } + } + + pub(super) fn obligations_for_self_ty<'b>( + &'b self, + self_ty: ty::TyVid, + ) -> impl Iterator, traits::PredicateObligation<'tcx>)> + + Captures<'tcx> + + 'b { + // FIXME: consider using `sub_root_var` here so we + // can see through subtyping. + let ty_var_root = self.root_var(self_ty); + debug!( + "obligations_for_self_ty: self_ty={:?} ty_var_root={:?} pending_obligations={:?}", + self_ty, + ty_var_root, + self.fulfillment_cx.borrow().pending_obligations() + ); + + self.fulfillment_cx + .borrow() + .pending_obligations() + .into_iter() + .filter_map(move |obligation| { + match obligation.predicate.skip_binders() { + ty::PredicateAtom::Projection(data) => { + Some((ty::Binder::bind(data).to_poly_trait_ref(self.tcx), obligation)) + } + ty::PredicateAtom::Trait(data, _) => { + Some((ty::Binder::bind(data).to_poly_trait_ref(), obligation)) + } + ty::PredicateAtom::Subtype(..) => None, + ty::PredicateAtom::RegionOutlives(..) => None, + ty::PredicateAtom::TypeOutlives(..) => None, + ty::PredicateAtom::WellFormed(..) => None, + ty::PredicateAtom::ObjectSafe(..) => None, + ty::PredicateAtom::ConstEvaluatable(..) => None, + ty::PredicateAtom::ConstEquate(..) => None, + // N.B., this predicate is created by breaking down a + // `ClosureType: FnFoo()` predicate, where + // `ClosureType` represents some `Closure`. It can't + // possibly be referring to the current closure, + // because we haven't produced the `Closure` for + // this closure yet; this is exactly why the other + // code is looking for a self type of a unresolved + // inference variable. + ty::PredicateAtom::ClosureKind(..) => None, + ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, + } + }) + .filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root)) + } + + pub(super) fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool { + self.obligations_for_self_ty(self_ty) + .any(|(tr, _)| Some(tr.def_id()) == self.tcx.lang_items().sized_trait()) + } + + /// Generic function that factors out common logic from function calls, + /// method calls and overloaded operators. + pub(super) fn check_argument_types( + &self, + sp: Span, + expr: &'tcx hir::Expr<'tcx>, + fn_inputs: &[Ty<'tcx>], + expected_arg_tys: &[Ty<'tcx>], + args: &'tcx [hir::Expr<'tcx>], + c_variadic: bool, + tuple_arguments: TupleArgumentsFlag, + def_span: Option, + ) { + let tcx = self.tcx; + // Grab the argument types, supplying fresh type variables + // if the wrong number of arguments were supplied + let supplied_arg_count = if tuple_arguments == DontTupleArguments { args.len() } else { 1 }; + + // All the input types from the fn signature must outlive the call + // so as to validate implied bounds. + for (&fn_input_ty, arg_expr) in fn_inputs.iter().zip(args.iter()) { + self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation); + } + + let expected_arg_count = fn_inputs.len(); + + let param_count_error = |expected_count: usize, + arg_count: usize, + error_code: &str, + c_variadic: bool, + sugg_unit: bool| { + let (span, start_span, args) = match &expr.kind { + hir::ExprKind::Call(hir::Expr { span, .. }, args) => (*span, *span, &args[..]), + hir::ExprKind::MethodCall(path_segment, span, args, _) => ( + *span, + // `sp` doesn't point at the whole `foo.bar()`, only at `bar`. + path_segment + .args + .and_then(|args| args.args.iter().last()) + // Account for `foo.bar::()`. + .map(|arg| { + // Skip the closing `>`. + tcx.sess + .source_map() + .next_point(tcx.sess.source_map().next_point(arg.span())) + }) + .unwrap_or(*span), + &args[1..], // Skip the receiver. + ), + k => span_bug!(sp, "checking argument types on a non-call: `{:?}`", k), + }; + let arg_spans = if args.is_empty() { + // foo() + // ^^^-- supplied 0 arguments + // | + // expected 2 arguments + vec![tcx.sess.source_map().next_point(start_span).with_hi(sp.hi())] + } else { + // foo(1, 2, 3) + // ^^^ - - - supplied 3 arguments + // | + // expected 2 arguments + args.iter().map(|arg| arg.span).collect::>() + }; + + let mut err = tcx.sess.struct_span_err_with_code( + span, + &format!( + "this function takes {}{} but {} {} supplied", + if c_variadic { "at least " } else { "" }, + potentially_plural_count(expected_count, "argument"), + potentially_plural_count(arg_count, "argument"), + if arg_count == 1 { "was" } else { "were" } + ), + DiagnosticId::Error(error_code.to_owned()), + ); + let label = format!("supplied {}", potentially_plural_count(arg_count, "argument")); + for (i, span) in arg_spans.into_iter().enumerate() { + err.span_label( + span, + if arg_count == 0 || i + 1 == arg_count { &label } else { "" }, + ); + } + + if let Some(def_s) = def_span.map(|sp| tcx.sess.source_map().guess_head_span(sp)) { + err.span_label(def_s, "defined here"); + } + if sugg_unit { + let sugg_span = tcx.sess.source_map().end_point(expr.span); + // remove closing `)` from the span + let sugg_span = sugg_span.shrink_to_lo(); + err.span_suggestion( + sugg_span, + "expected the unit value `()`; create it with empty parentheses", + String::from("()"), + Applicability::MachineApplicable, + ); + } else { + err.span_label( + span, + format!( + "expected {}{}", + if c_variadic { "at least " } else { "" }, + potentially_plural_count(expected_count, "argument") + ), + ); + } + err.emit(); + }; + + let mut expected_arg_tys = expected_arg_tys.to_vec(); + + let formal_tys = if tuple_arguments == TupleArguments { + let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]); + match tuple_type.kind() { + ty::Tuple(arg_types) if arg_types.len() != args.len() => { + param_count_error(arg_types.len(), args.len(), "E0057", false, false); + expected_arg_tys = vec![]; + self.err_args(args.len()) + } + ty::Tuple(arg_types) => { + expected_arg_tys = match expected_arg_tys.get(0) { + Some(&ty) => match ty.kind() { + ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(), + _ => vec![], + }, + None => vec![], + }; + arg_types.iter().map(|k| k.expect_ty()).collect() + } + _ => { + struct_span_err!( + tcx.sess, + sp, + E0059, + "cannot use call notation; the first type parameter \ + for the function trait is neither a tuple nor unit" + ) + .emit(); + expected_arg_tys = vec![]; + self.err_args(args.len()) + } + } + } else if expected_arg_count == supplied_arg_count { + fn_inputs.to_vec() + } else if c_variadic { + if supplied_arg_count >= expected_arg_count { + fn_inputs.to_vec() + } else { + param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false); + expected_arg_tys = vec![]; + self.err_args(supplied_arg_count) + } + } else { + // is the missing argument of type `()`? + let sugg_unit = if expected_arg_tys.len() == 1 && supplied_arg_count == 0 { + self.resolve_vars_if_possible(&expected_arg_tys[0]).is_unit() + } else if fn_inputs.len() == 1 && supplied_arg_count == 0 { + self.resolve_vars_if_possible(&fn_inputs[0]).is_unit() + } else { + false + }; + param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit); + + expected_arg_tys = vec![]; + self.err_args(supplied_arg_count) + }; + + debug!( + "check_argument_types: formal_tys={:?}", + formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::>() + ); + + // If there is no expectation, expect formal_tys. + let expected_arg_tys = + if !expected_arg_tys.is_empty() { expected_arg_tys } else { formal_tys.clone() }; + + let mut final_arg_types: Vec<(usize, Ty<'_>, Ty<'_>)> = vec![]; + + // Check the arguments. + // We do this in a pretty awful way: first we type-check any arguments + // that are not closures, then we type-check the closures. This is so + // that we have more information about the types of arguments when we + // type-check the functions. This isn't really the right way to do this. + for &check_closures in &[false, true] { + debug!("check_closures={}", check_closures); + + // More awful hacks: before we check argument types, try to do + // an "opportunistic" trait resolution of any trait bounds on + // the call. This helps coercions. + if check_closures { + self.select_obligations_where_possible(false, |errors| { + self.point_at_type_arg_instead_of_call_if_possible(errors, expr); + self.point_at_arg_instead_of_call_if_possible( + errors, + &final_arg_types[..], + sp, + &args, + ); + }) + } + + // For C-variadic functions, we don't have a declared type for all of + // the arguments hence we only do our usual type checking with + // the arguments who's types we do know. + let t = if c_variadic { + expected_arg_count + } else if tuple_arguments == TupleArguments { + args.len() + } else { + supplied_arg_count + }; + for (i, arg) in args.iter().take(t).enumerate() { + // Warn only for the first loop (the "no closures" one). + // Closure arguments themselves can't be diverging, but + // a previous argument can, e.g., `foo(panic!(), || {})`. + if !check_closures { + self.warn_if_unreachable(arg.hir_id, arg.span, "expression"); + } + + let is_closure = match arg.kind { + ExprKind::Closure(..) => true, + _ => false, + }; + + if is_closure != check_closures { + continue; + } + + debug!("checking the argument"); + let formal_ty = formal_tys[i]; + + // The special-cased logic below has three functions: + // 1. Provide as good of an expected type as possible. + let expected = Expectation::rvalue_hint(self, expected_arg_tys[i]); + + let checked_ty = self.check_expr_with_expectation(&arg, expected); + + // 2. Coerce to the most detailed type that could be coerced + // to, which is `expected_ty` if `rvalue_hint` returns an + // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. + let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty); + // We're processing function arguments so we definitely want to use + // two-phase borrows. + self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes); + final_arg_types.push((i, checked_ty, coerce_ty)); + + // 3. Relate the expected type and the formal one, + // if the expected type was used for the coercion. + self.demand_suptype(arg.span, formal_ty, coerce_ty); + } + } + + // We also need to make sure we at least write the ty of the other + // arguments which we skipped above. + if c_variadic { + fn variadic_error<'tcx>(s: &Session, span: Span, t: Ty<'tcx>, cast_ty: &str) { + use crate::structured_errors::{StructuredDiagnostic, VariadicError}; + VariadicError::new(s, span, t, cast_ty).diagnostic().emit(); + } + + for arg in args.iter().skip(expected_arg_count) { + let arg_ty = self.check_expr(&arg); + + // There are a few types which get autopromoted when passed via varargs + // in C but we just error out instead and require explicit casts. + let arg_ty = self.structurally_resolved_type(arg.span, arg_ty); + match arg_ty.kind() { + ty::Float(ast::FloatTy::F32) => { + variadic_error(tcx.sess, arg.span, arg_ty, "c_double"); + } + ty::Int(ast::IntTy::I8 | ast::IntTy::I16) | ty::Bool => { + variadic_error(tcx.sess, arg.span, arg_ty, "c_int"); + } + ty::Uint(ast::UintTy::U8 | ast::UintTy::U16) => { + variadic_error(tcx.sess, arg.span, arg_ty, "c_uint"); + } + ty::FnDef(..) => { + let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx)); + let ptr_ty = self.resolve_vars_if_possible(&ptr_ty); + variadic_error(tcx.sess, arg.span, arg_ty, &ptr_ty.to_string()); + } + _ => {} + } + } + } + } + + pub(super) fn err_args(&self, len: usize) -> Vec> { + vec![self.tcx.ty_error(); len] + } + + /// Given a vec of evaluated `FulfillmentError`s and an `fn` call argument expressions, we walk + /// the checked and coerced types for each argument to see if any of the `FulfillmentError`s + /// reference a type argument. The reason to walk also the checked type is that the coerced type + /// can be not easily comparable with predicate type (because of coercion). If the types match + /// for either checked or coerced type, and there's only *one* argument that does, we point at + /// the corresponding argument's expression span instead of the `fn` call path span. + fn point_at_arg_instead_of_call_if_possible( + &self, + errors: &mut Vec>, + final_arg_types: &[(usize, Ty<'tcx>, Ty<'tcx>)], + call_sp: Span, + args: &'tcx [hir::Expr<'tcx>], + ) { + // We *do not* do this for desugared call spans to keep good diagnostics when involving + // the `?` operator. + if call_sp.desugaring_kind().is_some() { + return; + } + + for error in errors { + // Only if the cause is somewhere inside the expression we want try to point at arg. + // Otherwise, it means that the cause is somewhere else and we should not change + // anything because we can break the correct span. + if !call_sp.contains(error.obligation.cause.span) { + continue; + } + + if let ty::PredicateAtom::Trait(predicate, _) = + error.obligation.predicate.skip_binders() + { + // Collect the argument position for all arguments that could have caused this + // `FulfillmentError`. + let mut referenced_in = final_arg_types + .iter() + .map(|&(i, checked_ty, _)| (i, checked_ty)) + .chain(final_arg_types.iter().map(|&(i, _, coerced_ty)| (i, coerced_ty))) + .flat_map(|(i, ty)| { + let ty = self.resolve_vars_if_possible(&ty); + // We walk the argument type because the argument's type could have + // been `Option`, but the `FulfillmentError` references `T`. + if ty.walk().any(|arg| arg == predicate.self_ty().into()) { + Some(i) + } else { + None + } + }) + .collect::>(); + + // Both checked and coerced types could have matched, thus we need to remove + // duplicates. + + // We sort primitive type usize here and can use unstable sort + referenced_in.sort_unstable(); + referenced_in.dedup(); + + if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) { + // We make sure that only *one* argument matches the obligation failure + // and we assign the obligation's span to its expression's. + error.obligation.cause.make_mut().span = args[ref_in].span; + error.points_at_arg_span = true; + } + } + } + } + + /// Given a vec of evaluated `FulfillmentError`s and an `fn` call expression, we walk the + /// `PathSegment`s and resolve their type parameters to see if any of the `FulfillmentError`s + /// were caused by them. If they were, we point at the corresponding type argument's span + /// instead of the `fn` call path span. + fn point_at_type_arg_instead_of_call_if_possible( + &self, + errors: &mut Vec>, + call_expr: &'tcx hir::Expr<'tcx>, + ) { + if let hir::ExprKind::Call(path, _) = &call_expr.kind { + if let hir::ExprKind::Path(qpath) = &path.kind { + if let hir::QPath::Resolved(_, path) = &qpath { + for error in errors { + if let ty::PredicateAtom::Trait(predicate, _) = + error.obligation.predicate.skip_binders() + { + // If any of the type arguments in this path segment caused the + // `FullfillmentError`, point at its span (#61860). + for arg in path + .segments + .iter() + .filter_map(|seg| seg.args.as_ref()) + .flat_map(|a| a.args.iter()) + { + if let hir::GenericArg::Type(hir_ty) = &arg { + if let hir::TyKind::Path(hir::QPath::TypeRelative(..)) = + &hir_ty.kind + { + // Avoid ICE with associated types. As this is best + // effort only, it's ok to ignore the case. It + // would trigger in `is_send::();` + // from `typeck-default-trait-impl-assoc-type.rs`. + } else { + let ty = AstConv::ast_ty_to_ty(self, hir_ty); + let ty = self.resolve_vars_if_possible(&ty); + if ty == predicate.self_ty() { + error.obligation.cause.make_mut().span = hir_ty.span; + } + } + } + } + } + } + } + } + } + } + + // AST fragment checking + pub(super) fn check_lit(&self, lit: &hir::Lit, expected: Expectation<'tcx>) -> Ty<'tcx> { + let tcx = self.tcx; + + match lit.node { + ast::LitKind::Str(..) => tcx.mk_static_str(), + ast::LitKind::ByteStr(ref v) => { + tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.u8, v.len() as u64)) + } + ast::LitKind::Byte(_) => tcx.types.u8, + ast::LitKind::Char(_) => tcx.types.char, + ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(t), + ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(t), + ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => { + let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { + ty::Int(_) | ty::Uint(_) => Some(ty), + ty::Char => Some(tcx.types.u8), + ty::RawPtr(..) => Some(tcx.types.usize), + ty::FnDef(..) | ty::FnPtr(_) => Some(tcx.types.usize), + _ => None, + }); + opt_ty.unwrap_or_else(|| self.next_int_var()) + } + ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => tcx.mk_mach_float(t), + ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => { + let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { + ty::Float(_) => Some(ty), + _ => None, + }); + opt_ty.unwrap_or_else(|| self.next_float_var()) + } + ast::LitKind::Bool(_) => tcx.types.bool, + ast::LitKind::Err(_) => tcx.ty_error(), + } + } + + /// Unifies the output type with the expected type early, for more coercions + /// and forward type information on the input expressions. + pub(super) fn expected_inputs_for_expected_output( + &self, + call_span: Span, + expected_ret: Expectation<'tcx>, + formal_ret: Ty<'tcx>, + formal_args: &[Ty<'tcx>], + ) -> Vec> { + let formal_ret = self.resolve_vars_with_obligations(formal_ret); + let ret_ty = match expected_ret.only_has_type(self) { + Some(ret) => ret, + None => return Vec::new(), + }; + let expect_args = self + .fudge_inference_if_ok(|| { + // Attempt to apply a subtyping relationship between the formal + // return type (likely containing type variables if the function + // is polymorphic) and the expected return type. + // No argument expectations are produced if unification fails. + let origin = self.misc(call_span); + let ures = self.at(&origin, self.param_env).sup(ret_ty, &formal_ret); + + // FIXME(#27336) can't use ? here, Try::from_error doesn't default + // to identity so the resulting type is not constrained. + match ures { + Ok(ok) => { + // Process any obligations locally as much as + // we can. We don't care if some things turn + // out unconstrained or ambiguous, as we're + // just trying to get hints here. + self.save_and_restore_in_snapshot_flag(|_| { + let mut fulfill = TraitEngine::new(self.tcx); + for obligation in ok.obligations { + fulfill.register_predicate_obligation(self, obligation); + } + fulfill.select_where_possible(self) + }) + .map_err(|_| ())?; + } + Err(_) => return Err(()), + } + + // Record all the argument types, with the substitutions + // produced from the above subtyping unification. + Ok(formal_args.iter().map(|ty| self.resolve_vars_if_possible(ty)).collect()) + }) + .unwrap_or_default(); + debug!( + "expected_inputs_for_expected_output(formal={:?} -> {:?}, expected={:?} -> {:?})", + formal_args, formal_ret, expect_args, expected_ret + ); + expect_args + } + + pub fn check_struct_path( + &self, + qpath: &QPath<'_>, + hir_id: hir::HirId, + ) -> Option<(&'tcx ty::VariantDef, Ty<'tcx>)> { + let path_span = qpath.qself_span(); + let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id); + let variant = match def { + Res::Err => { + self.set_tainted_by_errors(); + return None; + } + Res::Def(DefKind::Variant, _) => match ty.kind() { + ty::Adt(adt, substs) => Some((adt.variant_of_res(def), adt.did, substs)), + _ => bug!("unexpected type: {:?}", ty), + }, + Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) + | Res::SelfTy(..) => match ty.kind() { + ty::Adt(adt, substs) if !adt.is_enum() => { + Some((adt.non_enum_variant(), adt.did, substs)) + } + _ => None, + }, + _ => bug!("unexpected definition: {:?}", def), + }; + + if let Some((variant, did, substs)) = variant { + debug!("check_struct_path: did={:?} substs={:?}", did, substs); + self.write_user_type_annotation_from_substs(hir_id, did, substs, None); + + // Check bounds on type arguments used in the path. + let (bounds, _) = self.instantiate_bounds(path_span, did, substs); + let cause = + traits::ObligationCause::new(path_span, self.body_id, traits::ItemObligation(did)); + self.add_obligations_for_parameters(cause, bounds); + + Some((variant, ty)) + } else { + struct_span_err!( + self.tcx.sess, + path_span, + E0071, + "expected struct, variant or union type, found {}", + ty.sort_string(self.tcx) + ) + .span_label(path_span, "not a struct") + .emit(); + None + } + } + + // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary. + // The newly resolved definition is written into `type_dependent_defs`. + fn finish_resolving_struct_path( + &self, + qpath: &QPath<'_>, + path_span: Span, + hir_id: hir::HirId, + ) -> (Res, Ty<'tcx>) { + match *qpath { + QPath::Resolved(ref maybe_qself, ref path) => { + let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself)); + let ty = AstConv::res_to_ty(self, self_ty, path, true); + (path.res, ty) + } + QPath::TypeRelative(ref qself, ref segment) => { + let ty = self.to_ty(qself); + + let res = if let hir::TyKind::Path(QPath::Resolved(_, ref path)) = qself.kind { + path.res + } else { + Res::Err + }; + let result = + AstConv::associated_path_to_ty(self, hir_id, path_span, ty, res, segment, true); + let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error()); + let result = result.map(|(_, kind, def_id)| (kind, def_id)); + + // Write back the new resolution. + self.write_resolution(hir_id, result); + + (result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), ty) + } + QPath::LangItem(lang_item, span) => { + self.resolve_lang_item_path(lang_item, span, hir_id) + } + } + } + + pub(super) fn resolve_lang_item_path( + &self, + lang_item: hir::LangItem, + span: Span, + hir_id: hir::HirId, + ) -> (Res, Ty<'tcx>) { + let def_id = self.tcx.require_lang_item(lang_item, Some(span)); + let def_kind = self.tcx.def_kind(def_id); + + let item_ty = if let DefKind::Variant = def_kind { + self.tcx.type_of(self.tcx.parent(def_id).expect("variant w/out parent")) + } else { + self.tcx.type_of(def_id) + }; + let substs = self.infcx.fresh_substs_for_item(span, def_id); + let ty = item_ty.subst(self.tcx, substs); + + self.write_resolution(hir_id, Ok((def_kind, def_id))); + self.add_required_obligations(span, def_id, &substs); + (Res::Def(def_kind, def_id), ty) + } + + /// Resolves an associated value path into a base type and associated constant, or method + /// resolution. The newly resolved definition is written into `type_dependent_defs`. + pub fn resolve_ty_and_res_ufcs<'b>( + &self, + qpath: &'b QPath<'b>, + hir_id: hir::HirId, + span: Span, + ) -> (Res, Option>, &'b [hir::PathSegment<'b>]) { + debug!("resolve_ty_and_res_ufcs: qpath={:?} hir_id={:?} span={:?}", qpath, hir_id, span); + let (ty, qself, item_segment) = match *qpath { + QPath::Resolved(ref opt_qself, ref path) => { + return ( + path.res, + opt_qself.as_ref().map(|qself| self.to_ty(qself)), + &path.segments[..], + ); + } + QPath::TypeRelative(ref qself, ref segment) => (self.to_ty(qself), qself, segment), + QPath::LangItem(..) => bug!("`resolve_ty_and_res_ufcs` called on `LangItem`"), + }; + if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id) + { + // Return directly on cache hit. This is useful to avoid doubly reporting + // errors with default match binding modes. See #44614. + let def = + cached_result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err); + return (def, Some(ty), slice::from_ref(&**item_segment)); + } + let item_name = item_segment.ident; + let result = self.resolve_ufcs(span, item_name, ty, hir_id).or_else(|error| { + let result = match error { + method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)), + _ => Err(ErrorReported), + }; + if item_name.name != kw::Invalid { + if let Some(mut e) = self.report_method_error( + span, + ty, + item_name, + SelfSource::QPath(qself), + error, + None, + ) { + e.emit(); + } + } + result + }); + + // Write back the new resolution. + self.write_resolution(hir_id, result); + ( + result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), + Some(ty), + slice::from_ref(&**item_segment), + ) + } + + pub fn check_decl_initializer( + &self, + local: &'tcx hir::Local<'tcx>, + init: &'tcx hir::Expr<'tcx>, + ) -> Ty<'tcx> { + // FIXME(tschottdorf): `contains_explicit_ref_binding()` must be removed + // for #42640 (default match binding modes). + // + // See #44848. + let ref_bindings = local.pat.contains_explicit_ref_binding(); + + let local_ty = self.local_ty(init.span, local.hir_id).revealed_ty; + if let Some(m) = ref_bindings { + // Somewhat subtle: if we have a `ref` binding in the pattern, + // we want to avoid introducing coercions for the RHS. This is + // both because it helps preserve sanity and, in the case of + // ref mut, for soundness (issue #23116). In particular, in + // the latter case, we need to be clear that the type of the + // referent for the reference that results is *equal to* the + // type of the place it is referencing, and not some + // supertype thereof. + let init_ty = self.check_expr_with_needs(init, Needs::maybe_mut_place(m)); + self.demand_eqtype(init.span, local_ty, init_ty); + init_ty + } else { + self.check_expr_coercable_to_type(init, local_ty, None) + } + } + + /// Type check a `let` statement. + pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) { + // Determine and write the type which we'll check the pattern against. + let ty = self.local_ty(local.span, local.hir_id).decl_ty; + self.write_ty(local.hir_id, ty); + + // Type check the initializer. + if let Some(ref init) = local.init { + let init_ty = self.check_decl_initializer(local, &init); + self.overwrite_local_ty_if_err(local, ty, init_ty); + } + + // Does the expected pattern type originate from an expression and what is the span? + let (origin_expr, ty_span) = match (local.ty, local.init) { + (Some(ty), _) => (false, Some(ty.span)), // Bias towards the explicit user type. + (_, Some(init)) => (true, Some(init.span)), // No explicit type; so use the scrutinee. + _ => (false, None), // We have `let $pat;`, so the expected type is unconstrained. + }; + + // Type check the pattern. Override if necessary to avoid knock-on errors. + self.check_pat_top(&local.pat, ty, ty_span, origin_expr); + let pat_ty = self.node_ty(local.pat.hir_id); + self.overwrite_local_ty_if_err(local, ty, pat_ty); + } + + fn overwrite_local_ty_if_err( + &self, + local: &'tcx hir::Local<'tcx>, + decl_ty: Ty<'tcx>, + ty: Ty<'tcx>, + ) { + if ty.references_error() { + // Override the types everywhere with `err()` to avoid knock on errors. + self.write_ty(local.hir_id, ty); + self.write_ty(local.pat.hir_id, ty); + let local_ty = LocalTy { decl_ty, revealed_ty: ty }; + self.locals.borrow_mut().insert(local.hir_id, local_ty); + self.locals.borrow_mut().insert(local.pat.hir_id, local_ty); + } + } + + pub(super) fn suggest_semicolon_at_end(&self, span: Span, err: &mut DiagnosticBuilder<'_>) { + err.span_suggestion_short( + span.shrink_to_hi(), + "consider using a semicolon here", + ";".to_string(), + Applicability::MachineApplicable, + ); + } + + pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>) { + // Don't do all the complex logic below for `DeclItem`. + match stmt.kind { + hir::StmtKind::Item(..) => return, + hir::StmtKind::Local(..) | hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {} + } + + self.warn_if_unreachable(stmt.hir_id, stmt.span, "statement"); + + // Hide the outer diverging and `has_errors` flags. + let old_diverges = self.diverges.replace(Diverges::Maybe); + let old_has_errors = self.has_errors.replace(false); + + match stmt.kind { + hir::StmtKind::Local(ref l) => { + self.check_decl_local(&l); + } + // Ignore for now. + hir::StmtKind::Item(_) => {} + hir::StmtKind::Expr(ref expr) => { + // Check with expected type of `()`. + self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit(), |err| { + self.suggest_semicolon_at_end(expr.span, err); + }); + } + hir::StmtKind::Semi(ref expr) => { + self.check_expr(&expr); + } + } + + // Combine the diverging and `has_error` flags. + self.diverges.set(self.diverges.get() | old_diverges); + self.has_errors.set(self.has_errors.get() | old_has_errors); + } + + pub fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) { + let unit = self.tcx.mk_unit(); + let ty = self.check_block_with_expected(blk, ExpectHasType(unit)); + + // if the block produces a `!` value, that can always be + // (effectively) coerced to unit. + if !ty.is_never() { + self.demand_suptype(blk.span, unit, ty); + } + } + + /// If `expr` is a `match` expression that has only one non-`!` arm, use that arm's tail + /// expression's `Span`, otherwise return `expr.span`. This is done to give better errors + /// when given code like the following: + /// ```text + /// if false { return 0i32; } else { 1u32 } + /// // ^^^^ point at this instead of the whole `if` expression + /// ``` + fn get_expr_coercion_span(&self, expr: &hir::Expr<'_>) -> rustc_span::Span { + if let hir::ExprKind::Match(_, arms, _) = &expr.kind { + let arm_spans: Vec = arms + .iter() + .filter_map(|arm| { + self.in_progress_typeck_results + .and_then(|typeck_results| { + typeck_results.borrow().node_type_opt(arm.body.hir_id) + }) + .and_then(|arm_ty| { + if arm_ty.is_never() { + None + } else { + Some(match &arm.body.kind { + // Point at the tail expression when possible. + hir::ExprKind::Block(block, _) => { + block.expr.as_ref().map(|e| e.span).unwrap_or(block.span) + } + _ => arm.body.span, + }) + } + }) + }) + .collect(); + if arm_spans.len() == 1 { + return arm_spans[0]; + } + } + expr.span + } + + pub(super) fn check_block_with_expected( + &self, + blk: &'tcx hir::Block<'tcx>, + expected: Expectation<'tcx>, + ) -> Ty<'tcx> { + let prev = { + let mut fcx_ps = self.ps.borrow_mut(); + let unsafety_state = fcx_ps.recurse(blk); + replace(&mut *fcx_ps, unsafety_state) + }; + + // In some cases, blocks have just one exit, but other blocks + // can be targeted by multiple breaks. This can happen both + // with labeled blocks as well as when we desugar + // a `try { ... }` expression. + // + // Example 1: + // + // 'a: { if true { break 'a Err(()); } Ok(()) } + // + // Here we would wind up with two coercions, one from + // `Err(())` and the other from the tail expression + // `Ok(())`. If the tail expression is omitted, that's a + // "forced unit" -- unless the block diverges, in which + // case we can ignore the tail expression (e.g., `'a: { + // break 'a 22; }` would not force the type of the block + // to be `()`). + let tail_expr = blk.expr.as_ref(); + let coerce_to_ty = expected.coercion_target_type(self, blk.span); + let coerce = if blk.targeted_by_break { + CoerceMany::new(coerce_to_ty) + } else { + let tail_expr: &[&hir::Expr<'_>] = match tail_expr { + Some(e) => slice::from_ref(e), + None => &[], + }; + CoerceMany::with_coercion_sites(coerce_to_ty, tail_expr) + }; + + let prev_diverges = self.diverges.get(); + let ctxt = BreakableCtxt { coerce: Some(coerce), may_break: false }; + + let (ctxt, ()) = self.with_breakable_ctxt(blk.hir_id, ctxt, || { + for s in blk.stmts { + self.check_stmt(s); + } + + // check the tail expression **without** holding the + // `enclosing_breakables` lock below. + let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected)); + + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + let ctxt = enclosing_breakables.find_breakable(blk.hir_id); + let coerce = ctxt.coerce.as_mut().unwrap(); + if let Some(tail_expr_ty) = tail_expr_ty { + let tail_expr = tail_expr.unwrap(); + let span = self.get_expr_coercion_span(tail_expr); + let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id)); + coerce.coerce(self, &cause, tail_expr, tail_expr_ty); + } else { + // Subtle: if there is no explicit tail expression, + // that is typically equivalent to a tail expression + // of `()` -- except if the block diverges. In that + // case, there is no value supplied from the tail + // expression (assuming there are no other breaks, + // this implies that the type of the block will be + // `!`). + // + // #41425 -- label the implicit `()` as being the + // "found type" here, rather than the "expected type". + if !self.diverges.get().is_always() { + // #50009 -- Do not point at the entire fn block span, point at the return type + // span, as it is the cause of the requirement, and + // `consider_hint_about_removing_semicolon` will point at the last expression + // if it were a relevant part of the error. This improves usability in editors + // that highlight errors inline. + let mut sp = blk.span; + let mut fn_span = None; + if let Some((decl, ident)) = self.get_parent_fn_decl(blk.hir_id) { + let ret_sp = decl.output.span(); + if let Some(block_sp) = self.parent_item_span(blk.hir_id) { + // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the + // output would otherwise be incorrect and even misleading. Make sure + // the span we're aiming at correspond to a `fn` body. + if block_sp == blk.span { + sp = ret_sp; + fn_span = Some(ident.span); + } + } + } + coerce.coerce_forced_unit( + self, + &self.misc(sp), + &mut |err| { + if let Some(expected_ty) = expected.only_has_type(self) { + self.consider_hint_about_removing_semicolon(blk, expected_ty, err); + } + if let Some(fn_span) = fn_span { + err.span_label( + fn_span, + "implicitly returns `()` as its body has no tail or `return` \ + expression", + ); + } + }, + false, + ); + } + } + }); + + if ctxt.may_break { + // If we can break from the block, then the block's exit is always reachable + // (... as long as the entry is reachable) - regardless of the tail of the block. + self.diverges.set(prev_diverges); + } + + let mut ty = ctxt.coerce.unwrap().complete(self); + + if self.has_errors.get() || ty.references_error() { + ty = self.tcx.ty_error() + } + + self.write_ty(blk.hir_id, ty); + + *self.ps.borrow_mut() = prev; + ty + } + + fn parent_item_span(&self, id: hir::HirId) -> Option { + let node = self.tcx.hir().get(self.tcx.hir().get_parent_item(id)); + match node { + Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. }) + | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body_id), .. }) => { + let body = self.tcx.hir().body(body_id); + if let ExprKind::Block(block, _) = &body.value.kind { + return Some(block.span); + } + } + _ => {} + } + None + } + + /// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise. + fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> { + let parent = self.tcx.hir().get(self.tcx.hir().get_parent_item(blk_id)); + self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident)) + } + + /// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise. + pub(super) fn get_node_fn_decl( + &self, + node: Node<'tcx>, + ) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident, bool)> { + match node { + Node::Item(&hir::Item { ident, kind: hir::ItemKind::Fn(ref sig, ..), .. }) => { + // This is less than ideal, it will not suggest a return type span on any + // method called `main`, regardless of whether it is actually the entry point, + // but it will still present it as the reason for the expected type. + Some((&sig.decl, ident, ident.name != sym::main)) + } + Node::TraitItem(&hir::TraitItem { + ident, + kind: hir::TraitItemKind::Fn(ref sig, ..), + .. + }) => Some((&sig.decl, ident, true)), + Node::ImplItem(&hir::ImplItem { + ident, + kind: hir::ImplItemKind::Fn(ref sig, ..), + .. + }) => Some((&sig.decl, ident, false)), + _ => None, + } + } + + /// Given a `HirId`, return the `FnDecl` of the method it is enclosed by and whether a + /// suggestion can be made, `None` otherwise. + pub fn get_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, bool)> { + // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or + // `while` before reaching it, as block tail returns are not available in them. + self.tcx.hir().get_return_block(blk_id).and_then(|blk_id| { + let parent = self.tcx.hir().get(blk_id); + self.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main)) + }) + } + + /// On implicit return expressions with mismatched types, provides the following suggestions: + /// + /// - Points out the method's return type as the reason for the expected type. + /// - Possible missing semicolon. + /// - Possible missing return type if the return type is the default, and not `fn main()`. + pub fn suggest_mismatched_types_on_tail( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &'tcx hir::Expr<'tcx>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + cause_span: Span, + blk_id: hir::HirId, + ) -> bool { + let expr = expr.peel_drop_temps(); + self.suggest_missing_semicolon(err, expr, expected, cause_span); + let mut pointing_at_return_type = false; + if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) { + pointing_at_return_type = + self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest); + } + pointing_at_return_type + } + + /// When encountering an fn-like ctor that needs to unify with a value, check whether calling + /// the ctor would successfully solve the type mismatch and if so, suggest it: + /// ``` + /// fn foo(x: usize) -> usize { x } + /// let x: usize = foo; // suggest calling the `foo` function: `foo(42)` + /// ``` + fn suggest_fn_call( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) -> bool { + let hir = self.tcx.hir(); + let (def_id, sig) = match *found.kind() { + ty::FnDef(def_id, _) => (def_id, found.fn_sig(self.tcx)), + ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig()), + _ => return false, + }; + + let sig = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, &sig).0; + let sig = self.normalize_associated_types_in(expr.span, &sig); + if self.can_coerce(sig.output(), expected) { + let (mut sugg_call, applicability) = if sig.inputs().is_empty() { + (String::new(), Applicability::MachineApplicable) + } else { + ("...".to_string(), Applicability::HasPlaceholders) + }; + let mut msg = "call this function"; + match hir.get_if_local(def_id) { + Some( + Node::Item(hir::Item { kind: ItemKind::Fn(.., body_id), .. }) + | Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Fn(_, body_id), .. + }) + | Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Provided(body_id)), + .. + }), + ) => { + let body = hir.body(*body_id); + sugg_call = body + .params + .iter() + .map(|param| match ¶m.pat.kind { + hir::PatKind::Binding(_, _, ident, None) + if ident.name != kw::SelfLower => + { + ident.to_string() + } + _ => "_".to_string(), + }) + .collect::>() + .join(", "); + } + Some(Node::Expr(hir::Expr { + kind: ExprKind::Closure(_, _, body_id, _, _), + span: full_closure_span, + .. + })) => { + if *full_closure_span == expr.span { + return false; + } + msg = "call this closure"; + let body = hir.body(*body_id); + sugg_call = body + .params + .iter() + .map(|param| match ¶m.pat.kind { + hir::PatKind::Binding(_, _, ident, None) + if ident.name != kw::SelfLower => + { + ident.to_string() + } + _ => "_".to_string(), + }) + .collect::>() + .join(", "); + } + Some(Node::Ctor(hir::VariantData::Tuple(fields, _))) => { + sugg_call = fields.iter().map(|_| "_").collect::>().join(", "); + match def_id.as_local().map(|def_id| hir.def_kind(def_id)) { + Some(DefKind::Ctor(hir::def::CtorOf::Variant, _)) => { + msg = "instantiate this tuple variant"; + } + Some(DefKind::Ctor(CtorOf::Struct, _)) => { + msg = "instantiate this tuple struct"; + } + _ => {} + } + } + Some(Node::ForeignItem(hir::ForeignItem { + kind: hir::ForeignItemKind::Fn(_, idents, _), + .. + })) => { + sugg_call = idents + .iter() + .map(|ident| { + if ident.name != kw::SelfLower { + ident.to_string() + } else { + "_".to_string() + } + }) + .collect::>() + .join(", ") + } + Some(Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Required(idents)), + .. + })) => { + sugg_call = idents + .iter() + .map(|ident| { + if ident.name != kw::SelfLower { + ident.to_string() + } else { + "_".to_string() + } + }) + .collect::>() + .join(", ") + } + _ => {} + } + err.span_suggestion_verbose( + expr.span.shrink_to_hi(), + &format!("use parentheses to {}", msg), + format!("({})", sugg_call), + applicability, + ); + return true; + } + false + } + + pub fn suggest_deref_ref_or_into( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, + ) { + if let Some((sp, msg, suggestion, applicability)) = self.check_ref(expr, found, expected) { + err.span_suggestion(sp, msg, suggestion, applicability); + } else if let (ty::FnDef(def_id, ..), true) = + (&found.kind(), self.suggest_fn_call(err, expr, expected, found)) + { + if let Some(sp) = self.tcx.hir().span_if_local(*def_id) { + let sp = self.sess().source_map().guess_head_span(sp); + err.span_label(sp, &format!("{} defined here", found)); + } + } else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) { + let is_struct_pat_shorthand_field = + self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, expr.span); + let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id); + if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) { + let mut suggestions = iter::repeat(&expr_text) + .zip(methods.iter()) + .filter_map(|(receiver, method)| { + let method_call = format!(".{}()", method.ident); + if receiver.ends_with(&method_call) { + None // do not suggest code that is already there (#53348) + } else { + let method_call_list = [".to_vec()", ".to_string()"]; + let sugg = if receiver.ends_with(".clone()") + && method_call_list.contains(&method_call.as_str()) + { + let max_len = receiver.rfind('.').unwrap(); + format!("{}{}", &receiver[..max_len], method_call) + } else { + if expr.precedence().order() < ExprPrecedence::MethodCall.order() { + format!("({}){}", receiver, method_call) + } else { + format!("{}{}", receiver, method_call) + } + }; + Some(if is_struct_pat_shorthand_field { + format!("{}: {}", receiver, sugg) + } else { + sugg + }) + } + }) + .peekable(); + if suggestions.peek().is_some() { + err.span_suggestions( + expr.span, + "try using a conversion method", + suggestions, + Applicability::MaybeIncorrect, + ); + } + } + } + } + + /// When encountering the expected boxed value allocated in the stack, suggest allocating it + /// in the heap by calling `Box::new()`. + pub(super) fn suggest_boxing_when_appropriate( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) { + if self.tcx.hir().is_inside_const_context(expr.hir_id) { + // Do not suggest `Box::new` in const context. + return; + } + if !expected.is_box() || found.is_box() { + return; + } + let boxed_found = self.tcx.mk_box(found); + if let (true, Ok(snippet)) = ( + self.can_coerce(boxed_found, expected), + self.sess().source_map().span_to_snippet(expr.span), + ) { + err.span_suggestion( + expr.span, + "store this in the heap by calling `Box::new`", + format!("Box::new({})", snippet), + Applicability::MachineApplicable, + ); + err.note( + "for more on the distinction between the stack and the heap, read \ + https://doc.rust-lang.org/book/ch15-01-box.html, \ + https://doc.rust-lang.org/rust-by-example/std/box.html, and \ + https://doc.rust-lang.org/std/boxed/index.html", + ); + } + } + + pub(super) fn note_internal_mutation_in_method( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) { + if found != self.tcx.types.unit { + return; + } + if let ExprKind::MethodCall(path_segment, _, [rcvr, ..], _) = expr.kind { + if self + .typeck_results + .borrow() + .expr_ty_adjusted_opt(rcvr) + .map_or(true, |ty| expected.peel_refs() != ty.peel_refs()) + { + return; + } + let mut sp = MultiSpan::from_span(path_segment.ident.span); + sp.push_span_label( + path_segment.ident.span, + format!( + "this call modifies {} in-place", + match rcvr.kind { + ExprKind::Path(QPath::Resolved( + None, + hir::Path { segments: [segment], .. }, + )) => format!("`{}`", segment.ident), + _ => "its receiver".to_string(), + } + ), + ); + sp.push_span_label( + rcvr.span, + "you probably want to use this value after calling the method...".to_string(), + ); + err.span_note( + sp, + &format!("method `{}` modifies its receiver in-place", path_segment.ident), + ); + err.note(&format!("...instead of the `()` output of method `{}`", path_segment.ident)); + } + } + + /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`. + pub(super) fn suggest_calling_boxed_future_when_appropriate( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) -> bool { + // Handle #68197. + + if self.tcx.hir().is_inside_const_context(expr.hir_id) { + // Do not suggest `Box::new` in const context. + return false; + } + let pin_did = self.tcx.lang_items().pin_type(); + match expected.kind() { + ty::Adt(def, _) if Some(def.did) != pin_did => return false, + // This guards the `unwrap` and `mk_box` below. + _ if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() => return false, + _ => {} + } + let boxed_found = self.tcx.mk_box(found); + let new_found = self.tcx.mk_lang_item(boxed_found, LangItem::Pin).unwrap(); + if let (true, Ok(snippet)) = ( + self.can_coerce(new_found, expected), + self.sess().source_map().span_to_snippet(expr.span), + ) { + match found.kind() { + ty::Adt(def, _) if def.is_box() => { + err.help("use `Box::pin`"); + } + _ => { + err.span_suggestion( + expr.span, + "you need to pin and box this expression", + format!("Box::pin({})", snippet), + Applicability::MachineApplicable, + ); + } + } + true + } else { + false + } + } + + /// A common error is to forget to add a semicolon at the end of a block, e.g., + /// + /// ``` + /// fn foo() { + /// bar_that_returns_u32() + /// } + /// ``` + /// + /// This routine checks if the return expression in a block would make sense on its own as a + /// statement and the return type has been left as default or has been specified as `()`. If so, + /// it suggests adding a semicolon. + fn suggest_missing_semicolon( + &self, + err: &mut DiagnosticBuilder<'_>, + expression: &'tcx hir::Expr<'tcx>, + expected: Ty<'tcx>, + cause_span: Span, + ) { + if expected.is_unit() { + // `BlockTailExpression` only relevant if the tail expr would be + // useful on its own. + match expression.kind { + ExprKind::Call(..) + | ExprKind::MethodCall(..) + | ExprKind::Loop(..) + | ExprKind::Match(..) + | ExprKind::Block(..) => { + err.span_suggestion( + cause_span.shrink_to_hi(), + "try adding a semicolon", + ";".to_string(), + Applicability::MachineApplicable, + ); + } + _ => (), + } + } + } + + /// A possible error is to forget to add a return type that is needed: + /// + /// ``` + /// fn foo() { + /// bar_that_returns_u32() + /// } + /// ``` + /// + /// This routine checks if the return type is left as default, the method is not part of an + /// `impl` block and that it isn't the `main` method. If so, it suggests setting the return + /// type. + pub(super) fn suggest_missing_return_type( + &self, + err: &mut DiagnosticBuilder<'_>, + fn_decl: &hir::FnDecl<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + can_suggest: bool, + ) -> bool { + // Only suggest changing the return type for methods that + // haven't set a return type at all (and aren't `fn main()` or an impl). + match (&fn_decl.output, found.is_suggestable(), can_suggest, expected.is_unit()) { + (&hir::FnRetTy::DefaultReturn(span), true, true, true) => { + err.span_suggestion( + span, + "try adding a return type", + format!("-> {} ", self.resolve_vars_with_obligations(found)), + Applicability::MachineApplicable, + ); + true + } + (&hir::FnRetTy::DefaultReturn(span), false, true, true) => { + err.span_label(span, "possibly return type missing here?"); + true + } + (&hir::FnRetTy::DefaultReturn(span), _, false, true) => { + // `fn main()` must return `()`, do not suggest changing return type + err.span_label(span, "expected `()` because of default return type"); + true + } + // expectation was caused by something else, not the default return + (&hir::FnRetTy::DefaultReturn(_), _, _, false) => false, + (&hir::FnRetTy::Return(ref ty), _, _, _) => { + // Only point to return type if the expected type is the return type, as if they + // are not, the expectation must have been caused by something else. + debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind); + let sp = ty.span; + let ty = AstConv::ast_ty_to_ty(self, ty); + debug!("suggest_missing_return_type: return type {:?}", ty); + debug!("suggest_missing_return_type: expected type {:?}", ty); + if ty.kind() == expected.kind() { + err.span_label(sp, format!("expected `{}` because of return type", expected)); + return true; + } + false + } + } + } + + /// A possible error is to forget to add `.await` when using futures: + /// + /// ``` + /// async fn make_u32() -> u32 { + /// 22 + /// } + /// + /// fn take_u32(x: u32) {} + /// + /// async fn foo() { + /// let x = make_u32(); + /// take_u32(x); + /// } + /// ``` + /// + /// This routine checks if the found type `T` implements `Future` where `U` is the + /// expected type. If this is the case, and we are inside of an async body, it suggests adding + /// `.await` to the tail of the expression. + pub(super) fn suggest_missing_await( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) { + debug!("suggest_missing_await: expr={:?} expected={:?}, found={:?}", expr, expected, found); + // `.await` is not permitted outside of `async` bodies, so don't bother to suggest if the + // body isn't `async`. + let item_id = self.tcx().hir().get_parent_node(self.body_id); + if let Some(body_id) = self.tcx().hir().maybe_body_owned_by(item_id) { + let body = self.tcx().hir().body(body_id); + if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind { + let sp = expr.span; + // Check for `Future` implementations by constructing a predicate to + // prove: `::Output == U` + let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(sp)); + let item_def_id = self + .tcx + .associated_items(future_trait) + .in_definition_order() + .next() + .unwrap() + .def_id; + // `::Output` + let projection_ty = ty::ProjectionTy { + // `T` + substs: self + .tcx + .mk_substs_trait(found, self.fresh_substs_for_item(sp, item_def_id)), + // `Future::Output` + item_def_id, + }; + + let predicate = ty::PredicateAtom::Projection(ty::ProjectionPredicate { + projection_ty, + ty: expected, + }) + .potentially_quantified(self.tcx, ty::PredicateKind::ForAll); + let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate); + + debug!("suggest_missing_await: trying obligation {:?}", obligation); + + if self.infcx.predicate_may_hold(&obligation) { + debug!("suggest_missing_await: obligation held: {:?}", obligation); + if let Ok(code) = self.sess().source_map().span_to_snippet(sp) { + err.span_suggestion( + sp, + "consider using `.await` here", + format!("{}.await", code), + Applicability::MaybeIncorrect, + ); + } else { + debug!("suggest_missing_await: no snippet for {:?}", sp); + } + } else { + debug!("suggest_missing_await: obligation did not hold: {:?}", obligation) + } + } + } + } + + pub(super) fn suggest_missing_parentheses( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr<'_>, + ) { + let sp = self.tcx.sess.source_map().start_point(expr.span); + if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) { + // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }` + self.tcx.sess.parse_sess.expr_parentheses_needed(err, *sp, None); + } + } + + pub(super) fn note_need_for_fn_pointer( + &self, + err: &mut DiagnosticBuilder<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) { + let (sig, did, substs) = match (&expected.kind(), &found.kind()) { + (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => { + let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1); + let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2); + if sig1 != sig2 { + return; + } + err.note( + "different `fn` items always have unique types, even if their signatures are \ + the same", + ); + (sig1, *did1, substs1) + } + (ty::FnDef(did, substs), ty::FnPtr(sig2)) => { + let sig1 = self.tcx.fn_sig(*did).subst(self.tcx, substs); + if sig1 != *sig2 { + return; + } + (sig1, *did, substs) + } + _ => return, + }; + err.help(&format!("change the expected type to be function pointer `{}`", sig)); + err.help(&format!( + "if the expected type is due to type inference, cast the expected `fn` to a function \ + pointer: `{} as {}`", + self.tcx.def_path_str_with_substs(did, substs), + sig + )); + } + + /// A common error is to add an extra semicolon: + /// + /// ``` + /// fn foo() -> usize { + /// 22; + /// } + /// ``` + /// + /// This routine checks if the final statement in a block is an + /// expression with an explicit semicolon whose type is compatible + /// with `expected_ty`. If so, it suggests removing the semicolon. + fn consider_hint_about_removing_semicolon( + &self, + blk: &'tcx hir::Block<'tcx>, + expected_ty: Ty<'tcx>, + err: &mut DiagnosticBuilder<'_>, + ) { + if let Some(span_semi) = self.could_remove_semicolon(blk, expected_ty) { + err.span_suggestion( + span_semi, + "consider removing this semicolon", + String::new(), + Applicability::MachineApplicable, + ); + } + } + + pub(super) fn could_remove_semicolon( + &self, + blk: &'tcx hir::Block<'tcx>, + expected_ty: Ty<'tcx>, + ) -> Option { + // Be helpful when the user wrote `{... expr;}` and + // taking the `;` off is enough to fix the error. + let last_stmt = blk.stmts.last()?; + let last_expr = match last_stmt.kind { + hir::StmtKind::Semi(ref e) => e, + _ => return None, + }; + let last_expr_ty = self.node_ty(last_expr.hir_id); + if matches!(last_expr_ty.kind(), ty::Error(_)) + || self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err() + { + return None; + } + let original_span = original_sp(last_stmt.span, blk.span); + Some(original_span.with_lo(original_span.hi() - BytePos(1))) + } + + // Instantiates the given path, which must refer to an item with the given + // number of type parameters and type. + pub fn instantiate_value_path( + &self, + segments: &[hir::PathSegment<'_>], + self_ty: Option>, + res: Res, + span: Span, + hir_id: hir::HirId, + ) -> (Ty<'tcx>, Res) { + debug!( + "instantiate_value_path(segments={:?}, self_ty={:?}, res={:?}, hir_id={})", + segments, self_ty, res, hir_id, + ); + + let tcx = self.tcx; + + let path_segs = match res { + Res::Local(_) | Res::SelfCtor(_) => vec![], + Res::Def(kind, def_id) => { + AstConv::def_ids_for_value_path_segments(self, segments, self_ty, kind, def_id) + } + _ => bug!("instantiate_value_path on {:?}", res), + }; + + let mut user_self_ty = None; + let mut is_alias_variant_ctor = false; + match res { + Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) => { + if let Some(self_ty) = self_ty { + let adt_def = self_ty.ty_adt_def().unwrap(); + user_self_ty = Some(UserSelfTy { impl_def_id: adt_def.did, self_ty }); + is_alias_variant_ctor = true; + } + } + Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => { + let container = tcx.associated_item(def_id).container; + debug!("instantiate_value_path: def_id={:?} container={:?}", def_id, container); + match container { + ty::TraitContainer(trait_did) => { + callee::check_legal_trait_for_method_call(tcx, span, None, trait_did) + } + ty::ImplContainer(impl_def_id) => { + if segments.len() == 1 { + // `::assoc` will end up here, and so + // can `T::assoc`. It this came from an + // inherent impl, we need to record the + // `T` for posterity (see `UserSelfTy` for + // details). + let self_ty = self_ty.expect("UFCS sugared assoc missing Self"); + user_self_ty = Some(UserSelfTy { impl_def_id, self_ty }); + } + } + } + } + _ => {} + } + + // Now that we have categorized what space the parameters for each + // segment belong to, let's sort out the parameters that the user + // provided (if any) into their appropriate spaces. We'll also report + // errors if type parameters are provided in an inappropriate place. + + let generic_segs: FxHashSet<_> = path_segs.iter().map(|PathSeg(_, index)| index).collect(); + let generics_has_err = AstConv::prohibit_generics( + self, + segments.iter().enumerate().filter_map(|(index, seg)| { + if !generic_segs.contains(&index) || is_alias_variant_ctor { + Some(seg) + } else { + None + } + }), + ); + + if let Res::Local(hid) = res { + let ty = self.local_ty(span, hid).decl_ty; + let ty = self.normalize_associated_types_in(span, &ty); + self.write_ty(hir_id, ty); + return (ty, res); + } + + if generics_has_err { + // Don't try to infer type parameters when prohibited generic arguments were given. + user_self_ty = None; + } + + // Now we have to compare the types that the user *actually* + // provided against the types that were *expected*. If the user + // did not provide any types, then we want to substitute inference + // variables. If the user provided some types, we may still need + // to add defaults. If the user provided *too many* types, that's + // a problem. + + let mut infer_args_for_err = FxHashSet::default(); + for &PathSeg(def_id, index) in &path_segs { + let seg = &segments[index]; + let generics = tcx.generics_of(def_id); + // Argument-position `impl Trait` is treated as a normal generic + // parameter internally, but we don't allow users to specify the + // parameter's value explicitly, so we have to do some error- + // checking here. + if let GenericArgCountResult { + correct: Err(GenericArgCountMismatch { reported: Some(ErrorReported), .. }), + .. + } = AstConv::check_generic_arg_count_for_call( + tcx, span, &generics, &seg, false, // `is_method_call` + ) { + infer_args_for_err.insert(index); + self.set_tainted_by_errors(); // See issue #53251. + } + } + + let has_self = path_segs + .last() + .map(|PathSeg(def_id, _)| tcx.generics_of(*def_id).has_self) + .unwrap_or(false); + + let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res { + let ty = self.normalize_ty(span, tcx.at(span).type_of(impl_def_id)); + match *ty.kind() { + ty::Adt(adt_def, substs) if adt_def.has_ctor() => { + let variant = adt_def.non_enum_variant(); + let ctor_def_id = variant.ctor_def_id.unwrap(); + ( + Res::Def(DefKind::Ctor(CtorOf::Struct, variant.ctor_kind), ctor_def_id), + Some(substs), + ) + } + _ => { + let mut err = tcx.sess.struct_span_err( + span, + "the `Self` constructor can only be used with tuple or unit structs", + ); + if let Some(adt_def) = ty.ty_adt_def() { + match adt_def.adt_kind() { + AdtKind::Enum => { + err.help("did you mean to use one of the enum's variants?"); + } + AdtKind::Struct | AdtKind::Union => { + err.span_suggestion( + span, + "use curly brackets", + String::from("Self { /* fields */ }"), + Applicability::HasPlaceholders, + ); + } + } + } + err.emit(); + + return (tcx.ty_error(), res); + } + } + } else { + (res, None) + }; + let def_id = res.def_id(); + + // The things we are substituting into the type should not contain + // escaping late-bound regions, and nor should the base type scheme. + let ty = tcx.type_of(def_id); + + let arg_count = GenericArgCountResult { + explicit_late_bound: ExplicitLateBound::No, + correct: if infer_args_for_err.is_empty() { + Ok(()) + } else { + Err(GenericArgCountMismatch::default()) + }, + }; + + let substs = self_ctor_substs.unwrap_or_else(|| { + AstConv::create_substs_for_generic_args( + tcx, + def_id, + &[][..], + has_self, + self_ty, + arg_count, + // Provide the generic args, and whether types should be inferred. + |def_id| { + if let Some(&PathSeg(_, index)) = + path_segs.iter().find(|&PathSeg(did, _)| *did == def_id) + { + // If we've encountered an `impl Trait`-related error, we're just + // going to infer the arguments for better error messages. + if !infer_args_for_err.contains(&index) { + // Check whether the user has provided generic arguments. + if let Some(ref data) = segments[index].args { + return (Some(data), segments[index].infer_args); + } + } + return (None, segments[index].infer_args); + } + + (None, true) + }, + // Provide substitutions for parameters for which (valid) arguments have been provided. + |param, arg| match (¶m.kind, arg) { + (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { + AstConv::ast_region_to_region(self, lt, Some(param)).into() + } + (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { + self.to_ty(ty).into() + } + (GenericParamDefKind::Const, GenericArg::Const(ct)) => { + self.const_arg_to_const(&ct.value, param.def_id).into() + } + _ => unreachable!(), + }, + // Provide substitutions for parameters for which arguments are inferred. + |substs, param, infer_args| { + match param.kind { + GenericParamDefKind::Lifetime => { + self.re_infer(Some(param), span).unwrap().into() + } + GenericParamDefKind::Type { has_default, .. } => { + if !infer_args && has_default { + // If we have a default, then we it doesn't matter that we're not + // inferring the type arguments: we provide the default where any + // is missing. + let default = tcx.type_of(param.def_id); + self.normalize_ty( + span, + default.subst_spanned(tcx, substs.unwrap(), Some(span)), + ) + .into() + } else { + // If no type arguments were provided, we have to infer them. + // This case also occurs as a result of some malformed input, e.g. + // a lifetime argument being given instead of a type parameter. + // Using inference instead of `Error` gives better error messages. + self.var_for_def(span, param) + } + } + GenericParamDefKind::Const => { + // FIXME(const_generics:defaults) + // No const parameters were provided, we have to infer them. + self.var_for_def(span, param) + } + } + }, + ) + }); + assert!(!substs.has_escaping_bound_vars()); + assert!(!ty.has_escaping_bound_vars()); + + // First, store the "user substs" for later. + self.write_user_type_annotation_from_substs(hir_id, def_id, substs, user_self_ty); + + self.add_required_obligations(span, def_id, &substs); + + // Substitute the values for the type parameters into the type of + // the referenced item. + let ty_substituted = self.instantiate_type_scheme(span, &substs, &ty); + + if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { + // In the case of `Foo::method` and `>::method`, if `method` + // is inherent, there is no `Self` parameter; instead, the impl needs + // type parameters, which we can infer by unifying the provided `Self` + // with the substituted impl type. + // This also occurs for an enum variant on a type alias. + let ty = tcx.type_of(impl_def_id); + + let impl_ty = self.instantiate_type_scheme(span, &substs, &ty); + match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) { + Ok(ok) => self.register_infer_ok_obligations(ok), + Err(_) => { + self.tcx.sess.delay_span_bug( + span, + &format!( + "instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?", + self_ty, + impl_ty, + ), + ); + } + } + } + + self.check_rustc_args_require_const(def_id, hir_id, span); + + debug!("instantiate_value_path: type of {:?} is {:?}", hir_id, ty_substituted); + self.write_substs(hir_id, substs); + + (ty_substituted, res) + } + + /// Add all the obligations that are required, substituting and normalized appropriately. + fn add_required_obligations(&self, span: Span, def_id: DefId, substs: &SubstsRef<'tcx>) { + let (bounds, spans) = self.instantiate_bounds(span, def_id, &substs); + + for (i, mut obligation) in traits::predicates_for_generics( + traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def_id)), + self.param_env, + bounds, + ) + .enumerate() + { + // This makes the error point at the bound, but we want to point at the argument + if let Some(span) = spans.get(i) { + obligation.cause.make_mut().code = traits::BindingObligation(def_id, *span); + } + self.register_predicate(obligation); + } + } + + fn check_rustc_args_require_const(&self, def_id: DefId, hir_id: hir::HirId, span: Span) { + // We're only interested in functions tagged with + // #[rustc_args_required_const], so ignore anything that's not. + if !self.tcx.has_attr(def_id, sym::rustc_args_required_const) { + return; + } + + // If our calling expression is indeed the function itself, we're good! + // If not, generate an error that this can only be called directly. + if let Node::Expr(expr) = self.tcx.hir().get(self.tcx.hir().get_parent_node(hir_id)) { + if let ExprKind::Call(ref callee, ..) = expr.kind { + if callee.hir_id == hir_id { + return; + } + } + } + + self.tcx.sess.span_err( + span, + "this function can only be invoked directly, not through a function pointer", + ); + } + + /// Resolves `typ` by a single level if `typ` is a type variable. + /// If no resolution is possible, then an error is reported. + /// Numeric inference variables may be left unresolved. + pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + let ty = self.resolve_vars_with_obligations(ty); + if !ty.is_ty_var() { + ty + } else { + if !self.is_tainted_by_errors() { + self.need_type_info_err((**self).body_id, sp, ty, E0282) + .note("type must be known at this point") + .emit(); + } + let err = self.tcx.ty_error(); + self.demand_suptype(sp, err, ty); + err + } + } + + pub(super) fn with_breakable_ctxt R, R>( + &self, + id: hir::HirId, + ctxt: BreakableCtxt<'tcx>, + f: F, + ) -> (BreakableCtxt<'tcx>, R) { + let index; + { + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + index = enclosing_breakables.stack.len(); + enclosing_breakables.by_id.insert(id, index); + enclosing_breakables.stack.push(ctxt); + } + let result = f(); + let ctxt = { + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + debug_assert!(enclosing_breakables.stack.len() == index + 1); + enclosing_breakables.by_id.remove(&id).expect("missing breakable context"); + enclosing_breakables.stack.pop().expect("missing breakable context") + }; + (ctxt, result) + } + + /// Instantiate a QueryResponse in a probe context, without a + /// good ObligationCause. + pub(super) fn probe_instantiate_query_response( + &self, + span: Span, + original_values: &OriginalQueryValues<'tcx>, + query_result: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, + ) -> InferResult<'tcx, Ty<'tcx>> { + self.instantiate_query_response_and_region_obligations( + &traits::ObligationCause::misc(span, self.body_id), + self.param_env, + original_values, + query_result, + ) + } + + /// Returns `true` if an expression is contained inside the LHS of an assignment expression. + pub(super) fn expr_in_place(&self, mut expr_id: hir::HirId) -> bool { + let mut contained_in_place = false; + + while let hir::Node::Expr(parent_expr) = + self.tcx.hir().get(self.tcx.hir().get_parent_node(expr_id)) + { + match &parent_expr.kind { + hir::ExprKind::Assign(lhs, ..) | hir::ExprKind::AssignOp(_, lhs, ..) => { + if lhs.hir_id == expr_id { + contained_in_place = true; + break; + } + } + _ => (), + } + expr_id = parent_expr.hir_id; + } + + contained_in_place + } +} +impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> { + type Target = Inherited<'a, 'tcx>; + fn deref(&self) -> &Self::Target { + &self.inh + } +} + +impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { + self.tcx + } + + fn item_def_id(&self) -> Option { + None + } + + fn default_constness_for_trait_bounds(&self) -> hir::Constness { + // FIXME: refactor this into a method + let node = self.tcx.hir().get(self.body_id); + if let Some(fn_like) = FnLikeNode::from_node(node) { + fn_like.constness() + } else { + hir::Constness::NotConst + } + } + + fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> { + let tcx = self.tcx; + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + let item_id = tcx.hir().ty_param_owner(hir_id); + let item_def_id = tcx.hir().local_def_id(item_id); + let generics = tcx.generics_of(item_def_id); + let index = generics.param_def_id_to_index[&def_id]; + ty::GenericPredicates { + parent: None, + predicates: tcx.arena.alloc_from_iter( + self.param_env.caller_bounds().iter().filter_map(|predicate| { + match predicate.skip_binders() { + ty::PredicateAtom::Trait(data, _) if data.self_ty().is_param(index) => { + // HACK(eddyb) should get the original `Span`. + let span = tcx.def_span(def_id); + Some((predicate, span)) + } + _ => None, + } + }), + ), + } + } + + fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option> { + let v = match def { + Some(def) => infer::EarlyBoundRegion(span, def.name), + None => infer::MiscVariable(span), + }; + Some(self.next_region_var(v)) + } + + fn allow_ty_infer(&self) -> bool { + true + } + + fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { + if let Some(param) = param { + if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() { + return ty; + } + unreachable!() + } else { + self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span, + }) + } + } + + fn ct_infer( + &self, + ty: Ty<'tcx>, + param: Option<&ty::GenericParamDef>, + span: Span, + ) -> &'tcx Const<'tcx> { + if let Some(param) = param { + if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() { + return ct; + } + unreachable!() + } else { + self.next_const_var( + ty, + ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span }, + ) + } + } + + fn projected_ty_from_poly_trait_ref( + &self, + span: Span, + item_def_id: DefId, + item_segment: &hir::PathSegment<'_>, + poly_trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Ty<'tcx> { + let (trait_ref, _) = self.replace_bound_vars_with_fresh_vars( + span, + infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id), + &poly_trait_ref, + ); + + let item_substs = >::create_substs_for_associated_item( + self, + self.tcx, + span, + item_def_id, + item_segment, + trait_ref.substs, + ); + + self.tcx().mk_projection(item_def_id, item_substs) + } + + fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + if ty.has_escaping_bound_vars() { + ty // FIXME: normalization and escaping regions + } else { + self.normalize_associated_types_in(span, &ty) + } + } + + fn set_tainted_by_errors(&self) { + self.infcx.set_tainted_by_errors() + } + + fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) { + self.write_ty(hir_id, ty) + } +} diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 2b8940f1813d1..5ef718c98ee6b 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -72,6 +72,7 @@ mod compare_method; pub mod demand; pub mod dropck; mod expr; +mod fn_ctxt; mod gather_locals; mod generator_interior; pub mod intrinsic; @@ -85,71 +86,49 @@ mod util; mod wfcheck; pub mod writeback; -use crate::astconv::{ - AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, PathSeg, -}; +pub use fn_ctxt::FnCtxt; + +use crate::astconv::AstConv; use crate::check::gather_locals::GatherLocalsVisitor; use crate::check::util::MaybeInProgressTables; -use rustc_ast as ast; -use rustc_ast::util::parser::ExprPrecedence; use rustc_attr as attr; -use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::ErrorReported; -use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId}; +use rustc_errors::{pluralize, struct_span_err, Applicability}; use rustc_hir as hir; -use rustc_hir::def::{CtorOf, DefKind, Res}; +use rustc_hir::def::Res; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; -use rustc_hir::{ExprKind, GenericArg, HirIdMap, ItemKind, Node, QPath}; +use rustc_hir::{HirIdMap, ItemKind, Node}; use rustc_index::bit_set::BitSet; use rustc_index::vec::Idx; use rustc_infer::infer; -use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; -use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_infer::infer::{InferCtxt, InferOk, InferResult, RegionVariableOrigin, TyCtxtInferExt}; -use rustc_middle::hir::map::blocks::FnLikeNode; -use rustc_middle::ty::adjustment::{ - Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, -}; +use rustc_infer::infer::{InferCtxt, InferOk, RegionVariableOrigin, TyCtxtInferExt}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::subst::{self, InternalSubsts, Subst, SubstsRef}; -use rustc_middle::ty::subst::{GenericArgKind, UserSelfTy, UserSubsts}; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; use rustc_middle::ty::util::{Discr, IntTypeExt, Representability}; use rustc_middle::ty::WithConstness; -use rustc_middle::ty::{self, AdtKind, CanonicalUserType, Const, DefIdTree, GenericParamDefKind}; -use rustc_middle::ty::{RegionKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, UserType}; +use rustc_middle::ty::{self, RegionKind, ToPredicate, Ty, TyCtxt, UserType}; use rustc_session::config::{self, EntryFnType}; -use rustc_session::lint; use rustc_session::parse::feature_err; use rustc_session::Session; -use rustc_span::hygiene::DesugaringKind; -use rustc_span::source_map::{original_sp, DUMMY_SP}; +use rustc_span::source_map::DUMMY_SP; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{self, BytePos, MultiSpan, Span}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; use rustc_trait_selection::infer::InferCtxtExt as _; -use rustc_trait_selection::opaque_types::{InferCtxtExt as _, OpaqueTypeDecl}; +use rustc_trait_selection::opaque_types::OpaqueTypeDecl; use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error; use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; -use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; -use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; -use rustc_trait_selection::traits::{ - self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt, -}; +use rustc_trait_selection::traits::{self, ObligationCauseCode, TraitEngine, TraitEngineExt}; -use std::cell::{Cell, RefCell}; +use std::cell::RefCell; use std::cmp; -use std::collections::hash_map::Entry; -use std::iter; -use std::mem::replace; use std::ops::{self, Deref}; -use std::slice; use crate::require_c_abi_if_c_variadic; use crate::util::common::indenter; @@ -157,9 +136,7 @@ use crate::util::common::indenter; use self::callee::DeferredCallResolution; use self::coercion::{CoerceMany, DynamicCoerceMany}; use self::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl}; -use self::method::{MethodCallee, SelfSource}; pub use self::Expectation::*; -use self::TupleArgumentsFlag::*; #[macro_export] macro_rules! type_error_struct { @@ -513,100 +490,6 @@ impl<'tcx> EnclosingBreakables<'tcx> { } } -pub struct FnCtxt<'a, 'tcx> { - body_id: hir::HirId, - - /// The parameter environment used for proving trait obligations - /// in this function. This can change when we descend into - /// closures (as they bring new things into scope), hence it is - /// not part of `Inherited` (as of the time of this writing, - /// closures do not yet change the environment, but they will - /// eventually). - param_env: ty::ParamEnv<'tcx>, - - /// Number of errors that had been reported when we started - /// checking this function. On exit, if we find that *more* errors - /// have been reported, we will skip regionck and other work that - /// expects the types within the function to be consistent. - // FIXME(matthewjasper) This should not exist, and it's not correct - // if type checking is run in parallel. - err_count_on_creation: usize, - - /// If `Some`, this stores coercion information for returned - /// expressions. If `None`, this is in a context where return is - /// inappropriate, such as a const expression. - /// - /// This is a `RefCell`, which means that we - /// can track all the return expressions and then use them to - /// compute a useful coercion from the set, similar to a match - /// expression or other branching context. You can use methods - /// like `expected_ty` to access the declared return type (if - /// any). - ret_coercion: Option>>, - - ret_coercion_impl_trait: Option>, - - ret_type_span: Option, - - /// Used exclusively to reduce cost of advanced evaluation used for - /// more helpful diagnostics. - in_tail_expr: bool, - - /// First span of a return site that we find. Used in error messages. - ret_coercion_span: RefCell>, - - resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>, - - ps: RefCell, - - /// Whether the last checked node generates a divergence (e.g., - /// `return` will set this to `Always`). In general, when entering - /// an expression or other node in the tree, the initial value - /// indicates whether prior parts of the containing expression may - /// have diverged. It is then typically set to `Maybe` (and the - /// old value remembered) for processing the subparts of the - /// current expression. As each subpart is processed, they may set - /// the flag to `Always`, etc. Finally, at the end, we take the - /// result and "union" it with the original value, so that when we - /// return the flag indicates if any subpart of the parent - /// expression (up to and including this part) has diverged. So, - /// if you read it after evaluating a subexpression `X`, the value - /// you get indicates whether any subexpression that was - /// evaluating up to and including `X` diverged. - /// - /// We currently use this flag only for diagnostic purposes: - /// - /// - To warn about unreachable code: if, after processing a - /// sub-expression but before we have applied the effects of the - /// current node, we see that the flag is set to `Always`, we - /// can issue a warning. This corresponds to something like - /// `foo(return)`; we warn on the `foo()` expression. (We then - /// update the flag to `WarnedAlways` to suppress duplicate - /// reports.) Similarly, if we traverse to a fresh statement (or - /// tail expression) from a `Always` setting, we will issue a - /// warning. This corresponds to something like `{return; - /// foo();}` or `{return; 22}`, where we would warn on the - /// `foo()` or `22`. - /// - /// An expression represents dead code if, after checking it, - /// the diverges flag is set to something other than `Maybe`. - diverges: Cell, - - /// Whether any child nodes have any type errors. - has_errors: Cell, - - enclosing_breakables: RefCell>, - - inh: &'a Inherited<'a, 'tcx>, -} - -impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> { - type Target = Inherited<'a, 'tcx>; - fn deref(&self) -> &Self::Target { - &self.inh - } -} - /// Helper type of a temporary returned by `Inherited::build(...)`. /// Necessary because we can't write the following bound: /// `F: for<'b, 'tcx> where 'tcx FnOnce(Inherited<'b, 'tcx>)`. @@ -2760,136 +2643,6 @@ fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, span: Span) { .emit(); } -impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.tcx - } - - fn item_def_id(&self) -> Option { - None - } - - fn default_constness_for_trait_bounds(&self) -> hir::Constness { - // FIXME: refactor this into a method - let node = self.tcx.hir().get(self.body_id); - if let Some(fn_like) = FnLikeNode::from_node(node) { - fn_like.constness() - } else { - hir::Constness::NotConst - } - } - - fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> { - let tcx = self.tcx; - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - let item_id = tcx.hir().ty_param_owner(hir_id); - let item_def_id = tcx.hir().local_def_id(item_id); - let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&def_id]; - ty::GenericPredicates { - parent: None, - predicates: tcx.arena.alloc_from_iter( - self.param_env.caller_bounds().iter().filter_map(|predicate| { - match predicate.skip_binders() { - ty::PredicateAtom::Trait(data, _) if data.self_ty().is_param(index) => { - // HACK(eddyb) should get the original `Span`. - let span = tcx.def_span(def_id); - Some((predicate, span)) - } - _ => None, - } - }), - ), - } - } - - fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option> { - let v = match def { - Some(def) => infer::EarlyBoundRegion(span, def.name), - None => infer::MiscVariable(span), - }; - Some(self.next_region_var(v)) - } - - fn allow_ty_infer(&self) -> bool { - true - } - - fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { - if let Some(param) = param { - if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() { - return ty; - } - unreachable!() - } else { - self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, - span, - }) - } - } - - fn ct_infer( - &self, - ty: Ty<'tcx>, - param: Option<&ty::GenericParamDef>, - span: Span, - ) -> &'tcx Const<'tcx> { - if let Some(param) = param { - if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() { - return ct; - } - unreachable!() - } else { - self.next_const_var( - ty, - ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span }, - ) - } - } - - fn projected_ty_from_poly_trait_ref( - &self, - span: Span, - item_def_id: DefId, - item_segment: &hir::PathSegment<'_>, - poly_trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Ty<'tcx> { - let (trait_ref, _) = self.replace_bound_vars_with_fresh_vars( - span, - infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id), - &poly_trait_ref, - ); - - let item_substs = >::create_substs_for_associated_item( - self, - self.tcx, - span, - item_def_id, - item_segment, - trait_ref.substs, - ); - - self.tcx().mk_projection(item_def_id, item_substs) - } - - fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - if ty.has_escaping_bound_vars() { - ty // FIXME: normalization and escaping regions - } else { - self.normalize_associated_types_in(span, &ty) - } - } - - fn set_tainted_by_errors(&self) { - self.infcx.set_tainted_by_errors() - } - - fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) { - self.write_ty(hir_id, ty) - } -} - /// Controls whether the arguments are tupled. This is used for the call /// operator. /// @@ -2922,2911 +2675,6 @@ enum FallbackMode { All, } -impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - pub fn new( - inh: &'a Inherited<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, - ) -> FnCtxt<'a, 'tcx> { - FnCtxt { - body_id, - param_env, - err_count_on_creation: inh.tcx.sess.err_count(), - ret_coercion: None, - ret_coercion_impl_trait: None, - ret_type_span: None, - in_tail_expr: false, - ret_coercion_span: RefCell::new(None), - resume_yield_tys: None, - ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)), - diverges: Cell::new(Diverges::Maybe), - has_errors: Cell::new(false), - enclosing_breakables: RefCell::new(EnclosingBreakables { - stack: Vec::new(), - by_id: Default::default(), - }), - inh, - } - } - - pub fn sess(&self) -> &Session { - &self.tcx.sess - } - - pub fn errors_reported_since_creation(&self) -> bool { - self.tcx.sess.err_count() > self.err_count_on_creation - } - - /// Produces warning on the given node, if the current point in the - /// function is unreachable, and there hasn't been another warning. - fn warn_if_unreachable(&self, id: hir::HirId, span: Span, kind: &str) { - // FIXME: Combine these two 'if' expressions into one once - // let chains are implemented - if let Diverges::Always { span: orig_span, custom_note } = self.diverges.get() { - // If span arose from a desugaring of `if` or `while`, then it is the condition itself, - // which diverges, that we are about to lint on. This gives suboptimal diagnostics. - // Instead, stop here so that the `if`- or `while`-expression's block is linted instead. - if !span.is_desugaring(DesugaringKind::CondTemporary) - && !span.is_desugaring(DesugaringKind::Async) - && !orig_span.is_desugaring(DesugaringKind::Await) - { - self.diverges.set(Diverges::WarnedAlways); - - debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind); - - self.tcx().struct_span_lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, |lint| { - let msg = format!("unreachable {}", kind); - lint.build(&msg) - .span_label(span, &msg) - .span_label( - orig_span, - custom_note - .unwrap_or("any code following this expression is unreachable"), - ) - .emit(); - }) - } - } - } - - pub fn cause(&self, span: Span, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> { - ObligationCause::new(span, self.body_id, code) - } - - pub fn misc(&self, span: Span) -> ObligationCause<'tcx> { - self.cause(span, ObligationCauseCode::MiscObligation) - } - - /// Resolves type and const variables in `ty` if possible. Unlike the infcx - /// version (resolve_vars_if_possible), this version will - /// also select obligations if it seems useful, in an effort - /// to get more type information. - fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { - debug!("resolve_vars_with_obligations(ty={:?})", ty); - - // No Infer()? Nothing needs doing. - if !ty.has_infer_types_or_consts() { - debug!("resolve_vars_with_obligations: ty={:?}", ty); - return ty; - } - - // If `ty` is a type variable, see whether we already know what it is. - ty = self.resolve_vars_if_possible(&ty); - if !ty.has_infer_types_or_consts() { - debug!("resolve_vars_with_obligations: ty={:?}", ty); - return ty; - } - - // If not, try resolving pending obligations as much as - // possible. This can help substantially when there are - // indirect dependencies that don't seem worth tracking - // precisely. - self.select_obligations_where_possible(false, |_| {}); - ty = self.resolve_vars_if_possible(&ty); - - debug!("resolve_vars_with_obligations: ty={:?}", ty); - ty - } - - fn record_deferred_call_resolution( - &self, - closure_def_id: DefId, - r: DeferredCallResolution<'tcx>, - ) { - let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut(); - deferred_call_resolutions.entry(closure_def_id).or_default().push(r); - } - - fn remove_deferred_call_resolutions( - &self, - closure_def_id: DefId, - ) -> Vec> { - let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut(); - deferred_call_resolutions.remove(&closure_def_id).unwrap_or(vec![]) - } - - pub fn tag(&self) -> String { - format!("{:p}", self) - } - - pub fn local_ty(&self, span: Span, nid: hir::HirId) -> LocalTy<'tcx> { - self.locals.borrow().get(&nid).cloned().unwrap_or_else(|| { - span_bug!(span, "no type for local variable {}", self.tcx.hir().node_to_string(nid)) - }) - } - - #[inline] - pub fn write_ty(&self, id: hir::HirId, ty: Ty<'tcx>) { - debug!( - "write_ty({:?}, {:?}) in fcx {}", - id, - self.resolve_vars_if_possible(&ty), - self.tag() - ); - self.typeck_results.borrow_mut().node_types_mut().insert(id, ty); - - if ty.references_error() { - self.has_errors.set(true); - self.set_tainted_by_errors(); - } - } - - pub fn write_field_index(&self, hir_id: hir::HirId, index: usize) { - self.typeck_results.borrow_mut().field_indices_mut().insert(hir_id, index); - } - - fn write_resolution(&self, hir_id: hir::HirId, r: Result<(DefKind, DefId), ErrorReported>) { - self.typeck_results.borrow_mut().type_dependent_defs_mut().insert(hir_id, r); - } - - pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) { - debug!("write_method_call(hir_id={:?}, method={:?})", hir_id, method); - self.write_resolution(hir_id, Ok((DefKind::AssocFn, method.def_id))); - self.write_substs(hir_id, method.substs); - - // When the method is confirmed, the `method.substs` includes - // parameters from not just the method, but also the impl of - // the method -- in particular, the `Self` type will be fully - // resolved. However, those are not something that the "user - // specified" -- i.e., those types come from the inferred type - // of the receiver, not something the user wrote. So when we - // create the user-substs, we want to replace those earlier - // types with just the types that the user actually wrote -- - // that is, those that appear on the *method itself*. - // - // As an example, if the user wrote something like - // `foo.bar::(...)` -- the `Self` type here will be the - // type of `foo` (possibly adjusted), but we don't want to - // include that. We want just the `[_, u32]` part. - if !method.substs.is_noop() { - let method_generics = self.tcx.generics_of(method.def_id); - if !method_generics.params.is_empty() { - let user_type_annotation = self.infcx.probe(|_| { - let user_substs = UserSubsts { - substs: InternalSubsts::for_item(self.tcx, method.def_id, |param, _| { - let i = param.index as usize; - if i < method_generics.parent_count { - self.infcx.var_for_def(DUMMY_SP, param) - } else { - method.substs[i] - } - }), - user_self_ty: None, // not relevant here - }; - - self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf( - method.def_id, - user_substs, - )) - }); - - debug!("write_method_call: user_type_annotation={:?}", user_type_annotation); - self.write_user_type_annotation(hir_id, user_type_annotation); - } - } - } - - pub fn write_substs(&self, node_id: hir::HirId, substs: SubstsRef<'tcx>) { - if !substs.is_noop() { - debug!("write_substs({:?}, {:?}) in fcx {}", node_id, substs, self.tag()); - - self.typeck_results.borrow_mut().node_substs_mut().insert(node_id, substs); - } - } - - /// Given the substs that we just converted from the HIR, try to - /// canonicalize them and store them as user-given substitutions - /// (i.e., substitutions that must be respected by the NLL check). - /// - /// This should be invoked **before any unifications have - /// occurred**, so that annotations like `Vec<_>` are preserved - /// properly. - pub fn write_user_type_annotation_from_substs( - &self, - hir_id: hir::HirId, - def_id: DefId, - substs: SubstsRef<'tcx>, - user_self_ty: Option>, - ) { - debug!( - "write_user_type_annotation_from_substs: hir_id={:?} def_id={:?} substs={:?} \ - user_self_ty={:?} in fcx {}", - hir_id, - def_id, - substs, - user_self_ty, - self.tag(), - ); - - if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) { - let canonicalized = self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf( - def_id, - UserSubsts { substs, user_self_ty }, - )); - debug!("write_user_type_annotation_from_substs: canonicalized={:?}", canonicalized); - self.write_user_type_annotation(hir_id, canonicalized); - } - } - - pub fn write_user_type_annotation( - &self, - hir_id: hir::HirId, - canonical_user_type_annotation: CanonicalUserType<'tcx>, - ) { - debug!( - "write_user_type_annotation: hir_id={:?} canonical_user_type_annotation={:?} tag={}", - hir_id, - canonical_user_type_annotation, - self.tag(), - ); - - if !canonical_user_type_annotation.is_identity() { - self.typeck_results - .borrow_mut() - .user_provided_types_mut() - .insert(hir_id, canonical_user_type_annotation); - } else { - debug!("write_user_type_annotation: skipping identity substs"); - } - } - - pub fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec>) { - debug!("apply_adjustments(expr={:?}, adj={:?})", expr, adj); - - if adj.is_empty() { - return; - } - - let autoborrow_mut = adj.iter().any(|adj| { - matches!(adj, &Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. })), - .. - }) - }); - - match self.typeck_results.borrow_mut().adjustments_mut().entry(expr.hir_id) { - Entry::Vacant(entry) => { - entry.insert(adj); - } - Entry::Occupied(mut entry) => { - debug!(" - composing on top of {:?}", entry.get()); - match (&entry.get()[..], &adj[..]) { - // Applying any adjustment on top of a NeverToAny - // is a valid NeverToAny adjustment, because it can't - // be reached. - (&[Adjustment { kind: Adjust::NeverToAny, .. }], _) => return, - (&[ - Adjustment { kind: Adjust::Deref(_), .. }, - Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. }, - ], &[ - Adjustment { kind: Adjust::Deref(_), .. }, - .. // Any following adjustments are allowed. - ]) => { - // A reborrow has no effect before a dereference. - } - // FIXME: currently we never try to compose autoderefs - // and ReifyFnPointer/UnsafeFnPointer, but we could. - _ => - bug!("while adjusting {:?}, can't compose {:?} and {:?}", - expr, entry.get(), adj) - }; - *entry.get_mut() = adj; - } - } - - // If there is an mutable auto-borrow, it is equivalent to `&mut `. - // In this case implicit use of `Deref` and `Index` within `` should - // instead be `DerefMut` and `IndexMut`, so fix those up. - if autoborrow_mut { - self.convert_place_derefs_to_mutable(expr); - } - } - - /// Basically whenever we are converting from a type scheme into - /// the fn body space, we always want to normalize associated - /// types as well. This function combines the two. - fn instantiate_type_scheme(&self, span: Span, substs: SubstsRef<'tcx>, value: &T) -> T - where - T: TypeFoldable<'tcx>, - { - let value = value.subst(self.tcx, substs); - let result = self.normalize_associated_types_in(span, &value); - debug!("instantiate_type_scheme(value={:?}, substs={:?}) = {:?}", value, substs, result); - result - } - - /// As `instantiate_type_scheme`, but for the bounds found in a - /// generic type scheme. - fn instantiate_bounds( - &self, - span: Span, - def_id: DefId, - substs: SubstsRef<'tcx>, - ) -> (ty::InstantiatedPredicates<'tcx>, Vec) { - let bounds = self.tcx.predicates_of(def_id); - let spans: Vec = bounds.predicates.iter().map(|(_, span)| *span).collect(); - let result = bounds.instantiate(self.tcx, substs); - let result = self.normalize_associated_types_in(span, &result); - debug!( - "instantiate_bounds(bounds={:?}, substs={:?}) = {:?}, {:?}", - bounds, substs, result, spans, - ); - (result, spans) - } - - /// Replaces the opaque types from the given value with type variables, - /// and records the `OpaqueTypeMap` for later use during writeback. See - /// `InferCtxt::instantiate_opaque_types` for more details. - fn instantiate_opaque_types_from_value>( - &self, - parent_id: hir::HirId, - value: &T, - value_span: Span, - ) -> T { - let parent_def_id = self.tcx.hir().local_def_id(parent_id); - debug!( - "instantiate_opaque_types_from_value(parent_def_id={:?}, value={:?})", - parent_def_id, value - ); - - let (value, opaque_type_map) = - self.register_infer_ok_obligations(self.instantiate_opaque_types( - parent_def_id, - self.body_id, - self.param_env, - value, - value_span, - )); - - let mut opaque_types = self.opaque_types.borrow_mut(); - let mut opaque_types_vars = self.opaque_types_vars.borrow_mut(); - for (ty, decl) in opaque_type_map { - let _ = opaque_types.insert(ty, decl); - let _ = opaque_types_vars.insert(decl.concrete_ty, decl.opaque_type); - } - - value - } - - fn normalize_associated_types_in(&self, span: Span, value: &T) -> T - where - T: TypeFoldable<'tcx>, - { - self.inh.normalize_associated_types_in(span, self.body_id, self.param_env, value) - } - - fn normalize_associated_types_in_as_infer_ok( - &self, - span: Span, - value: &T, - ) -> InferOk<'tcx, T> - where - T: TypeFoldable<'tcx>, - { - self.inh.partially_normalize_associated_types_in(span, self.body_id, self.param_env, value) - } - - pub fn require_type_meets( - &self, - ty: Ty<'tcx>, - span: Span, - code: traits::ObligationCauseCode<'tcx>, - def_id: DefId, - ) { - self.register_bound(ty, def_id, traits::ObligationCause::new(span, self.body_id, code)); - } - - pub fn require_type_is_sized( - &self, - ty: Ty<'tcx>, - span: Span, - code: traits::ObligationCauseCode<'tcx>, - ) { - if !ty.references_error() { - let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); - self.require_type_meets(ty, span, code, lang_item); - } - } - - pub fn require_type_is_sized_deferred( - &self, - ty: Ty<'tcx>, - span: Span, - code: traits::ObligationCauseCode<'tcx>, - ) { - if !ty.references_error() { - self.deferred_sized_obligations.borrow_mut().push((ty, span, code)); - } - } - - pub fn register_bound( - &self, - ty: Ty<'tcx>, - def_id: DefId, - cause: traits::ObligationCause<'tcx>, - ) { - if !ty.references_error() { - self.fulfillment_cx.borrow_mut().register_bound( - self, - self.param_env, - ty, - def_id, - cause, - ); - } - } - - pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> Ty<'tcx> { - let t = AstConv::ast_ty_to_ty(self, ast_t); - self.register_wf_obligation(t.into(), ast_t.span, traits::MiscObligation); - t - } - - pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> { - let ty = self.to_ty(ast_ty); - debug!("to_ty_saving_user_provided_ty: ty={:?}", ty); - - if Self::can_contain_user_lifetime_bounds(ty) { - let c_ty = self.infcx.canonicalize_response(&UserType::Ty(ty)); - debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty); - self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty); - } - - ty - } - - pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> { - let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id); - let c = ty::Const::from_anon_const(self.tcx, const_def_id); - self.register_wf_obligation( - c.into(), - self.tcx.hir().span(ast_c.hir_id), - ObligationCauseCode::MiscObligation, - ); - c - } - - pub fn const_arg_to_const( - &self, - ast_c: &hir::AnonConst, - param_def_id: DefId, - ) -> &'tcx ty::Const<'tcx> { - let const_def = ty::WithOptConstParam { - did: self.tcx.hir().local_def_id(ast_c.hir_id), - const_param_did: Some(param_def_id), - }; - let c = ty::Const::from_opt_const_arg_anon_const(self.tcx, const_def); - self.register_wf_obligation( - c.into(), - self.tcx.hir().span(ast_c.hir_id), - ObligationCauseCode::MiscObligation, - ); - c - } - - // If the type given by the user has free regions, save it for later, since - // NLL would like to enforce those. Also pass in types that involve - // projections, since those can resolve to `'static` bounds (modulo #54940, - // which hopefully will be fixed by the time you see this comment, dear - // reader, although I have my doubts). Also pass in types with inference - // types, because they may be repeated. Other sorts of things are already - // sufficiently enforced with erased regions. =) - fn can_contain_user_lifetime_bounds(t: T) -> bool - where - T: TypeFoldable<'tcx>, - { - t.has_free_regions() || t.has_projections() || t.has_infer_types() - } - - pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> { - match self.typeck_results.borrow().node_types().get(id) { - Some(&t) => t, - None if self.is_tainted_by_errors() => self.tcx.ty_error(), - None => { - bug!( - "no type for node {}: {} in fcx {}", - id, - self.tcx.hir().node_to_string(id), - self.tag() - ); - } - } - } - - /// Registers an obligation for checking later, during regionck, that `arg` is well-formed. - pub fn register_wf_obligation( - &self, - arg: subst::GenericArg<'tcx>, - span: Span, - code: traits::ObligationCauseCode<'tcx>, - ) { - // WF obligations never themselves fail, so no real need to give a detailed cause: - let cause = traits::ObligationCause::new(span, self.body_id, code); - self.register_predicate(traits::Obligation::new( - cause, - self.param_env, - ty::PredicateAtom::WellFormed(arg).to_predicate(self.tcx), - )); - } - - /// Registers obligations that all `substs` are well-formed. - pub fn add_wf_bounds(&self, substs: SubstsRef<'tcx>, expr: &hir::Expr<'_>) { - for arg in substs.iter().filter(|arg| { - matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..)) - }) { - self.register_wf_obligation(arg, expr.span, traits::MiscObligation); - } - } - - /// Given a fully substituted set of bounds (`generic_bounds`), and the values with which each - /// type/region parameter was instantiated (`substs`), creates and registers suitable - /// trait/region obligations. - /// - /// For example, if there is a function: - /// - /// ``` - /// fn foo<'a,T:'a>(...) - /// ``` - /// - /// and a reference: - /// - /// ``` - /// let f = foo; - /// ``` - /// - /// Then we will create a fresh region variable `'$0` and a fresh type variable `$1` for `'a` - /// and `T`. This routine will add a region obligation `$1:'$0` and register it locally. - pub fn add_obligations_for_parameters( - &self, - cause: traits::ObligationCause<'tcx>, - predicates: ty::InstantiatedPredicates<'tcx>, - ) { - assert!(!predicates.has_escaping_bound_vars()); - - debug!("add_obligations_for_parameters(predicates={:?})", predicates); - - for obligation in traits::predicates_for_generics(cause, self.param_env, predicates) { - self.register_predicate(obligation); - } - } - - // FIXME(arielb1): use this instead of field.ty everywhere - // Only for fields! Returns for methods> - // Indifferent to privacy flags - pub fn field_ty( - &self, - span: Span, - field: &'tcx ty::FieldDef, - substs: SubstsRef<'tcx>, - ) -> Ty<'tcx> { - self.normalize_associated_types_in(span, &field.ty(self.tcx, substs)) - } - - fn check_casts(&self) { - let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); - for cast in deferred_cast_checks.drain(..) { - cast.check(self); - } - } - - fn resolve_generator_interiors(&self, def_id: DefId) { - let mut generators = self.deferred_generator_interiors.borrow_mut(); - for (body_id, interior, kind) in generators.drain(..) { - self.select_obligations_where_possible(false, |_| {}); - generator_interior::resolve_interior(self, def_id, body_id, interior, kind); - } - } - - // Tries to apply a fallback to `ty` if it is an unsolved variable. - // - // - Unconstrained ints are replaced with `i32`. - // - // - Unconstrained floats are replaced with with `f64`. - // - // - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]` - // is enabled. Otherwise, they are replaced with `()`. - // - // Fallback becomes very dubious if we have encountered type-checking errors. - // In that case, fallback to Error. - // The return value indicates whether fallback has occurred. - fn fallback_if_possible(&self, ty: Ty<'tcx>, mode: FallbackMode) -> bool { - use rustc_middle::ty::error::UnconstrainedNumeric::Neither; - use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt}; - - assert!(ty.is_ty_infer()); - let fallback = match self.type_is_unconstrained_numeric(ty) { - _ if self.is_tainted_by_errors() => self.tcx().ty_error(), - UnconstrainedInt => self.tcx.types.i32, - UnconstrainedFloat => self.tcx.types.f64, - Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(), - Neither => { - // This type variable was created from the instantiation of an opaque - // type. The fact that we're attempting to perform fallback for it - // means that the function neither constrained it to a concrete - // type, nor to the opaque type itself. - // - // For example, in this code: - // - //``` - // type MyType = impl Copy; - // fn defining_use() -> MyType { true } - // fn other_use() -> MyType { defining_use() } - // ``` - // - // `defining_use` will constrain the instantiated inference - // variable to `bool`, while `other_use` will constrain - // the instantiated inference variable to `MyType`. - // - // When we process opaque types during writeback, we - // will handle cases like `other_use`, and not count - // them as defining usages - // - // However, we also need to handle cases like this: - // - // ```rust - // pub type Foo = impl Copy; - // fn produce() -> Option { - // None - // } - // ``` - // - // In the above snippet, the inference variable created by - // instantiating `Option` will be completely unconstrained. - // We treat this as a non-defining use by making the inference - // variable fall back to the opaque type itself. - if let FallbackMode::All = mode { - if let Some(opaque_ty) = self.opaque_types_vars.borrow().get(ty) { - debug!( - "fallback_if_possible: falling back opaque type var {:?} to {:?}", - ty, opaque_ty - ); - *opaque_ty - } else { - return false; - } - } else { - return false; - } - } - }; - debug!("fallback_if_possible: defaulting `{:?}` to `{:?}`", ty, fallback); - self.demand_eqtype(rustc_span::DUMMY_SP, ty, fallback); - true - } - - fn select_all_obligations_or_error(&self) { - debug!("select_all_obligations_or_error"); - if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) { - self.report_fulfillment_errors(&errors, self.inh.body_id, false); - } - } - - /// Select as many obligations as we can at present. - fn select_obligations_where_possible( - &self, - fallback_has_occurred: bool, - mutate_fullfillment_errors: impl Fn(&mut Vec>), - ) { - let result = self.fulfillment_cx.borrow_mut().select_where_possible(self); - if let Err(mut errors) = result { - mutate_fullfillment_errors(&mut errors); - self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred); - } - } - - /// For the overloaded place expressions (`*x`, `x[3]`), the trait - /// returns a type of `&T`, but the actual type we assign to the - /// *expression* is `T`. So this function just peels off the return - /// type by one layer to yield `T`. - fn make_overloaded_place_return_type( - &self, - method: MethodCallee<'tcx>, - ) -> ty::TypeAndMut<'tcx> { - // extract method return type, which will be &T; - let ret_ty = method.sig.output(); - - // method returns &T, but the type as visible to user is T, so deref - ret_ty.builtin_deref(true).unwrap() - } - - fn check_method_argument_types( - &self, - sp: Span, - expr: &'tcx hir::Expr<'tcx>, - method: Result, ()>, - args_no_rcvr: &'tcx [hir::Expr<'tcx>], - tuple_arguments: TupleArgumentsFlag, - expected: Expectation<'tcx>, - ) -> Ty<'tcx> { - let has_error = match method { - Ok(method) => method.substs.references_error() || method.sig.references_error(), - Err(_) => true, - }; - if has_error { - let err_inputs = self.err_args(args_no_rcvr.len()); - - let err_inputs = match tuple_arguments { - DontTupleArguments => err_inputs, - TupleArguments => vec![self.tcx.intern_tup(&err_inputs[..])], - }; - - self.check_argument_types( - sp, - expr, - &err_inputs[..], - &[], - args_no_rcvr, - false, - tuple_arguments, - None, - ); - return self.tcx.ty_error(); - } - - let method = method.unwrap(); - // HACK(eddyb) ignore self in the definition (see above). - let expected_arg_tys = self.expected_inputs_for_expected_output( - sp, - expected, - method.sig.output(), - &method.sig.inputs()[1..], - ); - self.check_argument_types( - sp, - expr, - &method.sig.inputs()[1..], - &expected_arg_tys[..], - args_no_rcvr, - method.sig.c_variadic, - tuple_arguments, - self.tcx.hir().span_if_local(method.def_id), - ); - method.sig.output() - } - - fn self_type_matches_expected_vid( - &self, - trait_ref: ty::PolyTraitRef<'tcx>, - expected_vid: ty::TyVid, - ) -> bool { - let self_ty = self.shallow_resolve(trait_ref.skip_binder().self_ty()); - debug!( - "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?}, expected_vid={:?})", - trait_ref, self_ty, expected_vid - ); - match *self_ty.kind() { - ty::Infer(ty::TyVar(found_vid)) => { - // FIXME: consider using `sub_root_var` here so we - // can see through subtyping. - let found_vid = self.root_var(found_vid); - debug!("self_type_matches_expected_vid - found_vid={:?}", found_vid); - expected_vid == found_vid - } - _ => false, - } - } - - fn obligations_for_self_ty<'b>( - &'b self, - self_ty: ty::TyVid, - ) -> impl Iterator, traits::PredicateObligation<'tcx>)> - + Captures<'tcx> - + 'b { - // FIXME: consider using `sub_root_var` here so we - // can see through subtyping. - let ty_var_root = self.root_var(self_ty); - debug!( - "obligations_for_self_ty: self_ty={:?} ty_var_root={:?} pending_obligations={:?}", - self_ty, - ty_var_root, - self.fulfillment_cx.borrow().pending_obligations() - ); - - self.fulfillment_cx - .borrow() - .pending_obligations() - .into_iter() - .filter_map(move |obligation| { - match obligation.predicate.skip_binders() { - ty::PredicateAtom::Projection(data) => { - Some((ty::Binder::bind(data).to_poly_trait_ref(self.tcx), obligation)) - } - ty::PredicateAtom::Trait(data, _) => { - Some((ty::Binder::bind(data).to_poly_trait_ref(), obligation)) - } - ty::PredicateAtom::Subtype(..) => None, - ty::PredicateAtom::RegionOutlives(..) => None, - ty::PredicateAtom::TypeOutlives(..) => None, - ty::PredicateAtom::WellFormed(..) => None, - ty::PredicateAtom::ObjectSafe(..) => None, - ty::PredicateAtom::ConstEvaluatable(..) => None, - ty::PredicateAtom::ConstEquate(..) => None, - // N.B., this predicate is created by breaking down a - // `ClosureType: FnFoo()` predicate, where - // `ClosureType` represents some `Closure`. It can't - // possibly be referring to the current closure, - // because we haven't produced the `Closure` for - // this closure yet; this is exactly why the other - // code is looking for a self type of a unresolved - // inference variable. - ty::PredicateAtom::ClosureKind(..) => None, - ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, - } - }) - .filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root)) - } - - fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool { - self.obligations_for_self_ty(self_ty) - .any(|(tr, _)| Some(tr.def_id()) == self.tcx.lang_items().sized_trait()) - } - - /// Generic function that factors out common logic from function calls, - /// method calls and overloaded operators. - fn check_argument_types( - &self, - sp: Span, - expr: &'tcx hir::Expr<'tcx>, - fn_inputs: &[Ty<'tcx>], - expected_arg_tys: &[Ty<'tcx>], - args: &'tcx [hir::Expr<'tcx>], - c_variadic: bool, - tuple_arguments: TupleArgumentsFlag, - def_span: Option, - ) { - let tcx = self.tcx; - // Grab the argument types, supplying fresh type variables - // if the wrong number of arguments were supplied - let supplied_arg_count = if tuple_arguments == DontTupleArguments { args.len() } else { 1 }; - - // All the input types from the fn signature must outlive the call - // so as to validate implied bounds. - for (&fn_input_ty, arg_expr) in fn_inputs.iter().zip(args.iter()) { - self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation); - } - - let expected_arg_count = fn_inputs.len(); - - let param_count_error = |expected_count: usize, - arg_count: usize, - error_code: &str, - c_variadic: bool, - sugg_unit: bool| { - let (span, start_span, args) = match &expr.kind { - hir::ExprKind::Call(hir::Expr { span, .. }, args) => (*span, *span, &args[..]), - hir::ExprKind::MethodCall(path_segment, span, args, _) => ( - *span, - // `sp` doesn't point at the whole `foo.bar()`, only at `bar`. - path_segment - .args - .and_then(|args| args.args.iter().last()) - // Account for `foo.bar::()`. - .map(|arg| { - // Skip the closing `>`. - tcx.sess - .source_map() - .next_point(tcx.sess.source_map().next_point(arg.span())) - }) - .unwrap_or(*span), - &args[1..], // Skip the receiver. - ), - k => span_bug!(sp, "checking argument types on a non-call: `{:?}`", k), - }; - let arg_spans = if args.is_empty() { - // foo() - // ^^^-- supplied 0 arguments - // | - // expected 2 arguments - vec![tcx.sess.source_map().next_point(start_span).with_hi(sp.hi())] - } else { - // foo(1, 2, 3) - // ^^^ - - - supplied 3 arguments - // | - // expected 2 arguments - args.iter().map(|arg| arg.span).collect::>() - }; - - let mut err = tcx.sess.struct_span_err_with_code( - span, - &format!( - "this function takes {}{} but {} {} supplied", - if c_variadic { "at least " } else { "" }, - potentially_plural_count(expected_count, "argument"), - potentially_plural_count(arg_count, "argument"), - if arg_count == 1 { "was" } else { "were" } - ), - DiagnosticId::Error(error_code.to_owned()), - ); - let label = format!("supplied {}", potentially_plural_count(arg_count, "argument")); - for (i, span) in arg_spans.into_iter().enumerate() { - err.span_label( - span, - if arg_count == 0 || i + 1 == arg_count { &label } else { "" }, - ); - } - - if let Some(def_s) = def_span.map(|sp| tcx.sess.source_map().guess_head_span(sp)) { - err.span_label(def_s, "defined here"); - } - if sugg_unit { - let sugg_span = tcx.sess.source_map().end_point(expr.span); - // remove closing `)` from the span - let sugg_span = sugg_span.shrink_to_lo(); - err.span_suggestion( - sugg_span, - "expected the unit value `()`; create it with empty parentheses", - String::from("()"), - Applicability::MachineApplicable, - ); - } else { - err.span_label( - span, - format!( - "expected {}{}", - if c_variadic { "at least " } else { "" }, - potentially_plural_count(expected_count, "argument") - ), - ); - } - err.emit(); - }; - - let mut expected_arg_tys = expected_arg_tys.to_vec(); - - let formal_tys = if tuple_arguments == TupleArguments { - let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]); - match tuple_type.kind() { - ty::Tuple(arg_types) if arg_types.len() != args.len() => { - param_count_error(arg_types.len(), args.len(), "E0057", false, false); - expected_arg_tys = vec![]; - self.err_args(args.len()) - } - ty::Tuple(arg_types) => { - expected_arg_tys = match expected_arg_tys.get(0) { - Some(&ty) => match ty.kind() { - ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(), - _ => vec![], - }, - None => vec![], - }; - arg_types.iter().map(|k| k.expect_ty()).collect() - } - _ => { - struct_span_err!( - tcx.sess, - sp, - E0059, - "cannot use call notation; the first type parameter \ - for the function trait is neither a tuple nor unit" - ) - .emit(); - expected_arg_tys = vec![]; - self.err_args(args.len()) - } - } - } else if expected_arg_count == supplied_arg_count { - fn_inputs.to_vec() - } else if c_variadic { - if supplied_arg_count >= expected_arg_count { - fn_inputs.to_vec() - } else { - param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false); - expected_arg_tys = vec![]; - self.err_args(supplied_arg_count) - } - } else { - // is the missing argument of type `()`? - let sugg_unit = if expected_arg_tys.len() == 1 && supplied_arg_count == 0 { - self.resolve_vars_if_possible(&expected_arg_tys[0]).is_unit() - } else if fn_inputs.len() == 1 && supplied_arg_count == 0 { - self.resolve_vars_if_possible(&fn_inputs[0]).is_unit() - } else { - false - }; - param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit); - - expected_arg_tys = vec![]; - self.err_args(supplied_arg_count) - }; - - debug!( - "check_argument_types: formal_tys={:?}", - formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::>() - ); - - // If there is no expectation, expect formal_tys. - let expected_arg_tys = - if !expected_arg_tys.is_empty() { expected_arg_tys } else { formal_tys.clone() }; - - let mut final_arg_types: Vec<(usize, Ty<'_>, Ty<'_>)> = vec![]; - - // Check the arguments. - // We do this in a pretty awful way: first we type-check any arguments - // that are not closures, then we type-check the closures. This is so - // that we have more information about the types of arguments when we - // type-check the functions. This isn't really the right way to do this. - for &check_closures in &[false, true] { - debug!("check_closures={}", check_closures); - - // More awful hacks: before we check argument types, try to do - // an "opportunistic" trait resolution of any trait bounds on - // the call. This helps coercions. - if check_closures { - self.select_obligations_where_possible(false, |errors| { - self.point_at_type_arg_instead_of_call_if_possible(errors, expr); - self.point_at_arg_instead_of_call_if_possible( - errors, - &final_arg_types[..], - sp, - &args, - ); - }) - } - - // For C-variadic functions, we don't have a declared type for all of - // the arguments hence we only do our usual type checking with - // the arguments who's types we do know. - let t = if c_variadic { - expected_arg_count - } else if tuple_arguments == TupleArguments { - args.len() - } else { - supplied_arg_count - }; - for (i, arg) in args.iter().take(t).enumerate() { - // Warn only for the first loop (the "no closures" one). - // Closure arguments themselves can't be diverging, but - // a previous argument can, e.g., `foo(panic!(), || {})`. - if !check_closures { - self.warn_if_unreachable(arg.hir_id, arg.span, "expression"); - } - - let is_closure = match arg.kind { - ExprKind::Closure(..) => true, - _ => false, - }; - - if is_closure != check_closures { - continue; - } - - debug!("checking the argument"); - let formal_ty = formal_tys[i]; - - // The special-cased logic below has three functions: - // 1. Provide as good of an expected type as possible. - let expected = Expectation::rvalue_hint(self, expected_arg_tys[i]); - - let checked_ty = self.check_expr_with_expectation(&arg, expected); - - // 2. Coerce to the most detailed type that could be coerced - // to, which is `expected_ty` if `rvalue_hint` returns an - // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. - let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty); - // We're processing function arguments so we definitely want to use - // two-phase borrows. - self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes); - final_arg_types.push((i, checked_ty, coerce_ty)); - - // 3. Relate the expected type and the formal one, - // if the expected type was used for the coercion. - self.demand_suptype(arg.span, formal_ty, coerce_ty); - } - } - - // We also need to make sure we at least write the ty of the other - // arguments which we skipped above. - if c_variadic { - fn variadic_error<'tcx>(s: &Session, span: Span, t: Ty<'tcx>, cast_ty: &str) { - use crate::structured_errors::{StructuredDiagnostic, VariadicError}; - VariadicError::new(s, span, t, cast_ty).diagnostic().emit(); - } - - for arg in args.iter().skip(expected_arg_count) { - let arg_ty = self.check_expr(&arg); - - // There are a few types which get autopromoted when passed via varargs - // in C but we just error out instead and require explicit casts. - let arg_ty = self.structurally_resolved_type(arg.span, arg_ty); - match arg_ty.kind() { - ty::Float(ast::FloatTy::F32) => { - variadic_error(tcx.sess, arg.span, arg_ty, "c_double"); - } - ty::Int(ast::IntTy::I8 | ast::IntTy::I16) | ty::Bool => { - variadic_error(tcx.sess, arg.span, arg_ty, "c_int"); - } - ty::Uint(ast::UintTy::U8 | ast::UintTy::U16) => { - variadic_error(tcx.sess, arg.span, arg_ty, "c_uint"); - } - ty::FnDef(..) => { - let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx)); - let ptr_ty = self.resolve_vars_if_possible(&ptr_ty); - variadic_error(tcx.sess, arg.span, arg_ty, &ptr_ty.to_string()); - } - _ => {} - } - } - } - } - - fn err_args(&self, len: usize) -> Vec> { - vec![self.tcx.ty_error(); len] - } - - /// Given a vec of evaluated `FulfillmentError`s and an `fn` call argument expressions, we walk - /// the checked and coerced types for each argument to see if any of the `FulfillmentError`s - /// reference a type argument. The reason to walk also the checked type is that the coerced type - /// can be not easily comparable with predicate type (because of coercion). If the types match - /// for either checked or coerced type, and there's only *one* argument that does, we point at - /// the corresponding argument's expression span instead of the `fn` call path span. - fn point_at_arg_instead_of_call_if_possible( - &self, - errors: &mut Vec>, - final_arg_types: &[(usize, Ty<'tcx>, Ty<'tcx>)], - call_sp: Span, - args: &'tcx [hir::Expr<'tcx>], - ) { - // We *do not* do this for desugared call spans to keep good diagnostics when involving - // the `?` operator. - if call_sp.desugaring_kind().is_some() { - return; - } - - for error in errors { - // Only if the cause is somewhere inside the expression we want try to point at arg. - // Otherwise, it means that the cause is somewhere else and we should not change - // anything because we can break the correct span. - if !call_sp.contains(error.obligation.cause.span) { - continue; - } - - if let ty::PredicateAtom::Trait(predicate, _) = - error.obligation.predicate.skip_binders() - { - // Collect the argument position for all arguments that could have caused this - // `FulfillmentError`. - let mut referenced_in = final_arg_types - .iter() - .map(|&(i, checked_ty, _)| (i, checked_ty)) - .chain(final_arg_types.iter().map(|&(i, _, coerced_ty)| (i, coerced_ty))) - .flat_map(|(i, ty)| { - let ty = self.resolve_vars_if_possible(&ty); - // We walk the argument type because the argument's type could have - // been `Option`, but the `FulfillmentError` references `T`. - if ty.walk().any(|arg| arg == predicate.self_ty().into()) { - Some(i) - } else { - None - } - }) - .collect::>(); - - // Both checked and coerced types could have matched, thus we need to remove - // duplicates. - - // We sort primitive type usize here and can use unstable sort - referenced_in.sort_unstable(); - referenced_in.dedup(); - - if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) { - // We make sure that only *one* argument matches the obligation failure - // and we assign the obligation's span to its expression's. - error.obligation.cause.make_mut().span = args[ref_in].span; - error.points_at_arg_span = true; - } - } - } - } - - /// Given a vec of evaluated `FulfillmentError`s and an `fn` call expression, we walk the - /// `PathSegment`s and resolve their type parameters to see if any of the `FulfillmentError`s - /// were caused by them. If they were, we point at the corresponding type argument's span - /// instead of the `fn` call path span. - fn point_at_type_arg_instead_of_call_if_possible( - &self, - errors: &mut Vec>, - call_expr: &'tcx hir::Expr<'tcx>, - ) { - if let hir::ExprKind::Call(path, _) = &call_expr.kind { - if let hir::ExprKind::Path(qpath) = &path.kind { - if let hir::QPath::Resolved(_, path) = &qpath { - for error in errors { - if let ty::PredicateAtom::Trait(predicate, _) = - error.obligation.predicate.skip_binders() - { - // If any of the type arguments in this path segment caused the - // `FullfillmentError`, point at its span (#61860). - for arg in path - .segments - .iter() - .filter_map(|seg| seg.args.as_ref()) - .flat_map(|a| a.args.iter()) - { - if let hir::GenericArg::Type(hir_ty) = &arg { - if let hir::TyKind::Path(hir::QPath::TypeRelative(..)) = - &hir_ty.kind - { - // Avoid ICE with associated types. As this is best - // effort only, it's ok to ignore the case. It - // would trigger in `is_send::();` - // from `typeck-default-trait-impl-assoc-type.rs`. - } else { - let ty = AstConv::ast_ty_to_ty(self, hir_ty); - let ty = self.resolve_vars_if_possible(&ty); - if ty == predicate.self_ty() { - error.obligation.cause.make_mut().span = hir_ty.span; - } - } - } - } - } - } - } - } - } - } - - // AST fragment checking - fn check_lit(&self, lit: &hir::Lit, expected: Expectation<'tcx>) -> Ty<'tcx> { - let tcx = self.tcx; - - match lit.node { - ast::LitKind::Str(..) => tcx.mk_static_str(), - ast::LitKind::ByteStr(ref v) => { - tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.u8, v.len() as u64)) - } - ast::LitKind::Byte(_) => tcx.types.u8, - ast::LitKind::Char(_) => tcx.types.char, - ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(t), - ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(t), - ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => { - let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { - ty::Int(_) | ty::Uint(_) => Some(ty), - ty::Char => Some(tcx.types.u8), - ty::RawPtr(..) => Some(tcx.types.usize), - ty::FnDef(..) | ty::FnPtr(_) => Some(tcx.types.usize), - _ => None, - }); - opt_ty.unwrap_or_else(|| self.next_int_var()) - } - ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => tcx.mk_mach_float(t), - ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => { - let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { - ty::Float(_) => Some(ty), - _ => None, - }); - opt_ty.unwrap_or_else(|| self.next_float_var()) - } - ast::LitKind::Bool(_) => tcx.types.bool, - ast::LitKind::Err(_) => tcx.ty_error(), - } - } - - /// Unifies the output type with the expected type early, for more coercions - /// and forward type information on the input expressions. - fn expected_inputs_for_expected_output( - &self, - call_span: Span, - expected_ret: Expectation<'tcx>, - formal_ret: Ty<'tcx>, - formal_args: &[Ty<'tcx>], - ) -> Vec> { - let formal_ret = self.resolve_vars_with_obligations(formal_ret); - let ret_ty = match expected_ret.only_has_type(self) { - Some(ret) => ret, - None => return Vec::new(), - }; - let expect_args = self - .fudge_inference_if_ok(|| { - // Attempt to apply a subtyping relationship between the formal - // return type (likely containing type variables if the function - // is polymorphic) and the expected return type. - // No argument expectations are produced if unification fails. - let origin = self.misc(call_span); - let ures = self.at(&origin, self.param_env).sup(ret_ty, &formal_ret); - - // FIXME(#27336) can't use ? here, Try::from_error doesn't default - // to identity so the resulting type is not constrained. - match ures { - Ok(ok) => { - // Process any obligations locally as much as - // we can. We don't care if some things turn - // out unconstrained or ambiguous, as we're - // just trying to get hints here. - self.save_and_restore_in_snapshot_flag(|_| { - let mut fulfill = TraitEngine::new(self.tcx); - for obligation in ok.obligations { - fulfill.register_predicate_obligation(self, obligation); - } - fulfill.select_where_possible(self) - }) - .map_err(|_| ())?; - } - Err(_) => return Err(()), - } - - // Record all the argument types, with the substitutions - // produced from the above subtyping unification. - Ok(formal_args.iter().map(|ty| self.resolve_vars_if_possible(ty)).collect()) - }) - .unwrap_or_default(); - debug!( - "expected_inputs_for_expected_output(formal={:?} -> {:?}, expected={:?} -> {:?})", - formal_args, formal_ret, expect_args, expected_ret - ); - expect_args - } - - pub fn check_struct_path( - &self, - qpath: &QPath<'_>, - hir_id: hir::HirId, - ) -> Option<(&'tcx ty::VariantDef, Ty<'tcx>)> { - let path_span = qpath.qself_span(); - let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id); - let variant = match def { - Res::Err => { - self.set_tainted_by_errors(); - return None; - } - Res::Def(DefKind::Variant, _) => match ty.kind() { - ty::Adt(adt, substs) => Some((adt.variant_of_res(def), adt.did, substs)), - _ => bug!("unexpected type: {:?}", ty), - }, - Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) - | Res::SelfTy(..) => match ty.kind() { - ty::Adt(adt, substs) if !adt.is_enum() => { - Some((adt.non_enum_variant(), adt.did, substs)) - } - _ => None, - }, - _ => bug!("unexpected definition: {:?}", def), - }; - - if let Some((variant, did, substs)) = variant { - debug!("check_struct_path: did={:?} substs={:?}", did, substs); - self.write_user_type_annotation_from_substs(hir_id, did, substs, None); - - // Check bounds on type arguments used in the path. - let (bounds, _) = self.instantiate_bounds(path_span, did, substs); - let cause = - traits::ObligationCause::new(path_span, self.body_id, traits::ItemObligation(did)); - self.add_obligations_for_parameters(cause, bounds); - - Some((variant, ty)) - } else { - struct_span_err!( - self.tcx.sess, - path_span, - E0071, - "expected struct, variant or union type, found {}", - ty.sort_string(self.tcx) - ) - .span_label(path_span, "not a struct") - .emit(); - None - } - } - - // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary. - // The newly resolved definition is written into `type_dependent_defs`. - fn finish_resolving_struct_path( - &self, - qpath: &QPath<'_>, - path_span: Span, - hir_id: hir::HirId, - ) -> (Res, Ty<'tcx>) { - match *qpath { - QPath::Resolved(ref maybe_qself, ref path) => { - let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself)); - let ty = AstConv::res_to_ty(self, self_ty, path, true); - (path.res, ty) - } - QPath::TypeRelative(ref qself, ref segment) => { - let ty = self.to_ty(qself); - - let res = if let hir::TyKind::Path(QPath::Resolved(_, ref path)) = qself.kind { - path.res - } else { - Res::Err - }; - let result = - AstConv::associated_path_to_ty(self, hir_id, path_span, ty, res, segment, true); - let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error()); - let result = result.map(|(_, kind, def_id)| (kind, def_id)); - - // Write back the new resolution. - self.write_resolution(hir_id, result); - - (result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), ty) - } - QPath::LangItem(lang_item, span) => { - self.resolve_lang_item_path(lang_item, span, hir_id) - } - } - } - - fn resolve_lang_item_path( - &self, - lang_item: hir::LangItem, - span: Span, - hir_id: hir::HirId, - ) -> (Res, Ty<'tcx>) { - let def_id = self.tcx.require_lang_item(lang_item, Some(span)); - let def_kind = self.tcx.def_kind(def_id); - - let item_ty = if let DefKind::Variant = def_kind { - self.tcx.type_of(self.tcx.parent(def_id).expect("variant w/out parent")) - } else { - self.tcx.type_of(def_id) - }; - let substs = self.infcx.fresh_substs_for_item(span, def_id); - let ty = item_ty.subst(self.tcx, substs); - - self.write_resolution(hir_id, Ok((def_kind, def_id))); - self.add_required_obligations(span, def_id, &substs); - (Res::Def(def_kind, def_id), ty) - } - - /// Resolves an associated value path into a base type and associated constant, or method - /// resolution. The newly resolved definition is written into `type_dependent_defs`. - pub fn resolve_ty_and_res_ufcs<'b>( - &self, - qpath: &'b QPath<'b>, - hir_id: hir::HirId, - span: Span, - ) -> (Res, Option>, &'b [hir::PathSegment<'b>]) { - debug!("resolve_ty_and_res_ufcs: qpath={:?} hir_id={:?} span={:?}", qpath, hir_id, span); - let (ty, qself, item_segment) = match *qpath { - QPath::Resolved(ref opt_qself, ref path) => { - return ( - path.res, - opt_qself.as_ref().map(|qself| self.to_ty(qself)), - &path.segments[..], - ); - } - QPath::TypeRelative(ref qself, ref segment) => (self.to_ty(qself), qself, segment), - QPath::LangItem(..) => bug!("`resolve_ty_and_res_ufcs` called on `LangItem`"), - }; - if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id) - { - // Return directly on cache hit. This is useful to avoid doubly reporting - // errors with default match binding modes. See #44614. - let def = - cached_result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err); - return (def, Some(ty), slice::from_ref(&**item_segment)); - } - let item_name = item_segment.ident; - let result = self.resolve_ufcs(span, item_name, ty, hir_id).or_else(|error| { - let result = match error { - method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)), - _ => Err(ErrorReported), - }; - if item_name.name != kw::Invalid { - if let Some(mut e) = self.report_method_error( - span, - ty, - item_name, - SelfSource::QPath(qself), - error, - None, - ) { - e.emit(); - } - } - result - }); - - // Write back the new resolution. - self.write_resolution(hir_id, result); - ( - result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), - Some(ty), - slice::from_ref(&**item_segment), - ) - } - - pub fn check_decl_initializer( - &self, - local: &'tcx hir::Local<'tcx>, - init: &'tcx hir::Expr<'tcx>, - ) -> Ty<'tcx> { - // FIXME(tschottdorf): `contains_explicit_ref_binding()` must be removed - // for #42640 (default match binding modes). - // - // See #44848. - let ref_bindings = local.pat.contains_explicit_ref_binding(); - - let local_ty = self.local_ty(init.span, local.hir_id).revealed_ty; - if let Some(m) = ref_bindings { - // Somewhat subtle: if we have a `ref` binding in the pattern, - // we want to avoid introducing coercions for the RHS. This is - // both because it helps preserve sanity and, in the case of - // ref mut, for soundness (issue #23116). In particular, in - // the latter case, we need to be clear that the type of the - // referent for the reference that results is *equal to* the - // type of the place it is referencing, and not some - // supertype thereof. - let init_ty = self.check_expr_with_needs(init, Needs::maybe_mut_place(m)); - self.demand_eqtype(init.span, local_ty, init_ty); - init_ty - } else { - self.check_expr_coercable_to_type(init, local_ty, None) - } - } - - /// Type check a `let` statement. - pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) { - // Determine and write the type which we'll check the pattern against. - let ty = self.local_ty(local.span, local.hir_id).decl_ty; - self.write_ty(local.hir_id, ty); - - // Type check the initializer. - if let Some(ref init) = local.init { - let init_ty = self.check_decl_initializer(local, &init); - self.overwrite_local_ty_if_err(local, ty, init_ty); - } - - // Does the expected pattern type originate from an expression and what is the span? - let (origin_expr, ty_span) = match (local.ty, local.init) { - (Some(ty), _) => (false, Some(ty.span)), // Bias towards the explicit user type. - (_, Some(init)) => (true, Some(init.span)), // No explicit type; so use the scrutinee. - _ => (false, None), // We have `let $pat;`, so the expected type is unconstrained. - }; - - // Type check the pattern. Override if necessary to avoid knock-on errors. - self.check_pat_top(&local.pat, ty, ty_span, origin_expr); - let pat_ty = self.node_ty(local.pat.hir_id); - self.overwrite_local_ty_if_err(local, ty, pat_ty); - } - - fn overwrite_local_ty_if_err( - &self, - local: &'tcx hir::Local<'tcx>, - decl_ty: Ty<'tcx>, - ty: Ty<'tcx>, - ) { - if ty.references_error() { - // Override the types everywhere with `err()` to avoid knock on errors. - self.write_ty(local.hir_id, ty); - self.write_ty(local.pat.hir_id, ty); - let local_ty = LocalTy { decl_ty, revealed_ty: ty }; - self.locals.borrow_mut().insert(local.hir_id, local_ty); - self.locals.borrow_mut().insert(local.pat.hir_id, local_ty); - } - } - - fn suggest_semicolon_at_end(&self, span: Span, err: &mut DiagnosticBuilder<'_>) { - err.span_suggestion_short( - span.shrink_to_hi(), - "consider using a semicolon here", - ";".to_string(), - Applicability::MachineApplicable, - ); - } - - pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>) { - // Don't do all the complex logic below for `DeclItem`. - match stmt.kind { - hir::StmtKind::Item(..) => return, - hir::StmtKind::Local(..) | hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {} - } - - self.warn_if_unreachable(stmt.hir_id, stmt.span, "statement"); - - // Hide the outer diverging and `has_errors` flags. - let old_diverges = self.diverges.replace(Diverges::Maybe); - let old_has_errors = self.has_errors.replace(false); - - match stmt.kind { - hir::StmtKind::Local(ref l) => { - self.check_decl_local(&l); - } - // Ignore for now. - hir::StmtKind::Item(_) => {} - hir::StmtKind::Expr(ref expr) => { - // Check with expected type of `()`. - self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit(), |err| { - self.suggest_semicolon_at_end(expr.span, err); - }); - } - hir::StmtKind::Semi(ref expr) => { - self.check_expr(&expr); - } - } - - // Combine the diverging and `has_error` flags. - self.diverges.set(self.diverges.get() | old_diverges); - self.has_errors.set(self.has_errors.get() | old_has_errors); - } - - pub fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) { - let unit = self.tcx.mk_unit(); - let ty = self.check_block_with_expected(blk, ExpectHasType(unit)); - - // if the block produces a `!` value, that can always be - // (effectively) coerced to unit. - if !ty.is_never() { - self.demand_suptype(blk.span, unit, ty); - } - } - - /// If `expr` is a `match` expression that has only one non-`!` arm, use that arm's tail - /// expression's `Span`, otherwise return `expr.span`. This is done to give better errors - /// when given code like the following: - /// ```text - /// if false { return 0i32; } else { 1u32 } - /// // ^^^^ point at this instead of the whole `if` expression - /// ``` - fn get_expr_coercion_span(&self, expr: &hir::Expr<'_>) -> rustc_span::Span { - if let hir::ExprKind::Match(_, arms, _) = &expr.kind { - let arm_spans: Vec = arms - .iter() - .filter_map(|arm| { - self.in_progress_typeck_results - .and_then(|typeck_results| { - typeck_results.borrow().node_type_opt(arm.body.hir_id) - }) - .and_then(|arm_ty| { - if arm_ty.is_never() { - None - } else { - Some(match &arm.body.kind { - // Point at the tail expression when possible. - hir::ExprKind::Block(block, _) => { - block.expr.as_ref().map(|e| e.span).unwrap_or(block.span) - } - _ => arm.body.span, - }) - } - }) - }) - .collect(); - if arm_spans.len() == 1 { - return arm_spans[0]; - } - } - expr.span - } - - fn check_block_with_expected( - &self, - blk: &'tcx hir::Block<'tcx>, - expected: Expectation<'tcx>, - ) -> Ty<'tcx> { - let prev = { - let mut fcx_ps = self.ps.borrow_mut(); - let unsafety_state = fcx_ps.recurse(blk); - replace(&mut *fcx_ps, unsafety_state) - }; - - // In some cases, blocks have just one exit, but other blocks - // can be targeted by multiple breaks. This can happen both - // with labeled blocks as well as when we desugar - // a `try { ... }` expression. - // - // Example 1: - // - // 'a: { if true { break 'a Err(()); } Ok(()) } - // - // Here we would wind up with two coercions, one from - // `Err(())` and the other from the tail expression - // `Ok(())`. If the tail expression is omitted, that's a - // "forced unit" -- unless the block diverges, in which - // case we can ignore the tail expression (e.g., `'a: { - // break 'a 22; }` would not force the type of the block - // to be `()`). - let tail_expr = blk.expr.as_ref(); - let coerce_to_ty = expected.coercion_target_type(self, blk.span); - let coerce = if blk.targeted_by_break { - CoerceMany::new(coerce_to_ty) - } else { - let tail_expr: &[&hir::Expr<'_>] = match tail_expr { - Some(e) => slice::from_ref(e), - None => &[], - }; - CoerceMany::with_coercion_sites(coerce_to_ty, tail_expr) - }; - - let prev_diverges = self.diverges.get(); - let ctxt = BreakableCtxt { coerce: Some(coerce), may_break: false }; - - let (ctxt, ()) = self.with_breakable_ctxt(blk.hir_id, ctxt, || { - for s in blk.stmts { - self.check_stmt(s); - } - - // check the tail expression **without** holding the - // `enclosing_breakables` lock below. - let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected)); - - let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - let ctxt = enclosing_breakables.find_breakable(blk.hir_id); - let coerce = ctxt.coerce.as_mut().unwrap(); - if let Some(tail_expr_ty) = tail_expr_ty { - let tail_expr = tail_expr.unwrap(); - let span = self.get_expr_coercion_span(tail_expr); - let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id)); - coerce.coerce(self, &cause, tail_expr, tail_expr_ty); - } else { - // Subtle: if there is no explicit tail expression, - // that is typically equivalent to a tail expression - // of `()` -- except if the block diverges. In that - // case, there is no value supplied from the tail - // expression (assuming there are no other breaks, - // this implies that the type of the block will be - // `!`). - // - // #41425 -- label the implicit `()` as being the - // "found type" here, rather than the "expected type". - if !self.diverges.get().is_always() { - // #50009 -- Do not point at the entire fn block span, point at the return type - // span, as it is the cause of the requirement, and - // `consider_hint_about_removing_semicolon` will point at the last expression - // if it were a relevant part of the error. This improves usability in editors - // that highlight errors inline. - let mut sp = blk.span; - let mut fn_span = None; - if let Some((decl, ident)) = self.get_parent_fn_decl(blk.hir_id) { - let ret_sp = decl.output.span(); - if let Some(block_sp) = self.parent_item_span(blk.hir_id) { - // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the - // output would otherwise be incorrect and even misleading. Make sure - // the span we're aiming at correspond to a `fn` body. - if block_sp == blk.span { - sp = ret_sp; - fn_span = Some(ident.span); - } - } - } - coerce.coerce_forced_unit( - self, - &self.misc(sp), - &mut |err| { - if let Some(expected_ty) = expected.only_has_type(self) { - self.consider_hint_about_removing_semicolon(blk, expected_ty, err); - } - if let Some(fn_span) = fn_span { - err.span_label( - fn_span, - "implicitly returns `()` as its body has no tail or `return` \ - expression", - ); - } - }, - false, - ); - } - } - }); - - if ctxt.may_break { - // If we can break from the block, then the block's exit is always reachable - // (... as long as the entry is reachable) - regardless of the tail of the block. - self.diverges.set(prev_diverges); - } - - let mut ty = ctxt.coerce.unwrap().complete(self); - - if self.has_errors.get() || ty.references_error() { - ty = self.tcx.ty_error() - } - - self.write_ty(blk.hir_id, ty); - - *self.ps.borrow_mut() = prev; - ty - } - - fn parent_item_span(&self, id: hir::HirId) -> Option { - let node = self.tcx.hir().get(self.tcx.hir().get_parent_item(id)); - match node { - Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. }) - | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body_id), .. }) => { - let body = self.tcx.hir().body(body_id); - if let ExprKind::Block(block, _) = &body.value.kind { - return Some(block.span); - } - } - _ => {} - } - None - } - - /// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise. - fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> { - let parent = self.tcx.hir().get(self.tcx.hir().get_parent_item(blk_id)); - self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident)) - } - - /// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise. - fn get_node_fn_decl(&self, node: Node<'tcx>) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident, bool)> { - match node { - Node::Item(&hir::Item { ident, kind: hir::ItemKind::Fn(ref sig, ..), .. }) => { - // This is less than ideal, it will not suggest a return type span on any - // method called `main`, regardless of whether it is actually the entry point, - // but it will still present it as the reason for the expected type. - Some((&sig.decl, ident, ident.name != sym::main)) - } - Node::TraitItem(&hir::TraitItem { - ident, - kind: hir::TraitItemKind::Fn(ref sig, ..), - .. - }) => Some((&sig.decl, ident, true)), - Node::ImplItem(&hir::ImplItem { - ident, - kind: hir::ImplItemKind::Fn(ref sig, ..), - .. - }) => Some((&sig.decl, ident, false)), - _ => None, - } - } - - /// Given a `HirId`, return the `FnDecl` of the method it is enclosed by and whether a - /// suggestion can be made, `None` otherwise. - pub fn get_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, bool)> { - // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or - // `while` before reaching it, as block tail returns are not available in them. - self.tcx.hir().get_return_block(blk_id).and_then(|blk_id| { - let parent = self.tcx.hir().get(blk_id); - self.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main)) - }) - } - - /// On implicit return expressions with mismatched types, provides the following suggestions: - /// - /// - Points out the method's return type as the reason for the expected type. - /// - Possible missing semicolon. - /// - Possible missing return type if the return type is the default, and not `fn main()`. - pub fn suggest_mismatched_types_on_tail( - &self, - err: &mut DiagnosticBuilder<'_>, - expr: &'tcx hir::Expr<'tcx>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - cause_span: Span, - blk_id: hir::HirId, - ) -> bool { - let expr = expr.peel_drop_temps(); - self.suggest_missing_semicolon(err, expr, expected, cause_span); - let mut pointing_at_return_type = false; - if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) { - pointing_at_return_type = - self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest); - } - pointing_at_return_type - } - - /// When encountering an fn-like ctor that needs to unify with a value, check whether calling - /// the ctor would successfully solve the type mismatch and if so, suggest it: - /// ``` - /// fn foo(x: usize) -> usize { x } - /// let x: usize = foo; // suggest calling the `foo` function: `foo(42)` - /// ``` - fn suggest_fn_call( - &self, - err: &mut DiagnosticBuilder<'_>, - expr: &hir::Expr<'_>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - ) -> bool { - let hir = self.tcx.hir(); - let (def_id, sig) = match *found.kind() { - ty::FnDef(def_id, _) => (def_id, found.fn_sig(self.tcx)), - ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig()), - _ => return false, - }; - - let sig = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, &sig).0; - let sig = self.normalize_associated_types_in(expr.span, &sig); - if self.can_coerce(sig.output(), expected) { - let (mut sugg_call, applicability) = if sig.inputs().is_empty() { - (String::new(), Applicability::MachineApplicable) - } else { - ("...".to_string(), Applicability::HasPlaceholders) - }; - let mut msg = "call this function"; - match hir.get_if_local(def_id) { - Some( - Node::Item(hir::Item { kind: ItemKind::Fn(.., body_id), .. }) - | Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Fn(_, body_id), .. - }) - | Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Provided(body_id)), - .. - }), - ) => { - let body = hir.body(*body_id); - sugg_call = body - .params - .iter() - .map(|param| match ¶m.pat.kind { - hir::PatKind::Binding(_, _, ident, None) - if ident.name != kw::SelfLower => - { - ident.to_string() - } - _ => "_".to_string(), - }) - .collect::>() - .join(", "); - } - Some(Node::Expr(hir::Expr { - kind: ExprKind::Closure(_, _, body_id, _, _), - span: full_closure_span, - .. - })) => { - if *full_closure_span == expr.span { - return false; - } - msg = "call this closure"; - let body = hir.body(*body_id); - sugg_call = body - .params - .iter() - .map(|param| match ¶m.pat.kind { - hir::PatKind::Binding(_, _, ident, None) - if ident.name != kw::SelfLower => - { - ident.to_string() - } - _ => "_".to_string(), - }) - .collect::>() - .join(", "); - } - Some(Node::Ctor(hir::VariantData::Tuple(fields, _))) => { - sugg_call = fields.iter().map(|_| "_").collect::>().join(", "); - match def_id.as_local().map(|def_id| hir.def_kind(def_id)) { - Some(DefKind::Ctor(hir::def::CtorOf::Variant, _)) => { - msg = "instantiate this tuple variant"; - } - Some(DefKind::Ctor(CtorOf::Struct, _)) => { - msg = "instantiate this tuple struct"; - } - _ => {} - } - } - Some(Node::ForeignItem(hir::ForeignItem { - kind: hir::ForeignItemKind::Fn(_, idents, _), - .. - })) => { - sugg_call = idents - .iter() - .map(|ident| { - if ident.name != kw::SelfLower { - ident.to_string() - } else { - "_".to_string() - } - }) - .collect::>() - .join(", ") - } - Some(Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Required(idents)), - .. - })) => { - sugg_call = idents - .iter() - .map(|ident| { - if ident.name != kw::SelfLower { - ident.to_string() - } else { - "_".to_string() - } - }) - .collect::>() - .join(", ") - } - _ => {} - } - err.span_suggestion_verbose( - expr.span.shrink_to_hi(), - &format!("use parentheses to {}", msg), - format!("({})", sugg_call), - applicability, - ); - return true; - } - false - } - - pub fn suggest_deref_ref_or_into( - &self, - err: &mut DiagnosticBuilder<'_>, - expr: &hir::Expr<'_>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, - ) { - if let Some((sp, msg, suggestion, applicability)) = self.check_ref(expr, found, expected) { - err.span_suggestion(sp, msg, suggestion, applicability); - } else if let (ty::FnDef(def_id, ..), true) = - (&found.kind(), self.suggest_fn_call(err, expr, expected, found)) - { - if let Some(sp) = self.tcx.hir().span_if_local(*def_id) { - let sp = self.sess().source_map().guess_head_span(sp); - err.span_label(sp, &format!("{} defined here", found)); - } - } else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) { - let is_struct_pat_shorthand_field = - self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, expr.span); - let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id); - if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) { - let mut suggestions = iter::repeat(&expr_text) - .zip(methods.iter()) - .filter_map(|(receiver, method)| { - let method_call = format!(".{}()", method.ident); - if receiver.ends_with(&method_call) { - None // do not suggest code that is already there (#53348) - } else { - let method_call_list = [".to_vec()", ".to_string()"]; - let sugg = if receiver.ends_with(".clone()") - && method_call_list.contains(&method_call.as_str()) - { - let max_len = receiver.rfind('.').unwrap(); - format!("{}{}", &receiver[..max_len], method_call) - } else { - if expr.precedence().order() < ExprPrecedence::MethodCall.order() { - format!("({}){}", receiver, method_call) - } else { - format!("{}{}", receiver, method_call) - } - }; - Some(if is_struct_pat_shorthand_field { - format!("{}: {}", receiver, sugg) - } else { - sugg - }) - } - }) - .peekable(); - if suggestions.peek().is_some() { - err.span_suggestions( - expr.span, - "try using a conversion method", - suggestions, - Applicability::MaybeIncorrect, - ); - } - } - } - } - - /// When encountering the expected boxed value allocated in the stack, suggest allocating it - /// in the heap by calling `Box::new()`. - fn suggest_boxing_when_appropriate( - &self, - err: &mut DiagnosticBuilder<'_>, - expr: &hir::Expr<'_>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - ) { - if self.tcx.hir().is_inside_const_context(expr.hir_id) { - // Do not suggest `Box::new` in const context. - return; - } - if !expected.is_box() || found.is_box() { - return; - } - let boxed_found = self.tcx.mk_box(found); - if let (true, Ok(snippet)) = ( - self.can_coerce(boxed_found, expected), - self.sess().source_map().span_to_snippet(expr.span), - ) { - err.span_suggestion( - expr.span, - "store this in the heap by calling `Box::new`", - format!("Box::new({})", snippet), - Applicability::MachineApplicable, - ); - err.note( - "for more on the distinction between the stack and the heap, read \ - https://doc.rust-lang.org/book/ch15-01-box.html, \ - https://doc.rust-lang.org/rust-by-example/std/box.html, and \ - https://doc.rust-lang.org/std/boxed/index.html", - ); - } - } - - fn note_internal_mutation_in_method( - &self, - err: &mut DiagnosticBuilder<'_>, - expr: &hir::Expr<'_>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - ) { - if found != self.tcx.types.unit { - return; - } - if let ExprKind::MethodCall(path_segment, _, [rcvr, ..], _) = expr.kind { - if self - .typeck_results - .borrow() - .expr_ty_adjusted_opt(rcvr) - .map_or(true, |ty| expected.peel_refs() != ty.peel_refs()) - { - return; - } - let mut sp = MultiSpan::from_span(path_segment.ident.span); - sp.push_span_label( - path_segment.ident.span, - format!( - "this call modifies {} in-place", - match rcvr.kind { - ExprKind::Path(QPath::Resolved( - None, - hir::Path { segments: [segment], .. }, - )) => format!("`{}`", segment.ident), - _ => "its receiver".to_string(), - } - ), - ); - sp.push_span_label( - rcvr.span, - "you probably want to use this value after calling the method...".to_string(), - ); - err.span_note( - sp, - &format!("method `{}` modifies its receiver in-place", path_segment.ident), - ); - err.note(&format!("...instead of the `()` output of method `{}`", path_segment.ident)); - } - } - - /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`. - fn suggest_calling_boxed_future_when_appropriate( - &self, - err: &mut DiagnosticBuilder<'_>, - expr: &hir::Expr<'_>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - ) -> bool { - // Handle #68197. - - if self.tcx.hir().is_inside_const_context(expr.hir_id) { - // Do not suggest `Box::new` in const context. - return false; - } - let pin_did = self.tcx.lang_items().pin_type(); - match expected.kind() { - ty::Adt(def, _) if Some(def.did) != pin_did => return false, - // This guards the `unwrap` and `mk_box` below. - _ if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() => return false, - _ => {} - } - let boxed_found = self.tcx.mk_box(found); - let new_found = self.tcx.mk_lang_item(boxed_found, LangItem::Pin).unwrap(); - if let (true, Ok(snippet)) = ( - self.can_coerce(new_found, expected), - self.sess().source_map().span_to_snippet(expr.span), - ) { - match found.kind() { - ty::Adt(def, _) if def.is_box() => { - err.help("use `Box::pin`"); - } - _ => { - err.span_suggestion( - expr.span, - "you need to pin and box this expression", - format!("Box::pin({})", snippet), - Applicability::MachineApplicable, - ); - } - } - true - } else { - false - } - } - - /// A common error is to forget to add a semicolon at the end of a block, e.g., - /// - /// ``` - /// fn foo() { - /// bar_that_returns_u32() - /// } - /// ``` - /// - /// This routine checks if the return expression in a block would make sense on its own as a - /// statement and the return type has been left as default or has been specified as `()`. If so, - /// it suggests adding a semicolon. - fn suggest_missing_semicolon( - &self, - err: &mut DiagnosticBuilder<'_>, - expression: &'tcx hir::Expr<'tcx>, - expected: Ty<'tcx>, - cause_span: Span, - ) { - if expected.is_unit() { - // `BlockTailExpression` only relevant if the tail expr would be - // useful on its own. - match expression.kind { - ExprKind::Call(..) - | ExprKind::MethodCall(..) - | ExprKind::Loop(..) - | ExprKind::Match(..) - | ExprKind::Block(..) => { - err.span_suggestion( - cause_span.shrink_to_hi(), - "try adding a semicolon", - ";".to_string(), - Applicability::MachineApplicable, - ); - } - _ => (), - } - } - } - - /// A possible error is to forget to add a return type that is needed: - /// - /// ``` - /// fn foo() { - /// bar_that_returns_u32() - /// } - /// ``` - /// - /// This routine checks if the return type is left as default, the method is not part of an - /// `impl` block and that it isn't the `main` method. If so, it suggests setting the return - /// type. - fn suggest_missing_return_type( - &self, - err: &mut DiagnosticBuilder<'_>, - fn_decl: &hir::FnDecl<'_>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - can_suggest: bool, - ) -> bool { - // Only suggest changing the return type for methods that - // haven't set a return type at all (and aren't `fn main()` or an impl). - match (&fn_decl.output, found.is_suggestable(), can_suggest, expected.is_unit()) { - (&hir::FnRetTy::DefaultReturn(span), true, true, true) => { - err.span_suggestion( - span, - "try adding a return type", - format!("-> {} ", self.resolve_vars_with_obligations(found)), - Applicability::MachineApplicable, - ); - true - } - (&hir::FnRetTy::DefaultReturn(span), false, true, true) => { - err.span_label(span, "possibly return type missing here?"); - true - } - (&hir::FnRetTy::DefaultReturn(span), _, false, true) => { - // `fn main()` must return `()`, do not suggest changing return type - err.span_label(span, "expected `()` because of default return type"); - true - } - // expectation was caused by something else, not the default return - (&hir::FnRetTy::DefaultReturn(_), _, _, false) => false, - (&hir::FnRetTy::Return(ref ty), _, _, _) => { - // Only point to return type if the expected type is the return type, as if they - // are not, the expectation must have been caused by something else. - debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind); - let sp = ty.span; - let ty = AstConv::ast_ty_to_ty(self, ty); - debug!("suggest_missing_return_type: return type {:?}", ty); - debug!("suggest_missing_return_type: expected type {:?}", ty); - if ty.kind() == expected.kind() { - err.span_label(sp, format!("expected `{}` because of return type", expected)); - return true; - } - false - } - } - } - - /// A possible error is to forget to add `.await` when using futures: - /// - /// ``` - /// async fn make_u32() -> u32 { - /// 22 - /// } - /// - /// fn take_u32(x: u32) {} - /// - /// async fn foo() { - /// let x = make_u32(); - /// take_u32(x); - /// } - /// ``` - /// - /// This routine checks if the found type `T` implements `Future` where `U` is the - /// expected type. If this is the case, and we are inside of an async body, it suggests adding - /// `.await` to the tail of the expression. - fn suggest_missing_await( - &self, - err: &mut DiagnosticBuilder<'_>, - expr: &hir::Expr<'_>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - ) { - debug!("suggest_missing_await: expr={:?} expected={:?}, found={:?}", expr, expected, found); - // `.await` is not permitted outside of `async` bodies, so don't bother to suggest if the - // body isn't `async`. - let item_id = self.tcx().hir().get_parent_node(self.body_id); - if let Some(body_id) = self.tcx().hir().maybe_body_owned_by(item_id) { - let body = self.tcx().hir().body(body_id); - if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind { - let sp = expr.span; - // Check for `Future` implementations by constructing a predicate to - // prove: `::Output == U` - let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(sp)); - let item_def_id = self - .tcx - .associated_items(future_trait) - .in_definition_order() - .next() - .unwrap() - .def_id; - // `::Output` - let projection_ty = ty::ProjectionTy { - // `T` - substs: self - .tcx - .mk_substs_trait(found, self.fresh_substs_for_item(sp, item_def_id)), - // `Future::Output` - item_def_id, - }; - - let predicate = ty::PredicateAtom::Projection(ty::ProjectionPredicate { - projection_ty, - ty: expected, - }) - .potentially_quantified(self.tcx, ty::PredicateKind::ForAll); - let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate); - - debug!("suggest_missing_await: trying obligation {:?}", obligation); - - if self.infcx.predicate_may_hold(&obligation) { - debug!("suggest_missing_await: obligation held: {:?}", obligation); - if let Ok(code) = self.sess().source_map().span_to_snippet(sp) { - err.span_suggestion( - sp, - "consider using `.await` here", - format!("{}.await", code), - Applicability::MaybeIncorrect, - ); - } else { - debug!("suggest_missing_await: no snippet for {:?}", sp); - } - } else { - debug!("suggest_missing_await: obligation did not hold: {:?}", obligation) - } - } - } - } - - fn suggest_missing_parentheses(&self, err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>) { - let sp = self.tcx.sess.source_map().start_point(expr.span); - if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) { - // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }` - self.tcx.sess.parse_sess.expr_parentheses_needed(err, *sp, None); - } - } - - fn note_need_for_fn_pointer( - &self, - err: &mut DiagnosticBuilder<'_>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - ) { - let (sig, did, substs) = match (&expected.kind(), &found.kind()) { - (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => { - let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1); - let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2); - if sig1 != sig2 { - return; - } - err.note( - "different `fn` items always have unique types, even if their signatures are \ - the same", - ); - (sig1, *did1, substs1) - } - (ty::FnDef(did, substs), ty::FnPtr(sig2)) => { - let sig1 = self.tcx.fn_sig(*did).subst(self.tcx, substs); - if sig1 != *sig2 { - return; - } - (sig1, *did, substs) - } - _ => return, - }; - err.help(&format!("change the expected type to be function pointer `{}`", sig)); - err.help(&format!( - "if the expected type is due to type inference, cast the expected `fn` to a function \ - pointer: `{} as {}`", - self.tcx.def_path_str_with_substs(did, substs), - sig - )); - } - - /// A common error is to add an extra semicolon: - /// - /// ``` - /// fn foo() -> usize { - /// 22; - /// } - /// ``` - /// - /// This routine checks if the final statement in a block is an - /// expression with an explicit semicolon whose type is compatible - /// with `expected_ty`. If so, it suggests removing the semicolon. - fn consider_hint_about_removing_semicolon( - &self, - blk: &'tcx hir::Block<'tcx>, - expected_ty: Ty<'tcx>, - err: &mut DiagnosticBuilder<'_>, - ) { - if let Some(span_semi) = self.could_remove_semicolon(blk, expected_ty) { - err.span_suggestion( - span_semi, - "consider removing this semicolon", - String::new(), - Applicability::MachineApplicable, - ); - } - } - - fn could_remove_semicolon( - &self, - blk: &'tcx hir::Block<'tcx>, - expected_ty: Ty<'tcx>, - ) -> Option { - // Be helpful when the user wrote `{... expr;}` and - // taking the `;` off is enough to fix the error. - let last_stmt = blk.stmts.last()?; - let last_expr = match last_stmt.kind { - hir::StmtKind::Semi(ref e) => e, - _ => return None, - }; - let last_expr_ty = self.node_ty(last_expr.hir_id); - if matches!(last_expr_ty.kind(), ty::Error(_)) - || self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err() - { - return None; - } - let original_span = original_sp(last_stmt.span, blk.span); - Some(original_span.with_lo(original_span.hi() - BytePos(1))) - } - - // Instantiates the given path, which must refer to an item with the given - // number of type parameters and type. - pub fn instantiate_value_path( - &self, - segments: &[hir::PathSegment<'_>], - self_ty: Option>, - res: Res, - span: Span, - hir_id: hir::HirId, - ) -> (Ty<'tcx>, Res) { - debug!( - "instantiate_value_path(segments={:?}, self_ty={:?}, res={:?}, hir_id={})", - segments, self_ty, res, hir_id, - ); - - let tcx = self.tcx; - - let path_segs = match res { - Res::Local(_) | Res::SelfCtor(_) => vec![], - Res::Def(kind, def_id) => { - AstConv::def_ids_for_value_path_segments(self, segments, self_ty, kind, def_id) - } - _ => bug!("instantiate_value_path on {:?}", res), - }; - - let mut user_self_ty = None; - let mut is_alias_variant_ctor = false; - match res { - Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) => { - if let Some(self_ty) = self_ty { - let adt_def = self_ty.ty_adt_def().unwrap(); - user_self_ty = Some(UserSelfTy { impl_def_id: adt_def.did, self_ty }); - is_alias_variant_ctor = true; - } - } - Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => { - let container = tcx.associated_item(def_id).container; - debug!("instantiate_value_path: def_id={:?} container={:?}", def_id, container); - match container { - ty::TraitContainer(trait_did) => { - callee::check_legal_trait_for_method_call(tcx, span, None, trait_did) - } - ty::ImplContainer(impl_def_id) => { - if segments.len() == 1 { - // `::assoc` will end up here, and so - // can `T::assoc`. It this came from an - // inherent impl, we need to record the - // `T` for posterity (see `UserSelfTy` for - // details). - let self_ty = self_ty.expect("UFCS sugared assoc missing Self"); - user_self_ty = Some(UserSelfTy { impl_def_id, self_ty }); - } - } - } - } - _ => {} - } - - // Now that we have categorized what space the parameters for each - // segment belong to, let's sort out the parameters that the user - // provided (if any) into their appropriate spaces. We'll also report - // errors if type parameters are provided in an inappropriate place. - - let generic_segs: FxHashSet<_> = path_segs.iter().map(|PathSeg(_, index)| index).collect(); - let generics_has_err = AstConv::prohibit_generics( - self, - segments.iter().enumerate().filter_map(|(index, seg)| { - if !generic_segs.contains(&index) || is_alias_variant_ctor { - Some(seg) - } else { - None - } - }), - ); - - if let Res::Local(hid) = res { - let ty = self.local_ty(span, hid).decl_ty; - let ty = self.normalize_associated_types_in(span, &ty); - self.write_ty(hir_id, ty); - return (ty, res); - } - - if generics_has_err { - // Don't try to infer type parameters when prohibited generic arguments were given. - user_self_ty = None; - } - - // Now we have to compare the types that the user *actually* - // provided against the types that were *expected*. If the user - // did not provide any types, then we want to substitute inference - // variables. If the user provided some types, we may still need - // to add defaults. If the user provided *too many* types, that's - // a problem. - - let mut infer_args_for_err = FxHashSet::default(); - for &PathSeg(def_id, index) in &path_segs { - let seg = &segments[index]; - let generics = tcx.generics_of(def_id); - // Argument-position `impl Trait` is treated as a normal generic - // parameter internally, but we don't allow users to specify the - // parameter's value explicitly, so we have to do some error- - // checking here. - if let GenericArgCountResult { - correct: Err(GenericArgCountMismatch { reported: Some(ErrorReported), .. }), - .. - } = AstConv::check_generic_arg_count_for_call( - tcx, span, &generics, &seg, false, // `is_method_call` - ) { - infer_args_for_err.insert(index); - self.set_tainted_by_errors(); // See issue #53251. - } - } - - let has_self = path_segs - .last() - .map(|PathSeg(def_id, _)| tcx.generics_of(*def_id).has_self) - .unwrap_or(false); - - let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res { - let ty = self.normalize_ty(span, tcx.at(span).type_of(impl_def_id)); - match *ty.kind() { - ty::Adt(adt_def, substs) if adt_def.has_ctor() => { - let variant = adt_def.non_enum_variant(); - let ctor_def_id = variant.ctor_def_id.unwrap(); - ( - Res::Def(DefKind::Ctor(CtorOf::Struct, variant.ctor_kind), ctor_def_id), - Some(substs), - ) - } - _ => { - let mut err = tcx.sess.struct_span_err( - span, - "the `Self` constructor can only be used with tuple or unit structs", - ); - if let Some(adt_def) = ty.ty_adt_def() { - match adt_def.adt_kind() { - AdtKind::Enum => { - err.help("did you mean to use one of the enum's variants?"); - } - AdtKind::Struct | AdtKind::Union => { - err.span_suggestion( - span, - "use curly brackets", - String::from("Self { /* fields */ }"), - Applicability::HasPlaceholders, - ); - } - } - } - err.emit(); - - return (tcx.ty_error(), res); - } - } - } else { - (res, None) - }; - let def_id = res.def_id(); - - // The things we are substituting into the type should not contain - // escaping late-bound regions, and nor should the base type scheme. - let ty = tcx.type_of(def_id); - - let arg_count = GenericArgCountResult { - explicit_late_bound: ExplicitLateBound::No, - correct: if infer_args_for_err.is_empty() { - Ok(()) - } else { - Err(GenericArgCountMismatch::default()) - }, - }; - - let substs = self_ctor_substs.unwrap_or_else(|| { - AstConv::create_substs_for_generic_args( - tcx, - def_id, - &[][..], - has_self, - self_ty, - arg_count, - // Provide the generic args, and whether types should be inferred. - |def_id| { - if let Some(&PathSeg(_, index)) = - path_segs.iter().find(|&PathSeg(did, _)| *did == def_id) - { - // If we've encountered an `impl Trait`-related error, we're just - // going to infer the arguments for better error messages. - if !infer_args_for_err.contains(&index) { - // Check whether the user has provided generic arguments. - if let Some(ref data) = segments[index].args { - return (Some(data), segments[index].infer_args); - } - } - return (None, segments[index].infer_args); - } - - (None, true) - }, - // Provide substitutions for parameters for which (valid) arguments have been provided. - |param, arg| match (¶m.kind, arg) { - (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { - AstConv::ast_region_to_region(self, lt, Some(param)).into() - } - (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { - self.to_ty(ty).into() - } - (GenericParamDefKind::Const, GenericArg::Const(ct)) => { - self.const_arg_to_const(&ct.value, param.def_id).into() - } - _ => unreachable!(), - }, - // Provide substitutions for parameters for which arguments are inferred. - |substs, param, infer_args| { - match param.kind { - GenericParamDefKind::Lifetime => { - self.re_infer(Some(param), span).unwrap().into() - } - GenericParamDefKind::Type { has_default, .. } => { - if !infer_args && has_default { - // If we have a default, then we it doesn't matter that we're not - // inferring the type arguments: we provide the default where any - // is missing. - let default = tcx.type_of(param.def_id); - self.normalize_ty( - span, - default.subst_spanned(tcx, substs.unwrap(), Some(span)), - ) - .into() - } else { - // If no type arguments were provided, we have to infer them. - // This case also occurs as a result of some malformed input, e.g. - // a lifetime argument being given instead of a type parameter. - // Using inference instead of `Error` gives better error messages. - self.var_for_def(span, param) - } - } - GenericParamDefKind::Const => { - // FIXME(const_generics:defaults) - // No const parameters were provided, we have to infer them. - self.var_for_def(span, param) - } - } - }, - ) - }); - assert!(!substs.has_escaping_bound_vars()); - assert!(!ty.has_escaping_bound_vars()); - - // First, store the "user substs" for later. - self.write_user_type_annotation_from_substs(hir_id, def_id, substs, user_self_ty); - - self.add_required_obligations(span, def_id, &substs); - - // Substitute the values for the type parameters into the type of - // the referenced item. - let ty_substituted = self.instantiate_type_scheme(span, &substs, &ty); - - if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { - // In the case of `Foo::method` and `>::method`, if `method` - // is inherent, there is no `Self` parameter; instead, the impl needs - // type parameters, which we can infer by unifying the provided `Self` - // with the substituted impl type. - // This also occurs for an enum variant on a type alias. - let ty = tcx.type_of(impl_def_id); - - let impl_ty = self.instantiate_type_scheme(span, &substs, &ty); - match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) { - Ok(ok) => self.register_infer_ok_obligations(ok), - Err(_) => { - self.tcx.sess.delay_span_bug( - span, - &format!( - "instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?", - self_ty, - impl_ty, - ), - ); - } - } - } - - self.check_rustc_args_require_const(def_id, hir_id, span); - - debug!("instantiate_value_path: type of {:?} is {:?}", hir_id, ty_substituted); - self.write_substs(hir_id, substs); - - (ty_substituted, res) - } - - /// Add all the obligations that are required, substituting and normalized appropriately. - fn add_required_obligations(&self, span: Span, def_id: DefId, substs: &SubstsRef<'tcx>) { - let (bounds, spans) = self.instantiate_bounds(span, def_id, &substs); - - for (i, mut obligation) in traits::predicates_for_generics( - traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def_id)), - self.param_env, - bounds, - ) - .enumerate() - { - // This makes the error point at the bound, but we want to point at the argument - if let Some(span) = spans.get(i) { - obligation.cause.make_mut().code = traits::BindingObligation(def_id, *span); - } - self.register_predicate(obligation); - } - } - - fn check_rustc_args_require_const(&self, def_id: DefId, hir_id: hir::HirId, span: Span) { - // We're only interested in functions tagged with - // #[rustc_args_required_const], so ignore anything that's not. - if !self.tcx.has_attr(def_id, sym::rustc_args_required_const) { - return; - } - - // If our calling expression is indeed the function itself, we're good! - // If not, generate an error that this can only be called directly. - if let Node::Expr(expr) = self.tcx.hir().get(self.tcx.hir().get_parent_node(hir_id)) { - if let ExprKind::Call(ref callee, ..) = expr.kind { - if callee.hir_id == hir_id { - return; - } - } - } - - self.tcx.sess.span_err( - span, - "this function can only be invoked directly, not through a function pointer", - ); - } - - /// Resolves `typ` by a single level if `typ` is a type variable. - /// If no resolution is possible, then an error is reported. - /// Numeric inference variables may be left unresolved. - pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - let ty = self.resolve_vars_with_obligations(ty); - if !ty.is_ty_var() { - ty - } else { - if !self.is_tainted_by_errors() { - self.need_type_info_err((**self).body_id, sp, ty, E0282) - .note("type must be known at this point") - .emit(); - } - let err = self.tcx.ty_error(); - self.demand_suptype(sp, err, ty); - err - } - } - - fn with_breakable_ctxt R, R>( - &self, - id: hir::HirId, - ctxt: BreakableCtxt<'tcx>, - f: F, - ) -> (BreakableCtxt<'tcx>, R) { - let index; - { - let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - index = enclosing_breakables.stack.len(); - enclosing_breakables.by_id.insert(id, index); - enclosing_breakables.stack.push(ctxt); - } - let result = f(); - let ctxt = { - let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - debug_assert!(enclosing_breakables.stack.len() == index + 1); - enclosing_breakables.by_id.remove(&id).expect("missing breakable context"); - enclosing_breakables.stack.pop().expect("missing breakable context") - }; - (ctxt, result) - } - - /// Instantiate a QueryResponse in a probe context, without a - /// good ObligationCause. - fn probe_instantiate_query_response( - &self, - span: Span, - original_values: &OriginalQueryValues<'tcx>, - query_result: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, - ) -> InferResult<'tcx, Ty<'tcx>> { - self.instantiate_query_response_and_region_obligations( - &traits::ObligationCause::misc(span, self.body_id), - self.param_env, - original_values, - query_result, - ) - } - - /// Returns `true` if an expression is contained inside the LHS of an assignment expression. - fn expr_in_place(&self, mut expr_id: hir::HirId) -> bool { - let mut contained_in_place = false; - - while let hir::Node::Expr(parent_expr) = - self.tcx.hir().get(self.tcx.hir().get_parent_node(expr_id)) - { - match &parent_expr.kind { - hir::ExprKind::Assign(lhs, ..) | hir::ExprKind::AssignOp(_, lhs, ..) => { - if lhs.hir_id == expr_id { - contained_in_place = true; - break; - } - } - _ => (), - } - expr_id = parent_expr.hir_id; - } - - contained_in_place - } -} - fn check_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, generics: &ty::Generics, ty: Ty<'tcx>) { debug!("check_type_params_are_used(generics={:?}, ty={:?})", generics, ty); From 45fdf97d1131324b32510ab012825ccf600e947a Mon Sep 17 00:00:00 2001 From: Nicholas-Baron Date: Sat, 19 Sep 2020 04:25:30 -0700 Subject: [PATCH 0758/1052] Removed util.rs Per suggestion of @oli-obk. This file was rather short and joining it did not cause mod.rs to become significantly bigger. --- compiler/rustc_typeck/src/check/mod.rs | 72 ++++++++++++++++++++++--- compiler/rustc_typeck/src/check/util.rs | 69 ------------------------ 2 files changed, 64 insertions(+), 77 deletions(-) delete mode 100644 compiler/rustc_typeck/src/check/util.rs diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 5ef718c98ee6b..cc9e1176fc8b6 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -82,7 +82,6 @@ mod pat; mod place_op; mod regionck; mod upvar; -mod util; mod wfcheck; pub mod writeback; @@ -90,14 +89,14 @@ pub use fn_ctxt::FnCtxt; use crate::astconv::AstConv; use crate::check::gather_locals::GatherLocalsVisitor; -use crate::check::util::MaybeInProgressTables; use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{pluralize, struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def::Res; -use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; use rustc_hir::intravisit::Visitor; +use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{HirIdMap, ItemKind, Node}; use rustc_index::bit_set::BitSet; @@ -126,7 +125,7 @@ use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; use rustc_trait_selection::traits::{self, ObligationCauseCode, TraitEngine, TraitEngineExt}; -use std::cell::RefCell; +use std::cell::{Ref, RefCell, RefMut}; use std::cmp; use std::ops::{self, Deref}; @@ -586,10 +585,6 @@ pub fn check_wf_new(tcx: TyCtxt<'_>) { pub fn provide(providers: &mut Providers) { method::provide(providers); - use util::{ - check_impl_item_well_formed, check_item_well_formed, check_mod_item_types, - check_trait_item_well_formed, typeck_item_bodies, - }; *providers = Providers { typeck_item_bodies, typeck_const_arg, @@ -2720,6 +2715,67 @@ fn check_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, generics: &ty::Generics, } } +/// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field. +#[derive(Copy, Clone)] +struct MaybeInProgressTables<'a, 'tcx> { + maybe_typeck_results: Option<&'a RefCell>>, +} + +impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> { + fn borrow(self) -> Ref<'a, ty::TypeckResults<'tcx>> { + match self.maybe_typeck_results { + Some(typeck_results) => typeck_results.borrow(), + None => bug!( + "MaybeInProgressTables: inh/fcx.typeck_results.borrow() with no typeck results" + ), + } + } + + fn borrow_mut(self) -> RefMut<'a, ty::TypeckResults<'tcx>> { + match self.maybe_typeck_results { + Some(typeck_results) => typeck_results.borrow_mut(), + None => bug!( + "MaybeInProgressTables: inh/fcx.typeck_results.borrow_mut() with no typeck results" + ), + } + } +} + +struct CheckItemTypesVisitor<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'tcx> { + fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) { + check_item_type(self.tcx, i); + } + fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {} + fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {} +} + +fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { + tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx }); +} + +fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { + wfcheck::check_item_well_formed(tcx, def_id); +} + +fn check_trait_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { + wfcheck::check_trait_item(tcx, def_id); +} + +fn check_impl_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { + wfcheck::check_impl_item(tcx, def_id); +} + +fn typeck_item_bodies(tcx: TyCtxt<'_>, crate_num: CrateNum) { + debug_assert!(crate_num == LOCAL_CRATE); + tcx.par_body_owners(|body_owner_def_id| { + tcx.ensure().typeck(body_owner_def_id); + }); +} + fn fatally_break_rust(sess: &Session) { let handler = sess.diagnostic(); handler.span_bug_no_panic( diff --git a/compiler/rustc_typeck/src/check/util.rs b/compiler/rustc_typeck/src/check/util.rs deleted file mode 100644 index 62865accad4ad..0000000000000 --- a/compiler/rustc_typeck/src/check/util.rs +++ /dev/null @@ -1,69 +0,0 @@ -use rustc_hir as hir; -use rustc_hir::def_id::{CrateNum, LocalDefId, LOCAL_CRATE}; -use rustc_hir::itemlikevisit::ItemLikeVisitor; - -use std::cell::{Ref, RefCell, RefMut}; - -use super::wfcheck; -use crate::{ty, TyCtxt}; - -/// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field. -#[derive(Copy, Clone)] -pub(super) struct MaybeInProgressTables<'a, 'tcx> { - pub(super) maybe_typeck_results: Option<&'a RefCell>>, -} - -impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> { - pub(super) fn borrow(self) -> Ref<'a, ty::TypeckResults<'tcx>> { - match self.maybe_typeck_results { - Some(typeck_results) => typeck_results.borrow(), - None => bug!( - "MaybeInProgressTables: inh/fcx.typeck_results.borrow() with no typeck results" - ), - } - } - - pub(super) fn borrow_mut(self) -> RefMut<'a, ty::TypeckResults<'tcx>> { - match self.maybe_typeck_results { - Some(typeck_results) => typeck_results.borrow_mut(), - None => bug!( - "MaybeInProgressTables: inh/fcx.typeck_results.borrow_mut() with no typeck results" - ), - } - } -} - -struct CheckItemTypesVisitor<'tcx> { - tcx: TyCtxt<'tcx>, -} - -impl ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'tcx> { - fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) { - super::check_item_type(self.tcx, i); - } - fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {} - fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {} -} - -pub(super) fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { - tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx }); -} - -pub(super) fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { - wfcheck::check_item_well_formed(tcx, def_id); -} - -pub(super) fn check_trait_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { - wfcheck::check_trait_item(tcx, def_id); -} - -pub(super) fn check_impl_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { - wfcheck::check_impl_item(tcx, def_id); -} - -pub(super) fn typeck_item_bodies(tcx: TyCtxt<'_>, crate_num: CrateNum) { - debug_assert!(crate_num == LOCAL_CRATE); - tcx.par_body_owners(|body_owner_def_id| { - tcx.ensure().typeck(body_owner_def_id); - }); -} From 7995d5cda4cd5154def40770f4527e7867f37c1a Mon Sep 17 00:00:00 2001 From: Nicholas-Baron Date: Sat, 19 Sep 2020 05:05:42 -0700 Subject: [PATCH 0759/1052] Moved Inherited struct to own file --- compiler/rustc_typeck/src/check/inherited.rs | 167 +++++++++++++++++++ compiler/rustc_typeck/src/check/mod.rs | 161 +----------------- 2 files changed, 173 insertions(+), 155 deletions(-) create mode 100644 compiler/rustc_typeck/src/check/inherited.rs diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs new file mode 100644 index 0000000000000..7e580485c3de4 --- /dev/null +++ b/compiler/rustc_typeck/src/check/inherited.rs @@ -0,0 +1,167 @@ +use super::callee::DeferredCallResolution; +use super::MaybeInProgressTables; + +use rustc_data_structures::fx::FxHashMap; +use rustc_hir as hir; +use rustc_hir::def_id::{DefIdMap, LocalDefId}; +use rustc_hir::HirIdMap; +use rustc_infer::infer; +use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::{self, Span}; +use rustc_trait_selection::infer::InferCtxtExt as _; +use rustc_trait_selection::opaque_types::OpaqueTypeDecl; +use rustc_trait_selection::traits::{self, TraitEngine, TraitEngineExt}; + +use std::cell::RefCell; +use std::ops::Deref; + +/// Closures defined within the function. For example: +/// +/// fn foo() { +/// bar(move|| { ... }) +/// } +/// +/// Here, the function `foo()` and the closure passed to +/// `bar()` will each have their own `FnCtxt`, but they will +/// share the inherited fields. +pub struct Inherited<'a, 'tcx> { + pub(super) infcx: InferCtxt<'a, 'tcx>, + + pub(super) typeck_results: super::MaybeInProgressTables<'a, 'tcx>, + + pub(super) locals: RefCell>>, + + pub(super) fulfillment_cx: RefCell>>, + + // Some additional `Sized` obligations badly affect type inference. + // These obligations are added in a later stage of typeck. + pub(super) deferred_sized_obligations: + RefCell, Span, traits::ObligationCauseCode<'tcx>)>>, + + // When we process a call like `c()` where `c` is a closure type, + // we may not have decided yet whether `c` is a `Fn`, `FnMut`, or + // `FnOnce` closure. In that case, we defer full resolution of the + // call until upvar inference can kick in and make the + // decision. We keep these deferred resolutions grouped by the + // def-id of the closure, so that once we decide, we can easily go + // back and process them. + pub(super) deferred_call_resolutions: RefCell>>>, + + pub(super) deferred_cast_checks: RefCell>>, + + pub(super) deferred_generator_interiors: + RefCell, hir::GeneratorKind)>>, + + // Opaque types found in explicit return types and their + // associated fresh inference variable. Writeback resolves these + // variables to get the concrete type, which can be used to + // 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions. + pub(super) opaque_types: RefCell>>, + + /// A map from inference variables created from opaque + /// type instantiations (`ty::Infer`) to the actual opaque + /// type (`ty::Opaque`). Used during fallback to map unconstrained + /// opaque type inference variables to their corresponding + /// opaque type. + pub(super) opaque_types_vars: RefCell, Ty<'tcx>>>, + + pub(super) body_id: Option, +} + +impl<'a, 'tcx> Deref for Inherited<'a, 'tcx> { + type Target = InferCtxt<'a, 'tcx>; + fn deref(&self) -> &Self::Target { + &self.infcx + } +} + +/// Helper type of a temporary returned by `Inherited::build(...)`. +/// Necessary because we can't write the following bound: +/// `F: for<'b, 'tcx> where 'tcx FnOnce(Inherited<'b, 'tcx>)`. +pub struct InheritedBuilder<'tcx> { + infcx: infer::InferCtxtBuilder<'tcx>, + def_id: LocalDefId, +} + +impl Inherited<'_, 'tcx> { + pub fn build(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> InheritedBuilder<'tcx> { + let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner; + + InheritedBuilder { + infcx: tcx.infer_ctxt().with_fresh_in_progress_typeck_results(hir_owner), + def_id, + } + } +} + +impl<'tcx> InheritedBuilder<'tcx> { + pub fn enter(&mut self, f: F) -> R + where + F: for<'a> FnOnce(Inherited<'a, 'tcx>) -> R, + { + let def_id = self.def_id; + self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id))) + } +} + +impl Inherited<'a, 'tcx> { + pub(super) fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self { + let tcx = infcx.tcx; + let item_id = tcx.hir().local_def_id_to_hir_id(def_id); + let body_id = tcx.hir().maybe_body_owned_by(item_id); + + Inherited { + typeck_results: MaybeInProgressTables { + maybe_typeck_results: infcx.in_progress_typeck_results, + }, + infcx, + fulfillment_cx: RefCell::new(TraitEngine::new(tcx)), + locals: RefCell::new(Default::default()), + deferred_sized_obligations: RefCell::new(Vec::new()), + deferred_call_resolutions: RefCell::new(Default::default()), + deferred_cast_checks: RefCell::new(Vec::new()), + deferred_generator_interiors: RefCell::new(Vec::new()), + opaque_types: RefCell::new(Default::default()), + opaque_types_vars: RefCell::new(Default::default()), + body_id, + } + } + + pub(super) fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) { + debug!("register_predicate({:?})", obligation); + if obligation.has_escaping_bound_vars() { + span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation); + } + self.fulfillment_cx.borrow_mut().register_predicate_obligation(self, obligation); + } + + pub(super) fn register_predicates(&self, obligations: I) + where + I: IntoIterator>, + { + for obligation in obligations { + self.register_predicate(obligation); + } + } + + pub(super) fn register_infer_ok_obligations(&self, infer_ok: InferOk<'tcx, T>) -> T { + self.register_predicates(infer_ok.obligations); + infer_ok.value + } + + pub(super) fn normalize_associated_types_in( + &self, + span: Span, + body_id: hir::HirId, + param_env: ty::ParamEnv<'tcx>, + value: &T, + ) -> T + where + T: TypeFoldable<'tcx>, + { + let ok = self.partially_normalize_associated_types_in(span, body_id, param_env, value); + self.register_infer_ok_obligations(ok) + } +} diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index cc9e1176fc8b6..529cf491dd894 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -75,6 +75,7 @@ mod expr; mod fn_ctxt; mod gather_locals; mod generator_interior; +mod inherited; pub mod intrinsic; pub mod method; mod op; @@ -86,6 +87,7 @@ mod wfcheck; pub mod writeback; pub use fn_ctxt::FnCtxt; +pub use inherited::{Inherited, InheritedBuilder}; use crate::astconv::AstConv; use crate::check::gather_locals::GatherLocalsVisitor; @@ -94,16 +96,15 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{pluralize, struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def::Res; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::intravisit::Visitor; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{HirIdMap, ItemKind, Node}; use rustc_index::bit_set::BitSet; use rustc_index::vec::Idx; -use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::{InferCtxt, InferOk, RegionVariableOrigin, TyCtxtInferExt}; +use rustc_infer::infer::RegionVariableOrigin; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::GenericArgKind; @@ -119,20 +120,17 @@ use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{self, BytePos, MultiSpan, Span}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::infer::InferCtxtExt as _; -use rustc_trait_selection::opaque_types::OpaqueTypeDecl; use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error; use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; -use rustc_trait_selection::traits::{self, ObligationCauseCode, TraitEngine, TraitEngineExt}; +use rustc_trait_selection::traits::{self, ObligationCauseCode}; use std::cell::{Ref, RefCell, RefMut}; use std::cmp; -use std::ops::{self, Deref}; +use std::ops::{self}; use crate::require_c_abi_if_c_variadic; use crate::util::common::indenter; -use self::callee::DeferredCallResolution; use self::coercion::{CoerceMany, DynamicCoerceMany}; use self::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl}; pub use self::Expectation::*; @@ -155,64 +153,6 @@ pub struct LocalTy<'tcx> { revealed_ty: Ty<'tcx>, } -/// Closures defined within the function. For example: -/// -/// fn foo() { -/// bar(move|| { ... }) -/// } -/// -/// Here, the function `foo()` and the closure passed to -/// `bar()` will each have their own `FnCtxt`, but they will -/// share the inherited fields. -pub struct Inherited<'a, 'tcx> { - infcx: InferCtxt<'a, 'tcx>, - - typeck_results: MaybeInProgressTables<'a, 'tcx>, - - locals: RefCell>>, - - fulfillment_cx: RefCell>>, - - // Some additional `Sized` obligations badly affect type inference. - // These obligations are added in a later stage of typeck. - deferred_sized_obligations: RefCell, Span, traits::ObligationCauseCode<'tcx>)>>, - - // When we process a call like `c()` where `c` is a closure type, - // we may not have decided yet whether `c` is a `Fn`, `FnMut`, or - // `FnOnce` closure. In that case, we defer full resolution of the - // call until upvar inference can kick in and make the - // decision. We keep these deferred resolutions grouped by the - // def-id of the closure, so that once we decide, we can easily go - // back and process them. - deferred_call_resolutions: RefCell>>>, - - deferred_cast_checks: RefCell>>, - - deferred_generator_interiors: RefCell, hir::GeneratorKind)>>, - - // Opaque types found in explicit return types and their - // associated fresh inference variable. Writeback resolves these - // variables to get the concrete type, which can be used to - // 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions. - opaque_types: RefCell>>, - - /// A map from inference variables created from opaque - /// type instantiations (`ty::Infer`) to the actual opaque - /// type (`ty::Opaque`). Used during fallback to map unconstrained - /// opaque type inference variables to their corresponding - /// opaque type. - opaque_types_vars: RefCell, Ty<'tcx>>>, - - body_id: Option, -} - -impl<'a, 'tcx> Deref for Inherited<'a, 'tcx> { - type Target = InferCtxt<'a, 'tcx>; - fn deref(&self) -> &Self::Target { - &self.infcx - } -} - /// When type-checking an expression, we propagate downward /// whatever type hint we are able in the form of an `Expectation`. #[derive(Copy, Clone, Debug)] @@ -489,95 +429,6 @@ impl<'tcx> EnclosingBreakables<'tcx> { } } -/// Helper type of a temporary returned by `Inherited::build(...)`. -/// Necessary because we can't write the following bound: -/// `F: for<'b, 'tcx> where 'tcx FnOnce(Inherited<'b, 'tcx>)`. -pub struct InheritedBuilder<'tcx> { - infcx: infer::InferCtxtBuilder<'tcx>, - def_id: LocalDefId, -} - -impl Inherited<'_, 'tcx> { - pub fn build(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> InheritedBuilder<'tcx> { - let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner; - - InheritedBuilder { - infcx: tcx.infer_ctxt().with_fresh_in_progress_typeck_results(hir_owner), - def_id, - } - } -} - -impl<'tcx> InheritedBuilder<'tcx> { - pub fn enter(&mut self, f: F) -> R - where - F: for<'a> FnOnce(Inherited<'a, 'tcx>) -> R, - { - let def_id = self.def_id; - self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id))) - } -} - -impl Inherited<'a, 'tcx> { - fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self { - let tcx = infcx.tcx; - let item_id = tcx.hir().local_def_id_to_hir_id(def_id); - let body_id = tcx.hir().maybe_body_owned_by(item_id); - - Inherited { - typeck_results: MaybeInProgressTables { - maybe_typeck_results: infcx.in_progress_typeck_results, - }, - infcx, - fulfillment_cx: RefCell::new(TraitEngine::new(tcx)), - locals: RefCell::new(Default::default()), - deferred_sized_obligations: RefCell::new(Vec::new()), - deferred_call_resolutions: RefCell::new(Default::default()), - deferred_cast_checks: RefCell::new(Vec::new()), - deferred_generator_interiors: RefCell::new(Vec::new()), - opaque_types: RefCell::new(Default::default()), - opaque_types_vars: RefCell::new(Default::default()), - body_id, - } - } - - fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) { - debug!("register_predicate({:?})", obligation); - if obligation.has_escaping_bound_vars() { - span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation); - } - self.fulfillment_cx.borrow_mut().register_predicate_obligation(self, obligation); - } - - fn register_predicates(&self, obligations: I) - where - I: IntoIterator>, - { - for obligation in obligations { - self.register_predicate(obligation); - } - } - - fn register_infer_ok_obligations(&self, infer_ok: InferOk<'tcx, T>) -> T { - self.register_predicates(infer_ok.obligations); - infer_ok.value - } - - fn normalize_associated_types_in( - &self, - span: Span, - body_id: hir::HirId, - param_env: ty::ParamEnv<'tcx>, - value: &T, - ) -> T - where - T: TypeFoldable<'tcx>, - { - let ok = self.partially_normalize_associated_types_in(span, body_id, param_env, value); - self.register_infer_ok_obligations(ok) - } -} - pub fn check_wf_new(tcx: TyCtxt<'_>) { let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx); tcx.hir().krate().par_visit_all_item_likes(&visit); From b1e93796797624f33ea4f0f8563d002f28234d7d Mon Sep 17 00:00:00 2001 From: Nicholas-Baron Date: Sat, 19 Sep 2020 12:31:48 -0700 Subject: [PATCH 0760/1052] Formatted use statements for fewer lines --- compiler/rustc_typeck/src/check/fn_ctxt.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_typeck/src/check/fn_ctxt.rs b/compiler/rustc_typeck/src/check/fn_ctxt.rs index f7046468511c2..2a906f5b6ed07 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt.rs @@ -1,12 +1,11 @@ use super::callee::{self, DeferredCallResolution}; use super::coercion::{CoerceMany, DynamicCoerceMany}; -use super::method::{MethodCallee, SelfSource}; +use super::method::{self, MethodCallee, SelfSource}; use super::Expectation::*; use super::TupleArgumentsFlag::*; use super::{ - method, potentially_plural_count, struct_span_err, BreakableCtxt, Diverges, - EnclosingBreakables, Expectation, FallbackMode, Inherited, LocalTy, Needs, TupleArgumentsFlag, - UnsafetyState, + potentially_plural_count, struct_span_err, BreakableCtxt, Diverges, EnclosingBreakables, + Expectation, FallbackMode, Inherited, LocalTy, Needs, TupleArgumentsFlag, UnsafetyState, }; use crate::astconv::{ AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, PathSeg, @@ -23,12 +22,11 @@ use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, GenericArg, ItemKind, Node, QPath}; -use rustc_infer::infer; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_infer::infer::{InferOk, InferResult}; +use rustc_infer::infer::{self, InferOk, InferResult}; use rustc_middle::hir::map::blocks::FnLikeNode; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, @@ -41,8 +39,7 @@ use rustc_middle::ty::{ self, AdtKind, CanonicalUserType, Const, DefIdTree, GenericParamDefKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, UserType, }; -use rustc_session::lint; -use rustc_session::Session; +use rustc_session::{lint, Session}; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::{original_sp, DUMMY_SP}; use rustc_span::symbol::{kw, sym, Ident}; From 428a8c6eae7eadc08e8048929050818829ea7b4d Mon Sep 17 00:00:00 2001 From: Nicholas-Baron Date: Sat, 19 Sep 2020 12:45:14 -0700 Subject: [PATCH 0761/1052] Moved the Diverges struct to its own file --- compiler/rustc_typeck/src/check/diverges.rs | 78 ++++++++++++++++++++ compiler/rustc_typeck/src/check/mod.rs | 79 +-------------------- 2 files changed, 80 insertions(+), 77 deletions(-) create mode 100644 compiler/rustc_typeck/src/check/diverges.rs diff --git a/compiler/rustc_typeck/src/check/diverges.rs b/compiler/rustc_typeck/src/check/diverges.rs new file mode 100644 index 0000000000000..963a93a95c2bb --- /dev/null +++ b/compiler/rustc_typeck/src/check/diverges.rs @@ -0,0 +1,78 @@ +use rustc_span::source_map::DUMMY_SP; +use rustc_span::{self, Span}; +use std::{cmp, ops}; + +/// Tracks whether executing a node may exit normally (versus +/// return/break/panic, which "diverge", leaving dead code in their +/// wake). Tracked semi-automatically (through type variables marked +/// as diverging), with some manual adjustments for control-flow +/// primitives (approximating a CFG). +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum Diverges { + /// Potentially unknown, some cases converge, + /// others require a CFG to determine them. + Maybe, + + /// Definitely known to diverge and therefore + /// not reach the next sibling or its parent. + Always { + /// The `Span` points to the expression + /// that caused us to diverge + /// (e.g. `return`, `break`, etc). + span: Span, + /// In some cases (e.g. a `match` expression + /// where all arms diverge), we may be + /// able to provide a more informative + /// message to the user. + /// If this is `None`, a default message + /// will be generated, which is suitable + /// for most cases. + custom_note: Option<&'static str>, + }, + + /// Same as `Always` but with a reachability + /// warning already emitted. + WarnedAlways, +} + +// Convenience impls for combining `Diverges`. + +impl ops::BitAnd for Diverges { + type Output = Self; + fn bitand(self, other: Self) -> Self { + cmp::min(self, other) + } +} + +impl ops::BitOr for Diverges { + type Output = Self; + fn bitor(self, other: Self) -> Self { + cmp::max(self, other) + } +} + +impl ops::BitAndAssign for Diverges { + fn bitand_assign(&mut self, other: Self) { + *self = *self & other; + } +} + +impl ops::BitOrAssign for Diverges { + fn bitor_assign(&mut self, other: Self) { + *self = *self | other; + } +} + +impl Diverges { + /// Creates a `Diverges::Always` with the provided `span` and the default note message. + pub(super) fn always(span: Span) -> Diverges { + Diverges::Always { span, custom_note: None } + } + + pub(super) fn is_always(self) -> bool { + // Enum comparison ignores the + // contents of fields, so we just + // fill them in with garbage here. + self >= Diverges::Always { span: DUMMY_SP, custom_note: None } + } +} diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 529cf491dd894..98370d858d193 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -70,6 +70,7 @@ mod closure; pub mod coercion; mod compare_method; pub mod demand; +mod diverges; pub mod dropck; mod expr; mod fn_ctxt; @@ -86,6 +87,7 @@ mod upvar; mod wfcheck; pub mod writeback; +pub use diverges::Diverges; pub use fn_ctxt::FnCtxt; pub use inherited::{Inherited, InheritedBuilder}; @@ -125,8 +127,6 @@ use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; use rustc_trait_selection::traits::{self, ObligationCauseCode}; use std::cell::{Ref, RefCell, RefMut}; -use std::cmp; -use std::ops::{self}; use crate::require_c_abi_if_c_variadic; use crate::util::common::indenter; @@ -326,81 +326,6 @@ pub enum PlaceOp { Index, } -/// Tracks whether executing a node may exit normally (versus -/// return/break/panic, which "diverge", leaving dead code in their -/// wake). Tracked semi-automatically (through type variables marked -/// as diverging), with some manual adjustments for control-flow -/// primitives (approximating a CFG). -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub enum Diverges { - /// Potentially unknown, some cases converge, - /// others require a CFG to determine them. - Maybe, - - /// Definitely known to diverge and therefore - /// not reach the next sibling or its parent. - Always { - /// The `Span` points to the expression - /// that caused us to diverge - /// (e.g. `return`, `break`, etc). - span: Span, - /// In some cases (e.g. a `match` expression - /// where all arms diverge), we may be - /// able to provide a more informative - /// message to the user. - /// If this is `None`, a default message - /// will be generated, which is suitable - /// for most cases. - custom_note: Option<&'static str>, - }, - - /// Same as `Always` but with a reachability - /// warning already emitted. - WarnedAlways, -} - -// Convenience impls for combining `Diverges`. - -impl ops::BitAnd for Diverges { - type Output = Self; - fn bitand(self, other: Self) -> Self { - cmp::min(self, other) - } -} - -impl ops::BitOr for Diverges { - type Output = Self; - fn bitor(self, other: Self) -> Self { - cmp::max(self, other) - } -} - -impl ops::BitAndAssign for Diverges { - fn bitand_assign(&mut self, other: Self) { - *self = *self & other; - } -} - -impl ops::BitOrAssign for Diverges { - fn bitor_assign(&mut self, other: Self) { - *self = *self | other; - } -} - -impl Diverges { - /// Creates a `Diverges::Always` with the provided `span` and the default note message. - fn always(span: Span) -> Diverges { - Diverges::Always { span, custom_note: None } - } - - fn is_always(self) -> bool { - // Enum comparison ignores the - // contents of fields, so we just - // fill them in with garbage here. - self >= Diverges::Always { span: DUMMY_SP, custom_note: None } - } -} - pub struct BreakableCtxt<'tcx> { may_break: bool, From f896ddfc737d9ba9be22f60e8194986a6dc589ad Mon Sep 17 00:00:00 2001 From: Nicholas-Baron Date: Sat, 19 Sep 2020 13:00:39 -0700 Subject: [PATCH 0762/1052] Moved the Expectation enum to its own file --- .../rustc_typeck/src/check/expectation.rs | 117 ++++++++++++++++++ compiler/rustc_typeck/src/check/mod.rs | 113 +---------------- 2 files changed, 119 insertions(+), 111 deletions(-) create mode 100644 compiler/rustc_typeck/src/check/expectation.rs diff --git a/compiler/rustc_typeck/src/check/expectation.rs b/compiler/rustc_typeck/src/check/expectation.rs new file mode 100644 index 0000000000000..fd6fe1406c840 --- /dev/null +++ b/compiler/rustc_typeck/src/check/expectation.rs @@ -0,0 +1,117 @@ +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_middle::ty::{self, Ty}; +use rustc_span::{self, Span}; + +use super::Expectation::*; +use super::FnCtxt; + +/// When type-checking an expression, we propagate downward +/// whatever type hint we are able in the form of an `Expectation`. +#[derive(Copy, Clone, Debug)] +pub enum Expectation<'tcx> { + /// We know nothing about what type this expression should have. + NoExpectation, + + /// This expression should have the type given (or some subtype). + ExpectHasType(Ty<'tcx>), + + /// This expression will be cast to the `Ty`. + ExpectCastableToType(Ty<'tcx>), + + /// This rvalue expression will be wrapped in `&` or `Box` and coerced + /// to `&Ty` or `Box`, respectively. `Ty` is `[A]` or `Trait`. + ExpectRvalueLikeUnsized(Ty<'tcx>), +} + +impl<'a, 'tcx> Expectation<'tcx> { + // Disregard "castable to" expectations because they + // can lead us astray. Consider for example `if cond + // {22} else {c} as u8` -- if we propagate the + // "castable to u8" constraint to 22, it will pick the + // type 22u8, which is overly constrained (c might not + // be a u8). In effect, the problem is that the + // "castable to" expectation is not the tightest thing + // we can say, so we want to drop it in this case. + // The tightest thing we can say is "must unify with + // else branch". Note that in the case of a "has type" + // constraint, this limitation does not hold. + + // If the expected type is just a type variable, then don't use + // an expected type. Otherwise, we might write parts of the type + // when checking the 'then' block which are incompatible with the + // 'else' branch. + pub(super) fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> { + match *self { + ExpectHasType(ety) => { + let ety = fcx.shallow_resolve(ety); + if !ety.is_ty_var() { ExpectHasType(ety) } else { NoExpectation } + } + ExpectRvalueLikeUnsized(ety) => ExpectRvalueLikeUnsized(ety), + _ => NoExpectation, + } + } + + /// Provides an expectation for an rvalue expression given an *optional* + /// hint, which is not required for type safety (the resulting type might + /// be checked higher up, as is the case with `&expr` and `box expr`), but + /// is useful in determining the concrete type. + /// + /// The primary use case is where the expected type is a fat pointer, + /// like `&[isize]`. For example, consider the following statement: + /// + /// let x: &[isize] = &[1, 2, 3]; + /// + /// In this case, the expected type for the `&[1, 2, 3]` expression is + /// `&[isize]`. If however we were to say that `[1, 2, 3]` has the + /// expectation `ExpectHasType([isize])`, that would be too strong -- + /// `[1, 2, 3]` does not have the type `[isize]` but rather `[isize; 3]`. + /// It is only the `&[1, 2, 3]` expression as a whole that can be coerced + /// to the type `&[isize]`. Therefore, we propagate this more limited hint, + /// which still is useful, because it informs integer literals and the like. + /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169 + /// for examples of where this comes up,. + pub(super) fn rvalue_hint(fcx: &FnCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> { + match fcx.tcx.struct_tail_without_normalization(ty).kind() { + ty::Slice(_) | ty::Str | ty::Dynamic(..) => ExpectRvalueLikeUnsized(ty), + _ => ExpectHasType(ty), + } + } + + // Resolves `expected` by a single level if it is a variable. If + // there is no expected type or resolution is not possible (e.g., + // no constraints yet present), just returns `None`. + fn resolve(self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> { + match self { + NoExpectation => NoExpectation, + ExpectCastableToType(t) => ExpectCastableToType(fcx.resolve_vars_if_possible(&t)), + ExpectHasType(t) => ExpectHasType(fcx.resolve_vars_if_possible(&t)), + ExpectRvalueLikeUnsized(t) => ExpectRvalueLikeUnsized(fcx.resolve_vars_if_possible(&t)), + } + } + + pub(super) fn to_option(self, fcx: &FnCtxt<'a, 'tcx>) -> Option> { + match self.resolve(fcx) { + NoExpectation => None, + ExpectCastableToType(ty) | ExpectHasType(ty) | ExpectRvalueLikeUnsized(ty) => Some(ty), + } + } + + /// It sometimes happens that we want to turn an expectation into + /// a **hard constraint** (i.e., something that must be satisfied + /// for the program to type-check). `only_has_type` will return + /// such a constraint, if it exists. + pub(super) fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option> { + match self.resolve(fcx) { + ExpectHasType(ty) => Some(ty), + NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) => None, + } + } + + /// Like `only_has_type`, but instead of returning `None` if no + /// hard constraint exists, creates a fresh type variable. + pub(super) fn coercion_target_type(self, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> Ty<'tcx> { + self.only_has_type(fcx).unwrap_or_else(|| { + fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span }) + }) + } +} diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 98370d858d193..d45b51c42eae2 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -72,6 +72,7 @@ mod compare_method; pub mod demand; mod diverges; pub mod dropck; +mod expectation; mod expr; mod fn_ctxt; mod gather_locals; @@ -88,6 +89,7 @@ mod wfcheck; pub mod writeback; pub use diverges::Diverges; +pub use expectation::Expectation; pub use fn_ctxt::FnCtxt; pub use inherited::{Inherited, InheritedBuilder}; @@ -153,117 +155,6 @@ pub struct LocalTy<'tcx> { revealed_ty: Ty<'tcx>, } -/// When type-checking an expression, we propagate downward -/// whatever type hint we are able in the form of an `Expectation`. -#[derive(Copy, Clone, Debug)] -pub enum Expectation<'tcx> { - /// We know nothing about what type this expression should have. - NoExpectation, - - /// This expression should have the type given (or some subtype). - ExpectHasType(Ty<'tcx>), - - /// This expression will be cast to the `Ty`. - ExpectCastableToType(Ty<'tcx>), - - /// This rvalue expression will be wrapped in `&` or `Box` and coerced - /// to `&Ty` or `Box`, respectively. `Ty` is `[A]` or `Trait`. - ExpectRvalueLikeUnsized(Ty<'tcx>), -} - -impl<'a, 'tcx> Expectation<'tcx> { - // Disregard "castable to" expectations because they - // can lead us astray. Consider for example `if cond - // {22} else {c} as u8` -- if we propagate the - // "castable to u8" constraint to 22, it will pick the - // type 22u8, which is overly constrained (c might not - // be a u8). In effect, the problem is that the - // "castable to" expectation is not the tightest thing - // we can say, so we want to drop it in this case. - // The tightest thing we can say is "must unify with - // else branch". Note that in the case of a "has type" - // constraint, this limitation does not hold. - - // If the expected type is just a type variable, then don't use - // an expected type. Otherwise, we might write parts of the type - // when checking the 'then' block which are incompatible with the - // 'else' branch. - fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> { - match *self { - ExpectHasType(ety) => { - let ety = fcx.shallow_resolve(ety); - if !ety.is_ty_var() { ExpectHasType(ety) } else { NoExpectation } - } - ExpectRvalueLikeUnsized(ety) => ExpectRvalueLikeUnsized(ety), - _ => NoExpectation, - } - } - - /// Provides an expectation for an rvalue expression given an *optional* - /// hint, which is not required for type safety (the resulting type might - /// be checked higher up, as is the case with `&expr` and `box expr`), but - /// is useful in determining the concrete type. - /// - /// The primary use case is where the expected type is a fat pointer, - /// like `&[isize]`. For example, consider the following statement: - /// - /// let x: &[isize] = &[1, 2, 3]; - /// - /// In this case, the expected type for the `&[1, 2, 3]` expression is - /// `&[isize]`. If however we were to say that `[1, 2, 3]` has the - /// expectation `ExpectHasType([isize])`, that would be too strong -- - /// `[1, 2, 3]` does not have the type `[isize]` but rather `[isize; 3]`. - /// It is only the `&[1, 2, 3]` expression as a whole that can be coerced - /// to the type `&[isize]`. Therefore, we propagate this more limited hint, - /// which still is useful, because it informs integer literals and the like. - /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169 - /// for examples of where this comes up,. - fn rvalue_hint(fcx: &FnCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> { - match fcx.tcx.struct_tail_without_normalization(ty).kind() { - ty::Slice(_) | ty::Str | ty::Dynamic(..) => ExpectRvalueLikeUnsized(ty), - _ => ExpectHasType(ty), - } - } - - // Resolves `expected` by a single level if it is a variable. If - // there is no expected type or resolution is not possible (e.g., - // no constraints yet present), just returns `None`. - fn resolve(self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> { - match self { - NoExpectation => NoExpectation, - ExpectCastableToType(t) => ExpectCastableToType(fcx.resolve_vars_if_possible(&t)), - ExpectHasType(t) => ExpectHasType(fcx.resolve_vars_if_possible(&t)), - ExpectRvalueLikeUnsized(t) => ExpectRvalueLikeUnsized(fcx.resolve_vars_if_possible(&t)), - } - } - - fn to_option(self, fcx: &FnCtxt<'a, 'tcx>) -> Option> { - match self.resolve(fcx) { - NoExpectation => None, - ExpectCastableToType(ty) | ExpectHasType(ty) | ExpectRvalueLikeUnsized(ty) => Some(ty), - } - } - - /// It sometimes happens that we want to turn an expectation into - /// a **hard constraint** (i.e., something that must be satisfied - /// for the program to type-check). `only_has_type` will return - /// such a constraint, if it exists. - fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option> { - match self.resolve(fcx) { - ExpectHasType(ty) => Some(ty), - NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) => None, - } - } - - /// Like `only_has_type`, but instead of returning `None` if no - /// hard constraint exists, creates a fresh type variable. - fn coercion_target_type(self, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> Ty<'tcx> { - self.only_has_type(fcx).unwrap_or_else(|| { - fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span }) - }) - } -} - #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Needs { MutPlace, From 99e2e7075c0e32644498dd0bb64aae9a76ecfbce Mon Sep 17 00:00:00 2001 From: Nicholas-Baron Date: Sat, 19 Sep 2020 13:51:59 -0700 Subject: [PATCH 0763/1052] Moved all functions prefixed with 'check' to a separate file --- compiler/rustc_typeck/src/check/check.rs | 1344 ++++++++++++++++++++++ compiler/rustc_typeck/src/check/mod.rs | 1339 +-------------------- 2 files changed, 1356 insertions(+), 1327 deletions(-) create mode 100644 compiler/rustc_typeck/src/check/check.rs diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs new file mode 100644 index 0000000000000..2daa0354acb0b --- /dev/null +++ b/compiler/rustc_typeck/src/check/check.rs @@ -0,0 +1,1344 @@ +use super::coercion::CoerceMany; +use super::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl}; +use super::*; + +use rustc_attr as attr; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; +use rustc_hir::lang_items::LangItem; +use rustc_hir::{ItemKind, Node}; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::RegionVariableOrigin; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::util::{Discr, IntTypeExt, Representability}; +use rustc_middle::ty::{self, RegionKind, ToPredicate, Ty, TyCtxt}; +use rustc_session::config::EntryFnType; +use rustc_span::symbol::sym; +use rustc_span::{self, MultiSpan, Span}; +use rustc_target::spec::abi::Abi; +use rustc_trait_selection::traits::{self, ObligationCauseCode}; + +pub fn check_wf_new(tcx: TyCtxt<'_>) { + let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx); + tcx.hir().krate().par_visit_all_item_likes(&visit); +} + +pub(super) fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: Abi) { + if !tcx.sess.target.target.is_abi_supported(abi) { + struct_span_err!( + tcx.sess, + span, + E0570, + "The ABI `{}` is not supported for the current target", + abi + ) + .emit() + } +} + +/// Helper used for fns and closures. Does the grungy work of checking a function +/// body and returns the function context used for that purpose, since in the case of a fn item +/// there is still a bit more to do. +/// +/// * ... +/// * inherited: other fields inherited from the enclosing fn (if any) +pub(super) fn check_fn<'a, 'tcx>( + inherited: &'a Inherited<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + fn_sig: ty::FnSig<'tcx>, + decl: &'tcx hir::FnDecl<'tcx>, + fn_id: hir::HirId, + body: &'tcx hir::Body<'tcx>, + can_be_generator: Option, +) -> (FnCtxt<'a, 'tcx>, Option>) { + let mut fn_sig = fn_sig; + + debug!("check_fn(sig={:?}, fn_id={}, param_env={:?})", fn_sig, fn_id, param_env); + + // Create the function context. This is either derived from scratch or, + // in the case of closures, based on the outer context. + let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id); + *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id); + + let tcx = fcx.tcx; + let sess = tcx.sess; + let hir = tcx.hir(); + + let declared_ret_ty = fn_sig.output(); + + let revealed_ret_ty = + fcx.instantiate_opaque_types_from_value(fn_id, &declared_ret_ty, decl.output.span()); + debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty); + fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty))); + fcx.ret_type_span = Some(decl.output.span()); + if let ty::Opaque(..) = declared_ret_ty.kind() { + fcx.ret_coercion_impl_trait = Some(declared_ret_ty); + } + fn_sig = tcx.mk_fn_sig( + fn_sig.inputs().iter().cloned(), + revealed_ret_ty, + fn_sig.c_variadic, + fn_sig.unsafety, + fn_sig.abi, + ); + + let span = body.value.span; + + fn_maybe_err(tcx, span, fn_sig.abi); + + if body.generator_kind.is_some() && can_be_generator.is_some() { + let yield_ty = fcx + .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }); + fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType); + + // Resume type defaults to `()` if the generator has no argument. + let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit()); + + fcx.resume_yield_tys = Some((resume_ty, yield_ty)); + } + + let outer_def_id = tcx.closure_base_def_id(hir.local_def_id(fn_id).to_def_id()).expect_local(); + let outer_hir_id = hir.local_def_id_to_hir_id(outer_def_id); + GatherLocalsVisitor::new(&fcx, outer_hir_id).visit_body(body); + + // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` + // (as it's created inside the body itself, not passed in from outside). + let maybe_va_list = if fn_sig.c_variadic { + let span = body.params.last().unwrap().span; + let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span)); + let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span)); + + Some(tcx.type_of(va_list_did).subst(tcx, &[region.into()])) + } else { + None + }; + + // Add formal parameters. + let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs); + let inputs_fn = fn_sig.inputs().iter().copied(); + for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() { + // Check the pattern. + let ty_span = try { inputs_hir?.get(idx)?.span }; + fcx.check_pat_top(¶m.pat, param_ty, ty_span, false); + + // Check that argument is Sized. + // The check for a non-trivial pattern is a hack to avoid duplicate warnings + // for simple cases like `fn foo(x: Trait)`, + // where we would error once on the parameter as a whole, and once on the binding `x`. + if param.pat.simple_ident().is_none() && !tcx.features().unsized_locals { + fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span)); + } + + fcx.write_ty(param.hir_id, param_ty); + } + + inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig); + + fcx.in_tail_expr = true; + if let ty::Dynamic(..) = declared_ret_ty.kind() { + // FIXME: We need to verify that the return type is `Sized` after the return expression has + // been evaluated so that we have types available for all the nodes being returned, but that + // requires the coerced evaluated type to be stored. Moving `check_return_expr` before this + // causes unsized errors caused by the `declared_ret_ty` to point at the return expression, + // while keeping the current ordering we will ignore the tail expression's type because we + // don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr` + // because we will trigger "unreachable expression" lints unconditionally. + // Because of all of this, we perform a crude check to know whether the simplest `!Sized` + // case that a newcomer might make, returning a bare trait, and in that case we populate + // the tail expression's type so that the suggestion will be correct, but ignore all other + // possible cases. + fcx.check_expr(&body.value); + fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); + tcx.sess.delay_span_bug(decl.output.span(), "`!Sized` return type"); + } else { + fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); + fcx.check_return_expr(&body.value); + } + fcx.in_tail_expr = false; + + // We insert the deferred_generator_interiors entry after visiting the body. + // This ensures that all nested generators appear before the entry of this generator. + // resolve_generator_interiors relies on this property. + let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) { + let interior = fcx + .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span }); + fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind)); + + let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap(); + Some(GeneratorTypes { + resume_ty, + yield_ty, + interior, + movability: can_be_generator.unwrap(), + }) + } else { + None + }; + + // Finalize the return check by taking the LUB of the return types + // we saw and assigning it to the expected return type. This isn't + // really expected to fail, since the coercions would have failed + // earlier when trying to find a LUB. + // + // However, the behavior around `!` is sort of complex. In the + // event that the `actual_return_ty` comes back as `!`, that + // indicates that the fn either does not return or "returns" only + // values of type `!`. In this case, if there is an expected + // return type that is *not* `!`, that should be ok. But if the + // return type is being inferred, we want to "fallback" to `!`: + // + // let x = move || panic!(); + // + // To allow for that, I am creating a type variable with diverging + // fallback. This was deemed ever so slightly better than unifying + // the return value with `!` because it allows for the caller to + // make more assumptions about the return type (e.g., they could do + // + // let y: Option = Some(x()); + // + // which would then cause this return type to become `u32`, not + // `!`). + let coercion = fcx.ret_coercion.take().unwrap().into_inner(); + let mut actual_return_ty = coercion.complete(&fcx); + if actual_return_ty.is_never() { + actual_return_ty = fcx.next_diverging_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::DivergingFn, + span, + }); + } + fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty); + + // Check that the main return type implements the termination trait. + if let Some(term_id) = tcx.lang_items().termination() { + if let Some((def_id, EntryFnType::Main)) = tcx.entry_fn(LOCAL_CRATE) { + let main_id = hir.local_def_id_to_hir_id(def_id); + if main_id == fn_id { + let substs = tcx.mk_substs_trait(declared_ret_ty, &[]); + let trait_ref = ty::TraitRef::new(term_id, substs); + let return_ty_span = decl.output.span(); + let cause = traits::ObligationCause::new( + return_ty_span, + fn_id, + ObligationCauseCode::MainFunctionType, + ); + + inherited.register_predicate(traits::Obligation::new( + cause, + param_env, + trait_ref.without_const().to_predicate(tcx), + )); + } + } + } + + // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !` + if let Some(panic_impl_did) = tcx.lang_items().panic_impl() { + if panic_impl_did == hir.local_def_id(fn_id).to_def_id() { + if let Some(panic_info_did) = tcx.lang_items().panic_info() { + if *declared_ret_ty.kind() != ty::Never { + sess.span_err(decl.output.span(), "return type should be `!`"); + } + + let inputs = fn_sig.inputs(); + let span = hir.span(fn_id); + if inputs.len() == 1 { + let arg_is_panic_info = match *inputs[0].kind() { + ty::Ref(region, ty, mutbl) => match *ty.kind() { + ty::Adt(ref adt, _) => { + adt.did == panic_info_did + && mutbl == hir::Mutability::Not + && *region != RegionKind::ReStatic + } + _ => false, + }, + _ => false, + }; + + if !arg_is_panic_info { + sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`"); + } + + if let Node::Item(item) = hir.get(fn_id) { + if let ItemKind::Fn(_, ref generics, _) = item.kind { + if !generics.params.is_empty() { + sess.span_err(span, "should have no type parameters"); + } + } + } + } else { + let span = sess.source_map().guess_head_span(span); + sess.span_err(span, "function should have one argument"); + } + } else { + sess.err("language item required, but not found: `panic_info`"); + } + } + } + + // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !` + if let Some(alloc_error_handler_did) = tcx.lang_items().oom() { + if alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id() { + if let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() { + if *declared_ret_ty.kind() != ty::Never { + sess.span_err(decl.output.span(), "return type should be `!`"); + } + + let inputs = fn_sig.inputs(); + let span = hir.span(fn_id); + if inputs.len() == 1 { + let arg_is_alloc_layout = match inputs[0].kind() { + ty::Adt(ref adt, _) => adt.did == alloc_layout_did, + _ => false, + }; + + if !arg_is_alloc_layout { + sess.span_err(decl.inputs[0].span, "argument should be `Layout`"); + } + + if let Node::Item(item) = hir.get(fn_id) { + if let ItemKind::Fn(_, ref generics, _) = item.kind { + if !generics.params.is_empty() { + sess.span_err( + span, + "`#[alloc_error_handler]` function should have no type \ + parameters", + ); + } + } + } + } else { + let span = sess.source_map().guess_head_span(span); + sess.span_err(span, "function should have one argument"); + } + } else { + sess.err("language item required, but not found: `alloc_layout`"); + } + } + } + + (fcx, gen_ty) +} + +pub(super) fn check_struct(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) { + let def_id = tcx.hir().local_def_id(id); + let def = tcx.adt_def(def_id); + def.destructor(tcx); // force the destructor to be evaluated + check_representable(tcx, span, def_id); + + if def.repr.simd() { + check_simd(tcx, span, def_id); + } + + check_transparent(tcx, span, def); + check_packed(tcx, span, def); +} + +pub(super) fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) { + let def_id = tcx.hir().local_def_id(id); + let def = tcx.adt_def(def_id); + def.destructor(tcx); // force the destructor to be evaluated + check_representable(tcx, span, def_id); + check_transparent(tcx, span, def); + check_union_fields(tcx, span, def_id); + check_packed(tcx, span, def); +} + +/// When the `#![feature(untagged_unions)]` gate is active, +/// check that the fields of the `union` does not contain fields that need dropping. +pub(super) fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool { + let item_type = tcx.type_of(item_def_id); + if let ty::Adt(def, substs) = item_type.kind() { + assert!(def.is_union()); + let fields = &def.non_enum_variant().fields; + let param_env = tcx.param_env(item_def_id); + for field in fields { + let field_ty = field.ty(tcx, substs); + // We are currently checking the type this field came from, so it must be local. + let field_span = tcx.hir().span_if_local(field.did).unwrap(); + if field_ty.needs_drop(tcx, param_env) { + struct_span_err!( + tcx.sess, + field_span, + E0740, + "unions may not contain fields that need dropping" + ) + .span_note(field_span, "`std::mem::ManuallyDrop` can be used to wrap the type") + .emit(); + return false; + } + } + } else { + span_bug!(span, "unions must be ty::Adt, but got {:?}", item_type.kind()); + } + true +} + +/// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo` +/// projections that would result in "inheriting lifetimes". +pub(super) fn check_opaque<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + substs: SubstsRef<'tcx>, + span: Span, + origin: &hir::OpaqueTyOrigin, +) { + check_opaque_for_inheriting_lifetimes(tcx, def_id, span); + check_opaque_for_cycles(tcx, def_id, substs, span, origin); +} + +/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result +/// in "inheriting lifetimes". +pub(super) fn check_opaque_for_inheriting_lifetimes( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + span: Span, +) { + let item = tcx.hir().expect_item(tcx.hir().local_def_id_to_hir_id(def_id)); + debug!( + "check_opaque_for_inheriting_lifetimes: def_id={:?} span={:?} item={:?}", + def_id, span, item + ); + + #[derive(Debug)] + struct ProhibitOpaqueVisitor<'tcx> { + opaque_identity_ty: Ty<'tcx>, + generics: &'tcx ty::Generics, + ty: Option>, + }; + + impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t); + if t != self.opaque_identity_ty && t.super_visit_with(self) { + self.ty = Some(t); + return true; + } + false + } + + fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { + debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r); + if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r { + return *index < self.generics.parent_count as u32; + } + + r.super_visit_with(self) + } + + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { + if let ty::ConstKind::Unevaluated(..) = c.val { + // FIXME(#72219) We currenctly don't detect lifetimes within substs + // which would violate this check. Even though the particular substitution is not used + // within the const, this should still be fixed. + return false; + } + c.super_visit_with(self) + } + } + + if let ItemKind::OpaqueTy(hir::OpaqueTy { + origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn, + .. + }) = item.kind + { + let mut visitor = ProhibitOpaqueVisitor { + opaque_identity_ty: tcx.mk_opaque( + def_id.to_def_id(), + InternalSubsts::identity_for_item(tcx, def_id.to_def_id()), + ), + generics: tcx.generics_of(def_id), + ty: None, + }; + let prohibit_opaque = tcx + .predicates_of(def_id) + .predicates + .iter() + .any(|(predicate, _)| predicate.visit_with(&mut visitor)); + debug!( + "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}", + prohibit_opaque, visitor + ); + + if prohibit_opaque { + let is_async = match item.kind { + ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin { + hir::OpaqueTyOrigin::AsyncFn => true, + _ => false, + }, + _ => unreachable!(), + }; + + let mut err = struct_span_err!( + tcx.sess, + span, + E0760, + "`{}` return type cannot contain a projection or `Self` that references lifetimes from \ + a parent scope", + if is_async { "async fn" } else { "impl Trait" }, + ); + + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) { + if snippet == "Self" { + if let Some(ty) = visitor.ty { + err.span_suggestion( + span, + "consider spelling out the type instead", + format!("{:?}", ty), + Applicability::MaybeIncorrect, + ); + } + } + } + err.emit(); + } + } +} + +/// Checks that an opaque type does not contain cycles. +pub(super) fn check_opaque_for_cycles<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + substs: SubstsRef<'tcx>, + span: Span, + origin: &hir::OpaqueTyOrigin, +) { + if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id.to_def_id(), substs) + { + match origin { + hir::OpaqueTyOrigin::AsyncFn => async_opaque_type_cycle_error(tcx, span), + hir::OpaqueTyOrigin::Binding => { + binding_opaque_type_cycle_error(tcx, def_id, span, partially_expanded_type) + } + _ => opaque_type_cycle_error(tcx, def_id, span), + } + } +} + +pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) { + debug!( + "check_item_type(it.hir_id={}, it.name={})", + it.hir_id, + tcx.def_path_str(tcx.hir().local_def_id(it.hir_id).to_def_id()) + ); + let _indenter = indenter(); + match it.kind { + // Consts can play a role in type-checking, so they are included here. + hir::ItemKind::Static(..) => { + let def_id = tcx.hir().local_def_id(it.hir_id); + tcx.ensure().typeck(def_id); + maybe_check_static_with_link_section(tcx, def_id, it.span); + } + hir::ItemKind::Const(..) => { + tcx.ensure().typeck(tcx.hir().local_def_id(it.hir_id)); + } + hir::ItemKind::Enum(ref enum_definition, _) => { + check_enum(tcx, it.span, &enum_definition.variants, it.hir_id); + } + hir::ItemKind::Fn(..) => {} // entirely within check_item_body + hir::ItemKind::Impl { ref items, .. } => { + debug!("ItemKind::Impl {} with id {}", it.ident, it.hir_id); + let impl_def_id = tcx.hir().local_def_id(it.hir_id); + if let Some(impl_trait_ref) = tcx.impl_trait_ref(impl_def_id) { + check_impl_items_against_trait(tcx, it.span, impl_def_id, impl_trait_ref, items); + let trait_def_id = impl_trait_ref.def_id; + check_on_unimplemented(tcx, trait_def_id, it); + } + } + hir::ItemKind::Trait(_, _, _, _, ref items) => { + let def_id = tcx.hir().local_def_id(it.hir_id); + check_on_unimplemented(tcx, def_id.to_def_id(), it); + + for item in items.iter() { + let item = tcx.hir().trait_item(item.id); + if let hir::TraitItemKind::Fn(sig, _) = &item.kind { + let abi = sig.header.abi; + fn_maybe_err(tcx, item.ident.span, abi); + } + } + } + hir::ItemKind::Struct(..) => { + check_struct(tcx, it.hir_id, it.span); + } + hir::ItemKind::Union(..) => { + check_union(tcx, it.hir_id, it.span); + } + hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => { + // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting + // `async-std` (and `pub async fn` in general). + // Since rustdoc doesn't care about the concrete type behind `impl Trait`, just don't look at it! + // See https://github.com/rust-lang/rust/issues/75100 + if !tcx.sess.opts.actually_rustdoc { + let def_id = tcx.hir().local_def_id(it.hir_id); + + let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + check_opaque(tcx, def_id, substs, it.span, &origin); + } + } + hir::ItemKind::TyAlias(..) => { + let def_id = tcx.hir().local_def_id(it.hir_id); + let pty_ty = tcx.type_of(def_id); + 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); + + if m.abi == Abi::RustIntrinsic { + for item in m.items { + intrinsic::check_intrinsic_type(tcx, item); + } + } else if m.abi == Abi::PlatformIntrinsic { + for item in m.items { + intrinsic::check_platform_intrinsic_type(tcx, item); + } + } else { + for item in m.items { + let generics = tcx.generics_of(tcx.hir().local_def_id(item.hir_id)); + let own_counts = generics.own_counts(); + if generics.params.len() - own_counts.lifetimes != 0 { + let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts) { + (_, 0) => ("type", "types", Some("u32")), + // We don't specify an example value, because we can't generate + // a valid value for any type. + (0, _) => ("const", "consts", None), + _ => ("type or const", "types or consts", None), + }; + struct_span_err!( + tcx.sess, + item.span, + E0044, + "foreign items may not have {} parameters", + kinds, + ) + .span_label(item.span, &format!("can't have {} parameters", kinds)) + .help( + // FIXME: once we start storing spans for type arguments, turn this + // into a suggestion. + &format!( + "replace the {} parameters with concrete {}{}", + kinds, + kinds_pl, + egs.map(|egs| format!(" like `{}`", egs)).unwrap_or_default(), + ), + ) + .emit(); + } + + if let hir::ForeignItemKind::Fn(ref fn_decl, _, _) = item.kind { + require_c_abi_if_c_variadic(tcx, fn_decl, m.abi, item.span); + } + } + } + } + _ => { /* nothing to do */ } + } +} + +pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, trait_def_id: DefId, item: &hir::Item<'_>) { + let item_def_id = tcx.hir().local_def_id(item.hir_id); + // an error would be reported if this fails. + let _ = traits::OnUnimplementedDirective::of_item(tcx, trait_def_id, item_def_id.to_def_id()); +} + +pub(super) fn check_specialization_validity<'tcx>( + tcx: TyCtxt<'tcx>, + trait_def: &ty::TraitDef, + trait_item: &ty::AssocItem, + impl_id: DefId, + impl_item: &hir::ImplItem<'_>, +) { + let kind = match impl_item.kind { + hir::ImplItemKind::Const(..) => ty::AssocKind::Const, + hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn, + hir::ImplItemKind::TyAlias(_) => ty::AssocKind::Type, + }; + + let ancestors = match trait_def.ancestors(tcx, impl_id) { + Ok(ancestors) => ancestors, + Err(_) => return, + }; + let mut ancestor_impls = ancestors + .skip(1) + .filter_map(|parent| { + if parent.is_from_trait() { + None + } else { + Some((parent, parent.item(tcx, trait_item.ident, kind, trait_def.def_id))) + } + }) + .peekable(); + + if ancestor_impls.peek().is_none() { + // No parent, nothing to specialize. + return; + } + + let opt_result = ancestor_impls.find_map(|(parent_impl, parent_item)| { + match parent_item { + // Parent impl exists, and contains the parent item we're trying to specialize, but + // doesn't mark it `default`. + Some(parent_item) if traits::impl_item_is_final(tcx, &parent_item) => { + Some(Err(parent_impl.def_id())) + } + + // Parent impl contains item and makes it specializable. + Some(_) => Some(Ok(())), + + // Parent impl doesn't mention the item. This means it's inherited from the + // grandparent. In that case, if parent is a `default impl`, inherited items use the + // "defaultness" from the grandparent, else they are final. + None => { + if tcx.impl_defaultness(parent_impl.def_id()).is_default() { + None + } else { + Some(Err(parent_impl.def_id())) + } + } + } + }); + + // If `opt_result` is `None`, we have only encountered `default impl`s that don't contain the + // item. This is allowed, the item isn't actually getting specialized here. + let result = opt_result.unwrap_or(Ok(())); + + if let Err(parent_impl) = result { + report_forbidden_specialization(tcx, impl_item, parent_impl); + } +} + +pub(super) fn check_impl_items_against_trait<'tcx>( + tcx: TyCtxt<'tcx>, + full_impl_span: Span, + impl_id: LocalDefId, + impl_trait_ref: ty::TraitRef<'tcx>, + impl_item_refs: &[hir::ImplItemRef<'_>], +) { + let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span); + + // If the trait reference itself is erroneous (so the compilation is going + // to fail), skip checking the items here -- the `impl_item` table in `tcx` + // isn't populated for such impls. + if impl_trait_ref.references_error() { + return; + } + + // Negative impls are not expected to have any items + match tcx.impl_polarity(impl_id) { + ty::ImplPolarity::Reservation | ty::ImplPolarity::Positive => {} + ty::ImplPolarity::Negative => { + if let [first_item_ref, ..] = impl_item_refs { + let first_item_span = tcx.hir().impl_item(first_item_ref.id).span; + struct_span_err!( + tcx.sess, + first_item_span, + E0749, + "negative impls cannot have any items" + ) + .emit(); + } + return; + } + } + + // Locate trait definition and items + let trait_def = tcx.trait_def(impl_trait_ref.def_id); + + let impl_items = || impl_item_refs.iter().map(|iiref| tcx.hir().impl_item(iiref.id)); + + // Check existing impl methods to see if they are both present in trait + // and compatible with trait signature + for impl_item in impl_items() { + let namespace = impl_item.kind.namespace(); + let ty_impl_item = tcx.associated_item(tcx.hir().local_def_id(impl_item.hir_id)); + let ty_trait_item = tcx + .associated_items(impl_trait_ref.def_id) + .find_by_name_and_namespace(tcx, ty_impl_item.ident, namespace, impl_trait_ref.def_id) + .or_else(|| { + // Not compatible, but needed for the error message + tcx.associated_items(impl_trait_ref.def_id) + .filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id) + .next() + }); + + // Check that impl definition matches trait definition + if let Some(ty_trait_item) = ty_trait_item { + match impl_item.kind { + hir::ImplItemKind::Const(..) => { + // Find associated const definition. + if ty_trait_item.kind == ty::AssocKind::Const { + compare_const_impl( + tcx, + &ty_impl_item, + impl_item.span, + &ty_trait_item, + impl_trait_ref, + ); + } else { + let mut err = struct_span_err!( + tcx.sess, + impl_item.span, + E0323, + "item `{}` is an associated const, \ + which doesn't match its trait `{}`", + ty_impl_item.ident, + impl_trait_ref.print_only_trait_path() + ); + err.span_label(impl_item.span, "does not match trait"); + // We can only get the spans from local trait definition + // Same for E0324 and E0325 + if let Some(trait_span) = tcx.hir().span_if_local(ty_trait_item.def_id) { + err.span_label(trait_span, "item in trait"); + } + err.emit() + } + } + hir::ImplItemKind::Fn(..) => { + let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id); + if ty_trait_item.kind == ty::AssocKind::Fn { + compare_impl_method( + tcx, + &ty_impl_item, + impl_item.span, + &ty_trait_item, + impl_trait_ref, + opt_trait_span, + ); + } else { + let mut err = struct_span_err!( + tcx.sess, + impl_item.span, + E0324, + "item `{}` is an associated method, \ + which doesn't match its trait `{}`", + ty_impl_item.ident, + impl_trait_ref.print_only_trait_path() + ); + err.span_label(impl_item.span, "does not match trait"); + if let Some(trait_span) = opt_trait_span { + err.span_label(trait_span, "item in trait"); + } + err.emit() + } + } + hir::ImplItemKind::TyAlias(_) => { + let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id); + if ty_trait_item.kind == ty::AssocKind::Type { + compare_ty_impl( + tcx, + &ty_impl_item, + impl_item.span, + &ty_trait_item, + impl_trait_ref, + opt_trait_span, + ); + } else { + let mut err = struct_span_err!( + tcx.sess, + impl_item.span, + E0325, + "item `{}` is an associated type, \ + which doesn't match its trait `{}`", + ty_impl_item.ident, + impl_trait_ref.print_only_trait_path() + ); + err.span_label(impl_item.span, "does not match trait"); + if let Some(trait_span) = opt_trait_span { + err.span_label(trait_span, "item in trait"); + } + err.emit() + } + } + } + + check_specialization_validity( + tcx, + trait_def, + &ty_trait_item, + impl_id.to_def_id(), + impl_item, + ); + } + } + + // Check for missing items from trait + let mut missing_items = Vec::new(); + if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) { + for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() { + let is_implemented = ancestors + .leaf_def(tcx, trait_item.ident, trait_item.kind) + .map(|node_item| !node_item.defining_node.is_from_trait()) + .unwrap_or(false); + + if !is_implemented && tcx.impl_defaultness(impl_id).is_final() { + if !trait_item.defaultness.has_value() { + missing_items.push(*trait_item); + } + } + } + } + + if !missing_items.is_empty() { + missing_items_err(tcx, impl_span, &missing_items, full_impl_span); + } +} + +/// Checks whether a type can be represented in memory. In particular, it +/// identifies types that contain themselves without indirection through a +/// pointer, which would mean their size is unbounded. +pub(super) fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: LocalDefId) -> bool { + let rty = tcx.type_of(item_def_id); + + // Check that it is possible to represent this type. This call identifies + // (1) types that contain themselves and (2) types that contain a different + // recursive type. It is only necessary to throw an error on those that + // contain themselves. For case 2, there must be an inner type that will be + // caught by case 1. + match rty.is_representable(tcx, sp) { + Representability::SelfRecursive(spans) => { + recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id(), spans); + return false; + } + Representability::Representable | Representability::ContainsRecursive => (), + } + true +} + +pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { + let t = tcx.type_of(def_id); + if let ty::Adt(def, substs) = t.kind() { + if def.is_struct() { + let fields = &def.non_enum_variant().fields; + if fields.is_empty() { + struct_span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty").emit(); + return; + } + let e = fields[0].ty(tcx, substs); + if !fields.iter().all(|f| f.ty(tcx, substs) == e) { + struct_span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous") + .span_label(sp, "SIMD elements must have the same type") + .emit(); + return; + } + match e.kind() { + ty::Param(_) => { /* struct(T, T, T, T) is ok */ } + _ if e.is_machine() => { /* struct(u8, u8, u8, u8) is ok */ } + _ => { + struct_span_err!( + tcx.sess, + sp, + E0077, + "SIMD vector element type should be machine type" + ) + .emit(); + return; + } + } + } + } +} + +pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: &ty::AdtDef) { + let repr = def.repr; + if repr.packed() { + for attr in tcx.get_attrs(def.did).iter() { + for r in attr::find_repr_attrs(&tcx.sess, attr) { + if let attr::ReprPacked(pack) = r { + if let Some(repr_pack) = repr.pack { + if pack as u64 != repr_pack.bytes() { + struct_span_err!( + tcx.sess, + sp, + E0634, + "type has conflicting packed representation hints" + ) + .emit(); + } + } + } + } + } + if repr.align.is_some() { + struct_span_err!( + tcx.sess, + sp, + E0587, + "type has conflicting packed and align representation hints" + ) + .emit(); + } else { + if let Some(def_spans) = check_packed_inner(tcx, def.did, &mut vec![]) { + let mut err = struct_span_err!( + tcx.sess, + sp, + E0588, + "packed type cannot transitively contain a `#[repr(align)]` type" + ); + + err.span_note( + tcx.def_span(def_spans[0].0), + &format!( + "`{}` has a `#[repr(align)]` attribute", + tcx.item_name(def_spans[0].0) + ), + ); + + if def_spans.len() > 2 { + let mut first = true; + for (adt_def, span) in def_spans.iter().skip(1).rev() { + let ident = tcx.item_name(*adt_def); + err.span_note( + *span, + &if first { + format!( + "`{}` contains a field of type `{}`", + tcx.type_of(def.did), + ident + ) + } else { + format!("...which contains a field of type `{}`", ident) + }, + ); + first = false; + } + } + + err.emit(); + } + } + } +} + +pub(super) fn check_packed_inner( + tcx: TyCtxt<'_>, + def_id: DefId, + stack: &mut Vec, +) -> Option> { + if let ty::Adt(def, substs) = tcx.type_of(def_id).kind() { + if def.is_struct() || def.is_union() { + if def.repr.align.is_some() { + return Some(vec![(def.did, DUMMY_SP)]); + } + + stack.push(def_id); + for field in &def.non_enum_variant().fields { + if let ty::Adt(def, _) = field.ty(tcx, substs).kind() { + if !stack.contains(&def.did) { + if let Some(mut defs) = check_packed_inner(tcx, def.did, stack) { + defs.push((def.did, field.ident.span)); + return Some(defs); + } + } + } + } + stack.pop(); + } + } + + None +} + +pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: &'tcx ty::AdtDef) { + if !adt.repr.transparent() { + return; + } + let sp = tcx.sess.source_map().guess_head_span(sp); + + if adt.is_union() && !tcx.features().transparent_unions { + feature_err( + &tcx.sess.parse_sess, + sym::transparent_unions, + sp, + "transparent unions are unstable", + ) + .emit(); + } + + if adt.variants.len() != 1 { + bad_variant_count(tcx, adt, sp, adt.did); + if adt.variants.is_empty() { + // Don't bother checking the fields. No variants (and thus no fields) exist. + return; + } + } + + // For each field, figure out if it's known to be a ZST and align(1) + let field_infos = adt.all_fields().map(|field| { + let ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, field.did)); + let param_env = tcx.param_env(field.did); + let layout = tcx.layout_of(param_env.and(ty)); + // We are currently checking the type this field came from, so it must be local + let span = tcx.hir().span_if_local(field.did).unwrap(); + let zst = layout.map(|layout| layout.is_zst()).unwrap_or(false); + let align1 = layout.map(|layout| layout.align.abi.bytes() == 1).unwrap_or(false); + (span, zst, align1) + }); + + let non_zst_fields = + field_infos.clone().filter_map(|(span, zst, _align1)| if !zst { Some(span) } else { None }); + let non_zst_count = non_zst_fields.clone().count(); + if non_zst_count != 1 { + bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp); + } + for (span, zst, align1) in field_infos { + if zst && !align1 { + struct_span_err!( + tcx.sess, + span, + E0691, + "zero-sized field in transparent {} has alignment larger than 1", + adt.descr(), + ) + .span_label(span, "has alignment larger than 1") + .emit(); + } + } +} + +#[allow(trivial_numeric_casts)] +pub fn check_enum<'tcx>( + tcx: TyCtxt<'tcx>, + sp: Span, + vs: &'tcx [hir::Variant<'tcx>], + id: hir::HirId, +) { + let def_id = tcx.hir().local_def_id(id); + let def = tcx.adt_def(def_id); + def.destructor(tcx); // force the destructor to be evaluated + + if vs.is_empty() { + let attributes = tcx.get_attrs(def_id.to_def_id()); + if let Some(attr) = tcx.sess.find_by_name(&attributes, sym::repr) { + struct_span_err!( + tcx.sess, + attr.span, + E0084, + "unsupported representation for zero-variant enum" + ) + .span_label(sp, "zero-variant enum") + .emit(); + } + } + + let repr_type_ty = def.repr.discr_type().to_ty(tcx); + if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 { + if !tcx.features().repr128 { + feature_err( + &tcx.sess.parse_sess, + sym::repr128, + sp, + "repr with 128-bit type is unstable", + ) + .emit(); + } + } + + for v in vs { + if let Some(ref e) = v.disr_expr { + tcx.ensure().typeck(tcx.hir().local_def_id(e.hir_id)); + } + } + + 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 has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some(); + let has_non_units = vs.iter().any(|var| !is_unit(var)); + let disr_units = vs.iter().any(|var| is_unit(&var) && has_disr(&var)); + let disr_non_unit = vs.iter().any(|var| !is_unit(&var) && has_disr(&var)); + + if disr_non_unit || (disr_units && has_non_units) { + let mut err = + struct_span_err!(tcx.sess, sp, E0732, "`#[repr(inttype)]` must be specified"); + err.emit(); + } + } + + let mut disr_vals: Vec> = Vec::with_capacity(vs.len()); + for ((_, discr), v) in def.discriminants(tcx).zip(vs) { + // Check for duplicate discriminant values + if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) { + let variant_did = def.variants[VariantIdx::new(i)].def_id; + let variant_i_hir_id = tcx.hir().local_def_id_to_hir_id(variant_did.expect_local()); + let variant_i = tcx.hir().expect_variant(variant_i_hir_id); + let i_span = match variant_i.disr_expr { + Some(ref expr) => tcx.hir().span(expr.hir_id), + None => tcx.hir().span(variant_i_hir_id), + }; + let span = match v.disr_expr { + Some(ref expr) => tcx.hir().span(expr.hir_id), + None => v.span, + }; + struct_span_err!( + tcx.sess, + span, + E0081, + "discriminant value `{}` already exists", + disr_vals[i] + ) + .span_label(i_span, format!("first use of `{}`", disr_vals[i])) + .span_label(span, format!("enum already has `{}`", disr_vals[i])) + .emit(); + } + disr_vals.push(discr); + } + + check_representable(tcx, sp, def_id); + check_transparent(tcx, sp, def); +} + +pub(super) fn check_type_params_are_used<'tcx>( + tcx: TyCtxt<'tcx>, + generics: &ty::Generics, + ty: Ty<'tcx>, +) { + debug!("check_type_params_are_used(generics={:?}, ty={:?})", generics, ty); + + assert_eq!(generics.parent, None); + + if generics.own_counts().types == 0 { + return; + } + + let mut params_used = BitSet::new_empty(generics.params.len()); + + if ty.references_error() { + // If there is already another error, do not emit + // an error for not using a type parameter. + assert!(tcx.sess.has_errors()); + return; + } + + for leaf in ty.walk() { + if let GenericArgKind::Type(leaf_ty) = leaf.unpack() { + if let ty::Param(param) = leaf_ty.kind() { + debug!("found use of ty param {:?}", param); + params_used.insert(param.index); + } + } + } + + for param in &generics.params { + if !params_used.contains(param.index) { + if let ty::GenericParamDefKind::Type { .. } = param.kind { + let span = tcx.def_span(param.def_id); + struct_span_err!( + tcx.sess, + span, + E0091, + "type parameter `{}` is unused", + param.name, + ) + .span_label(span, "unused type parameter") + .emit(); + } + } + } +} + +pub(super) fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { + tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx }); +} + +pub(super) fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { + wfcheck::check_item_well_formed(tcx, def_id); +} + +pub(super) fn check_trait_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { + wfcheck::check_trait_item(tcx, def_id); +} + +pub(super) fn check_impl_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { + wfcheck::check_impl_item(tcx, def_id); +} + +fn async_opaque_type_cycle_error(tcx: TyCtxt<'tcx>, span: Span) { + struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing") + .span_label(span, "recursive `async fn`") + .note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`") + .emit(); +} + +/// Emit an error for recursive opaque types. +/// +/// If this is a return `impl Trait`, find the item's return expressions and point at them. For +/// direct recursion this is enough, but for indirect recursion also point at the last intermediary +/// `impl Trait`. +/// +/// If all the return expressions evaluate to `!`, then we explain that the error will go away +/// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder. +fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) { + let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type"); + + let mut label = false; + if let Some((hir_id, visitor)) = get_owner_return_paths(tcx, def_id) { + let typeck_results = tcx.typeck(tcx.hir().local_def_id(hir_id)); + if visitor + .returns + .iter() + .filter_map(|expr| typeck_results.node_type_opt(expr.hir_id)) + .all(|ty| matches!(ty.kind(), ty::Never)) + { + let spans = visitor + .returns + .iter() + .filter(|expr| typeck_results.node_type_opt(expr.hir_id).is_some()) + .map(|expr| expr.span) + .collect::>(); + let span_len = spans.len(); + if span_len == 1 { + err.span_label(spans[0], "this returned value is of `!` type"); + } else { + let mut multispan: MultiSpan = spans.clone().into(); + for span in spans { + multispan + .push_span_label(span, "this returned value is of `!` type".to_string()); + } + err.span_note(multispan, "these returned values have a concrete \"never\" type"); + } + err.help("this error will resolve once the item's body returns a concrete type"); + } else { + let mut seen = FxHashSet::default(); + seen.insert(span); + err.span_label(span, "recursive opaque type"); + label = true; + for (sp, ty) in visitor + .returns + .iter() + .filter_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t))) + .filter(|(_, ty)| !matches!(ty.kind(), ty::Never)) + { + struct VisitTypes(Vec); + impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes { + fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + match *t.kind() { + ty::Opaque(def, _) => { + self.0.push(def); + false + } + _ => t.super_visit_with(self), + } + } + } + let mut visitor = VisitTypes(vec![]); + ty.visit_with(&mut visitor); + for def_id in visitor.0 { + let ty_span = tcx.def_span(def_id); + if !seen.contains(&ty_span) { + err.span_label(ty_span, &format!("returning this opaque type `{}`", ty)); + seen.insert(ty_span); + } + err.span_label(sp, &format!("returning here with type `{}`", ty)); + } + } + } + } + if !label { + err.span_label(span, "cannot resolve opaque type"); + } + err.emit(); +} diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index d45b51c42eae2..04d4d8171d48a 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -66,6 +66,7 @@ pub mod _match; mod autoderef; mod callee; pub mod cast; +mod check; mod closure; pub mod coercion; mod compare_method; @@ -88,6 +89,11 @@ mod upvar; mod wfcheck; pub mod writeback; +use check::{ + check_abi, check_fn, check_impl_item_well_formed, check_item_well_formed, check_mod_item_types, + check_trait_item_well_formed, +}; +pub use check::{check_item_type, check_wf_new}; pub use diverges::Diverges; pub use expectation::Expectation; pub use fn_ctxt::FnCtxt; @@ -95,7 +101,6 @@ pub use inherited::{Inherited, InheritedBuilder}; use crate::astconv::AstConv; use crate::check::gather_locals::GatherLocalsVisitor; -use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{pluralize, struct_span_err, Applicability}; use rustc_hir as hir; @@ -103,38 +108,33 @@ use rustc_hir::def::Res; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::intravisit::Visitor; use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_hir::lang_items::LangItem; -use rustc_hir::{HirIdMap, ItemKind, Node}; +use rustc_hir::{HirIdMap, Node}; use rustc_index::bit_set::BitSet; use rustc_index::vec::Idx; -use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::RegionVariableOrigin; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; -use rustc_middle::ty::util::{Discr, IntTypeExt, Representability}; use rustc_middle::ty::WithConstness; -use rustc_middle::ty::{self, RegionKind, ToPredicate, Ty, TyCtxt, UserType}; -use rustc_session::config::{self, EntryFnType}; +use rustc_middle::ty::{self, RegionKind, Ty, TyCtxt, UserType}; +use rustc_session::config; use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::source_map::DUMMY_SP; -use rustc_span::symbol::{kw, sym, Ident}; +use rustc_span::symbol::{kw, Ident}; use rustc_span::{self, BytePos, MultiSpan, Span}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; +use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error; use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; -use rustc_trait_selection::traits::{self, ObligationCauseCode}; use std::cell::{Ref, RefCell, RefMut}; use crate::require_c_abi_if_c_variadic; use crate::util::common::indenter; -use self::coercion::{CoerceMany, DynamicCoerceMany}; -use self::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl}; +use self::coercion::DynamicCoerceMany; pub use self::Expectation::*; #[macro_export] @@ -245,11 +245,6 @@ impl<'tcx> EnclosingBreakables<'tcx> { } } -pub fn check_wf_new(tcx: TyCtxt<'_>) { - let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx); - tcx.hir().krate().par_visit_all_item_likes(&visit); -} - pub fn provide(providers: &mut Providers) { method::provide(providers); *providers = Providers { @@ -631,19 +626,6 @@ fn typeck_with_fallback<'tcx>( typeck_results } -fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: Abi) { - if !tcx.sess.target.target.is_abi_supported(abi) { - struct_span_err!( - tcx.sess, - span, - E0570, - "The ABI `{}` is not supported for the current target", - abi - ) - .emit() - } -} - /// When `check_fn` is invoked on a generator (i.e., a body that /// includes yield), it returns back some information about the yield /// points. @@ -661,460 +643,6 @@ struct GeneratorTypes<'tcx> { movability: hir::Movability, } -/// Helper used for fns and closures. Does the grungy work of checking a function -/// body and returns the function context used for that purpose, since in the case of a fn item -/// there is still a bit more to do. -/// -/// * ... -/// * inherited: other fields inherited from the enclosing fn (if any) -fn check_fn<'a, 'tcx>( - inherited: &'a Inherited<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - fn_sig: ty::FnSig<'tcx>, - decl: &'tcx hir::FnDecl<'tcx>, - fn_id: hir::HirId, - body: &'tcx hir::Body<'tcx>, - can_be_generator: Option, -) -> (FnCtxt<'a, 'tcx>, Option>) { - let mut fn_sig = fn_sig; - - debug!("check_fn(sig={:?}, fn_id={}, param_env={:?})", fn_sig, fn_id, param_env); - - // Create the function context. This is either derived from scratch or, - // in the case of closures, based on the outer context. - let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id); - *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id); - - let tcx = fcx.tcx; - let sess = tcx.sess; - let hir = tcx.hir(); - - let declared_ret_ty = fn_sig.output(); - - let revealed_ret_ty = - fcx.instantiate_opaque_types_from_value(fn_id, &declared_ret_ty, decl.output.span()); - debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty); - fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty))); - fcx.ret_type_span = Some(decl.output.span()); - if let ty::Opaque(..) = declared_ret_ty.kind() { - fcx.ret_coercion_impl_trait = Some(declared_ret_ty); - } - fn_sig = tcx.mk_fn_sig( - fn_sig.inputs().iter().cloned(), - revealed_ret_ty, - fn_sig.c_variadic, - fn_sig.unsafety, - fn_sig.abi, - ); - - let span = body.value.span; - - fn_maybe_err(tcx, span, fn_sig.abi); - - if body.generator_kind.is_some() && can_be_generator.is_some() { - let yield_ty = fcx - .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }); - fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType); - - // Resume type defaults to `()` if the generator has no argument. - let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit()); - - fcx.resume_yield_tys = Some((resume_ty, yield_ty)); - } - - let outer_def_id = tcx.closure_base_def_id(hir.local_def_id(fn_id).to_def_id()).expect_local(); - let outer_hir_id = hir.local_def_id_to_hir_id(outer_def_id); - GatherLocalsVisitor::new(&fcx, outer_hir_id).visit_body(body); - - // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` - // (as it's created inside the body itself, not passed in from outside). - let maybe_va_list = if fn_sig.c_variadic { - let span = body.params.last().unwrap().span; - let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span)); - let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span)); - - Some(tcx.type_of(va_list_did).subst(tcx, &[region.into()])) - } else { - None - }; - - // Add formal parameters. - let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs); - let inputs_fn = fn_sig.inputs().iter().copied(); - for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() { - // Check the pattern. - let ty_span = try { inputs_hir?.get(idx)?.span }; - fcx.check_pat_top(¶m.pat, param_ty, ty_span, false); - - // Check that argument is Sized. - // The check for a non-trivial pattern is a hack to avoid duplicate warnings - // for simple cases like `fn foo(x: Trait)`, - // where we would error once on the parameter as a whole, and once on the binding `x`. - if param.pat.simple_ident().is_none() && !tcx.features().unsized_locals { - fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span)); - } - - fcx.write_ty(param.hir_id, param_ty); - } - - inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig); - - fcx.in_tail_expr = true; - if let ty::Dynamic(..) = declared_ret_ty.kind() { - // FIXME: We need to verify that the return type is `Sized` after the return expression has - // been evaluated so that we have types available for all the nodes being returned, but that - // requires the coerced evaluated type to be stored. Moving `check_return_expr` before this - // causes unsized errors caused by the `declared_ret_ty` to point at the return expression, - // while keeping the current ordering we will ignore the tail expression's type because we - // don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr` - // because we will trigger "unreachable expression" lints unconditionally. - // Because of all of this, we perform a crude check to know whether the simplest `!Sized` - // case that a newcomer might make, returning a bare trait, and in that case we populate - // the tail expression's type so that the suggestion will be correct, but ignore all other - // possible cases. - fcx.check_expr(&body.value); - fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); - tcx.sess.delay_span_bug(decl.output.span(), "`!Sized` return type"); - } else { - fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); - fcx.check_return_expr(&body.value); - } - fcx.in_tail_expr = false; - - // We insert the deferred_generator_interiors entry after visiting the body. - // This ensures that all nested generators appear before the entry of this generator. - // resolve_generator_interiors relies on this property. - let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) { - let interior = fcx - .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span }); - fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind)); - - let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap(); - Some(GeneratorTypes { - resume_ty, - yield_ty, - interior, - movability: can_be_generator.unwrap(), - }) - } else { - None - }; - - // Finalize the return check by taking the LUB of the return types - // we saw and assigning it to the expected return type. This isn't - // really expected to fail, since the coercions would have failed - // earlier when trying to find a LUB. - // - // However, the behavior around `!` is sort of complex. In the - // event that the `actual_return_ty` comes back as `!`, that - // indicates that the fn either does not return or "returns" only - // values of type `!`. In this case, if there is an expected - // return type that is *not* `!`, that should be ok. But if the - // return type is being inferred, we want to "fallback" to `!`: - // - // let x = move || panic!(); - // - // To allow for that, I am creating a type variable with diverging - // fallback. This was deemed ever so slightly better than unifying - // the return value with `!` because it allows for the caller to - // make more assumptions about the return type (e.g., they could do - // - // let y: Option = Some(x()); - // - // which would then cause this return type to become `u32`, not - // `!`). - let coercion = fcx.ret_coercion.take().unwrap().into_inner(); - let mut actual_return_ty = coercion.complete(&fcx); - if actual_return_ty.is_never() { - actual_return_ty = fcx.next_diverging_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::DivergingFn, - span, - }); - } - fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty); - - // Check that the main return type implements the termination trait. - if let Some(term_id) = tcx.lang_items().termination() { - if let Some((def_id, EntryFnType::Main)) = tcx.entry_fn(LOCAL_CRATE) { - let main_id = hir.local_def_id_to_hir_id(def_id); - if main_id == fn_id { - let substs = tcx.mk_substs_trait(declared_ret_ty, &[]); - let trait_ref = ty::TraitRef::new(term_id, substs); - let return_ty_span = decl.output.span(); - let cause = traits::ObligationCause::new( - return_ty_span, - fn_id, - ObligationCauseCode::MainFunctionType, - ); - - inherited.register_predicate(traits::Obligation::new( - cause, - param_env, - trait_ref.without_const().to_predicate(tcx), - )); - } - } - } - - // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !` - if let Some(panic_impl_did) = tcx.lang_items().panic_impl() { - if panic_impl_did == hir.local_def_id(fn_id).to_def_id() { - if let Some(panic_info_did) = tcx.lang_items().panic_info() { - if *declared_ret_ty.kind() != ty::Never { - sess.span_err(decl.output.span(), "return type should be `!`"); - } - - let inputs = fn_sig.inputs(); - let span = hir.span(fn_id); - if inputs.len() == 1 { - let arg_is_panic_info = match *inputs[0].kind() { - ty::Ref(region, ty, mutbl) => match *ty.kind() { - ty::Adt(ref adt, _) => { - adt.did == panic_info_did - && mutbl == hir::Mutability::Not - && *region != RegionKind::ReStatic - } - _ => false, - }, - _ => false, - }; - - if !arg_is_panic_info { - sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`"); - } - - if let Node::Item(item) = hir.get(fn_id) { - if let ItemKind::Fn(_, ref generics, _) = item.kind { - if !generics.params.is_empty() { - sess.span_err(span, "should have no type parameters"); - } - } - } - } else { - let span = sess.source_map().guess_head_span(span); - sess.span_err(span, "function should have one argument"); - } - } else { - sess.err("language item required, but not found: `panic_info`"); - } - } - } - - // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !` - if let Some(alloc_error_handler_did) = tcx.lang_items().oom() { - if alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id() { - if let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() { - if *declared_ret_ty.kind() != ty::Never { - sess.span_err(decl.output.span(), "return type should be `!`"); - } - - let inputs = fn_sig.inputs(); - let span = hir.span(fn_id); - if inputs.len() == 1 { - let arg_is_alloc_layout = match inputs[0].kind() { - ty::Adt(ref adt, _) => adt.did == alloc_layout_did, - _ => false, - }; - - if !arg_is_alloc_layout { - sess.span_err(decl.inputs[0].span, "argument should be `Layout`"); - } - - if let Node::Item(item) = hir.get(fn_id) { - if let ItemKind::Fn(_, ref generics, _) = item.kind { - if !generics.params.is_empty() { - sess.span_err( - span, - "`#[alloc_error_handler]` function should have no type \ - parameters", - ); - } - } - } - } else { - let span = sess.source_map().guess_head_span(span); - sess.span_err(span, "function should have one argument"); - } - } else { - sess.err("language item required, but not found: `alloc_layout`"); - } - } - } - - (fcx, gen_ty) -} - -fn check_struct(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) { - let def_id = tcx.hir().local_def_id(id); - let def = tcx.adt_def(def_id); - def.destructor(tcx); // force the destructor to be evaluated - check_representable(tcx, span, def_id); - - if def.repr.simd() { - check_simd(tcx, span, def_id); - } - - check_transparent(tcx, span, def); - check_packed(tcx, span, def); -} - -fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) { - let def_id = tcx.hir().local_def_id(id); - let def = tcx.adt_def(def_id); - def.destructor(tcx); // force the destructor to be evaluated - check_representable(tcx, span, def_id); - check_transparent(tcx, span, def); - check_union_fields(tcx, span, def_id); - check_packed(tcx, span, def); -} - -/// When the `#![feature(untagged_unions)]` gate is active, -/// check that the fields of the `union` does not contain fields that need dropping. -fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool { - let item_type = tcx.type_of(item_def_id); - if let ty::Adt(def, substs) = item_type.kind() { - assert!(def.is_union()); - let fields = &def.non_enum_variant().fields; - let param_env = tcx.param_env(item_def_id); - for field in fields { - let field_ty = field.ty(tcx, substs); - // We are currently checking the type this field came from, so it must be local. - let field_span = tcx.hir().span_if_local(field.did).unwrap(); - if field_ty.needs_drop(tcx, param_env) { - struct_span_err!( - tcx.sess, - field_span, - E0740, - "unions may not contain fields that need dropping" - ) - .span_note(field_span, "`std::mem::ManuallyDrop` can be used to wrap the type") - .emit(); - return false; - } - } - } else { - span_bug!(span, "unions must be ty::Adt, but got {:?}", item_type.kind()); - } - true -} - -/// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo` -/// projections that would result in "inheriting lifetimes". -fn check_opaque<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: LocalDefId, - substs: SubstsRef<'tcx>, - span: Span, - origin: &hir::OpaqueTyOrigin, -) { - check_opaque_for_inheriting_lifetimes(tcx, def_id, span); - check_opaque_for_cycles(tcx, def_id, substs, span, origin); -} - -/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result -/// in "inheriting lifetimes". -fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) { - let item = tcx.hir().expect_item(tcx.hir().local_def_id_to_hir_id(def_id)); - debug!( - "check_opaque_for_inheriting_lifetimes: def_id={:?} span={:?} item={:?}", - def_id, span, item - ); - - #[derive(Debug)] - struct ProhibitOpaqueVisitor<'tcx> { - opaque_identity_ty: Ty<'tcx>, - generics: &'tcx ty::Generics, - ty: Option>, - }; - - impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t); - if t != self.opaque_identity_ty && t.super_visit_with(self) { - self.ty = Some(t); - return true; - } - false - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { - debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r); - if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r { - return *index < self.generics.parent_count as u32; - } - - r.super_visit_with(self) - } - - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { - if let ty::ConstKind::Unevaluated(..) = c.val { - // FIXME(#72219) We currenctly don't detect lifetimes within substs - // which would violate this check. Even though the particular substitution is not used - // within the const, this should still be fixed. - return false; - } - c.super_visit_with(self) - } - } - - if let ItemKind::OpaqueTy(hir::OpaqueTy { - origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn, - .. - }) = item.kind - { - let mut visitor = ProhibitOpaqueVisitor { - opaque_identity_ty: tcx.mk_opaque( - def_id.to_def_id(), - InternalSubsts::identity_for_item(tcx, def_id.to_def_id()), - ), - generics: tcx.generics_of(def_id), - ty: None, - }; - let prohibit_opaque = tcx - .predicates_of(def_id) - .predicates - .iter() - .any(|(predicate, _)| predicate.visit_with(&mut visitor)); - debug!( - "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}", - prohibit_opaque, visitor - ); - - if prohibit_opaque { - let is_async = match item.kind { - ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin { - hir::OpaqueTyOrigin::AsyncFn => true, - _ => false, - }, - _ => unreachable!(), - }; - - let mut err = struct_span_err!( - tcx.sess, - span, - E0760, - "`{}` return type cannot contain a projection or `Self` that references lifetimes from \ - a parent scope", - if is_async { "async fn" } else { "impl Trait" }, - ); - - if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) { - if snippet == "Self" { - if let Some(ty) = visitor.ty { - err.span_suggestion( - span, - "consider spelling out the type instead", - format!("{:?}", ty), - Applicability::MaybeIncorrect, - ); - } - } - } - err.emit(); - } - } -} - /// Given a `DefId` for an opaque type in return position, find its parent item's return /// expressions. fn get_owner_return_paths( @@ -1135,86 +663,6 @@ fn get_owner_return_paths( }) } -/// Emit an error for recursive opaque types. -/// -/// If this is a return `impl Trait`, find the item's return expressions and point at them. For -/// direct recursion this is enough, but for indirect recursion also point at the last intermediary -/// `impl Trait`. -/// -/// If all the return expressions evaluate to `!`, then we explain that the error will go away -/// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder. -fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) { - let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type"); - - let mut label = false; - if let Some((hir_id, visitor)) = get_owner_return_paths(tcx, def_id) { - let typeck_results = tcx.typeck(tcx.hir().local_def_id(hir_id)); - if visitor - .returns - .iter() - .filter_map(|expr| typeck_results.node_type_opt(expr.hir_id)) - .all(|ty| matches!(ty.kind(), ty::Never)) - { - let spans = visitor - .returns - .iter() - .filter(|expr| typeck_results.node_type_opt(expr.hir_id).is_some()) - .map(|expr| expr.span) - .collect::>(); - let span_len = spans.len(); - if span_len == 1 { - err.span_label(spans[0], "this returned value is of `!` type"); - } else { - let mut multispan: MultiSpan = spans.clone().into(); - for span in spans { - multispan - .push_span_label(span, "this returned value is of `!` type".to_string()); - } - err.span_note(multispan, "these returned values have a concrete \"never\" type"); - } - err.help("this error will resolve once the item's body returns a concrete type"); - } else { - let mut seen = FxHashSet::default(); - seen.insert(span); - err.span_label(span, "recursive opaque type"); - label = true; - for (sp, ty) in visitor - .returns - .iter() - .filter_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t))) - .filter(|(_, ty)| !matches!(ty.kind(), ty::Never)) - { - struct VisitTypes(Vec); - impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes { - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - match *t.kind() { - ty::Opaque(def, _) => { - self.0.push(def); - false - } - _ => t.super_visit_with(self), - } - } - } - let mut visitor = VisitTypes(vec![]); - ty.visit_with(&mut visitor); - for def_id in visitor.0 { - let ty_span = tcx.def_span(def_id); - if !seen.contains(&ty_span) { - err.span_label(ty_span, &format!("returning this opaque type `{}`", ty)); - seen.insert(ty_span); - } - err.span_label(sp, &format!("returning here with type `{}`", ty)); - } - } - } - } - if !label { - err.span_label(span, "cannot resolve opaque type"); - } - err.emit(); -} - /// Emit an error for recursive opaque types in a `let` binding. fn binding_opaque_type_cycle_error( tcx: TyCtxt<'tcx>, @@ -1275,33 +723,6 @@ fn binding_opaque_type_cycle_error( err.emit(); } -fn async_opaque_type_cycle_error(tcx: TyCtxt<'tcx>, span: Span) { - struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing") - .span_label(span, "recursive `async fn`") - .note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`") - .emit(); -} - -/// Checks that an opaque type does not contain cycles. -fn check_opaque_for_cycles<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: LocalDefId, - substs: SubstsRef<'tcx>, - span: Span, - origin: &hir::OpaqueTyOrigin, -) { - if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id.to_def_id(), substs) - { - match origin { - hir::OpaqueTyOrigin::AsyncFn => async_opaque_type_cycle_error(tcx, span), - hir::OpaqueTyOrigin::Binding => { - binding_opaque_type_cycle_error(tcx, def_id, span, partially_expanded_type) - } - _ => opaque_type_cycle_error(tcx, def_id, span), - } - } -} - // Forbid defining intrinsics in Rust code, // as they must always be defined by the compiler. fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) { @@ -1310,126 +731,6 @@ fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) { } } -pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) { - debug!( - "check_item_type(it.hir_id={}, it.name={})", - it.hir_id, - tcx.def_path_str(tcx.hir().local_def_id(it.hir_id).to_def_id()) - ); - let _indenter = indenter(); - match it.kind { - // Consts can play a role in type-checking, so they are included here. - hir::ItemKind::Static(..) => { - let def_id = tcx.hir().local_def_id(it.hir_id); - tcx.ensure().typeck(def_id); - maybe_check_static_with_link_section(tcx, def_id, it.span); - } - hir::ItemKind::Const(..) => { - tcx.ensure().typeck(tcx.hir().local_def_id(it.hir_id)); - } - hir::ItemKind::Enum(ref enum_definition, _) => { - check_enum(tcx, it.span, &enum_definition.variants, it.hir_id); - } - hir::ItemKind::Fn(..) => {} // entirely within check_item_body - hir::ItemKind::Impl { ref items, .. } => { - debug!("ItemKind::Impl {} with id {}", it.ident, it.hir_id); - let impl_def_id = tcx.hir().local_def_id(it.hir_id); - if let Some(impl_trait_ref) = tcx.impl_trait_ref(impl_def_id) { - check_impl_items_against_trait(tcx, it.span, impl_def_id, impl_trait_ref, items); - let trait_def_id = impl_trait_ref.def_id; - check_on_unimplemented(tcx, trait_def_id, it); - } - } - hir::ItemKind::Trait(_, _, _, _, ref items) => { - let def_id = tcx.hir().local_def_id(it.hir_id); - check_on_unimplemented(tcx, def_id.to_def_id(), it); - - for item in items.iter() { - let item = tcx.hir().trait_item(item.id); - if let hir::TraitItemKind::Fn(sig, _) = &item.kind { - let abi = sig.header.abi; - fn_maybe_err(tcx, item.ident.span, abi); - } - } - } - hir::ItemKind::Struct(..) => { - check_struct(tcx, it.hir_id, it.span); - } - hir::ItemKind::Union(..) => { - check_union(tcx, it.hir_id, it.span); - } - hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => { - // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting - // `async-std` (and `pub async fn` in general). - // Since rustdoc doesn't care about the concrete type behind `impl Trait`, just don't look at it! - // See https://github.com/rust-lang/rust/issues/75100 - if !tcx.sess.opts.actually_rustdoc { - let def_id = tcx.hir().local_def_id(it.hir_id); - - let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); - check_opaque(tcx, def_id, substs, it.span, &origin); - } - } - hir::ItemKind::TyAlias(..) => { - let def_id = tcx.hir().local_def_id(it.hir_id); - let pty_ty = tcx.type_of(def_id); - 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); - - if m.abi == Abi::RustIntrinsic { - for item in m.items { - intrinsic::check_intrinsic_type(tcx, item); - } - } else if m.abi == Abi::PlatformIntrinsic { - for item in m.items { - intrinsic::check_platform_intrinsic_type(tcx, item); - } - } else { - for item in m.items { - let generics = tcx.generics_of(tcx.hir().local_def_id(item.hir_id)); - let own_counts = generics.own_counts(); - if generics.params.len() - own_counts.lifetimes != 0 { - let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts) { - (_, 0) => ("type", "types", Some("u32")), - // We don't specify an example value, because we can't generate - // a valid value for any type. - (0, _) => ("const", "consts", None), - _ => ("type or const", "types or consts", None), - }; - struct_span_err!( - tcx.sess, - item.span, - E0044, - "foreign items may not have {} parameters", - kinds, - ) - .span_label(item.span, &format!("can't have {} parameters", kinds)) - .help( - // FIXME: once we start storing spans for type arguments, turn this - // into a suggestion. - &format!( - "replace the {} parameters with concrete {}{}", - kinds, - kinds_pl, - egs.map(|egs| format!(" like `{}`", egs)).unwrap_or_default(), - ), - ) - .emit(); - } - - if let hir::ForeignItemKind::Fn(ref fn_decl, _, _) = item.kind { - require_c_abi_if_c_variadic(tcx, fn_decl, m.abi, item.span); - } - } - } - } - _ => { /* nothing to do */ } - } -} - fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: Span) { // Only restricted on wasm32 target for now if !tcx.sess.opts.target_triple.triple().starts_with("wasm32") { @@ -1463,12 +764,6 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: S } } -fn check_on_unimplemented(tcx: TyCtxt<'_>, trait_def_id: DefId, item: &hir::Item<'_>) { - let item_def_id = tcx.hir().local_def_id(item.hir_id); - // an error would be reported if this fails. - let _ = traits::OnUnimplementedDirective::of_item(tcx, trait_def_id, item_def_id.to_def_id()); -} - fn report_forbidden_specialization( tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>, @@ -1500,248 +795,6 @@ fn report_forbidden_specialization( err.emit(); } -fn check_specialization_validity<'tcx>( - tcx: TyCtxt<'tcx>, - trait_def: &ty::TraitDef, - trait_item: &ty::AssocItem, - impl_id: DefId, - impl_item: &hir::ImplItem<'_>, -) { - let kind = match impl_item.kind { - hir::ImplItemKind::Const(..) => ty::AssocKind::Const, - hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn, - hir::ImplItemKind::TyAlias(_) => ty::AssocKind::Type, - }; - - let ancestors = match trait_def.ancestors(tcx, impl_id) { - Ok(ancestors) => ancestors, - Err(_) => return, - }; - let mut ancestor_impls = ancestors - .skip(1) - .filter_map(|parent| { - if parent.is_from_trait() { - None - } else { - Some((parent, parent.item(tcx, trait_item.ident, kind, trait_def.def_id))) - } - }) - .peekable(); - - if ancestor_impls.peek().is_none() { - // No parent, nothing to specialize. - return; - } - - let opt_result = ancestor_impls.find_map(|(parent_impl, parent_item)| { - match parent_item { - // Parent impl exists, and contains the parent item we're trying to specialize, but - // doesn't mark it `default`. - Some(parent_item) if traits::impl_item_is_final(tcx, &parent_item) => { - Some(Err(parent_impl.def_id())) - } - - // Parent impl contains item and makes it specializable. - Some(_) => Some(Ok(())), - - // Parent impl doesn't mention the item. This means it's inherited from the - // grandparent. In that case, if parent is a `default impl`, inherited items use the - // "defaultness" from the grandparent, else they are final. - None => { - if tcx.impl_defaultness(parent_impl.def_id()).is_default() { - None - } else { - Some(Err(parent_impl.def_id())) - } - } - } - }); - - // If `opt_result` is `None`, we have only encountered `default impl`s that don't contain the - // item. This is allowed, the item isn't actually getting specialized here. - let result = opt_result.unwrap_or(Ok(())); - - if let Err(parent_impl) = result { - report_forbidden_specialization(tcx, impl_item, parent_impl); - } -} - -fn check_impl_items_against_trait<'tcx>( - tcx: TyCtxt<'tcx>, - full_impl_span: Span, - impl_id: LocalDefId, - impl_trait_ref: ty::TraitRef<'tcx>, - impl_item_refs: &[hir::ImplItemRef<'_>], -) { - let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span); - - // If the trait reference itself is erroneous (so the compilation is going - // to fail), skip checking the items here -- the `impl_item` table in `tcx` - // isn't populated for such impls. - if impl_trait_ref.references_error() { - return; - } - - // Negative impls are not expected to have any items - match tcx.impl_polarity(impl_id) { - ty::ImplPolarity::Reservation | ty::ImplPolarity::Positive => {} - ty::ImplPolarity::Negative => { - if let [first_item_ref, ..] = impl_item_refs { - let first_item_span = tcx.hir().impl_item(first_item_ref.id).span; - struct_span_err!( - tcx.sess, - first_item_span, - E0749, - "negative impls cannot have any items" - ) - .emit(); - } - return; - } - } - - // Locate trait definition and items - let trait_def = tcx.trait_def(impl_trait_ref.def_id); - - let impl_items = || impl_item_refs.iter().map(|iiref| tcx.hir().impl_item(iiref.id)); - - // Check existing impl methods to see if they are both present in trait - // and compatible with trait signature - for impl_item in impl_items() { - let namespace = impl_item.kind.namespace(); - let ty_impl_item = tcx.associated_item(tcx.hir().local_def_id(impl_item.hir_id)); - let ty_trait_item = tcx - .associated_items(impl_trait_ref.def_id) - .find_by_name_and_namespace(tcx, ty_impl_item.ident, namespace, impl_trait_ref.def_id) - .or_else(|| { - // Not compatible, but needed for the error message - tcx.associated_items(impl_trait_ref.def_id) - .filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id) - .next() - }); - - // Check that impl definition matches trait definition - if let Some(ty_trait_item) = ty_trait_item { - match impl_item.kind { - hir::ImplItemKind::Const(..) => { - // Find associated const definition. - if ty_trait_item.kind == ty::AssocKind::Const { - compare_const_impl( - tcx, - &ty_impl_item, - impl_item.span, - &ty_trait_item, - impl_trait_ref, - ); - } else { - let mut err = struct_span_err!( - tcx.sess, - impl_item.span, - E0323, - "item `{}` is an associated const, \ - which doesn't match its trait `{}`", - ty_impl_item.ident, - impl_trait_ref.print_only_trait_path() - ); - err.span_label(impl_item.span, "does not match trait"); - // We can only get the spans from local trait definition - // Same for E0324 and E0325 - if let Some(trait_span) = tcx.hir().span_if_local(ty_trait_item.def_id) { - err.span_label(trait_span, "item in trait"); - } - err.emit() - } - } - hir::ImplItemKind::Fn(..) => { - let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id); - if ty_trait_item.kind == ty::AssocKind::Fn { - compare_impl_method( - tcx, - &ty_impl_item, - impl_item.span, - &ty_trait_item, - impl_trait_ref, - opt_trait_span, - ); - } else { - let mut err = struct_span_err!( - tcx.sess, - impl_item.span, - E0324, - "item `{}` is an associated method, \ - which doesn't match its trait `{}`", - ty_impl_item.ident, - impl_trait_ref.print_only_trait_path() - ); - err.span_label(impl_item.span, "does not match trait"); - if let Some(trait_span) = opt_trait_span { - err.span_label(trait_span, "item in trait"); - } - err.emit() - } - } - hir::ImplItemKind::TyAlias(_) => { - let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id); - if ty_trait_item.kind == ty::AssocKind::Type { - compare_ty_impl( - tcx, - &ty_impl_item, - impl_item.span, - &ty_trait_item, - impl_trait_ref, - opt_trait_span, - ); - } else { - let mut err = struct_span_err!( - tcx.sess, - impl_item.span, - E0325, - "item `{}` is an associated type, \ - which doesn't match its trait `{}`", - ty_impl_item.ident, - impl_trait_ref.print_only_trait_path() - ); - err.span_label(impl_item.span, "does not match trait"); - if let Some(trait_span) = opt_trait_span { - err.span_label(trait_span, "item in trait"); - } - err.emit() - } - } - } - - check_specialization_validity( - tcx, - trait_def, - &ty_trait_item, - impl_id.to_def_id(), - impl_item, - ); - } - } - - // Check for missing items from trait - let mut missing_items = Vec::new(); - if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) { - for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() { - let is_implemented = ancestors - .leaf_def(tcx, trait_item.ident, trait_item.kind) - .map(|node_item| !node_item.defining_node.is_from_trait()) - .unwrap_or(false); - - if !is_implemented && tcx.impl_defaultness(impl_id).is_final() { - if !trait_item.defaultness.has_value() { - missing_items.push(*trait_item); - } - } - } - } - - if !missing_items.is_empty() { - missing_items_err(tcx, impl_span, &missing_items, full_impl_span); - } -} - fn missing_items_err( tcx: TyCtxt<'_>, impl_span: Span, @@ -1941,161 +994,6 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String { } } -/// Checks whether a type can be represented in memory. In particular, it -/// identifies types that contain themselves without indirection through a -/// pointer, which would mean their size is unbounded. -fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: LocalDefId) -> bool { - let rty = tcx.type_of(item_def_id); - - // Check that it is possible to represent this type. This call identifies - // (1) types that contain themselves and (2) types that contain a different - // recursive type. It is only necessary to throw an error on those that - // contain themselves. For case 2, there must be an inner type that will be - // caught by case 1. - match rty.is_representable(tcx, sp) { - Representability::SelfRecursive(spans) => { - recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id(), spans); - return false; - } - Representability::Representable | Representability::ContainsRecursive => (), - } - true -} - -pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { - let t = tcx.type_of(def_id); - if let ty::Adt(def, substs) = t.kind() { - if def.is_struct() { - let fields = &def.non_enum_variant().fields; - if fields.is_empty() { - struct_span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty").emit(); - return; - } - let e = fields[0].ty(tcx, substs); - if !fields.iter().all(|f| f.ty(tcx, substs) == e) { - struct_span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous") - .span_label(sp, "SIMD elements must have the same type") - .emit(); - return; - } - match e.kind() { - ty::Param(_) => { /* struct(T, T, T, T) is ok */ } - _ if e.is_machine() => { /* struct(u8, u8, u8, u8) is ok */ } - _ => { - struct_span_err!( - tcx.sess, - sp, - E0077, - "SIMD vector element type should be machine type" - ) - .emit(); - return; - } - } - } - } -} - -fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: &ty::AdtDef) { - let repr = def.repr; - if repr.packed() { - for attr in tcx.get_attrs(def.did).iter() { - for r in attr::find_repr_attrs(&tcx.sess, attr) { - if let attr::ReprPacked(pack) = r { - if let Some(repr_pack) = repr.pack { - if pack as u64 != repr_pack.bytes() { - struct_span_err!( - tcx.sess, - sp, - E0634, - "type has conflicting packed representation hints" - ) - .emit(); - } - } - } - } - } - if repr.align.is_some() { - struct_span_err!( - tcx.sess, - sp, - E0587, - "type has conflicting packed and align representation hints" - ) - .emit(); - } else { - if let Some(def_spans) = check_packed_inner(tcx, def.did, &mut vec![]) { - let mut err = struct_span_err!( - tcx.sess, - sp, - E0588, - "packed type cannot transitively contain a `#[repr(align)]` type" - ); - - err.span_note( - tcx.def_span(def_spans[0].0), - &format!( - "`{}` has a `#[repr(align)]` attribute", - tcx.item_name(def_spans[0].0) - ), - ); - - if def_spans.len() > 2 { - let mut first = true; - for (adt_def, span) in def_spans.iter().skip(1).rev() { - let ident = tcx.item_name(*adt_def); - err.span_note( - *span, - &if first { - format!( - "`{}` contains a field of type `{}`", - tcx.type_of(def.did), - ident - ) - } else { - format!("...which contains a field of type `{}`", ident) - }, - ); - first = false; - } - } - - err.emit(); - } - } - } -} - -fn check_packed_inner( - tcx: TyCtxt<'_>, - def_id: DefId, - stack: &mut Vec, -) -> Option> { - if let ty::Adt(def, substs) = tcx.type_of(def_id).kind() { - if def.is_struct() || def.is_union() { - if def.repr.align.is_some() { - return Some(vec![(def.did, DUMMY_SP)]); - } - - stack.push(def_id); - for field in &def.non_enum_variant().fields { - if let ty::Adt(def, _) = field.ty(tcx, substs).kind() { - if !stack.contains(&def.did) { - if let Some(mut defs) = check_packed_inner(tcx, def.did, stack) { - defs.push((def.did, field.ident.span)); - return Some(defs); - } - } - } - } - stack.pop(); - } - } - - None -} - /// Emit an error when encountering more or less than one variant in a transparent enum. fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: &'tcx ty::AdtDef, sp: Span, did: DefId) { let variant_spans: Vec<_> = adt @@ -2141,158 +1039,6 @@ fn bad_non_zero_sized_fields<'tcx>( err.emit(); } -fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: &'tcx ty::AdtDef) { - if !adt.repr.transparent() { - return; - } - let sp = tcx.sess.source_map().guess_head_span(sp); - - if adt.is_union() && !tcx.features().transparent_unions { - feature_err( - &tcx.sess.parse_sess, - sym::transparent_unions, - sp, - "transparent unions are unstable", - ) - .emit(); - } - - if adt.variants.len() != 1 { - bad_variant_count(tcx, adt, sp, adt.did); - if adt.variants.is_empty() { - // Don't bother checking the fields. No variants (and thus no fields) exist. - return; - } - } - - // For each field, figure out if it's known to be a ZST and align(1) - let field_infos = adt.all_fields().map(|field| { - let ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, field.did)); - let param_env = tcx.param_env(field.did); - let layout = tcx.layout_of(param_env.and(ty)); - // We are currently checking the type this field came from, so it must be local - let span = tcx.hir().span_if_local(field.did).unwrap(); - let zst = layout.map(|layout| layout.is_zst()).unwrap_or(false); - let align1 = layout.map(|layout| layout.align.abi.bytes() == 1).unwrap_or(false); - (span, zst, align1) - }); - - let non_zst_fields = - field_infos.clone().filter_map(|(span, zst, _align1)| if !zst { Some(span) } else { None }); - let non_zst_count = non_zst_fields.clone().count(); - if non_zst_count != 1 { - bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp); - } - for (span, zst, align1) in field_infos { - if zst && !align1 { - struct_span_err!( - tcx.sess, - span, - E0691, - "zero-sized field in transparent {} has alignment larger than 1", - adt.descr(), - ) - .span_label(span, "has alignment larger than 1") - .emit(); - } - } -} - -#[allow(trivial_numeric_casts)] -pub fn check_enum<'tcx>( - tcx: TyCtxt<'tcx>, - sp: Span, - vs: &'tcx [hir::Variant<'tcx>], - id: hir::HirId, -) { - let def_id = tcx.hir().local_def_id(id); - let def = tcx.adt_def(def_id); - def.destructor(tcx); // force the destructor to be evaluated - - if vs.is_empty() { - let attributes = tcx.get_attrs(def_id.to_def_id()); - if let Some(attr) = tcx.sess.find_by_name(&attributes, sym::repr) { - struct_span_err!( - tcx.sess, - attr.span, - E0084, - "unsupported representation for zero-variant enum" - ) - .span_label(sp, "zero-variant enum") - .emit(); - } - } - - let repr_type_ty = def.repr.discr_type().to_ty(tcx); - if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 { - if !tcx.features().repr128 { - feature_err( - &tcx.sess.parse_sess, - sym::repr128, - sp, - "repr with 128-bit type is unstable", - ) - .emit(); - } - } - - for v in vs { - if let Some(ref e) = v.disr_expr { - tcx.ensure().typeck(tcx.hir().local_def_id(e.hir_id)); - } - } - - 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 has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some(); - let has_non_units = vs.iter().any(|var| !is_unit(var)); - let disr_units = vs.iter().any(|var| is_unit(&var) && has_disr(&var)); - let disr_non_unit = vs.iter().any(|var| !is_unit(&var) && has_disr(&var)); - - if disr_non_unit || (disr_units && has_non_units) { - let mut err = - struct_span_err!(tcx.sess, sp, E0732, "`#[repr(inttype)]` must be specified"); - err.emit(); - } - } - - let mut disr_vals: Vec> = Vec::with_capacity(vs.len()); - for ((_, discr), v) in def.discriminants(tcx).zip(vs) { - // Check for duplicate discriminant values - if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) { - let variant_did = def.variants[VariantIdx::new(i)].def_id; - let variant_i_hir_id = tcx.hir().local_def_id_to_hir_id(variant_did.expect_local()); - let variant_i = tcx.hir().expect_variant(variant_i_hir_id); - let i_span = match variant_i.disr_expr { - Some(ref expr) => tcx.hir().span(expr.hir_id), - None => tcx.hir().span(variant_i_hir_id), - }; - let span = match v.disr_expr { - Some(ref expr) => tcx.hir().span(expr.hir_id), - None => v.span, - }; - struct_span_err!( - tcx.sess, - span, - E0081, - "discriminant value `{}` already exists", - disr_vals[i] - ) - .span_label(i_span, format!("first use of `{}`", disr_vals[i])) - .span_label(span, format!("enum already has `{}`", disr_vals[i])) - .emit(); - } - disr_vals.push(discr); - } - - check_representable(tcx, sp, def_id); - check_transparent(tcx, sp, def); -} - fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, span: Span) { struct_span_err!( tcx.sess, @@ -2337,51 +1083,6 @@ enum FallbackMode { All, } -fn check_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, generics: &ty::Generics, ty: Ty<'tcx>) { - debug!("check_type_params_are_used(generics={:?}, ty={:?})", generics, ty); - - assert_eq!(generics.parent, None); - - if generics.own_counts().types == 0 { - return; - } - - let mut params_used = BitSet::new_empty(generics.params.len()); - - if ty.references_error() { - // If there is already another error, do not emit - // an error for not using a type parameter. - assert!(tcx.sess.has_errors()); - return; - } - - for leaf in ty.walk() { - if let GenericArgKind::Type(leaf_ty) = leaf.unpack() { - if let ty::Param(param) = leaf_ty.kind() { - debug!("found use of ty param {:?}", param); - params_used.insert(param.index); - } - } - } - - for param in &generics.params { - if !params_used.contains(param.index) { - if let ty::GenericParamDefKind::Type { .. } = param.kind { - let span = tcx.def_span(param.def_id); - struct_span_err!( - tcx.sess, - span, - E0091, - "type parameter `{}` is unused", - param.name, - ) - .span_label(span, "unused type parameter") - .emit(); - } - } - } -} - /// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field. #[derive(Copy, Clone)] struct MaybeInProgressTables<'a, 'tcx> { @@ -2420,22 +1121,6 @@ impl ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'tcx> { fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {} } -fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { - tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx }); -} - -fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { - wfcheck::check_item_well_formed(tcx, def_id); -} - -fn check_trait_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { - wfcheck::check_trait_item(tcx, def_id); -} - -fn check_impl_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { - wfcheck::check_impl_item(tcx, def_id); -} - fn typeck_item_bodies(tcx: TyCtxt<'_>, crate_num: CrateNum) { debug_assert!(crate_num == LOCAL_CRATE); tcx.par_body_owners(|body_owner_def_id| { From 16047d46a10813a25e956e659b8861cc67c20cd2 Mon Sep 17 00:00:00 2001 From: yuk1ty Date: Mon, 21 Sep 2020 12:14:28 +0900 Subject: [PATCH 0764/1052] fix typo in docs and comments --- compiler/rustc_lint/src/types.rs | 2 +- compiler/rustc_middle/src/mir/predecessors.rs | 2 +- compiler/rustc_mir/src/borrow_check/member_constraints.rs | 2 +- compiler/rustc_mir_build/src/build/matches/mod.rs | 2 +- compiler/rustc_parse/src/parser/ty.rs | 2 +- compiler/rustc_span/src/symbol.rs | 2 +- compiler/rustc_target/src/spec/wasm32_wasi.rs | 2 +- compiler/rustc_typeck/src/check/mod.rs | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index ccbe9f80e25b7..6aa28d04ae197 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -733,7 +733,7 @@ fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option MemberConstraintSet<'tcx, ty::RegionVid> { /// Pushes a member constraint into the set. /// /// The input member constraint `m_c` is in the form produced by - /// the the `rustc_middle::infer` code. + /// the `rustc_middle::infer` code. /// /// The `to_region_vid` callback fn is used to convert the regions /// within into `RegionVid` format -- it typically consults the diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 6e9d5eedf051f..a9b8a6181d499 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -321,7 +321,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let target_block = self.cfg.start_new_block(); let mut schedule_drops = true; // We keep a stack of all of the bindings and type asciptions - // from the the parent candidates that we visit, that also need to + // from the parent candidates that we visit, that also need to // be bound for each candidate. traverse_candidate( candidate, diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index fc4c62ccbd90e..d42a786a18fe9 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -67,7 +67,7 @@ impl<'a> Parser<'a> { /// Parse a type suitable for a function or function pointer parameter. /// The difference from `parse_ty` is that this version allows `...` - /// (`CVarArgs`) at the top level of the the type. + /// (`CVarArgs`) at the top level of the type. pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, P> { self.parse_ty_common(AllowPlus::Yes, RecoverQPath::Yes, AllowCVariadic::Yes) } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 6085eedf23694..65a26284186bd 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -110,7 +110,7 @@ symbols! { // called `sym::proc_macro` because then it's easy to mistakenly think it // represents "proc_macro". // - // As well as the symbols listed, there are symbols for the the strings + // As well as the symbols listed, there are symbols for the strings // "0", "1", ..., "9", which are accessible via `sym::integer`. // // The proc macro will abort if symbols are not in alphabetical order (as diff --git a/compiler/rustc_target/src/spec/wasm32_wasi.rs b/compiler/rustc_target/src/spec/wasm32_wasi.rs index 0bba7bdd4735c..351167105ec7a 100644 --- a/compiler/rustc_target/src/spec/wasm32_wasi.rs +++ b/compiler/rustc_target/src/spec/wasm32_wasi.rs @@ -30,7 +30,7 @@ //! ## No interop with C required //! //! By default the `crt-static` target feature is enabled, and when enabled -//! this means that the the bundled version of `libc.a` found in `liblibc.rlib` +//! this means that the bundled version of `libc.a` found in `liblibc.rlib` //! is used. This isn't intended really for interoperation with a C because it //! may be the case that Rust's bundled C library is incompatible with a //! foreign-compiled C library. In this use case, though, we use `rust-lld` and diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index e84cc3c9b8684..b85ffb535ff9d 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -1843,7 +1843,7 @@ fn binding_opaque_type_cycle_error( ) { let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type"); err.span_label(span, "cannot resolve opaque type"); - // Find the the owner that declared this `impl Trait` type. + // Find the owner that declared this `impl Trait` type. let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let mut prev_hir_id = hir_id; let mut hir_id = tcx.hir().get_parent_node(hir_id); From fc20b7841ccd0efed87ec063b63e35d35fde3544 Mon Sep 17 00:00:00 2001 From: LingMan Date: Mon, 21 Sep 2020 05:43:39 +0200 Subject: [PATCH 0765/1052] Fix typo in rustc_lexer docs Also add an Oxford comma while we're editing that line. --- compiler/rustc_lexer/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 44999bbe85713..d784a86f14cee 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -2,7 +2,7 @@ //! //! The idea with `librustc_lexer` is to make a reusable library, //! by separating out pure lexing and rustc-specific concerns, like spans, -//! error reporting an interning. So, rustc_lexer operates directly on `&str`, +//! error reporting, and interning. So, rustc_lexer operates directly on `&str`, //! produces simple tokens which are a pair of type-tag and a bit of original text, //! and does not report errors, instead storing them as flags on the token. //! From 88a29e630c1ce05fa28ec927e26cbf8a19d6efc4 Mon Sep 17 00:00:00 2001 From: Federico Ponzi Date: Mon, 21 Sep 2020 08:52:59 +0200 Subject: [PATCH 0766/1052] Updates stability attributes to the current nightly version --- library/std/src/io/stdio.rs | 4 ++-- library/std/src/io/util.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index cccc0aadf9989..b1033636a4536 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -607,7 +607,7 @@ impl Write for Stdout { } } -#[stable(feature = "write_mt", since = "1.47.0")] +#[stable(feature = "write_mt", since = "1.48.0")] impl Write for &Stdout { fn write(&mut self, buf: &[u8]) -> io::Result { self.lock().write(buf) @@ -810,7 +810,7 @@ impl Write for Stderr { } } -#[stable(feature = "write_mt", since = "1.47.0")] +#[stable(feature = "write_mt", since = "1.48.0")] impl Write for &Stderr { fn write(&mut self, buf: &[u8]) -> io::Result { self.lock().write(buf) diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index ce4dd1dcd493d..482378a6aba25 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -248,7 +248,7 @@ impl Write for Sink { } } -#[stable(feature = "write_mt", since = "1.47.0")] +#[stable(feature = "write_mt", since = "1.48.0")] impl Write for &Sink { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { From 0acb0ed1841d362a1119ba2ad293683660bdfaaf Mon Sep 17 00:00:00 2001 From: Federico Ponzi Date: Mon, 21 Sep 2020 08:12:40 +0100 Subject: [PATCH 0767/1052] Update library/std/src/process.rs Co-authored-by: David Tolnay --- library/std/src/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/process.rs b/library/std/src/process.rs index d620a720be3ab..b2815ba32c4f4 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -262,7 +262,7 @@ impl Write for ChildStdin { } } -#[stable(feature = "write_mt", since = "1.47.0")] +#[stable(feature = "write_mt", since = "1.48.0")] impl Write for &ChildStdin { fn write(&mut self, buf: &[u8]) -> io::Result { self.inner.write(buf) From ab83d372ed5b1799d418afe83c468e4c5973cc34 Mon Sep 17 00:00:00 2001 From: Bram van den Heuvel Date: Sat, 19 Sep 2020 12:06:17 +0200 Subject: [PATCH 0768/1052] Add an unused field of type `Option` to `ParamEnv` struct. --- compiler/rustc_infer/src/traits/mod.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 5 ++++- compiler/rustc_trait_selection/src/traits/fulfill.rs | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index a3c4920fa8af3..7e7c8588ffb40 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -57,7 +57,7 @@ pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; // `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -static_assert_size!(PredicateObligation<'_>, 32); +static_assert_size!(PredicateObligation<'_>, 40); pub type Obligations<'tcx, O> = Vec>; pub type PredicateObligations<'tcx> = Vec>; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index f23d666cfcfdd..637ef4c17ebc8 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1745,6 +1745,9 @@ pub struct ParamEnv<'tcx> { /// /// Note: This is packed, use the reveal() method to access it. packed: CopyTaggedPtr<&'tcx List>, traits::Reveal, true>, + + /// FIXME: This field is not used, but removing it causes a performance degradation. See #76913. + unused_field: Option, } unsafe impl rustc_data_structures::tagged_ptr::Tag for traits::Reveal { @@ -1825,7 +1828,7 @@ impl<'tcx> ParamEnv<'tcx> { /// Construct a trait environment with the given set of predicates. #[inline] pub fn new(caller_bounds: &'tcx List>, reveal: Reveal) -> Self { - ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, reveal) } + ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, reveal), unused_field: None } } pub fn with_user_facing(mut self) -> Self { diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 5b4314598deb5..77073f51eb7af 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -87,7 +87,7 @@ pub struct PendingPredicateObligation<'tcx> { // `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -static_assert_size!(PendingPredicateObligation<'_>, 56); +static_assert_size!(PendingPredicateObligation<'_>, 64); impl<'a, 'tcx> FulfillmentContext<'tcx> { /// Creates a new fulfillment context. From fc4b21fb6bfd4d966b9d30ce14442dd8af1c08c9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Sep 2020 09:42:34 +0200 Subject: [PATCH 0769/1052] update Miri --- src/tools/miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri b/src/tools/miri index 5a15c8a6dd620..cbc7560ae2d44 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit 5a15c8a6dd62033f69688f9d1c6eacd674158539 +Subproject commit cbc7560ae2d44669ef6ba0f43014e10ce881180e From f9457fb8097f583c470192181deb28f66d64abf5 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 20 Sep 2020 21:13:04 -0700 Subject: [PATCH 0770/1052] Remove duplicated library links between std and libc The libc crate is already responsible for linking in the appropriate libraries, and std doing the same thing results in duplicated library names on the linker command line. Removing this duplication slightly reduces linker time, and makes it simpler to adjust the set or order of linked libraries in one place (such as to add static linking support). --- library/std/build.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/library/std/build.rs b/library/std/build.rs index a787e6d43fc99..f2ed7552afb2d 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -8,10 +8,6 @@ fn main() { println!("cargo:rustc-link-lib=dl"); println!("cargo:rustc-link-lib=log"); println!("cargo:rustc-link-lib=gcc"); - } else if !target.contains("musl") { - println!("cargo:rustc-link-lib=dl"); - println!("cargo:rustc-link-lib=rt"); - println!("cargo:rustc-link-lib=pthread"); } } else if target.contains("freebsd") { println!("cargo:rustc-link-lib=execinfo"); From c160bf3c3ef4434d76cc4d093b34e9bb1fdab2a1 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 21 Sep 2020 11:38:39 +0200 Subject: [PATCH 0771/1052] Cache `eval_to_allocation_raw` on disk --- compiler/rustc_middle/src/mir/interpret/value.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 1f547d9dc3a43..206f01c249828 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -13,7 +13,7 @@ use crate::ty::{ParamEnv, Ty, TyCtxt}; use super::{sign_extend, truncate, AllocId, Allocation, InterpResult, Pointer, PointerArithmetic}; /// Represents the result of const evaluation via the `eval_to_allocation` query. -#[derive(Clone, HashStable)] +#[derive(Clone, HashStable, TyEncodable, TyDecodable)] pub struct ConstAlloc<'tcx> { // the value lives here, at offset 0, and that allocation definitely is a `AllocKind::Memory` // (so you can use `AllocMap::unwrap_memory`). diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index c0a606a586b6b..b181c3b05af21 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -716,6 +716,10 @@ rustc_queries! { "const-evaluating + checking `{}`", key.value.display(tcx) } + cache_on_disk_if(_, opt_result) { + // Only store results without errors + opt_result.map_or(true, |r| r.is_ok()) + } } /// Evaluates const items or anonymous constants From 39245400c53db98b2c4cb90cf712b282d8425d66 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Wed, 9 Sep 2020 09:43:18 +0200 Subject: [PATCH 0772/1052] fix InterpCx resolve --- compiler/rustc_mir/src/interpret/eval_context.rs | 6 +++--- compiler/rustc_mir/src/interpret/operand.rs | 2 +- compiler/rustc_mir/src/interpret/terminator.rs | 7 ++++++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs index 00d6ffb14eaf2..f97096984fa9b 100644 --- a/compiler/rustc_mir/src/interpret/eval_context.rs +++ b/compiler/rustc_mir/src/interpret/eval_context.rs @@ -482,13 +482,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// The `substs` are assumed to already be in our interpreter "universe" (param_env). pub(super) fn resolve( &self, - def_id: DefId, + def: ty::WithOptConstParam, substs: SubstsRef<'tcx>, ) -> InterpResult<'tcx, ty::Instance<'tcx>> { - trace!("resolve: {:?}, {:#?}", def_id, substs); + trace!("resolve: {:?}, {:#?}", def, substs); trace!("param_env: {:#?}", self.param_env); trace!("substs: {:#?}", substs); - match ty::Instance::resolve(*self.tcx, self.param_env, def_id, substs) { + match ty::Instance::resolve_opt_const_arg(*self.tcx, self.param_env, def, substs) { Ok(Some(instance)) => Ok(instance), Ok(None) => throw_inval!(TooGeneric), diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs index 8c4bb19866e3f..9fcbd60d4a3ba 100644 --- a/compiler/rustc_mir/src/interpret/operand.rs +++ b/compiler/rustc_mir/src/interpret/operand.rs @@ -552,7 +552,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::ConstKind::Param(_) => throw_inval!(TooGeneric), ty::ConstKind::Error(_) => throw_inval!(TypeckError(ErrorReported)), ty::ConstKind::Unevaluated(def, substs, promoted) => { - let instance = self.resolve(def.did, substs)?; + let instance = self.resolve(def, substs)?; return Ok(self.eval_to_allocation(GlobalId { instance, promoted })?.into()); } ty::ConstKind::Infer(..) diff --git a/compiler/rustc_mir/src/interpret/terminator.rs b/compiler/rustc_mir/src/interpret/terminator.rs index d3c0b497a1675..b789cb76e9f85 100644 --- a/compiler/rustc_mir/src/interpret/terminator.rs +++ b/compiler/rustc_mir/src/interpret/terminator.rs @@ -64,7 +64,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } ty::FnDef(def_id, substs) => { let sig = func.layout.ty.fn_sig(*self.tcx); - (FnVal::Instance(self.resolve(def_id, substs)?), sig.abi()) + ( + FnVal::Instance( + self.resolve(ty::WithOptConstParam::unknown(def_id), substs)?, + ), + sig.abi(), + ) } _ => span_bug!( terminator.source_info.span, From 9172e277f864205daaf8fde64868d833cc6e7eb2 Mon Sep 17 00:00:00 2001 From: est31 Date: Mon, 21 Sep 2020 12:13:26 +0200 Subject: [PATCH 0773/1052] Dogfood total_cmp in the test crate --- library/test/src/lib.rs | 1 + library/test/src/stats.rs | 18 +----------------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 6bd708ef48798..caea4b1e30941 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -29,6 +29,7 @@ #![feature(staged_api)] #![feature(termination_trait_lib)] #![feature(test)] +#![feature(total_cmp)] // Public reexports pub use self::bench::{black_box, Bencher}; diff --git a/library/test/src/stats.rs b/library/test/src/stats.rs index c02f93bf9d42f..1a2cb893a8a4f 100644 --- a/library/test/src/stats.rs +++ b/library/test/src/stats.rs @@ -1,29 +1,13 @@ #![allow(missing_docs)] #![allow(deprecated)] // Float -use std::cmp::Ordering::{self, Equal, Greater, Less}; use std::mem; #[cfg(test)] mod tests; -fn local_cmp(x: f64, y: f64) -> Ordering { - // arbitrarily decide that NaNs are larger than everything. - if y.is_nan() { - Less - } else if x.is_nan() { - Greater - } else if x < y { - Less - } else if x == y { - Equal - } else { - Greater - } -} - fn local_sort(v: &mut [f64]) { - v.sort_by(|x: &f64, y: &f64| local_cmp(*x, *y)); + v.sort_by(|x: &f64, y: &f64| x.total_cmp(y)); } /// Trait that provides simple descriptive statistics on a univariate set of numeric samples. From 073127a04fda615fe865808add119f96a241ec91 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Wed, 9 Sep 2020 09:43:47 +0200 Subject: [PATCH 0774/1052] check for cycles when unifying const variables --- compiler/rustc_infer/src/infer/combine.rs | 242 +++++++++++++++++- compiler/rustc_middle/src/ty/error.rs | 8 +- .../rustc_middle/src/ty/structural_impls.rs | 1 + 3 files changed, 237 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 5bd6c667fd7f6..33d26317c7134 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -45,7 +45,7 @@ use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{IntType, UintType}; -use rustc_span::DUMMY_SP; +use rustc_span::{Span, DUMMY_SP}; /// Small-storage-optimized implementation of a map /// made specifically for caching results. @@ -219,11 +219,11 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { } (ty::ConstKind::Infer(InferConst::Var(vid)), _) => { - return self.unify_const_variable(a_is_expected, vid, b); + return self.unify_const_variable(relation.param_env(), vid, b, a_is_expected); } (_, ty::ConstKind::Infer(InferConst::Var(vid))) => { - return self.unify_const_variable(!a_is_expected, vid, a); + return self.unify_const_variable(relation.param_env(), vid, a, !a_is_expected); } (ty::ConstKind::Unevaluated(..), _) if self.tcx.lazy_normalization() => { // FIXME(#59490): Need to remove the leak check to accommodate @@ -247,17 +247,66 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { ty::relate::super_relate_consts(relation, a, b) } - pub fn unify_const_variable( + /// Unifies the const variable `target_vid` with the given constant. + /// + /// This also tests if the given const `ct` contains an inference variable which was previously + /// unioned with `target_vid`. If this is the case, inferring `target_vid` to `ct` + /// would result in an infinite type as we continously replace an inference variable + /// in `ct` with `ct` itself. + /// + /// This is especially important as unevaluated consts use their parents generics. + /// They therefore often contain unused substs, making these errors far more likely. + /// + /// A good example of this is the following: + /// + /// ```rust + /// #![feature(const_generics)] + /// + /// fn bind(value: [u8; N]) -> [u8; 3 + 4] { + /// todo!() + /// } + /// + /// fn main() { + /// let mut arr = Default::default(); + /// arr = bind(arr); + /// } + /// ``` + /// + /// Here `3 + 4` ends up as `ConstKind::Unevaluated` which uses the generics + /// of `fn bind` (meaning that its substs contain `N`). + /// + /// `bind(arr)` now infers that the type of `arr` must be `[u8; N]`. + /// The assignment `arr = bind(arr)` now tries to equate `N` with `3 + 4`. + /// + /// As `3 + 4` contains `N` in its substs, this must not succeed. + /// + /// See `src/test/ui/const-generics/occurs-check/` for more examples where this is relevant. + fn unify_const_variable( &self, + param_env: ty::ParamEnv<'tcx>, + target_vid: ty::ConstVid<'tcx>, + ct: &'tcx ty::Const<'tcx>, vid_is_expected: bool, - vid: ty::ConstVid<'tcx>, - value: &'tcx ty::Const<'tcx>, ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { + let (for_universe, span) = { + let mut inner = self.inner.borrow_mut(); + let variable_table = &mut inner.const_unification_table(); + let var_value = variable_table.probe_value(target_vid); + match var_value.val { + ConstVariableValue::Known { value } => { + bug!("instantiating {:?} which has a known value {:?}", target_vid, value) + } + ConstVariableValue::Unknown { universe } => (universe, var_value.origin.span), + } + }; + let value = ConstInferUnifier { infcx: self, span, param_env, for_universe, target_vid } + .relate(ct, ct)?; + self.inner .borrow_mut() .const_unification_table() .unify_var_value( - vid, + target_vid, ConstVarValue { origin: ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, @@ -266,8 +315,8 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { val: ConstVariableValue::Known { value }, }, ) - .map_err(|e| const_unification_error(vid_is_expected, e))?; - Ok(value) + .map(|()| value) + .map_err(|e| const_unification_error(vid_is_expected, e)) } fn unify_integral_variable( @@ -422,7 +471,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { let for_universe = match self.infcx.inner.borrow_mut().type_variables().probe(for_vid) { v @ TypeVariableValue::Known { .. } => { - panic!("instantiating {:?} which has a known value {:?}", for_vid, v,) + bug!("instantiating {:?} which has a known value {:?}", for_vid, v,) } TypeVariableValue::Unknown { universe } => universe, }; @@ -740,7 +789,6 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { } } } - ty::ConstKind::Unevaluated(..) if self.tcx().lazy_normalization() => Ok(c), _ => relate::super_relate_consts(self, c, c), } } @@ -790,3 +838,175 @@ fn float_unification_error<'tcx>( let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v; TypeError::FloatMismatch(ty::relate::expected_found_bool(a_is_expected, a, b)) } + +struct ConstInferUnifier<'cx, 'tcx> { + infcx: &'cx InferCtxt<'cx, 'tcx>, + + span: Span, + + param_env: ty::ParamEnv<'tcx>, + + for_universe: ty::UniverseIndex, + + /// The vid of the const variable that is in the process of being + /// instantiated; if we find this within the const we are folding, + /// that means we would have created a cyclic const. + target_vid: ty::ConstVid<'tcx>, +} + +// We use `TypeRelation` here to propagate `RelateResult` upwards. +// +// Both inputs are expected to be the same. +impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.param_env + } + + fn tag(&self) -> &'static str { + "ConstInferUnifier" + } + + fn a_is_expected(&self) -> bool { + true + } + + fn relate_with_variance>( + &mut self, + _variance: ty::Variance, + a: T, + b: T, + ) -> RelateResult<'tcx, T> { + // We don't care about variance here. + self.relate(a, b) + } + + fn binders( + &mut self, + a: ty::Binder, + b: ty::Binder, + ) -> RelateResult<'tcx, ty::Binder> + where + T: Relate<'tcx>, + { + Ok(ty::Binder::bind(self.relate(a.skip_binder(), b.skip_binder())?)) + } + + fn tys(&mut self, t: Ty<'tcx>, _t: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + debug_assert_eq!(t, _t); + debug!("ConstInferUnifier: t={:?}", t); + + match t.kind() { + &ty::Infer(ty::TyVar(vid)) => { + let vid = self.infcx.inner.borrow_mut().type_variables().root_var(vid); + let probe = self.infcx.inner.borrow_mut().type_variables().probe(vid); + match probe { + TypeVariableValue::Known { value: u } => { + debug!("ConstOccursChecker: known value {:?}", u); + self.tys(u, u) + } + TypeVariableValue::Unknown { universe } => { + if self.for_universe.can_name(universe) { + return Ok(t); + } + + let origin = + *self.infcx.inner.borrow_mut().type_variables().var_origin(vid); + let new_var_id = self.infcx.inner.borrow_mut().type_variables().new_var( + self.for_universe, + false, + origin, + ); + let u = self.tcx().mk_ty_var(new_var_id); + debug!( + "ConstInferUnifier: replacing original vid={:?} with new={:?}", + vid, u + ); + Ok(u) + } + } + } + _ => relate::super_relate_tys(self, t, t), + } + } + + fn regions( + &mut self, + r: ty::Region<'tcx>, + _r: ty::Region<'tcx>, + ) -> RelateResult<'tcx, ty::Region<'tcx>> { + debug_assert_eq!(r, _r); + debug!("ConstInferUnifier: r={:?}", r); + + match r { + // Never make variables for regions bound within the type itself, + // nor for erased regions. + ty::ReLateBound(..) | ty::ReErased => { + return Ok(r); + } + + ty::RePlaceholder(..) + | ty::ReVar(..) + | ty::ReEmpty(_) + | ty::ReStatic + | ty::ReEarlyBound(..) + | ty::ReFree(..) => { + // see common code below + } + } + + let r_universe = self.infcx.universe_of_region(r); + if self.for_universe.can_name(r_universe) { + return Ok(r); + } else { + // FIXME: This is non-ideal because we don't give a + // very descriptive origin for this region variable. + Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.span), self.for_universe)) + } + } + + fn consts( + &mut self, + c: &'tcx ty::Const<'tcx>, + _c: &'tcx ty::Const<'tcx>, + ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { + debug_assert_eq!(c, _c); + debug!("ConstInferUnifier: c={:?}", c); + + match c.val { + ty::ConstKind::Infer(InferConst::Var(vid)) => { + let mut inner = self.infcx.inner.borrow_mut(); + let variable_table = &mut inner.const_unification_table(); + + // Check if the current unification would end up + // unifying `target_vid` with a const which contains + // an inference variable which is unioned with `target_vid`. + // + // Not doing so can easily result in stack overflows. + if variable_table.unioned(self.target_vid, vid) { + return Err(TypeError::CyclicConst(c)); + } + + let var_value = variable_table.probe_value(vid); + match var_value.val { + ConstVariableValue::Known { value: u } => self.consts(u, u), + ConstVariableValue::Unknown { universe } => { + if self.for_universe.can_name(universe) { + Ok(c) + } else { + let new_var_id = variable_table.new_key(ConstVarValue { + origin: var_value.origin, + val: ConstVariableValue::Unknown { universe: self.for_universe }, + }); + Ok(self.tcx().mk_const_var(new_var_id, c.ty)) + } + } + } + } + _ => relate::super_relate_consts(self, c, c), + } + } +} diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 475c3101c1e98..ff98a8b9bf0bf 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -56,6 +56,7 @@ pub enum TypeError<'tcx> { /// created a cycle (because it appears somewhere within that /// type). CyclicTy(Ty<'tcx>), + CyclicConst(&'tcx ty::Const<'tcx>), ProjectionMismatched(ExpectedFound), ExistentialMismatch(ExpectedFound<&'tcx ty::List>>), ObjectUnsafeCoercion(DefId), @@ -100,6 +101,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { match *self { CyclicTy(_) => write!(f, "cyclic type of infinite size"), + CyclicConst(_) => write!(f, "encountered a self-referencing constant"), Mismatch => write!(f, "types differ"), UnsafetyMismatch(values) => { write!(f, "expected {} fn, found {} fn", values.expected, values.found) @@ -195,9 +197,9 @@ impl<'tcx> TypeError<'tcx> { pub fn must_include_note(&self) -> bool { use self::TypeError::*; match self { - CyclicTy(_) | UnsafetyMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_) - | Sorts(_) | IntMismatch(_) | FloatMismatch(_) | VariadicMismatch(_) - | TargetFeatureCast(_) => false, + CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | Mismatch | AbiMismatch(_) + | FixedArraySize(_) | Sorts(_) | IntMismatch(_) | FloatMismatch(_) + | VariadicMismatch(_) | TargetFeatureCast(_) => false, Mutability | TupleSize(_) diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 6d9d23836fc69..597ceac9386a0 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -689,6 +689,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { Traits(x) => Traits(x), VariadicMismatch(x) => VariadicMismatch(x), CyclicTy(t) => return tcx.lift(&t).map(|t| CyclicTy(t)), + CyclicConst(ct) => return tcx.lift(&ct).map(|ct| CyclicConst(ct)), ProjectionMismatched(x) => ProjectionMismatched(x), Sorts(ref x) => return tcx.lift(x).map(Sorts), ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch), From 2855b92eb4fcc32d940de71dfd5eb383eaecc872 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Wed, 9 Sep 2020 09:43:53 +0200 Subject: [PATCH 0775/1052] add tests --- .../issues/issue-69654-run-pass.rs | 18 +++++++++++++ .../ui/const-generics/issues/issue-69654.rs | 18 +++++++++++++ .../const-generics/issues/issue-69654.stderr | 9 +++++++ .../const-generics/occurs-check/bind-param.rs | 17 ++++++++++++ .../occurs-check/unify-fixpoint.rs | 18 +++++++++++++ .../occurs-check/unify-fixpoint.stderr | 27 +++++++++++++++++++ .../occurs-check/unify-n-nplusone.rs | 17 ++++++++++++ .../occurs-check/unify-n-nplusone.stderr | 10 +++++++ .../occurs-check/unused-substs-1.rs | 14 ++++++++++ .../occurs-check/unused-substs-2.rs | 27 +++++++++++++++++++ .../occurs-check/unused-substs-3.rs | 18 +++++++++++++ .../occurs-check/unused-substs-4.rs | 12 +++++++++ 12 files changed, 205 insertions(+) create mode 100644 src/test/ui/const-generics/issues/issue-69654-run-pass.rs create mode 100644 src/test/ui/const-generics/issues/issue-69654.rs create mode 100644 src/test/ui/const-generics/issues/issue-69654.stderr create mode 100644 src/test/ui/const-generics/occurs-check/bind-param.rs create mode 100644 src/test/ui/const-generics/occurs-check/unify-fixpoint.rs create mode 100644 src/test/ui/const-generics/occurs-check/unify-fixpoint.stderr create mode 100644 src/test/ui/const-generics/occurs-check/unify-n-nplusone.rs create mode 100644 src/test/ui/const-generics/occurs-check/unify-n-nplusone.stderr create mode 100644 src/test/ui/const-generics/occurs-check/unused-substs-1.rs create mode 100644 src/test/ui/const-generics/occurs-check/unused-substs-2.rs create mode 100644 src/test/ui/const-generics/occurs-check/unused-substs-3.rs create mode 100644 src/test/ui/const-generics/occurs-check/unused-substs-4.rs diff --git a/src/test/ui/const-generics/issues/issue-69654-run-pass.rs b/src/test/ui/const-generics/issues/issue-69654-run-pass.rs new file mode 100644 index 0000000000000..bbfd2183b06e3 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-69654-run-pass.rs @@ -0,0 +1,18 @@ +// run-pass +#![feature(const_generics)] +#![allow(incomplete_features, unused_braces)] + +trait Bar {} +impl Bar for [u8; {7}] {} + +struct Foo {} +impl Foo +where + [u8; N]: Bar<[(); N]>, +{ + fn foo() {} +} + +fn main() { + Foo::foo(); +} diff --git a/src/test/ui/const-generics/issues/issue-69654.rs b/src/test/ui/const-generics/issues/issue-69654.rs new file mode 100644 index 0000000000000..7e775999ebd10 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-69654.rs @@ -0,0 +1,18 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +trait Bar {} +impl Bar for [u8; T] {} +//~^ ERROR expected value, found type parameter `T` + +struct Foo {} +impl Foo +where + [u8; N]: Bar<[(); N]>, +{ + fn foo() {} +} + +fn main() { + Foo::foo(); +} diff --git a/src/test/ui/const-generics/issues/issue-69654.stderr b/src/test/ui/const-generics/issues/issue-69654.stderr new file mode 100644 index 0000000000000..70af7bf25d849 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-69654.stderr @@ -0,0 +1,9 @@ +error[E0423]: expected value, found type parameter `T` + --> $DIR/issue-69654.rs:5:25 + | +LL | impl Bar for [u8; T] {} + | ^ not a value + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0423`. diff --git a/src/test/ui/const-generics/occurs-check/bind-param.rs b/src/test/ui/const-generics/occurs-check/bind-param.rs new file mode 100644 index 0000000000000..68d186500098d --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/bind-param.rs @@ -0,0 +1,17 @@ +// build-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +// This test does not use any "unevaluated" consts, so it should compile just fine. + +fn bind(value: [u8; N]) -> [u8; N] { + todo!() +} + +fn sink(_: [u8; 5]) {} + +fn main() { + let mut arr = Default::default(); + arr = bind(arr); + sink(arr); +} diff --git a/src/test/ui/const-generics/occurs-check/unify-fixpoint.rs b/src/test/ui/const-generics/occurs-check/unify-fixpoint.rs new file mode 100644 index 0000000000000..3cb9b7b9da880 --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unify-fixpoint.rs @@ -0,0 +1,18 @@ +#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete + +// It depends on how we normalize constants and how const equate works if this +// compiles. +// +// Please ping @lcnr if the output if this test changes. + + +fn bind(value: [u8; N + 2]) -> [u8; N * 2] { + //~^ ERROR constant expression depends on a generic parameter + //~| ERROR constant expression depends on a generic parameter + todo!() +} + +fn main() { + let mut arr = Default::default(); + arr = bind::<2>(arr); +} diff --git a/src/test/ui/const-generics/occurs-check/unify-fixpoint.stderr b/src/test/ui/const-generics/occurs-check/unify-fixpoint.stderr new file mode 100644 index 0000000000000..671f1103dccad --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unify-fixpoint.stderr @@ -0,0 +1,27 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/unify-fixpoint.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 for more information + +error: constant expression depends on a generic parameter + --> $DIR/unify-fixpoint.rs:9:32 + | +LL | fn bind(value: [u8; N + 2]) -> [u8; N * 2] { + | ^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: constant expression depends on a generic parameter + --> $DIR/unify-fixpoint.rs:9:48 + | +LL | fn bind(value: [u8; N + 2]) -> [u8; N * 2] { + | ^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 2 previous errors; 1 warning emitted + diff --git a/src/test/ui/const-generics/occurs-check/unify-n-nplusone.rs b/src/test/ui/const-generics/occurs-check/unify-n-nplusone.rs new file mode 100644 index 0000000000000..552b1b2a66ac5 --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unify-n-nplusone.rs @@ -0,0 +1,17 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +// This test would try to unify `N` with `N + 1` which must fail the occurs check. + +fn bind(value: [u8; N]) -> [u8; N + 1] { + //~^ ERROR constant expression depends on a generic parameter + todo!() +} + +fn sink(_: [u8; 5]) {} + +fn main() { + let mut arr = Default::default(); + arr = bind(arr); + sink(arr); +} diff --git a/src/test/ui/const-generics/occurs-check/unify-n-nplusone.stderr b/src/test/ui/const-generics/occurs-check/unify-n-nplusone.stderr new file mode 100644 index 0000000000000..c1ac7eec1e7d8 --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unify-n-nplusone.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/unify-n-nplusone.rs:6:44 + | +LL | fn bind(value: [u8; N]) -> [u8; N + 1] { + | ^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-1.rs b/src/test/ui/const-generics/occurs-check/unused-substs-1.rs new file mode 100644 index 0000000000000..f56687ecd9329 --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unused-substs-1.rs @@ -0,0 +1,14 @@ +// build-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +trait Bar {} +impl Bar for A<{ 6 + 1 }> {} + +struct A +where + A: Bar; + +fn main() { + let _ = A; +} diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-2.rs b/src/test/ui/const-generics/occurs-check/unused-substs-2.rs new file mode 100644 index 0000000000000..12444ec5312d9 --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unused-substs-2.rs @@ -0,0 +1,27 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +// The goal is is to get an unevaluated const `ct` with a `Ty::Infer(TyVar(_#1t)` subst. +// +// If we are then able to infer `ty::Infer(TyVar(_#1t) := Ty` we introduced an +// artificial inference cycle. +struct Foo; + +trait Bind { + fn bind() -> (T, Self); +} + +// `N` has to be `ConstKind::Unevaluated`. +impl Bind for Foo<{ 6 + 1 }> { + fn bind() -> (T, Self) { + (panic!(), Foo) + } +} + +fn main() { + let (mut t, foo) = Foo::bind(); + // `t` is `ty::Infer(TyVar(_#1t))` + // `foo` contains `ty::Infer(TyVar(_#1t))` in its substs + t = foo; +} diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-3.rs b/src/test/ui/const-generics/occurs-check/unused-substs-3.rs new file mode 100644 index 0000000000000..187e27382fcf2 --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unused-substs-3.rs @@ -0,0 +1,18 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +// The goal is is to get an unevaluated const `ct` with a `Ty::Infer(TyVar(_#1t)` subst. +// +// If we are then able to infer `ty::Infer(TyVar(_#1t) := Ty` we introduced an +// artificial inference cycle. +fn bind() -> (T, [u8; 6 + 1]) { + todo!() +} + +fn main() { + let (mut t, foo) = bind(); + // `t` is `ty::Infer(TyVar(_#1t))` + // `foo` contains `ty::Infer(TyVar(_#1t))` in its substs + t = foo; +} diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-4.rs b/src/test/ui/const-generics/occurs-check/unused-substs-4.rs new file mode 100644 index 0000000000000..8e42ceb6d70e9 --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unused-substs-4.rs @@ -0,0 +1,12 @@ +// build-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +fn bind(value: [u8; N]) -> [u8; 3 + 4] { + todo!() +} + +fn main() { + let mut arr = Default::default(); + arr = bind(arr); +} From f95e4f3ca9860bfef68ca279017db8c035966dbe Mon Sep 17 00:00:00 2001 From: Ishi Tatsuyuki Date: Mon, 21 Sep 2020 20:29:12 +0900 Subject: [PATCH 0776/1052] Improve code and documentation clarity --- .../src/thir/pattern/_match.rs | 116 +++++++++++------- 1 file changed, 75 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/_match.rs b/compiler/rustc_mir_build/src/thir/pattern/_match.rs index 1cbfc73a9c6dc..ff14ffc2a11bd 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/_match.rs @@ -139,10 +139,10 @@ //! //! It is computed as follows. We look at the pattern `p_1` on top of the stack, //! and we have three cases: -//! 1.1. `p_1 = c(r_1, .., r_a)`. We discard the current stack and return nothing. -//! 1.2. `p_1 = _`. We return the rest of the stack: +//! 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 -//! 1.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting +//! 2.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting //! stack. //! D((r_1, p_2, .., p_n)) //! D((r_2, p_2, .., p_n)) @@ -509,6 +509,14 @@ impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> { #[derive(Clone, Debug)] enum SpecializationCache { /// Patterns consist of only enum variants. + /// Variant patterns does not intersect with each other (in contrast to range patterns), + /// so it is possible to precompute the result of `Matrix::specialize_constructor` at a + /// lower computational complexity. + /// `lookup` is responsible for holding the precomputed result of + /// `Matrix::specialize_constructor`, while `wilds` is used for two purposes: the first one is + /// the precomputed result of `Matrix::specialize_wildcard`, and the second is to be used as a + /// fallback for `Matrix::specialize_constructor` when it tries to apply a constructor that + /// has not been seen in the `Matrix`. See `update_cache` for further explanations. Variants { lookup: FxHashMap>, wilds: SmallVec<[usize; 1]> }, /// Does not belong to the cases above, use the slow path. Incompatible, @@ -523,7 +531,8 @@ crate struct Matrix<'p, 'tcx> { impl<'p, 'tcx> Matrix<'p, 'tcx> { crate fn empty() -> Self { - // Use SpecializationCache::Incompatible as a placeholder; the initialization is in push(). + // Use `SpecializationCache::Incompatible` as a placeholder; we will initialize it on the + // first call to `push`. See the first half of `update_cache`. Matrix { patterns: vec![], cache: SpecializationCache::Incompatible } } @@ -536,47 +545,71 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { self.push(row) } } else { - if self.patterns.is_empty() { - self.cache = if row.is_empty() { - SpecializationCache::Incompatible - } else { - match *row.head().kind { - PatKind::Variant { .. } => SpecializationCache::Variants { - lookup: FxHashMap::default(), - wilds: SmallVec::new(), - }, - // Note: If the first pattern is a wildcard, then all patterns after that is not - // useful. The check is simple enough so we treat it as the same as unsupported - // patterns. - _ => SpecializationCache::Incompatible, - } - }; - } - let idx_to_insert = self.patterns.len(); - match &mut self.cache { - SpecializationCache::Variants { ref mut lookup, ref mut wilds } => { - let head = row.head(); - match *head.kind { - _ if head.is_wildcard() => { - for (_, v) in lookup.iter_mut() { - v.push(idx_to_insert); - } - wilds.push(idx_to_insert); - } - PatKind::Variant { adt_def, variant_index, .. } => { - lookup - .entry(adt_def.variants[variant_index].def_id) - .or_insert_with(|| wilds.clone()) - .push(idx_to_insert); - } - _ => { - self.cache = SpecializationCache::Incompatible; + self.patterns.push(row); + self.update_cache(self.patterns.len() - 1); + } + } + + fn update_cache(&mut self, idx: usize) { + let row = &self.patterns[idx]; + // We don't know which kind of cache could be used until we see the first row; therefore an + // empty `Matrix` is initialized with `SpecializationCache::Empty`, then the cache is + // assigned the appropriate variant below on the first call to `push`. + if self.patterns.is_empty() { + self.cache = if row.is_empty() { + SpecializationCache::Incompatible + } else { + match *row.head().kind { + PatKind::Variant { .. } => SpecializationCache::Variants { + lookup: FxHashMap::default(), + wilds: SmallVec::new(), + }, + // Note: If the first pattern is a wildcard, then all patterns after that is not + // useful. The check is simple enough so we treat it as the same as unsupported + // patterns. + _ => SpecializationCache::Incompatible, + } + }; + } + // Update the cache. + match &mut self.cache { + SpecializationCache::Variants { ref mut lookup, ref mut wilds } => { + let head = row.head(); + match *head.kind { + _ if head.is_wildcard() => { + // Per rule 1.3 in the top-level comments, a wildcard pattern is included in + // the result of `specialize_constructor` for *any* `Constructor`. + // We push the wildcard pattern to the precomputed result for constructors + // that we have seen before; results for constructors we have not yet seen + // defaults to `wilds`, which is updated right below. + for (_, v) in lookup.iter_mut() { + v.push(idx); } + // Per rule 2.1 and 2.2 in the top-level comments, only wildcard patterns + // are included in the result of `specialize_wildcard`. + // What we do here is to track the wildcards we have seen; so in addition to + // acting as the precomputed result of `specialize_wildcard`, `wilds` also + // serves as the default value of `specialize_constructor` for constructors + // that are not in `lookup`. + wilds.push(idx); + } + PatKind::Variant { adt_def, variant_index, .. } => { + // Handle the cases of rule 1.1 and 1.2 in the top-level comments. + // A variant pattern can only be included in the results of + // `specialize_constructor` for a particular constructor, therefore we are + // using a HashMap to track that. + lookup + .entry(adt_def.variants[variant_index].def_id) + // Default to `wilds` for absent keys. See above for an explanation. + .or_insert_with(|| wilds.clone()) + .push(idx); + } + _ => { + self.cache = SpecializationCache::Incompatible; } } - SpecializationCache::Incompatible => {} } - self.patterns.push(row); + SpecializationCache::Incompatible => {} } } @@ -609,6 +642,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { if let Constructor::Variant(id) = constructor { lookup .get(id) + // Default to `wilds` for absent keys. See `update_cache` for an explanation. .unwrap_or(&wilds) .iter() .filter_map(|&i| { From be3d8e5d6cc6833963c00404ec48a7f8f4a0c606 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 19 Sep 2020 13:43:10 +0200 Subject: [PATCH 0777/1052] Add missing code examples on HashMap types --- library/std/src/collections/hash/map.rs | 107 +++++++++++++++++++++++- 1 file changed, 106 insertions(+), 1 deletion(-) diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 1a3a493fbb8f6..7c1892c8bfde5 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -1102,6 +1102,16 @@ where /// documentation for more. /// /// [`iter`]: HashMap::iter +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter = map.iter(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, K: 'a, V: 'a> { base: base::Iter<'a, K, V>, @@ -1129,6 +1139,16 @@ impl fmt::Debug for Iter<'_, K, V> { /// documentation for more. /// /// [`iter_mut`]: HashMap::iter_mut +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter = map.iter_mut(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, K: 'a, V: 'a> { base: base::IterMut<'a, K, V>, @@ -1148,6 +1168,16 @@ impl<'a, K, V> IterMut<'a, K, V> { /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: IntoIterator::into_iter +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter = map.into_iter(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { base: base::IntoIter, @@ -1167,6 +1197,16 @@ impl IntoIter { /// documentation for more. /// /// [`keys`]: HashMap::keys +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter_keys = map.keys(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Keys<'a, K: 'a, V: 'a> { inner: Iter<'a, K, V>, @@ -1194,6 +1234,16 @@ impl fmt::Debug for Keys<'_, K, V> { /// documentation for more. /// /// [`values`]: HashMap::values +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter_values = map.values(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Values<'a, K: 'a, V: 'a> { inner: Iter<'a, K, V>, @@ -1221,6 +1271,16 @@ impl fmt::Debug for Values<'_, K, V> { /// documentation for more. /// /// [`drain`]: HashMap::drain +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter = map.drain(); +/// ``` #[stable(feature = "drain", since = "1.6.0")] pub struct Drain<'a, K: 'a, V: 'a> { base: base::Drain<'a, K, V>, @@ -1239,6 +1299,18 @@ impl<'a, K, V> Drain<'a, K, V> { /// This `struct` is created by the [`drain_filter`] method on [`HashMap`]. /// /// [`drain_filter`]: HashMap::drain_filter +/// +/// # Example +/// +/// ``` +/// #![feature(hash_drain_filter)] +/// +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter = map.drain_filter(|_k, v| *v % 2 == 0); +/// ``` #[unstable(feature = "hash_drain_filter", issue = "59618")] pub struct DrainFilter<'a, K, V, F> where @@ -1253,6 +1325,16 @@ where /// documentation for more. /// /// [`values_mut`]: HashMap::values_mut +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter_values = map.values_mut(); +/// ``` #[stable(feature = "map_values_mut", since = "1.10.0")] pub struct ValuesMut<'a, K: 'a, V: 'a> { inner: IterMut<'a, K, V>, @@ -1264,6 +1346,18 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> { /// See its documentation for more. /// /// [`into_keys`]: HashMap::into_keys +/// +/// # Example +/// +/// ``` +/// #![feature(map_into_keys_values)] +/// +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter_keys = map.into_keys(); +/// ``` #[unstable(feature = "map_into_keys_values", issue = "75294")] pub struct IntoKeys { inner: IntoIter, @@ -1275,6 +1369,18 @@ pub struct IntoKeys { /// See its documentation for more. /// /// [`into_values`]: HashMap::into_values +/// +/// # Example +/// +/// ``` +/// #![feature(map_into_keys_values)] +/// +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter_keys = map.into_values(); +/// ``` #[unstable(feature = "map_into_keys_values", issue = "75294")] pub struct IntoValues { inner: IntoIter, @@ -1285,7 +1391,6 @@ pub struct IntoValues { /// See the [`HashMap::raw_entry_mut`] docs for usage examples. /// /// [`HashMap::raw_entry_mut`]: HashMap::raw_entry_mut - #[unstable(feature = "hash_raw_entry", issue = "56167")] pub struct RawEntryBuilderMut<'a, K: 'a, V: 'a, S: 'a> { map: &'a mut HashMap, From 60b102de06f52102aa6c343de1f1ef31ff08f8df Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 31 Aug 2020 12:32:37 +0200 Subject: [PATCH 0778/1052] Don't recommend ManuallyDrop to customize drop order See https://internals.rust-lang.org/t/need-for-controlling-drop-order-of-fields/12914/21 for the discussion. TL;DR: ManuallyDrop is unsafe and footguny, but you can just ask the compiler to do all the work for you by re-ordering declarations. --- library/core/src/mem/manually_drop.rs | 55 +++++++++------------------ 1 file changed, 19 insertions(+), 36 deletions(-) diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index aab0e96d83ab9..d86939454be5b 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -15,50 +15,33 @@ use crate::ptr; /// be exposed through a public safe API. /// Correspondingly, `ManuallyDrop::drop` is unsafe. /// -/// # Examples +/// # `ManuallyDrop` and drop order. /// -/// This wrapper can be used to enforce a particular drop order on fields, regardless -/// of how they are defined in the struct: +/// Rust has a well-defined [drop order] of values. To make sure that fields or +/// locals are dropped in a specific order, reorder the declarations such that +/// the implicit drop order is the correct one. /// -/// ```rust -/// use std::mem::ManuallyDrop; -/// struct Peach; -/// struct Banana; -/// struct Melon; -/// struct FruitBox { -/// // Immediately clear there’s something non-trivial going on with these fields. -/// peach: ManuallyDrop, -/// melon: Melon, // Field that’s independent of the other two. -/// banana: ManuallyDrop, -/// } +/// It is possible to use `ManuallyDrop` to control the drop order, but this +/// requires unsafe code and is hard to do correctly in the presence of +/// unwinding. /// -/// impl Drop for FruitBox { -/// fn drop(&mut self) { -/// unsafe { -/// // Explicit ordering in which field destructors are run specified in the intuitive -/// // location – the destructor of the structure containing the fields. -/// // Moreover, one can now reorder fields within the struct however much they want. -/// ManuallyDrop::drop(&mut self.peach); -/// ManuallyDrop::drop(&mut self.banana); -/// } -/// // After destructor for `FruitBox` runs (this function), the destructor for Melon gets -/// // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`. -/// } -/// } -/// ``` +/// For example, if you want to make sure that a specific field is dropped after +/// the others, make it the last field of a struct: /// -/// However, care should be taken when using this pattern as it can lead to *leak amplification*. -/// In this example, if the `Drop` implementation for `Peach` were to panic, the `banana` field -/// would also be leaked. +/// ``` +/// struct Context; /// -/// In contrast, the automatically-generated compiler drop implementation would have ensured -/// that all fields are dropped even in the presence of panics. This is especially important when -/// working with [pinned] data, where reusing the memory without calling the destructor could lead -/// to Undefined Behaviour. +/// struct Widget { +/// children: Vec, +/// // `context` will be dropped after `children`. +/// // Rust guarantees that fields are dropped in the order of declaration. +/// context: Context, +/// } +/// ``` /// +/// [drop order]: https://doc.rust-lang.org/reference/destructors.html /// [`mem::zeroed`]: crate::mem::zeroed /// [`MaybeUninit`]: crate::mem::MaybeUninit -/// [pinned]: crate::pin #[stable(feature = "manually_drop", since = "1.20.0")] #[lang = "manually_drop"] #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] From f7eceef653c791ee9f5eef7728c50295d6808e14 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 21 Sep 2020 14:27:14 +0200 Subject: [PATCH 0779/1052] Document future incompat lints --- compiler/rustc_session/src/lint/builtin.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/compiler/rustc_session/src/lint/builtin.rs b/compiler/rustc_session/src/lint/builtin.rs index 919aaf81ed207..966b8f7e5f328 100644 --- a/compiler/rustc_session/src/lint/builtin.rs +++ b/compiler/rustc_session/src/lint/builtin.rs @@ -2207,6 +2207,16 @@ declare_lint! { /// } /// } /// ``` + /// + /// ### Explanation + /// + /// Previous versions of Rust allowed function pointers and wide raw pointers in patterns. + /// While these work in many cases as expected by users, it is possible that due to + /// optimizations pointers are "not equal to themselves" or pointers to different functions + /// compare as equal during runtime. This is because LLVM optimizations can deduplicate + /// functions if their bodies are the same, thus also making pointers to these functions point + /// to the same location. Additionally functions may get duplicated if they are instantiated + /// in different crates and not deduplicated again via LTO. pub POINTER_STRUCTURAL_MATCH, Allow, "pointers are not structural-match", @@ -2246,6 +2256,13 @@ declare_lint! { /// } /// } /// ``` + /// + /// ### Explanation + /// + /// Previous versions of Rust accepted constants in patterns, even if those constants's types + /// did not have `PartialEq` derived. Thus the compiler falls back to runtime execution of + /// `PartialEq`, which can report that two constants are not equal even if they are + /// bit-equivalent. pub NONTRIVIAL_STRUCTURAL_MATCH, Warn, "constant used in pattern of non-structural-match type and the constant's initializer \ From fe6fc555acd51bd7ba8755d9fbc7060feb67be25 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 11 Sep 2020 22:55:16 -0400 Subject: [PATCH 0780/1052] Add a changelog for x.py - Add a changelog and instructions for updating it - Use `changelog-seen` in `config.toml` and `VERSION` in bootstrap to determine whether the changelog has been read - Nag people if they haven't read the x.py changelog + Print message twice to make sure it's seen - Give different error messages depending on whether the version needs to be updated or added --- config.toml.example | 6 ++++++ src/bootstrap/CHANGELOG.md | 33 +++++++++++++++++++++++++++++++++ src/bootstrap/README.md | 14 ++++++++++++++ src/bootstrap/bin/main.rs | 35 +++++++++++++++++++++++++++++++++++ src/bootstrap/config.rs | 9 ++++++++- 5 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 src/bootstrap/CHANGELOG.md diff --git a/config.toml.example b/config.toml.example index 8bf1b48ce830e..fb62e1b4726bc 100644 --- a/config.toml.example +++ b/config.toml.example @@ -9,6 +9,12 @@ # a custom configuration file can also be specified with `--config` to the build # system. +# Keeps track of the last version of `x.py` used. +# If it does not match the version that is currently running, +# `x.py` will prompt you to update it and read the changelog. +# See `src/bootstrap/CHANGELOG.md` for more information. +changelog-seen = 1 + # ============================================================================= # Global Settings # ============================================================================= diff --git a/src/bootstrap/CHANGELOG.md b/src/bootstrap/CHANGELOG.md new file mode 100644 index 0000000000000..5fcaafab959e9 --- /dev/null +++ b/src/bootstrap/CHANGELOG.md @@ -0,0 +1,33 @@ +# Changelog + +All notable changes to bootstrap will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +## [Non-breaking changes since the last major version] + +- Add a changelog for x.py [#76626](https://github.com/rust-lang/rust/pull/76626) +- Optionally, download LLVM from CI on Linux and NixOS + + [#76439](https://github.com/rust-lang/rust/pull/76349) + + [#76667](https://github.com/rust-lang/rust/pull/76667) + + [#76708](https://github.com/rust-lang/rust/pull/76708) +- Distribute rustc sources as part of `rustc-dev` [#76856](https://github.com/rust-lang/rust/pull/76856) +- Make the default stage for x.py configurable [#76625](https://github.com/rust-lang/rust/pull/76625) +- Add a dedicated debug-logging option [#76588](https://github.com/rust-lang/rust/pull/76588) +- Add sample defaults for x.py [#76628](https://github.com/rust-lang/rust/pull/76628) + +## [Version 0] - 2020-09-11 + +This is the first changelog entry, and it does not attempt to be an exhaustive list of features in x.py. +Instead, this documents the changes to bootstrap in the past 2 months. + +- Improve defaults in `x.py` [#73964](https://github.com/rust-lang/rust/pull/73964) + (see [blog post] for details) +- Set `ninja = true` by default [#74922](https://github.com/rust-lang/rust/pull/74922) +- Avoid trying to inversely cross-compile for build triple from host triples [#76415](https://github.com/rust-lang/rust/pull/76415) +- Allow blessing expect-tests in tools [#75975](https://github.com/rust-lang/rust/pull/75975) +- `x.py check` checks tests/examples/benches [#76258](https://github.com/rust-lang/rust/pull/76258) +- Fix `rust.use-lld` when linker is not set [#76326](https://github.com/rust-lang/rust/pull/76326) +- Build tests with LLD if `use-lld = true` was passed [#76378](https://github.com/rust-lang/rust/pull/76378) + +[blog post]: https://blog.rust-lang.org/inside-rust/2020/08/30/changes-to-x-py-defaults.html diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index a69bd1cc3bc53..bc8bae14b210c 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -313,6 +313,20 @@ are: `Config` struct. * Adding a sanity check? Take a look at `bootstrap/sanity.rs`. +If you make a major change, please remember to: + ++ Update `VERSION` in `src/bootstrap/main.rs`. +* Update `changelog-seen = N` in `config.toml.example`. +* Add an entry in `src/bootstrap/CHANGELOG.md`. + +A 'major change' includes + +* A new option or +* A change in the default options. + +Changes that do not affect contributors to the compiler or users +building rustc from source don't need an update to `VERSION`. + If you have any questions feel free to reach out on the `#t-infra` channel in the [Rust Zulip server][rust-zulip] or ask on internals.rust-lang.org. When you encounter bugs, please file issues on the rust-lang/rust issue tracker. diff --git a/src/bootstrap/bin/main.rs b/src/bootstrap/bin/main.rs index b67486c9628cd..f7512aa9fcebd 100644 --- a/src/bootstrap/bin/main.rs +++ b/src/bootstrap/bin/main.rs @@ -12,5 +12,40 @@ use bootstrap::{Build, Config}; fn main() { let args = env::args().skip(1).collect::>(); let config = Config::parse(&args); + + let changelog_suggestion = check_version(&config); + if let Some(suggestion) = &changelog_suggestion { + println!("{}", suggestion); + } + Build::new(config).build(); + + if let Some(suggestion) = changelog_suggestion { + println!("{}", suggestion); + println!("note: this message was printed twice to make it more likely to be seen"); + } +} + +fn check_version(config: &Config) -> Option { + const VERSION: usize = 1; + + let mut msg = String::new(); + + let suggestion = if let Some(seen) = config.changelog_seen { + if seen != VERSION { + msg.push_str("warning: there have been changes to x.py since you last updated.\n"); + format!("update `config.toml` to use `changelog-seen = {}` instead", VERSION) + } else { + return None; + } + } else { + msg.push_str("warning: x.py has made several changes recently you may want to look at\n"); + format!("add `changelog-seen = {}` to `config.toml`", VERSION) + }; + + msg.push_str("help: consider looking at the changes in `src/bootstrap/CHANGELOG.md`\n"); + msg.push_str("note: to silence this warning, "); + msg.push_str(&suggestion); + + Some(msg) } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 801ed5ac6eeea..c74501979f0ec 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -42,6 +42,7 @@ macro_rules! check_ci_llvm { /// `config.toml.example`. #[derive(Default)] pub struct Config { + pub changelog_seen: Option, pub ccache: Option, /// Call Build::ninja() instead of this. pub ninja_in_file: bool, @@ -273,6 +274,7 @@ impl Target { #[derive(Deserialize, Default)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct TomlConfig { + changelog_seen: Option, build: Option, install: Option, llvm: Option, @@ -283,7 +285,10 @@ struct TomlConfig { } impl Merge for TomlConfig { - fn merge(&mut self, TomlConfig { build, install, llvm, rust, dist, target, profile: _ }: Self) { + fn merge( + &mut self, + TomlConfig { build, install, llvm, rust, dist, target, profile: _, changelog_seen: _ }: Self, + ) { fn do_merge(x: &mut Option, y: Option) { if let Some(new) = y { if let Some(original) = x { @@ -572,6 +577,8 @@ impl Config { toml.merge(included_toml); } + config.changelog_seen = toml.changelog_seen; + let build = toml.build.unwrap_or_default(); // If --target was specified but --host wasn't specified, don't run any host-only tests. From 57baec7d4342f3c2949c136aa2af2e151d36d093 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Sep 2020 15:26:50 +0200 Subject: [PATCH 0781/1052] update Miri for another bugfix --- src/tools/miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri b/src/tools/miri index cbc7560ae2d44..02a33d411d8e3 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit cbc7560ae2d44669ef6ba0f43014e10ce881180e +Subproject commit 02a33d411d8e385942776760a99535d69826349b From 4117ae1175430087441c9b34145f148d49c2f08c Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Mon, 21 Sep 2020 15:32:26 +0200 Subject: [PATCH 0782/1052] Split redundant_pattern_matching tests This is to avoid the 200 lines stderr file limit --- tests/ui/redundant_pattern_matching.fixed | 71 +------ tests/ui/redundant_pattern_matching.rs | 86 +-------- tests/ui/redundant_pattern_matching.stderr | 174 +++--------------- .../redundant_pattern_matching_option.fixed | 85 +++++++++ tests/ui/redundant_pattern_matching_option.rs | 100 ++++++++++ .../redundant_pattern_matching_option.stderr | 134 ++++++++++++++ 6 files changed, 351 insertions(+), 299 deletions(-) create mode 100644 tests/ui/redundant_pattern_matching_option.fixed create mode 100644 tests/ui/redundant_pattern_matching_option.rs create mode 100644 tests/ui/redundant_pattern_matching_option.stderr diff --git a/tests/ui/redundant_pattern_matching.fixed b/tests/ui/redundant_pattern_matching.fixed index 8084fdefdc23e..17d908336d593 100644 --- a/tests/ui/redundant_pattern_matching.fixed +++ b/tests/ui/redundant_pattern_matching.fixed @@ -18,39 +18,14 @@ fn main() { if Err::(42).is_err() {} - if None::<()>.is_none() {} - - if Some(42).is_some() {} - - if Some(42).is_some() { - foo(); - } else { - bar(); - } - - while Some(42).is_some() {} - - while Some(42).is_none() {} - - while None::<()>.is_none() {} - while Ok::(10).is_ok() {} while Ok::(10).is_err() {} - let mut v = vec![1, 2, 3]; - while v.pop().is_some() { - foo(); - } - if Ok::(42).is_ok() {} if Err::(42).is_err() {} - if None::.is_none() {} - - if Some(42).is_some() {} - if let Ok(x) = Ok::(42) { println!("{}", x); } @@ -63,48 +38,24 @@ fn main() { Err::(42).is_ok(); - Some(42).is_some(); - - None::<()>.is_none(); - - let _ = None::<()>.is_none(); - let _ = if Ok::(4).is_ok() { true } else { false }; - let opt = Some(false); - let x = if opt.is_some() { true } else { false }; - takes_bool(x); - issue5504(); issue6067(); - let _ = if gen_opt().is_some() { + let _ = if gen_res().is_ok() { 1 - } else if gen_opt().is_none() { - 2 - } else if gen_res().is_ok() { - 3 } else if gen_res().is_err() { - 4 + 2 } else { - 5 + 3 }; } -fn gen_opt() -> Option<()> { - None -} - fn gen_res() -> Result<(), ()> { Ok(()) } -fn takes_bool(_: bool) {} - -fn foo() {} - -fn bar() {} - macro_rules! m { () => { Some(42u32) @@ -129,30 +80,18 @@ fn issue5504() { } // Methods that are unstable const should not be suggested within a const context, see issue #5697. -// However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result`, and `is_some` and `is_none` -// of `Option` were stabilized as const, so the following should be linted. +// However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result` were stabilized as const, +// so the following should be linted. const fn issue6067() { if Ok::(42).is_ok() {} if Err::(42).is_err() {} - if Some(42).is_some() {} - - if None::<()>.is_none() {} - while Ok::(10).is_ok() {} while Ok::(10).is_err() {} - while Some(42).is_some() {} - - while None::<()>.is_none() {} - Ok::(42).is_ok(); Err::(42).is_err(); - - Some(42).is_some(); - - None::<()>.is_none(); } diff --git a/tests/ui/redundant_pattern_matching.rs b/tests/ui/redundant_pattern_matching.rs index 48a32cb1c7b7d..d57fbb14ae496 100644 --- a/tests/ui/redundant_pattern_matching.rs +++ b/tests/ui/redundant_pattern_matching.rs @@ -18,39 +18,14 @@ fn main() { if let Err(_) = Err::(42) {} - if let None = None::<()> {} - - if let Some(_) = Some(42) {} - - if let Some(_) = Some(42) { - foo(); - } else { - bar(); - } - - while let Some(_) = Some(42) {} - - while let None = Some(42) {} - - while let None = None::<()> {} - while let Ok(_) = Ok::(10) {} while let Err(_) = Ok::(10) {} - let mut v = vec![1, 2, 3]; - while let Some(_) = v.pop() { - foo(); - } - if Ok::(42).is_ok() {} if Err::(42).is_err() {} - if None::.is_none() {} - - if Some(42).is_some() {} - if let Ok(x) = Ok::(42) { println!("{}", x); } @@ -75,57 +50,24 @@ fn main() { Err(_) => false, }; - match Some(42) { - Some(_) => true, - None => false, - }; - - match None::<()> { - Some(_) => false, - None => true, - }; - - let _ = match None::<()> { - Some(_) => false, - None => true, - }; - let _ = if let Ok(_) = Ok::(4) { true } else { false }; - let opt = Some(false); - let x = if let Some(_) = opt { true } else { false }; - takes_bool(x); - issue5504(); issue6067(); - let _ = if let Some(_) = gen_opt() { + let _ = if let Ok(_) = gen_res() { 1 - } else if let None = gen_opt() { - 2 - } else if let Ok(_) = gen_res() { - 3 } else if let Err(_) = gen_res() { - 4 + 2 } else { - 5 + 3 }; } -fn gen_opt() -> Option<()> { - None -} - fn gen_res() -> Result<(), ()> { Ok(()) } -fn takes_bool(_: bool) {} - -fn foo() {} - -fn bar() {} - macro_rules! m { () => { Some(42u32) @@ -150,25 +92,17 @@ fn issue5504() { } // Methods that are unstable const should not be suggested within a const context, see issue #5697. -// However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result`, and `is_some` and `is_none` -// of `Option` were stabilized as const, so the following should be linted. +// However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result` were stabilized as const, +// so the following should be linted. const fn issue6067() { if let Ok(_) = Ok::(42) {} if let Err(_) = Err::(42) {} - if let Some(_) = Some(42) {} - - if let None = None::<()> {} - while let Ok(_) = Ok::(10) {} while let Err(_) = Ok::(10) {} - while let Some(_) = Some(42) {} - - while let None = None::<()> {} - match Ok::(42) { Ok(_) => true, Err(_) => false, @@ -178,14 +112,4 @@ const fn issue6067() { Ok(_) => false, Err(_) => true, }; - - match Some(42) { - Some(_) => true, - None => false, - }; - - match None::<()> { - Some(_) => false, - None => true, - }; } diff --git a/tests/ui/redundant_pattern_matching.stderr b/tests/ui/redundant_pattern_matching.stderr index 17185217e8950..955900f3e6c9e 100644 --- a/tests/ui/redundant_pattern_matching.stderr +++ b/tests/ui/redundant_pattern_matching.stderr @@ -18,62 +18,20 @@ error: redundant pattern matching, consider using `is_err()` LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` -error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:21:12 - | -LL | if let None = None::<()> {} - | -------^^^^------------- help: try this: `if None::<()>.is_none()` - -error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:23:12 - | -LL | if let Some(_) = Some(42) {} - | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` - -error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:25:12 - | -LL | if let Some(_) = Some(42) { - | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` - -error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:31:15 - | -LL | while let Some(_) = Some(42) {} - | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` - -error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:33:15 - | -LL | while let None = Some(42) {} - | ----------^^^^----------- help: try this: `while Some(42).is_none()` - -error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:35:15 - | -LL | while let None = None::<()> {} - | ----------^^^^------------- help: try this: `while None::<()>.is_none()` - error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:37:15 + --> $DIR/redundant_pattern_matching.rs:21:15 | LL | while let Ok(_) = Ok::(10) {} | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:39:15 + --> $DIR/redundant_pattern_matching.rs:23:15 | LL | while let Err(_) = Ok::(10) {} | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` -error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:42:15 - | -LL | while let Some(_) = v.pop() { - | ----------^^^^^^^---------- help: try this: `while v.pop().is_some()` - error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:58:5 + --> $DIR/redundant_pattern_matching.rs:33:5 | LL | / match Ok::(42) { LL | | Ok(_) => true, @@ -82,7 +40,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:63:5 + --> $DIR/redundant_pattern_matching.rs:38:5 | LL | / match Ok::(42) { LL | | Ok(_) => false, @@ -91,7 +49,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_err()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:68:5 + --> $DIR/redundant_pattern_matching.rs:43:5 | LL | / match Err::(42) { LL | | Ok(_) => false, @@ -100,7 +58,7 @@ LL | | }; | |_____^ help: try this: `Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:73:5 + --> $DIR/redundant_pattern_matching.rs:48:5 | LL | / match Err::(42) { LL | | Ok(_) => true, @@ -108,144 +66,74 @@ LL | | Err(_) => false, LL | | }; | |_____^ help: try this: `Err::(42).is_ok()` -error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:78:5 - | -LL | / match Some(42) { -LL | | Some(_) => true, -LL | | None => false, -LL | | }; - | |_____^ help: try this: `Some(42).is_some()` - -error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:83:5 - | -LL | / match None::<()> { -LL | | Some(_) => false, -LL | | None => true, -LL | | }; - | |_____^ help: try this: `None::<()>.is_none()` - -error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:88:13 - | -LL | let _ = match None::<()> { - | _____________^ -LL | | Some(_) => false, -LL | | None => true, -LL | | }; - | |_____^ help: try this: `None::<()>.is_none()` - error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:93:20 + --> $DIR/redundant_pattern_matching.rs:53:20 | LL | let _ = if let Ok(_) = Ok::(4) { true } else { false }; | -------^^^^^--------------------- help: try this: `if Ok::(4).is_ok()` -error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:96:20 - | -LL | let x = if let Some(_) = opt { true } else { false }; - | -------^^^^^^^------ help: try this: `if opt.is_some()` - -error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:102:20 - | -LL | let _ = if let Some(_) = gen_opt() { - | -------^^^^^^^------------ help: try this: `if gen_opt().is_some()` - -error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:104:19 - | -LL | } else if let None = gen_opt() { - | -------^^^^------------ help: try this: `if gen_opt().is_none()` - error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:106:19 + --> $DIR/redundant_pattern_matching.rs:58:20 | -LL | } else if let Ok(_) = gen_res() { - | -------^^^^^------------ help: try this: `if gen_res().is_ok()` +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:108:19 + --> $DIR/redundant_pattern_matching.rs:60: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:141:19 + --> $DIR/redundant_pattern_matching.rs:83: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:142:16 + --> $DIR/redundant_pattern_matching.rs:84: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:148:12 + --> $DIR/redundant_pattern_matching.rs:90: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:149:15 + --> $DIR/redundant_pattern_matching.rs:91: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:156:12 + --> $DIR/redundant_pattern_matching.rs:98:12 | LL | if let Ok(_) = Ok::(42) {} | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:158:12 + --> $DIR/redundant_pattern_matching.rs:100:12 | LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` -error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:160:12 - | -LL | if let Some(_) = Some(42) {} - | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` - -error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:162:12 - | -LL | if let None = None::<()> {} - | -------^^^^------------- help: try this: `if None::<()>.is_none()` - error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:164:15 + --> $DIR/redundant_pattern_matching.rs:102:15 | LL | while let Ok(_) = Ok::(10) {} | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:166:15 + --> $DIR/redundant_pattern_matching.rs:104:15 | LL | while let Err(_) = Ok::(10) {} | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` -error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:168:15 - | -LL | while let Some(_) = Some(42) {} - | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` - -error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:170:15 - | -LL | while let None = None::<()> {} - | ----------^^^^------------- help: try this: `while None::<()>.is_none()` - error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:172:5 + --> $DIR/redundant_pattern_matching.rs:106:5 | LL | / match Ok::(42) { LL | | Ok(_) => true, @@ -254,7 +142,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:177:5 + --> $DIR/redundant_pattern_matching.rs:111:5 | LL | / match Err::(42) { LL | | Ok(_) => false, @@ -262,23 +150,5 @@ LL | | Err(_) => true, LL | | }; | |_____^ help: try this: `Err::(42).is_err()` -error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:182:5 - | -LL | / match Some(42) { -LL | | Some(_) => true, -LL | | None => false, -LL | | }; - | |_____^ help: try this: `Some(42).is_some()` - -error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:187:5 - | -LL | / match None::<()> { -LL | | Some(_) => false, -LL | | None => true, -LL | | }; - | |_____^ help: try this: `None::<()>.is_none()` - -error: aborting due to 41 previous errors +error: aborting due to 22 previous errors diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed new file mode 100644 index 0000000000000..499b975b2bb47 --- /dev/null +++ b/tests/ui/redundant_pattern_matching_option.fixed @@ -0,0 +1,85 @@ +// run-rustfix + +#![warn(clippy::all)] +#![warn(clippy::redundant_pattern_matching)] +#![allow( + clippy::unit_arg, + unused_must_use, + clippy::needless_bool, + clippy::match_like_matches_macro, + deprecated +)] + +fn main() { + if None::<()>.is_none() {} + + if Some(42).is_some() {} + + if Some(42).is_some() { + foo(); + } else { + bar(); + } + + while Some(42).is_some() {} + + while Some(42).is_none() {} + + while None::<()>.is_none() {} + + let mut v = vec![1, 2, 3]; + while v.pop().is_some() { + foo(); + } + + if None::.is_none() {} + + if Some(42).is_some() {} + + Some(42).is_some(); + + None::<()>.is_none(); + + let _ = None::<()>.is_none(); + + let opt = Some(false); + let x = if opt.is_some() { true } else { false }; + takes_bool(x); + + issue6067(); + + let _ = if gen_opt().is_some() { + 1 + } else if gen_opt().is_none() { + 2 + } else { + 3 + }; +} + +fn gen_opt() -> Option<()> { + None +} + +fn takes_bool(_: bool) {} + +fn foo() {} + +fn bar() {} + +// Methods that are unstable const should not be suggested within a const context, see issue #5697. +// However, in Rust 1.48.0 the methods `is_some` and `is_none` of `Option` were stabilized as const, +// so the following should be linted. +const fn issue6067() { + if Some(42).is_some() {} + + if None::<()>.is_none() {} + + while Some(42).is_some() {} + + while None::<()>.is_none() {} + + Some(42).is_some(); + + None::<()>.is_none(); +} diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs new file mode 100644 index 0000000000000..2a98435e7902e --- /dev/null +++ b/tests/ui/redundant_pattern_matching_option.rs @@ -0,0 +1,100 @@ +// run-rustfix + +#![warn(clippy::all)] +#![warn(clippy::redundant_pattern_matching)] +#![allow( + clippy::unit_arg, + unused_must_use, + clippy::needless_bool, + clippy::match_like_matches_macro, + deprecated +)] + +fn main() { + if let None = None::<()> {} + + if let Some(_) = Some(42) {} + + if let Some(_) = Some(42) { + foo(); + } else { + bar(); + } + + while let Some(_) = Some(42) {} + + while let None = Some(42) {} + + while let None = None::<()> {} + + let mut v = vec![1, 2, 3]; + while let Some(_) = v.pop() { + foo(); + } + + if None::.is_none() {} + + if Some(42).is_some() {} + + match Some(42) { + Some(_) => true, + None => false, + }; + + match None::<()> { + Some(_) => false, + None => true, + }; + + let _ = match None::<()> { + Some(_) => false, + None => true, + }; + + let opt = Some(false); + let x = if let Some(_) = opt { true } else { false }; + takes_bool(x); + + issue6067(); + + let _ = if let Some(_) = gen_opt() { + 1 + } else if let None = gen_opt() { + 2 + } else { + 3 + }; +} + +fn gen_opt() -> Option<()> { + None +} + +fn takes_bool(_: bool) {} + +fn foo() {} + +fn bar() {} + +// Methods that are unstable const should not be suggested within a const context, see issue #5697. +// However, in Rust 1.48.0 the methods `is_some` and `is_none` of `Option` were stabilized as const, +// so the following should be linted. +const fn issue6067() { + if let Some(_) = Some(42) {} + + if let None = None::<()> {} + + while let Some(_) = Some(42) {} + + while let None = None::<()> {} + + match Some(42) { + Some(_) => true, + None => false, + }; + + match None::<()> { + Some(_) => false, + None => true, + }; +} diff --git a/tests/ui/redundant_pattern_matching_option.stderr b/tests/ui/redundant_pattern_matching_option.stderr new file mode 100644 index 0000000000000..eebb34484913e --- /dev/null +++ b/tests/ui/redundant_pattern_matching_option.stderr @@ -0,0 +1,134 @@ +error: redundant pattern matching, consider using `is_none()` + --> $DIR/redundant_pattern_matching_option.rs:14:12 + | +LL | if let None = None::<()> {} + | -------^^^^------------- help: try this: `if None::<()>.is_none()` + | + = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` + +error: redundant pattern matching, consider using `is_some()` + --> $DIR/redundant_pattern_matching_option.rs:16:12 + | +LL | if let Some(_) = Some(42) {} + | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` + +error: redundant pattern matching, consider using `is_some()` + --> $DIR/redundant_pattern_matching_option.rs:18:12 + | +LL | if let Some(_) = Some(42) { + | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` + +error: redundant pattern matching, consider using `is_some()` + --> $DIR/redundant_pattern_matching_option.rs:24:15 + | +LL | while let Some(_) = Some(42) {} + | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` + +error: redundant pattern matching, consider using `is_none()` + --> $DIR/redundant_pattern_matching_option.rs:26:15 + | +LL | while let None = Some(42) {} + | ----------^^^^----------- help: try this: `while Some(42).is_none()` + +error: redundant pattern matching, consider using `is_none()` + --> $DIR/redundant_pattern_matching_option.rs:28:15 + | +LL | while let None = None::<()> {} + | ----------^^^^------------- help: try this: `while None::<()>.is_none()` + +error: redundant pattern matching, consider using `is_some()` + --> $DIR/redundant_pattern_matching_option.rs:31:15 + | +LL | while let Some(_) = v.pop() { + | ----------^^^^^^^---------- help: try this: `while v.pop().is_some()` + +error: redundant pattern matching, consider using `is_some()` + --> $DIR/redundant_pattern_matching_option.rs:39:5 + | +LL | / match Some(42) { +LL | | Some(_) => true, +LL | | None => false, +LL | | }; + | |_____^ help: try this: `Some(42).is_some()` + +error: redundant pattern matching, consider using `is_none()` + --> $DIR/redundant_pattern_matching_option.rs:44:5 + | +LL | / match None::<()> { +LL | | Some(_) => false, +LL | | None => true, +LL | | }; + | |_____^ help: try this: `None::<()>.is_none()` + +error: redundant pattern matching, consider using `is_none()` + --> $DIR/redundant_pattern_matching_option.rs:49:13 + | +LL | let _ = match None::<()> { + | _____________^ +LL | | Some(_) => false, +LL | | None => true, +LL | | }; + | |_____^ help: try this: `None::<()>.is_none()` + +error: redundant pattern matching, consider using `is_some()` + --> $DIR/redundant_pattern_matching_option.rs:55:20 + | +LL | let x = if let Some(_) = opt { true } else { false }; + | -------^^^^^^^------ help: try this: `if opt.is_some()` + +error: redundant pattern matching, consider using `is_some()` + --> $DIR/redundant_pattern_matching_option.rs:60:20 + | +LL | let _ = if let Some(_) = gen_opt() { + | -------^^^^^^^------------ help: try this: `if gen_opt().is_some()` + +error: redundant pattern matching, consider using `is_none()` + --> $DIR/redundant_pattern_matching_option.rs:62:19 + | +LL | } else if let None = gen_opt() { + | -------^^^^------------ help: try this: `if gen_opt().is_none()` + +error: redundant pattern matching, consider using `is_some()` + --> $DIR/redundant_pattern_matching_option.rs:83:12 + | +LL | if let Some(_) = Some(42) {} + | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` + +error: redundant pattern matching, consider using `is_none()` + --> $DIR/redundant_pattern_matching_option.rs:85:12 + | +LL | if let None = None::<()> {} + | -------^^^^------------- help: try this: `if None::<()>.is_none()` + +error: redundant pattern matching, consider using `is_some()` + --> $DIR/redundant_pattern_matching_option.rs:87:15 + | +LL | while let Some(_) = Some(42) {} + | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` + +error: redundant pattern matching, consider using `is_none()` + --> $DIR/redundant_pattern_matching_option.rs:89:15 + | +LL | while let None = None::<()> {} + | ----------^^^^------------- help: try this: `while None::<()>.is_none()` + +error: redundant pattern matching, consider using `is_some()` + --> $DIR/redundant_pattern_matching_option.rs:91:5 + | +LL | / match Some(42) { +LL | | Some(_) => true, +LL | | None => false, +LL | | }; + | |_____^ help: try this: `Some(42).is_some()` + +error: redundant pattern matching, consider using `is_none()` + --> $DIR/redundant_pattern_matching_option.rs:96:5 + | +LL | / match None::<()> { +LL | | Some(_) => false, +LL | | None => true, +LL | | }; + | |_____^ help: try this: `None::<()>.is_none()` + +error: aborting due to 19 previous errors + From c7e887c64abe846dea4a0ee7a1cfee843bb8e820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Mon, 21 Sep 2020 00:00:00 +0000 Subject: [PATCH 0783/1052] DroplessArena: Allocate objects from the end of memory chunk Allocating from the end of memory chunk simplifies the alignment code and reduces the number of checked arithmetic operations. --- compiler/rustc_arena/src/lib.rs | 37 ++++++++++++++------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 6f9cccf58dd01..32783951a313d 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -299,11 +299,13 @@ unsafe impl<#[may_dangle] T> Drop for TypedArena { unsafe impl Send for TypedArena {} pub struct DroplessArena { - /// A pointer to the next object to be allocated. - ptr: Cell<*mut u8>, + /// A pointer to the start of the free space. + start: Cell<*mut u8>, - /// A pointer to the end of the allocated area. When this pointer is - /// reached, a new chunk is allocated. + /// A pointer to the end of free space. + /// + /// The allocation proceeds from the end of the chunk towards the start. + /// When this pointer crosses the start pointer, a new chunk is allocated. end: Cell<*mut u8>, /// A vector of arena chunks. @@ -316,7 +318,7 @@ impl Default for DroplessArena { #[inline] fn default() -> DroplessArena { DroplessArena { - ptr: Cell::new(ptr::null_mut()), + start: Cell::new(ptr::null_mut()), end: Cell::new(ptr::null_mut()), chunks: Default::default(), } @@ -348,7 +350,7 @@ impl DroplessArena { new_cap = cmp::max(additional, new_cap); let mut chunk = TypedArenaChunk::::new(new_cap); - self.ptr.set(chunk.start()); + self.start.set(chunk.start()); self.end.set(chunk.end()); chunks.push(chunk); } @@ -359,24 +361,17 @@ impl DroplessArena { /// request. #[inline] fn alloc_raw_without_grow(&self, layout: Layout) -> Option<*mut u8> { - let ptr = self.ptr.get() as usize; + let start = self.start.get() as usize; let end = self.end.get() as usize; + let align = layout.align(); let bytes = layout.size(); - // The allocation request fits into the current chunk iff: - // - // let aligned = align_to(ptr, align); - // ptr <= aligned && aligned + bytes <= end - // - // Except that we work with fixed width integers and need to be careful - // about potential overflow in the calcuation. If the overflow does - // happen, then we definitely don't have enough free and need to grow - // the arena. - let aligned = ptr.checked_add(align - 1)? & !(align - 1); - let new_ptr = aligned.checked_add(bytes)?; - if new_ptr <= end { - self.ptr.set(new_ptr as *mut u8); - Some(aligned as *mut u8) + + let new_end = end.checked_sub(bytes)? & !(align - 1); + if start <= new_end { + let new_end = new_end as *mut u8; + self.end.set(new_end); + Some(new_end) } else { None } From f12583a3302df829d2cf55f25303a74531067a97 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 21 Sep 2020 16:38:29 +0200 Subject: [PATCH 0784/1052] Pacify tidy --- compiler/rustc_session/src/lint/builtin.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_session/src/lint/builtin.rs b/compiler/rustc_session/src/lint/builtin.rs index 966b8f7e5f328..b39e01a009eb2 100644 --- a/compiler/rustc_session/src/lint/builtin.rs +++ b/compiler/rustc_session/src/lint/builtin.rs @@ -2208,6 +2208,8 @@ declare_lint! { /// } /// ``` /// + /// {{produces}} + /// /// ### Explanation /// /// Previous versions of Rust allowed function pointers and wide raw pointers in patterns. @@ -2257,6 +2259,8 @@ declare_lint! { /// } /// ``` /// + /// {{produces}} + /// /// ### Explanation /// /// Previous versions of Rust accepted constants in patterns, even if those constants's types From ccd218d04ce5124de69716316ff72b9356a00cb8 Mon Sep 17 00:00:00 2001 From: Nicholas-Baron Date: Mon, 21 Sep 2020 09:16:55 -0700 Subject: [PATCH 0785/1052] Added back the '// ignore-file-length' with an explanation --- compiler/rustc_typeck/src/check/fn_ctxt.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/rustc_typeck/src/check/fn_ctxt.rs b/compiler/rustc_typeck/src/check/fn_ctxt.rs index 2a906f5b6ed07..a03b8064b5909 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt.rs @@ -1,3 +1,8 @@ +// ignore-tidy-filelength +// FIXME: This file seems to have too much functionality wrapped into it, +// leading to it being too long. +// Splitting this file may involve abstracting functionality into other files. + use super::callee::{self, DeferredCallResolution}; use super::coercion::{CoerceMany, DynamicCoerceMany}; use super::method::{self, MethodCallee, SelfSource}; From b4b4a2f0927d2d1d838da1e128472ff8bf64e98b Mon Sep 17 00:00:00 2001 From: James Whaley Date: Mon, 21 Sep 2020 18:27:43 +0100 Subject: [PATCH 0786/1052] Reduce boilerplate for BytePos and CharPos --- compiler/rustc_span/src/lib.rs | 137 +++++++++++++-------------------- 1 file changed, 55 insertions(+), 82 deletions(-) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index a730c30378827..ad3a866463d45 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1558,58 +1558,71 @@ pub trait Pos { fn to_u32(&self) -> u32; } -/// A byte offset. Keep this small (currently 32-bits), as AST contains -/// a lot of them. -#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] -pub struct BytePos(pub u32); - -/// A character offset. Because of multibyte UTF-8 characters, a byte offset -/// is not equivalent to a character offset. The `SourceMap` will convert `BytePos` -/// values to `CharPos` values as necessary. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] -pub struct CharPos(pub usize); +macro_rules! impl_pos { + ( + $( + $(#[$attr:meta])* + $vis:vis struct $ident:ident($inner_vis:vis $inner_ty:ty); + )* + ) => { + $( + $(#[$attr])* + $vis struct $ident($inner_vis $inner_ty); + + impl Pos for $ident { + #[inline(always)] + fn from_usize(n: usize) -> $ident { + $ident(n as $inner_ty) + } -// FIXME: lots of boilerplate in these impls, but so far my attempts to fix -// have been unsuccessful. + #[inline(always)] + fn to_usize(&self) -> usize { + self.0 as usize + } -impl Pos for BytePos { - #[inline(always)] - fn from_usize(n: usize) -> BytePos { - BytePos(n as u32) - } + #[inline(always)] + fn from_u32(n: u32) -> $ident { + $ident(n as $inner_ty) + } - #[inline(always)] - fn to_usize(&self) -> usize { - self.0 as usize - } + #[inline(always)] + fn to_u32(&self) -> u32 { + self.0 as u32 + } + } - #[inline(always)] - fn from_u32(n: u32) -> BytePos { - BytePos(n) - } + impl Add for $ident { + type Output = $ident; - #[inline(always)] - fn to_u32(&self) -> u32 { - self.0 - } -} + #[inline(always)] + fn add(self, rhs: $ident) -> $ident { + $ident((self.to_usize() + rhs.to_usize()) as $inner_ty) + } + } -impl Add for BytePos { - type Output = BytePos; + impl Sub for $ident { + type Output = $ident; - #[inline(always)] - fn add(self, rhs: BytePos) -> BytePos { - BytePos((self.to_usize() + rhs.to_usize()) as u32) - } + #[inline(always)] + fn sub(self, rhs: $ident) -> $ident { + $ident((self.to_usize() - rhs.to_usize()) as $inner_ty) + } + } + )* + }; } -impl Sub for BytePos { - type Output = BytePos; +impl_pos! { + /// A byte offset. Keep this small (currently 32-bits), as AST contains + /// a lot of them. + #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] + pub struct BytePos(pub u32); - #[inline(always)] - fn sub(self, rhs: BytePos) -> BytePos { - BytePos((self.to_usize() - rhs.to_usize()) as u32) - } + /// A character offset. Because of multibyte UTF-8 characters, a byte offset + /// is not equivalent to a character offset. The `SourceMap` will convert `BytePos` + /// values to `CharPos` values as necessary. + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] + pub struct CharPos(pub usize); } impl Encodable for BytePos { @@ -1624,46 +1637,6 @@ impl Decodable for BytePos { } } -impl Pos for CharPos { - #[inline(always)] - fn from_usize(n: usize) -> CharPos { - CharPos(n) - } - - #[inline(always)] - fn to_usize(&self) -> usize { - self.0 - } - - #[inline(always)] - fn from_u32(n: u32) -> CharPos { - CharPos(n as usize) - } - - #[inline(always)] - fn to_u32(&self) -> u32 { - self.0 as u32 - } -} - -impl Add for CharPos { - type Output = CharPos; - - #[inline(always)] - fn add(self, rhs: CharPos) -> CharPos { - CharPos(self.to_usize() + rhs.to_usize()) - } -} - -impl Sub for CharPos { - type Output = CharPos; - - #[inline(always)] - fn sub(self, rhs: CharPos) -> CharPos { - CharPos(self.to_usize() - rhs.to_usize()) - } -} - // _____________________________________________________________________________ // Loc, SourceFileAndLine, SourceFileAndBytePos // From d4f158fa5cd5f4ae1cc690b37b0a8850cb013b69 Mon Sep 17 00:00:00 2001 From: Aleksei Latyshev Date: Sun, 20 Sep 2020 12:38:23 +0300 Subject: [PATCH 0787/1052] Forbid redundant_pattern_matching triggering in macros - remove ice-2636 test --- clippy_lints/src/matches.rs | 2 +- tests/ui/crashes/ice-2636.rs | 22 -------------------- tests/ui/crashes/ice-2636.stderr | 17 --------------- tests/ui/redundant_pattern_matching.fixed | 12 +++++++++++ tests/ui/redundant_pattern_matching.rs | 12 +++++++++++ tests/ui/redundant_pattern_matching.stderr | 24 +++++++++++----------- 6 files changed, 37 insertions(+), 52 deletions(-) delete mode 100644 tests/ui/crashes/ice-2636.rs delete mode 100644 tests/ui/crashes/ice-2636.stderr diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 6f47687c41088..b1a4e06d4c32f 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -502,7 +502,7 @@ impl_lint_pass!(Matches => [ impl<'tcx> LateLintPass<'tcx> for Matches { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if in_external_macro(cx.sess(), expr.span) { + if in_external_macro(cx.sess(), expr.span) || in_macro(expr.span) { return; } diff --git a/tests/ui/crashes/ice-2636.rs b/tests/ui/crashes/ice-2636.rs deleted file mode 100644 index e0b58157590ab..0000000000000 --- a/tests/ui/crashes/ice-2636.rs +++ /dev/null @@ -1,22 +0,0 @@ -#![allow(dead_code)] - -enum Foo { - A, - B, - C, -} - -macro_rules! test_hash { - ($foo:expr, $($t:ident => $ord:expr),+ ) => { - use self::Foo::*; - match $foo { - $ ( & $t => $ord, - )* - }; - }; -} - -fn main() { - let a = Foo::A; - test_hash!(&a, A => 0, B => 1, C => 2); -} diff --git a/tests/ui/crashes/ice-2636.stderr b/tests/ui/crashes/ice-2636.stderr deleted file mode 100644 index 53799b4fbf1d9..0000000000000 --- a/tests/ui/crashes/ice-2636.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error: you don't need to add `&` to both the expression and the patterns - --> $DIR/ice-2636.rs:12:9 - | -LL | / match $foo { -LL | | $ ( & $t => $ord, -LL | | )* -LL | | }; - | |_________^ -... -LL | test_hash!(&a, A => 0, B => 1, C => 2); - | --------------------------------------- in this macro invocation - | - = note: `-D clippy::match-ref-pats` implied by `-D warnings` - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to previous error - diff --git a/tests/ui/redundant_pattern_matching.fixed b/tests/ui/redundant_pattern_matching.fixed index 17d908336d593..fe8f62503b767 100644 --- a/tests/ui/redundant_pattern_matching.fixed +++ b/tests/ui/redundant_pattern_matching.fixed @@ -42,6 +42,7 @@ fn main() { issue5504(); issue6067(); + issue6065(); let _ = if gen_res().is_ok() { 1 @@ -79,6 +80,17 @@ fn issue5504() { while m!().is_some() {} } +fn issue6065() { + macro_rules! if_let_in_macro { + ($pat:pat, $x:expr) => { + if let Some($pat) = $x {} + }; + } + + // shouldn't be linted + if_let_in_macro!(_, Some(42)); +} + // Methods that are unstable const should not be suggested within a const context, see issue #5697. // However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result` were stabilized as const, // so the following should be linted. diff --git a/tests/ui/redundant_pattern_matching.rs b/tests/ui/redundant_pattern_matching.rs index d57fbb14ae496..09426a6e59082 100644 --- a/tests/ui/redundant_pattern_matching.rs +++ b/tests/ui/redundant_pattern_matching.rs @@ -54,6 +54,7 @@ fn main() { issue5504(); issue6067(); + issue6065(); let _ = if let Ok(_) = gen_res() { 1 @@ -91,6 +92,17 @@ fn issue5504() { while let Some(_) = m!() {} } +fn issue6065() { + macro_rules! if_let_in_macro { + ($pat:pat, $x:expr) => { + if let Some($pat) = $x {} + }; + } + + // shouldn't be linted + if_let_in_macro!(_, Some(42)); +} + // Methods that are unstable const should not be suggested within a const context, see issue #5697. // However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result` were stabilized as const, // so the following should be linted. diff --git a/tests/ui/redundant_pattern_matching.stderr b/tests/ui/redundant_pattern_matching.stderr index 955900f3e6c9e..3473ceea00e22 100644 --- a/tests/ui/redundant_pattern_matching.stderr +++ b/tests/ui/redundant_pattern_matching.stderr @@ -73,67 +73,67 @@ LL | let _ = if let Ok(_) = Ok::(4) { true } else { false }; | -------^^^^^--------------------- help: try this: `if Ok::(4).is_ok()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:58:20 + --> $DIR/redundant_pattern_matching.rs:59: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:60:19 + --> $DIR/redundant_pattern_matching.rs:61: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:83:19 + --> $DIR/redundant_pattern_matching.rs:84: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:84:16 + --> $DIR/redundant_pattern_matching.rs:85: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:90:12 + --> $DIR/redundant_pattern_matching.rs:91: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:91:15 + --> $DIR/redundant_pattern_matching.rs:92: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:98:12 + --> $DIR/redundant_pattern_matching.rs:110:12 | LL | if let Ok(_) = Ok::(42) {} | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:100:12 + --> $DIR/redundant_pattern_matching.rs:112:12 | LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:102:15 + --> $DIR/redundant_pattern_matching.rs:114:15 | LL | while let Ok(_) = Ok::(10) {} | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:104:15 + --> $DIR/redundant_pattern_matching.rs:116:15 | LL | while let Err(_) = Ok::(10) {} | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:106:5 + --> $DIR/redundant_pattern_matching.rs:118:5 | LL | / match Ok::(42) { LL | | Ok(_) => true, @@ -142,7 +142,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:111:5 + --> $DIR/redundant_pattern_matching.rs:123:5 | LL | / match Err::(42) { LL | | Ok(_) => false, From 8fc782afc204adf1d2d6c1e0f13b1242aef396d4 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 21 Sep 2020 20:28:52 +0200 Subject: [PATCH 0788/1052] add test --- compiler/rustc_lint/src/internal.rs | 6 ++++ .../internal-lints/pass_ty_by_ref_self.rs | 33 +++++++++++++++++++ .../internal-lints/pass_ty_by_ref_self.stderr | 20 +++++++++++ 3 files changed, 59 insertions(+) create mode 100644 src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs create mode 100644 src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 2bac4517409b4..c2d98b8e4ad37 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -191,6 +191,12 @@ fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, ty: &Ty<'_>) -> Option { Res::SelfTy(None, Some((did, _))) => { if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() { if cx.tcx.is_diagnostic_item(sym::Ty, adt.did) { + // NOTE: This path is currently unreachable as `Ty<'tcx>` is + // defined as a type alias meaning that `impl<'tcx> Ty<'tcx>` + // is not actually allowed. + // + // I(@lcnr) still kept this branch in so we don't miss this + // if we ever change it in the future. return Some(format!("Ty<{}>", substs[0])); } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, adt.did) { return Some(format!("TyCtxt<{}>", substs[0])); diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs new file mode 100644 index 0000000000000..f58446d559222 --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs @@ -0,0 +1,33 @@ +// NOTE: This test doesn't actually require `fulldeps` +// so we could instead use it as an `ui` test. +// +// Considering that all other `internal-lints` are tested here +// this seems like the cleaner solution though. +#![feature(rustc_attrs)] +#![deny(rustc::ty_pass_by_reference)] +#![allow(unused)] + +#[rustc_diagnostic_item = "TyCtxt"] +struct TyCtxt<'tcx> { + inner: &'tcx (), +} + +impl<'tcx> TyCtxt<'tcx> { + fn by_value(self) {} // OK + fn by_ref(&self) {} //~ ERROR passing `TyCtxt<'tcx>` by reference +} + + +struct TyS<'tcx> { + inner: &'tcx (), +} + +#[rustc_diagnostic_item = "Ty"] +type Ty<'tcx> = &'tcx TyS<'tcx>; + +impl<'tcx> TyS<'tcx> { + fn by_value(self: Ty<'tcx>) {} + fn by_ref(self: &Ty<'tcx>) {} //~ ERROR passing `Ty<'tcx>` by reference +} + +fn main() {} diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr new file mode 100644 index 0000000000000..b846b30f4ed37 --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr @@ -0,0 +1,20 @@ +error: passing `TyCtxt<'tcx>` by reference + --> $DIR/pass_ty_by_ref_self.rs:17:15 + | +LL | fn by_ref(&self) {} + | ^^^^^ help: try passing by value: `TyCtxt<'tcx>` + | +note: the lint level is defined here + --> $DIR/pass_ty_by_ref_self.rs:7:9 + | +LL | #![deny(rustc::ty_pass_by_reference)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: passing `Ty<'tcx>` by reference + --> $DIR/pass_ty_by_ref_self.rs:30:21 + | +LL | fn by_ref(self: &Ty<'tcx>) {} + | ^^^^^^^^^ help: try passing by value: `Ty<'tcx>` + +error: aborting due to 2 previous errors + From db74e1f1e3e5c7497bb9af68814497c8df1fd0b8 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 20 Sep 2020 12:09:22 +0200 Subject: [PATCH 0789/1052] Add cfg(target_has_atomic_equal_alignment). This is needed for Atomic::from_mut. --- compiler/rustc_feature/src/builtin_attrs.rs | 5 +++++ compiler/rustc_session/src/config.rs | 19 +++++++++++++++---- compiler/rustc_span/src/symbol.rs | 1 + 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index fc122db8ac1b1..8b7fd59cd874a 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -26,6 +26,11 @@ const GATED_CFGS: &[GatedCfg] = &[ (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), (sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), (sym::target_has_atomic_load_store, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), + ( + sym::target_has_atomic_equal_alignment, + sym::cfg_target_has_atomic, + cfg_fn!(cfg_target_has_atomic), + ), (sym::sanitize, sym::cfg_sanitize, cfg_fn!(cfg_sanitize)), (sym::version, sym::cfg_version, cfg_fn!(cfg_version)), ]; diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 8d004675d7f4d..09e5948cdd750 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -12,6 +12,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::impl_stable_hash_via_hash; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_target::abi::{Align, TargetDataLayout}; use rustc_target::spec::{Target, TargetTriple}; use crate::parse::CrateConfig; @@ -748,6 +749,7 @@ pub fn default_configuration(sess: &Session) -> CrateConfig { let min_atomic_width = sess.target.target.min_atomic_width(); let max_atomic_width = sess.target.target.max_atomic_width(); let atomic_cas = sess.target.target.options.atomic_cas; + let layout = TargetDataLayout::parse(&sess.target.target).unwrap(); let mut ret = FxHashSet::default(); ret.reserve(6); // the minimum number of insertions @@ -769,18 +771,27 @@ pub fn default_configuration(sess: &Session) -> CrateConfig { if sess.target.target.options.has_elf_tls { ret.insert((sym::target_thread_local, None)); } - for &i in &[8, 16, 32, 64, 128] { + for &(i, align) in &[ + (8, layout.i8_align.abi), + (16, layout.i16_align.abi), + (32, layout.i32_align.abi), + (64, layout.i64_align.abi), + (128, layout.i128_align.abi), + ] { if i >= min_atomic_width && i <= max_atomic_width { - let mut insert_atomic = |s| { + let mut insert_atomic = |s, align: Align| { ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s)))); if atomic_cas { ret.insert((sym::target_has_atomic, Some(Symbol::intern(s)))); } + if align.bits() == i { + ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s)))); + } }; let s = i.to_string(); - insert_atomic(&s); + insert_atomic(&s, align); if &s == wordsz { - insert_atomic("ptr"); + insert_atomic("ptr", layout.pointer_align.abi); } } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 6085eedf23694..60688d26d4ce0 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1071,6 +1071,7 @@ symbols! { target_feature, target_feature_11, target_has_atomic, + target_has_atomic_equal_alignment, target_has_atomic_load_store, target_os, target_pointer_width, From 9a1f1777d3602b267c78229e1d5de68fe7eab57a Mon Sep 17 00:00:00 2001 From: James Whaley Date: Mon, 21 Sep 2020 19:42:43 +0100 Subject: [PATCH 0790/1052] Remove cast to usize for BytePos and CharPos The case shouldn't be necessary and implicitly truncating BytePos is not desirable. --- compiler/rustc_span/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index ad3a866463d45..4b02a2d4076d7 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1596,7 +1596,7 @@ macro_rules! impl_pos { #[inline(always)] fn add(self, rhs: $ident) -> $ident { - $ident((self.to_usize() + rhs.to_usize()) as $inner_ty) + $ident(self.0 + rhs.0) } } @@ -1605,7 +1605,7 @@ macro_rules! impl_pos { #[inline(always)] fn sub(self, rhs: $ident) -> $ident { - $ident((self.to_usize() - rhs.to_usize()) as $inner_ty) + $ident(self.0 - rhs.0) } } )* From 9e3f94dabc334586d669f3aba0bded607ac782fc Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 20 Sep 2020 12:39:07 +0200 Subject: [PATCH 0791/1052] Don't unwrap but report a fatal error for TargetDataLayout::parse. --- compiler/rustc_session/src/config.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 09e5948cdd750..ab96b0333f43f 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -749,7 +749,9 @@ pub fn default_configuration(sess: &Session) -> CrateConfig { let min_atomic_width = sess.target.target.min_atomic_width(); let max_atomic_width = sess.target.target.max_atomic_width(); let atomic_cas = sess.target.target.options.atomic_cas; - let layout = TargetDataLayout::parse(&sess.target.target).unwrap(); + let layout = TargetDataLayout::parse(&sess.target.target).unwrap_or_else(|err| { + sess.fatal(&err); + }); let mut ret = FxHashSet::default(); ret.reserve(6); // the minimum number of insertions From af56ad7633668a790353f17440586e97b4e6a99b Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 20 Sep 2020 13:03:12 +0200 Subject: [PATCH 0792/1052] Add feature gate ui test for cfg(target_has_atomic_load_store). --- .../feature-gate-cfg-target-has-atomic.rs | 12 ++++ .../feature-gate-cfg-target-has-atomic.stderr | 56 ++++++++++++++++++- 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs index 506b21dc7d544..e336c63071814 100644 --- a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs +++ b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs @@ -87,6 +87,18 @@ fn main() { //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change cfg!(target_has_atomic = "ptr"); //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "8"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "16"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "32"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "64"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "128"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "ptr"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change } #[macro_export] diff --git a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr index 6132c53087879..c171d8e6d92fc 100644 --- a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr +++ b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr @@ -160,6 +160,60 @@ LL | cfg!(target_has_atomic = "ptr"); = note: see issue #32976 for more information = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable -error: aborting due to 18 previous errors +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:90:10 + | +LL | cfg!(target_has_atomic_load_store = "8"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:92:10 + | +LL | cfg!(target_has_atomic_load_store = "16"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:94:10 + | +LL | cfg!(target_has_atomic_load_store = "32"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:96:10 + | +LL | cfg!(target_has_atomic_load_store = "64"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:98:10 + | +LL | cfg!(target_has_atomic_load_store = "128"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:100:10 + | +LL | cfg!(target_has_atomic_load_store = "ptr"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error: aborting due to 24 previous errors For more information about this error, try `rustc --explain E0658`. From 54fdf54e06e3287958d906d2fb1b905b778d5e38 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 20 Sep 2020 13:03:12 +0200 Subject: [PATCH 0793/1052] Add feature gate ui test for cfg(target_has_atomic_equal_alignment). --- .../feature-gate-cfg-target-has-atomic.rs | 12 ++++ .../feature-gate-cfg-target-has-atomic.stderr | 56 ++++++++++++++++++- 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs index e336c63071814..049fdd84d8c22 100644 --- a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs +++ b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs @@ -99,6 +99,18 @@ fn main() { //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change cfg!(target_has_atomic_load_store = "ptr"); //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_equal_alignment = "8"); + //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + cfg!(target_has_atomic_equal_alignment = "16"); + //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + cfg!(target_has_atomic_equal_alignment = "32"); + //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + cfg!(target_has_atomic_equal_alignment = "64"); + //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + cfg!(target_has_atomic_equal_alignment = "128"); + //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + cfg!(target_has_atomic_equal_alignment = "ptr"); + //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change } #[macro_export] diff --git a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr index c171d8e6d92fc..16e1dc6440084 100644 --- a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr +++ b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr @@ -214,6 +214,60 @@ LL | cfg!(target_has_atomic_load_store = "ptr"); = note: see issue #32976 for more information = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable -error: aborting due to 24 previous errors +error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:102:10 + | +LL | cfg!(target_has_atomic_equal_alignment = "8"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:104:10 + | +LL | cfg!(target_has_atomic_equal_alignment = "16"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:106:10 + | +LL | cfg!(target_has_atomic_equal_alignment = "32"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:108:10 + | +LL | cfg!(target_has_atomic_equal_alignment = "64"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:110:10 + | +LL | cfg!(target_has_atomic_equal_alignment = "128"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:112:10 + | +LL | cfg!(target_has_atomic_equal_alignment = "ptr"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error: aborting due to 30 previous errors For more information about this error, try `rustc --explain E0658`. From 668225d157d91e5c55a02aa7abc1b65ec9690ffa Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 21 Sep 2020 20:42:40 +0200 Subject: [PATCH 0794/1052] Revert "Revert adding Atomic::from_mut." This reverts commit 5ef1db3622c373883571868cbdafbfbd568cddcb. --- library/core/src/sync/atomic.rs | 90 +++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 7eec2c487fef4..c67d6422c01ec 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -110,6 +110,7 @@ use self::Ordering::*; use crate::cell::UnsafeCell; use crate::fmt; use crate::intrinsics; +use crate::mem::align_of; use crate::hint::spin_loop; @@ -327,6 +328,27 @@ impl AtomicBool { unsafe { &mut *(self.v.get() as *mut bool) } } + /// Get atomic access to a `&mut bool`. + /// + /// # Examples + /// + /// ``` + /// #![feature(atomic_from_mut)] + /// use std::sync::atomic::{AtomicBool, Ordering}; + /// + /// let mut some_bool = true; + /// let a = AtomicBool::from_mut(&mut some_bool); + /// a.store(false, Ordering::Relaxed); + /// assert_eq!(some_bool, false); + /// ``` + #[inline] + #[unstable(feature = "atomic_from_mut", issue = "76314")] + pub fn from_mut(v: &mut bool) -> &Self { + // SAFETY: the mutable reference guarantees unique ownership, and + // alignment of both `bool` and `Self` is 1. + unsafe { &*(v as *mut bool as *mut Self) } + } + /// Consumes the atomic and returns the contained value. /// /// This is safe because passing `self` by value guarantees that no other threads are @@ -819,6 +841,30 @@ impl AtomicPtr { self.p.get_mut() } + /// Get atomic access to a pointer. + /// + /// # Examples + /// + /// ``` + /// #![feature(atomic_from_mut)] + /// use std::sync::atomic::{AtomicPtr, Ordering}; + /// + /// let mut some_ptr = &mut 123 as *mut i32; + /// let a = AtomicPtr::from_mut(&mut some_ptr); + /// a.store(&mut 456, Ordering::Relaxed); + /// assert_eq!(unsafe { *some_ptr }, 456); + /// ``` + #[inline] + #[unstable(feature = "atomic_from_mut", issue = "76314")] + pub fn from_mut(v: &mut *mut T) -> &Self { + let [] = [(); align_of::>() - align_of::<*mut ()>()]; + // SAFETY: + // - the mutable reference guarantees unique ownership. + // - the alignment of `*mut T` and `Self` is the same on all platforms + // supported by rust, as verified above. + unsafe { &*(v as *mut *mut T as *mut Self) } + } + /// Consumes the atomic and returns the contained value. /// /// This is safe because passing `self` by value guarantees that no other threads are @@ -1121,6 +1167,7 @@ macro_rules! atomic_int { $stable_nand:meta, $const_stable:meta, $stable_init_const:meta, + $(from_mut: cfg($from_mut_cfg:meta),)? $s_int_type:literal, $int_ref:expr, $extra_feature:expr, $min_fn:ident, $max_fn:ident, @@ -1231,6 +1278,45 @@ assert_eq!(some_var.load(Ordering::SeqCst), 5); } } + doc_comment! { + concat!("Get atomic access to a `&mut ", stringify!($int_type), "`. + +", +if_not_8_bit! { + $int_type, + concat!( + "**Note:** This function is only available on targets where `", + stringify!($int_type), "` has an alignment of ", $align, " bytes." + ) +}, +" + +# Examples + +``` +#![feature(atomic_from_mut)] +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let mut some_int = 123; +let a = ", stringify!($atomic_type), "::from_mut(&mut some_int); +a.store(100, Ordering::Relaxed); +assert_eq!(some_int, 100); +``` + "), + #[inline] + $(#[cfg($from_mut_cfg)])? + #[unstable(feature = "atomic_from_mut", issue = "76314")] + pub fn from_mut(v: &mut $int_type) -> &Self { + let [] = [(); align_of::() - align_of::<$int_type>()]; + // SAFETY: + // - the mutable reference guarantees unique ownership. + // - the alignment of `$int_type` and `Self` is the + // same on all platforms enabled by `$from_mut_cfg` + // as verified above. + unsafe { &*(v as *mut $int_type as *mut Self) } + } + } + doc_comment! { concat!("Consumes the atomic and returns the contained value. @@ -1989,6 +2075,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), + from_mut: cfg(not(target_arch = "x86")), "i64", "../../../std/primitive.i64.html", "", atomic_min, atomic_max, @@ -2007,6 +2094,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), + from_mut: cfg(not(target_arch = "x86")), "u64", "../../../std/primitive.u64.html", "", atomic_umin, atomic_umax, @@ -2025,6 +2113,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), + from_mut: cfg(not(target_arch = "x86_64")), "i128", "../../../std/primitive.i128.html", "#![feature(integer_atomics)]\n\n", atomic_min, atomic_max, @@ -2043,6 +2132,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), + from_mut: cfg(not(target_arch = "x86_64")), "u128", "../../../std/primitive.u128.html", "#![feature(integer_atomics)]\n\n", atomic_umin, atomic_umax, From 7a04ff6c33c8bc9b8b1012e12a9920df52956e2f Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 20 Sep 2020 12:14:41 +0200 Subject: [PATCH 0795/1052] Gate Atomic::from_mut on cfg(target_has_atomic_equal_alignment). Instead of a few hardcoded cfg(target_arch = ..) like before. --- library/core/src/sync/atomic.rs | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index c67d6422c01ec..fa9d3c95b1790 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -110,6 +110,8 @@ use self::Ordering::*; use crate::cell::UnsafeCell; use crate::fmt; use crate::intrinsics; + +#[allow(unused_imports)] use crate::mem::align_of; use crate::hint::spin_loop; @@ -342,6 +344,7 @@ impl AtomicBool { /// assert_eq!(some_bool, false); /// ``` #[inline] + #[cfg(target_has_atomic_equal_alignment = "8")] #[unstable(feature = "atomic_from_mut", issue = "76314")] pub fn from_mut(v: &mut bool) -> &Self { // SAFETY: the mutable reference guarantees unique ownership, and @@ -855,6 +858,7 @@ impl AtomicPtr { /// assert_eq!(unsafe { *some_ptr }, 456); /// ``` #[inline] + #[cfg(target_has_atomic_equal_alignment = "ptr")] #[unstable(feature = "atomic_from_mut", issue = "76314")] pub fn from_mut(v: &mut *mut T) -> &Self { let [] = [(); align_of::>() - align_of::<*mut ()>()]; @@ -1159,6 +1163,7 @@ macro_rules! if_not_8_bit { #[cfg(target_has_atomic_load_store = "8")] macro_rules! atomic_int { ($cfg_cas:meta, + $cfg_align:meta, $stable:meta, $stable_cxchg:meta, $stable_debug:meta, @@ -1167,7 +1172,6 @@ macro_rules! atomic_int { $stable_nand:meta, $const_stable:meta, $stable_init_const:meta, - $(from_mut: cfg($from_mut_cfg:meta),)? $s_int_type:literal, $int_ref:expr, $extra_feature:expr, $min_fn:ident, $max_fn:ident, @@ -1304,15 +1308,14 @@ assert_eq!(some_int, 100); ``` "), #[inline] - $(#[cfg($from_mut_cfg)])? + #[$cfg_align] #[unstable(feature = "atomic_from_mut", issue = "76314")] pub fn from_mut(v: &mut $int_type) -> &Self { let [] = [(); align_of::() - align_of::<$int_type>()]; // SAFETY: // - the mutable reference guarantees unique ownership. // - the alignment of `$int_type` and `Self` is the - // same on all platforms enabled by `$from_mut_cfg` - // as verified above. + // same, as promised by $cfg_align and verified above. unsafe { &*(v as *mut $int_type as *mut Self) } } } @@ -1959,6 +1962,7 @@ let mut atomic = ", stringify!($atomic_type), "::new(1); #[cfg(target_has_atomic_load_store = "8")] atomic_int! { cfg(target_has_atomic = "8"), + cfg(target_has_atomic_equal_alignment = "8"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -1977,6 +1981,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "8")] atomic_int! { cfg(target_has_atomic = "8"), + cfg(target_has_atomic_equal_alignment = "8"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -1995,6 +2000,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "16")] atomic_int! { cfg(target_has_atomic = "16"), + cfg(target_has_atomic_equal_alignment = "16"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -2013,6 +2019,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "16")] atomic_int! { cfg(target_has_atomic = "16"), + cfg(target_has_atomic_equal_alignment = "16"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -2031,6 +2038,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "32")] atomic_int! { cfg(target_has_atomic = "32"), + cfg(target_has_atomic_equal_alignment = "32"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -2049,6 +2057,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "32")] atomic_int! { cfg(target_has_atomic = "32"), + cfg(target_has_atomic_equal_alignment = "32"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -2067,6 +2076,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "64")] atomic_int! { cfg(target_has_atomic = "64"), + cfg(target_has_atomic_equal_alignment = "64"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -2075,7 +2085,6 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), - from_mut: cfg(not(target_arch = "x86")), "i64", "../../../std/primitive.i64.html", "", atomic_min, atomic_max, @@ -2086,6 +2095,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "64")] atomic_int! { cfg(target_has_atomic = "64"), + cfg(target_has_atomic_equal_alignment = "64"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -2094,7 +2104,6 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), - from_mut: cfg(not(target_arch = "x86")), "u64", "../../../std/primitive.u64.html", "", atomic_umin, atomic_umax, @@ -2105,6 +2114,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "128")] atomic_int! { cfg(target_has_atomic = "128"), + cfg(target_has_atomic_equal_alignment = "128"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), @@ -2113,7 +2123,6 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), - from_mut: cfg(not(target_arch = "x86_64")), "i128", "../../../std/primitive.i128.html", "#![feature(integer_atomics)]\n\n", atomic_min, atomic_max, @@ -2124,6 +2133,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "128")] atomic_int! { cfg(target_has_atomic = "128"), + cfg(target_has_atomic_equal_alignment = "128"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), @@ -2132,7 +2142,6 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), - from_mut: cfg(not(target_arch = "x86_64")), "u128", "../../../std/primitive.u128.html", "#![feature(integer_atomics)]\n\n", atomic_umin, atomic_umax, @@ -2164,6 +2173,7 @@ macro_rules! ptr_width { #[cfg(target_has_atomic_load_store = "ptr")] atomic_int! { cfg(target_has_atomic = "ptr"), + cfg(target_has_atomic_equal_alignment = "ptr"), stable(feature = "rust1", since = "1.0.0"), stable(feature = "extended_compare_and_swap", since = "1.10.0"), stable(feature = "atomic_debug", since = "1.3.0"), @@ -2182,6 +2192,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "ptr")] atomic_int! { cfg(target_has_atomic = "ptr"), + cfg(target_has_atomic_equal_alignment = "ptr"), stable(feature = "rust1", since = "1.0.0"), stable(feature = "extended_compare_and_swap", since = "1.10.0"), stable(feature = "atomic_debug", since = "1.3.0"), From 5d6f1a1e32de4936e5b269b04781b2737f6d410b Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 21 Sep 2020 20:44:45 +0200 Subject: [PATCH 0796/1052] Move `use align_of` in atomic.rs into the places where it is used. --- library/core/src/sync/atomic.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index fa9d3c95b1790..5c9cfe27101f0 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -111,9 +111,6 @@ use crate::cell::UnsafeCell; use crate::fmt; use crate::intrinsics; -#[allow(unused_imports)] -use crate::mem::align_of; - use crate::hint::spin_loop; /// Signals the processor that it is inside a busy-wait spin-loop ("spin lock"). @@ -861,6 +858,7 @@ impl AtomicPtr { #[cfg(target_has_atomic_equal_alignment = "ptr")] #[unstable(feature = "atomic_from_mut", issue = "76314")] pub fn from_mut(v: &mut *mut T) -> &Self { + use crate::mem::align_of; let [] = [(); align_of::>() - align_of::<*mut ()>()]; // SAFETY: // - the mutable reference guarantees unique ownership. @@ -1311,6 +1309,7 @@ assert_eq!(some_int, 100); #[$cfg_align] #[unstable(feature = "atomic_from_mut", issue = "76314")] pub fn from_mut(v: &mut $int_type) -> &Self { + use crate::mem::align_of; let [] = [(); align_of::() - align_of::<$int_type>()]; // SAFETY: // - the mutable reference guarantees unique ownership. From 63195ecb458bba01f36f407b6df69aa03828243e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 8 Sep 2020 21:02:18 +0200 Subject: [PATCH 0797/1052] Add explanation for E0756 --- compiler/rustc_error_codes/src/error_codes.rs | 2 +- .../src/error_codes/E0756.md | 29 +++++++++++++++++++ src/test/ui/ffi_const.stderr | 1 + 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0756.md diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 23a7b08016e50..a202736ea6cbe 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -441,6 +441,7 @@ E0752: include_str!("./error_codes/E0752.md"), E0753: include_str!("./error_codes/E0753.md"), E0754: include_str!("./error_codes/E0754.md"), E0755: include_str!("./error_codes/E0755.md"), +E0756: include_str!("./error_codes/E0756.md"), E0758: include_str!("./error_codes/E0758.md"), E0759: include_str!("./error_codes/E0759.md"), E0760: include_str!("./error_codes/E0760.md"), @@ -633,7 +634,6 @@ E0774: include_str!("./error_codes/E0774.md"), E0722, // Malformed `#[optimize]` attribute E0726, // non-explicit (not `'_`) elided lifetime in unsupported position // E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. - E0756, // `#[ffi_const]` is only allowed on foreign functions E0757, // `#[ffi_const]` functions cannot be `#[ffi_pure]` E0772, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`. } diff --git a/compiler/rustc_error_codes/src/error_codes/E0756.md b/compiler/rustc_error_codes/src/error_codes/E0756.md new file mode 100644 index 0000000000000..ffdc421aab584 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0756.md @@ -0,0 +1,29 @@ +The `ffi_const` attribute was used on something other than a foreign function +declaration. + +Erroneous code example: + +```compile_fail,E0756 +#![feature(ffi_const)] + +#[ffi_const] // error! +pub fn foo() {} +# fn main() {} +``` + +The `ffi_const` attribute can only be used on foreign function declarations +which have no side effects except for their return value: + +``` +#![feature(ffi_const)] + +extern "C" { + #[ffi_const] // ok! + pub fn strlen(s: *const i8) -> i32; +} +# fn main() {} +``` + +You can get more information about it in the [unstable Rust Book]. + +[unstable Rust Book]: https://doc.rust-lang.org/nightly/unstable-book/language-features/ffi-const.html diff --git a/src/test/ui/ffi_const.stderr b/src/test/ui/ffi_const.stderr index 623551cc07bbb..bc3c12eaf981b 100644 --- a/src/test/ui/ffi_const.stderr +++ b/src/test/ui/ffi_const.stderr @@ -6,3 +6,4 @@ LL | #[ffi_const] error: aborting due to previous error +For more information about this error, try `rustc --explain E0756`. From e734733a9e931cbbe26cfccbdf9849faef8e5125 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 18 Sep 2020 21:49:11 -0400 Subject: [PATCH 0798/1052] Record `tcx.def_span` instead of `item.span` in crate metadata This was missed in PR #75465. As a result, a few places have been using the full body span of functions, instead of just the header span. --- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- src/test/ui/consts/miri_unleashed/drop.stderr | 20 +++++++------------ src/test/ui/macros/same-sequence-span.stderr | 12 ++++------- .../ui/proc-macro/meta-macro-hygiene.stdout | 4 ++-- src/test/ui/proc-macro/meta-macro.stdout | 2 +- ...-38591-non-regular-dropck-recursion.stderr | 20 ++++--------------- src/test/ui/type_length_limit.stderr | 2 +- 7 files changed, 20 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index eb091d86b82c6..d5b0a868a364e 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1300,7 +1300,7 @@ impl EncodeContext<'a, 'tcx> { }); record!(self.tables.visibility[def_id] <- ty::Visibility::from_hir(&item.vis, item.hir_id, tcx)); - record!(self.tables.span[def_id] <- item.span); + record!(self.tables.span[def_id] <- self.tcx.def_span(def_id)); record!(self.tables.attributes[def_id] <- item.attrs); // FIXME(eddyb) there should be a nicer way to do this. match item.kind { diff --git a/src/test/ui/consts/miri_unleashed/drop.stderr b/src/test/ui/consts/miri_unleashed/drop.stderr index 8236250392fd6..eb1b42c57bc51 100644 --- a/src/test/ui/consts/miri_unleashed/drop.stderr +++ b/src/test/ui/consts/miri_unleashed/drop.stderr @@ -1,22 +1,16 @@ error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL | -LL | / pub unsafe fn drop_in_place(to_drop: *mut T) { -LL | | // Code here does not matter - this is replaced by the -LL | | // real drop glue by the compiler. -LL | | -LL | | // SAFETY: see comment above -LL | | unsafe { drop_in_place(to_drop) } -LL | | } - | | ^ - | | | - | |_calling non-const function ` as Drop>::drop` - | inside `drop_in_place::> - shim(Some(Vec))` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL +LL | pub unsafe fn drop_in_place(to_drop: *mut T) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | calling non-const function ` as Drop>::drop` + | inside `drop_in_place::> - shim(Some(Vec))` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL | ::: $DIR/drop.rs:18:1 | -LL | }; - | - inside `TEST_BAD` at $DIR/drop.rs:18:1 +LL | }; + | - inside `TEST_BAD` at $DIR/drop.rs:18:1 warning: skipping const checks | diff --git a/src/test/ui/macros/same-sequence-span.stderr b/src/test/ui/macros/same-sequence-span.stderr index 65b67a9423876..63b8b29d6ce28 100644 --- a/src/test/ui/macros/same-sequence-span.stderr +++ b/src/test/ui/macros/same-sequence-span.stderr @@ -17,15 +17,11 @@ LL | $(= $z:tt)* error: `$x:expr` may be followed by `$y:tt`, which is not allowed for `expr` fragments --> $DIR/same-sequence-span.rs:19:1 | -LL | proc_macro_sequence::make_foo!(); - | ^-------------------------------- - | | - | _in this macro invocation +LL | proc_macro_sequence::make_foo!(); + | ---------------------------------^^^^^^^^^^^^^ | | -LL | | -LL | | -LL | | fn main() {} -... | + | not allowed after `expr` fragments + | in this macro invocation | = note: allowed there are: `=>`, `,` or `;` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/proc-macro/meta-macro-hygiene.stdout b/src/test/ui/proc-macro/meta-macro-hygiene.stdout index e522bd258e14b..81cebae17aeba 100644 --- a/src/test/ui/proc-macro/meta-macro-hygiene.stdout +++ b/src/test/ui/proc-macro/meta-macro-hygiene.stdout @@ -1,6 +1,6 @@ -Def site: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#5) +Def site: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) Input: TokenStream [Ident { ident: "$crate", span: $DIR/meta-macro-hygiene.rs:24:37: 24:43 (#4) }, Punct { ch: ':', spacing: Joint, span: $DIR/meta-macro-hygiene.rs:24:43: 24:45 (#4) }, Punct { ch: ':', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:24:43: 24:45 (#4) }, Ident { ident: "dummy", span: $DIR/meta-macro-hygiene.rs:24:45: 24:50 (#4) }, Punct { ch: '!', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:24:50: 24:51 (#4) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/meta-macro-hygiene.rs:24:51: 24:53 (#4) }] -Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#5) }, Punct { ch: ':', spacing: Joint, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#5) }, Punct { ch: ':', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#5) }, Ident { ident: "dummy", span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#5) }, Punct { ch: '!', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#5) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#5) }] +Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) }, Punct { ch: ':', spacing: Joint, span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) }, Punct { ch: ':', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) }, Ident { ident: "dummy", span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) }, Punct { ch: '!', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) }] #![feature /* 0#0 */(prelude_import)] // ignore-tidy-linelength // aux-build:make-macro.rs diff --git a/src/test/ui/proc-macro/meta-macro.stdout b/src/test/ui/proc-macro/meta-macro.stdout index dddde482ef99b..662682d40b2c6 100644 --- a/src/test/ui/proc-macro/meta-macro.stdout +++ b/src/test/ui/proc-macro/meta-macro.stdout @@ -1,3 +1,3 @@ -Def site: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) +Def site: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) Input: TokenStream [] Respanned: TokenStream [] diff --git a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr index 3efe13b3de3d0..5bf381607c5ed 100644 --- a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr +++ b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr @@ -1,26 +1,14 @@ error: reached the recursion limit while instantiating `drop_in_place::))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL | -LL | / pub unsafe fn drop_in_place(to_drop: *mut T) { -LL | | // Code here does not matter - this is replaced by the -LL | | // real drop glue by the compiler. -LL | | -LL | | // SAFETY: see comment above -LL | | unsafe { drop_in_place(to_drop) } -LL | | } - | |_^ +LL | pub unsafe fn drop_in_place(to_drop: *mut T) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `drop_in_place` defined here --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL | -LL | / pub unsafe fn drop_in_place(to_drop: *mut T) { -LL | | // Code here does not matter - this is replaced by the -LL | | // real drop glue by the compiler. -LL | | -LL | | // SAFETY: see comment above -LL | | unsafe { drop_in_place(to_drop) } -LL | | } - | |_^ +LL | pub unsafe fn drop_in_place(to_drop: *mut T) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: the full type name has been written to '$TEST_BUILD_DIR/recursion/issue-38591-non-regular-dropck-recursion/issue-38591-non-regular-dropck-recursion.long-type.txt' error: aborting due to previous error diff --git a/src/test/ui/type_length_limit.stderr b/src/test/ui/type_length_limit.stderr index 1c0a596a64cb9..a2ddffff997d8 100644 --- a/src/test/ui/type_length_limit.stderr +++ b/src/test/ui/type_length_limit.stderr @@ -2,7 +2,7 @@ error: reached the type-length limit while instantiating `std::mem::drop:: $SRC_DIR/core/src/mem/mod.rs:LL:COL | LL | pub fn drop(_x: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ | = note: the full type name has been written to '$TEST_BUILD_DIR/type_length_limit/type_length_limit.long-type.txt' = help: consider adding a `#![type_length_limit="8"]` attribute to your crate From f5d71a9b3cf3018ec646acb6f8fa731fb8ca902e Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 30 Aug 2020 18:08:16 -0400 Subject: [PATCH 0799/1052] Don't use `zip` to compare iterators during pretty-print hack If the right-hand iterator has exactly one more element than the left-hand iterator, then both iterators will be fully consumed, but the extra element will never be compared. --- compiler/rustc_parse/src/lib.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 72a34b86ae20b..21bbdc9ba8dce 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -3,6 +3,7 @@ #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(bindings_after_at)] +#![feature(iter_order_by)] #![feature(or_patterns)] use rustc_ast as ast; @@ -459,14 +460,10 @@ pub fn tokenstream_probably_equal_for_proc_macro( // Break tokens after we expand any nonterminals, so that we break tokens // that are produced as a result of nonterminal expansion. - let mut t1 = first.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens); - let mut t2 = other.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens); - for (t1, t2) in t1.by_ref().zip(t2.by_ref()) { - if !tokentree_probably_equal_for_proc_macro(&t1, &t2, sess) { - return false; - } - } - t1.next().is_none() && t2.next().is_none() + let t1 = first.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens); + let t2 = other.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens); + + t1.eq_by(t2, |t1, t2| tokentree_probably_equal_for_proc_macro(&t1, &t2, sess)) } // See comments in `Nonterminal::to_tokenstream` for why we care about From bcc1d56917fe061071ebc539b5d2e304a44a7b00 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 21 Sep 2020 21:12:20 +0200 Subject: [PATCH 0800/1052] Test that AtomicU64::from_mut is not available on x86 linux. --- src/test/ui/atomic-from-mut-not-available.rs | 7 +++++++ src/test/ui/atomic-from-mut-not-available.stderr | 9 +++++++++ 2 files changed, 16 insertions(+) create mode 100644 src/test/ui/atomic-from-mut-not-available.rs create mode 100644 src/test/ui/atomic-from-mut-not-available.stderr diff --git a/src/test/ui/atomic-from-mut-not-available.rs b/src/test/ui/atomic-from-mut-not-available.rs new file mode 100644 index 0000000000000..bf94616007570 --- /dev/null +++ b/src/test/ui/atomic-from-mut-not-available.rs @@ -0,0 +1,7 @@ +// only-x86 +// only-linux + +fn main() { + core::sync::atomic::AtomicU64::from_mut(&mut 0u64); + //~^ ERROR: no function or associated item named `from_mut` found for struct `AtomicU64` +} diff --git a/src/test/ui/atomic-from-mut-not-available.stderr b/src/test/ui/atomic-from-mut-not-available.stderr new file mode 100644 index 0000000000000..d1ebca8a29e93 --- /dev/null +++ b/src/test/ui/atomic-from-mut-not-available.stderr @@ -0,0 +1,9 @@ +error[E0599]: no function or associated item named `from_mut` found for struct `AtomicU64` in the current scope + --> $DIR/atomic-from-mut-not-available.rs:5:36 + | +LL | core::sync::atomic::AtomicU64::from_mut(&mut 0u64); + | ^^^^^^^^ function or associated item not found in `AtomicU64` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. From 16eee2a04a4c3a93d398728d7a0c05a8afb6ca94 Mon Sep 17 00:00:00 2001 From: Erik Hofmayer Date: Mon, 21 Sep 2020 21:31:01 +0200 Subject: [PATCH 0801/1052] Applied review comments --- library/std/src/sync/mpsc/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs index d23a8161a229c..dc13c9433f121 100644 --- a/library/std/src/sync/mpsc/mod.rs +++ b/library/std/src/sync/mpsc/mod.rs @@ -1532,7 +1532,9 @@ impl error::Error for TrySendError { #[stable(feature = "mpsc_error_conversions", since = "1.24.0")] impl From> for TrySendError { /// Converts a `SendError` into a `TrySendError`. + /// /// This conversion always returns a `TrySendError::Disconnected` containing the data in the `SendError`. + /// /// No data is allocated on the heap. fn from(err: SendError) -> TrySendError { match err { @@ -1580,7 +1582,9 @@ impl error::Error for TryRecvError { #[stable(feature = "mpsc_error_conversions", since = "1.24.0")] impl From for TryRecvError { /// Converts a `RecvError` into a `TryRecvError`. + /// /// This conversion always returns `TryRecvError::Disconnected`. + /// /// No data is allocated on the heap. fn from(err: RecvError) -> TryRecvError { match err { @@ -1613,7 +1617,9 @@ impl error::Error for RecvTimeoutError { #[stable(feature = "mpsc_error_conversions", since = "1.24.0")] impl From for RecvTimeoutError { /// Converts a `RecvError` into a `RecvTimeoutError`. + /// /// This conversion always returns `RecvTimeoutError::Disconnected`. + /// /// No data is allocated on the heap. fn from(err: RecvError) -> RecvTimeoutError { match err { From 7a02ebd828c8d9c68e8e972326ede8696fb3f6b7 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 21 Sep 2020 21:50:00 +0200 Subject: [PATCH 0802/1052] bless tests --- .../const_evaluatable_checked/let-bindings.rs | 4 +-- .../let-bindings.stderr | 26 +++++++++++++------ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.rs b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.rs index d96788f8cd100..a6bb39208a42d 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.rs +++ b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.rs @@ -4,8 +4,8 @@ // We do not yet want to support let-bindings in abstract consts, // so this test should keep failing for now. fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - //~^ ERROR constant expression depends - //~| ERROR constant expression depends + //~^ ERROR overly complex generic constant + //~| ERROR overly complex generic constant Default::default() } diff --git a/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr index 95fb48bd43402..95fcde52af820 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr @@ -1,18 +1,28 @@ -error: constant expression depends on a generic parameter - --> $DIR/let-bindings.rs:6:91 +error: overly complex generic constant + --> $DIR/let-bindings.rs:6:68 | LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - | ^^^^^^^ required by this bound in `test::{{constant}}#0` + | ^^^^^^^^^^^^^^^^^^^^ | - = note: this may fail depending on what value the parameter takes +note: unsupported statement + --> $DIR/let-bindings.rs:6:74 + | +LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { + | ^ + = help: consider moving this anonymous constant into a `const` function -error: constant expression depends on a generic parameter - --> $DIR/let-bindings.rs:6:30 +error: overly complex generic constant + --> $DIR/let-bindings.rs:6:35 | LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ | - = note: this may fail depending on what value the parameter takes +note: unsupported statement + --> $DIR/let-bindings.rs:6:41 + | +LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { + | ^ + = help: consider moving this anonymous constant into a `const` function error: aborting due to 2 previous errors From 9a493ced748e2e3e7390fc6f28640d23cb90e67b Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 21 Sep 2020 22:01:18 +0200 Subject: [PATCH 0803/1052] add test for closures in abstract consts --- .../const_evaluatable_checked/closures.rs | 6 ++++++ .../const_evaluatable_checked/closures.stderr | 15 +++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/closures.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/closures.stderr diff --git a/src/test/ui/const-generics/const_evaluatable_checked/closures.rs b/src/test/ui/const-generics/const_evaluatable_checked/closures.rs new file mode 100644 index 0000000000000..32f43591e37b9 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/closures.rs @@ -0,0 +1,6 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] +fn test() -> [u8; N + (|| 42)()] {} +//~^ ERROR overly complex generic constant + +fn main() {} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/closures.stderr b/src/test/ui/const-generics/const_evaluatable_checked/closures.stderr new file mode 100644 index 0000000000000..7bb23f1488d93 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/closures.stderr @@ -0,0 +1,15 @@ +error: overly complex generic constant + --> $DIR/closures.rs:3:35 + | +LL | fn test() -> [u8; N + (|| 42)()] {} + | ^^^^^^^^^^^^^ + | +note: unsupported rvalue + --> $DIR/closures.rs:3:39 + | +LL | fn test() -> [u8; N + (|| 42)()] {} + | ^^^^^^^ + = help: consider moving this anonymous constant into a `const` function + +error: aborting due to previous error + From 2bb3844820434d460759c8bd89cdcb79bb1b1079 Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Sun, 13 Sep 2020 22:38:36 +0200 Subject: [PATCH 0804/1052] Add optimization to avoid load of address --- .../rustc_mir/src/transform/instcombine.rs | 117 +++++++++++++++++- .../const_prop/ref_deref.main.ConstProp.diff | 2 +- .../ref_deref_project.main.ConstProp.diff | 2 +- ...e_closure_borrows_arg.foo.Inline.after.mir | 20 +-- ...st_combine_deref.deep_opt.InstCombine.diff | 92 ++++++++++++++ ...e_deref.do_not_miscompile.InstCombine.diff | 85 +++++++++++++ ...st_combine_deref.dont_opt.InstCombine.diff | 53 ++++++++ ..._combine_deref.opt_struct.InstCombine.diff | 44 +++++++ src/test/mir-opt/inst_combine_deref.rs | 68 ++++++++++ ..._combine_deref.simple_opt.InstCombine.diff | 34 +++++ 10 files changed, 505 insertions(+), 12 deletions(-) create mode 100644 src/test/mir-opt/inst_combine_deref.deep_opt.InstCombine.diff create mode 100644 src/test/mir-opt/inst_combine_deref.do_not_miscompile.InstCombine.diff create mode 100644 src/test/mir-opt/inst_combine_deref.dont_opt.InstCombine.diff create mode 100644 src/test/mir-opt/inst_combine_deref.opt_struct.InstCombine.diff create mode 100644 src/test/mir-opt/inst_combine_deref.rs create mode 100644 src/test/mir-opt/inst_combine_deref.simple_opt.InstCombine.diff diff --git a/compiler/rustc_mir/src/transform/instcombine.rs b/compiler/rustc_mir/src/transform/instcombine.rs index b224df92e9da0..3ed0aea1404d4 100644 --- a/compiler/rustc_mir/src/transform/instcombine.rs +++ b/compiler/rustc_mir/src/transform/instcombine.rs @@ -4,9 +4,14 @@ use crate::transform::{MirPass, MirSource}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::Mutability; use rustc_index::vec::Idx; -use rustc_middle::mir::visit::{MutVisitor, Visitor}; use rustc_middle::mir::{ - BinOp, Body, Constant, Local, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, + visit::PlaceContext, + visit::{MutVisitor, Visitor}, + Statement, +}; +use rustc_middle::mir::{ + BinOp, Body, BorrowKind, Constant, Local, Location, Operand, Place, PlaceRef, ProjectionElem, + Rvalue, }; use rustc_middle::ty::{self, TyCtxt}; use std::mem; @@ -71,10 +76,36 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { *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)); + } + self.super_rvalue(rvalue, location) } } +struct MutatingUseVisitor { + has_mutating_use: bool, + local_to_look_for: Local, +} + +impl MutatingUseVisitor { + fn has_mutating_use_in_stmt(local: Local, stmt: &Statement<'tcx>, location: Location) -> bool { + let mut _self = Self { has_mutating_use: false, local_to_look_for: local }; + _self.visit_statement(stmt, location); + _self.has_mutating_use + } +} + +impl<'tcx> Visitor<'tcx> for MutatingUseVisitor { + fn visit_local(&mut self, local: &Local, context: PlaceContext, _: Location) { + if *local == self.local_to_look_for { + self.has_mutating_use |= context.is_mutating_use(); + } + } +} + /// Finds optimization opportunities on the MIR. struct OptimizationFinder<'b, 'tcx> { body: &'b Body<'tcx>, @@ -87,6 +118,85 @@ impl OptimizationFinder<'b, 'tcx> { OptimizationFinder { body, tcx, optimizations: OptimizationList::default() } } + fn find_deref_of_address(&mut self, rvalue: &Rvalue<'tcx>, location: Location) -> Option<()> { + // Look for the sequence + // + // _2 = &_1; + // ... + // _5 = (*_2); + // + // which we can replace the last statement with `_5 = _1;` to avoid the load of `_2`. + if let Rvalue::Use(op) = rvalue { + let local_being_derefed = match op.place()?.as_ref() { + PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(local), + _ => None, + }?; + + let stmt_index = location.statement_index; + // Look behind for statement that assigns the local from a address of operator. + // 6 is chosen as a heuristic determined by seeing the number of times + // the optimization kicked in compiling rust std. + let lower_index = stmt_index.saturating_sub(6); + let statements_to_look_in = self.body.basic_blocks()[location.block].statements + [lower_index..stmt_index] + .iter() + .rev(); + for stmt in statements_to_look_in { + match &stmt.kind { + // Exhaustive match on statements to detect conditions that warrant we bail out of the optimization. + rustc_middle::mir::StatementKind::Assign(box (l, r)) + if l.local == local_being_derefed => + { + match r { + // Looking for immutable reference e.g _local_being_deref = &_1; + Rvalue::Ref( + _, + // Only apply the optimization if it is an immutable borrow. + BorrowKind::Shared, + place_taken_address_of, + ) => { + self.optimizations + .unneeded_deref + .insert(location, *place_taken_address_of); + return Some(()); + } + + // We found an assignment of `local_being_deref` that is not an immutable ref, e.g the following sequence + // _2 = &_1; + // _3 = &5 + // _2 = _3; <-- this means it is no longer valid to replace the last statement with `_5 = _1;` + // _5 = (*_2); + _ => return None, + } + } + + // Inline asm can do anything, so bail out of the optimization. + rustc_middle::mir::StatementKind::LlvmInlineAsm(_) => return None, + + // Check that `local_being_deref` is not being used in a mutating way which can cause misoptimization. + rustc_middle::mir::StatementKind::Assign(box (_, _)) + | rustc_middle::mir::StatementKind::Coverage(_) + | rustc_middle::mir::StatementKind::Nop + | rustc_middle::mir::StatementKind::FakeRead(_, _) + | rustc_middle::mir::StatementKind::StorageLive(_) + | rustc_middle::mir::StatementKind::StorageDead(_) + | rustc_middle::mir::StatementKind::Retag(_, _) + | rustc_middle::mir::StatementKind::AscribeUserType(_, _) + | rustc_middle::mir::StatementKind::SetDiscriminant { .. } => { + if MutatingUseVisitor::has_mutating_use_in_stmt( + local_being_derefed, + stmt, + location, + ) { + return None; + } + } + } + } + } + Some(()) + } + fn find_unneeded_equality_comparison(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { // find Ne(_place, false) or Ne(false, _place) // or Eq(_place, true) or Eq(true, _place) @@ -153,6 +263,8 @@ impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> { } } + let _ = self.find_deref_of_address(rvalue, location); + self.find_unneeded_equality_comparison(rvalue, location); self.super_rvalue(rvalue, location) @@ -164,4 +276,5 @@ struct OptimizationList<'tcx> { and_stars: FxHashSet, arrays_lengths: FxHashMap>, unneeded_equality_comparison: FxHashMap>, + unneeded_deref: FxHashMap>, } diff --git a/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff index 31061233eeecc..e8168c98f0bcd 100644 --- a/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff @@ -19,7 +19,7 @@ // + span: $DIR/ref_deref.rs:5:6: 5:10 // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } _2 = _4; // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 -- _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10 +- _1 = (*_4); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10 + _1 = const 4_i32; // scope 0 at $DIR/ref_deref.rs:5:5: 5:10 StorageDead(_2); // scope 0 at $DIR/ref_deref.rs:5:10: 5:11 StorageDead(_1); // scope 0 at $DIR/ref_deref.rs:5:10: 5:11 diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff index e9398df1320ff..fd6388b95e477 100644 --- a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff @@ -19,7 +19,7 @@ // + span: $DIR/ref_deref_project.rs:5:6: 5:17 // + literal: Const { ty: &(i32, i32), val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 - _1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17 + _1 = ((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17 StorageDead(_2); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18 StorageDead(_1); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18 _0 = const (); // scope 0 at $DIR/ref_deref_project.rs:4:11: 6:2 diff --git a/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir index 7475be30c0dff..c49e0218327de 100644 --- a/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir @@ -9,13 +9,14 @@ fn foo(_1: T, _2: &i32) -> i32 { let mut _5: (&i32, &i32); // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 let mut _6: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:7: 16:8 let mut _7: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:10: 16:11 - let mut _8: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 let mut _9: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + let mut _10: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 scope 1 { debug x => _3; // in scope 1 at $DIR/inline-closure-borrows-arg.rs:12:9: 12:10 scope 2 { - debug r => _8; // in scope 2 at $DIR/inline-closure-borrows-arg.rs:12:14: 12:15 - debug _s => _9; // in scope 2 at $DIR/inline-closure-borrows-arg.rs:12:23: 12:25 + debug r => _9; // in scope 2 at $DIR/inline-closure-borrows-arg.rs:12:14: 12:15 + debug _s => _10; // in scope 2 at $DIR/inline-closure-borrows-arg.rs:12:23: 12:25 + let _8: &i32; // in scope 2 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 } } scope 3 { @@ -33,13 +34,16 @@ fn foo(_1: T, _2: &i32) -> i32 { _7 = &(*_2); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:10: 16:11 (_5.0: &i32) = move _6; // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 (_5.1: &i32) = move _7; // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 - StorageLive(_8); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 - _8 = move (_5.0: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 StorageLive(_9); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 - _9 = move (_5.1: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 - _0 = (*_8); // scope 3 at $DIR/inline-closure-borrows-arg.rs:14:9: 14:18 + _9 = move (_5.0: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + StorageLive(_10); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + _10 = move (_5.1: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + StorageLive(_8); // scope 2 at $DIR/inline-closure-borrows-arg.rs:13:13: 13:21 + _8 = _9; // scope 2 at $DIR/inline-closure-borrows-arg.rs:13:24: 13:27 + _0 = (*_9); // scope 3 at $DIR/inline-closure-borrows-arg.rs:14:9: 14:18 + StorageDead(_8); // scope 2 at $DIR/inline-closure-borrows-arg.rs:15:5: 15:6 + StorageDead(_10); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 StorageDead(_9); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 - StorageDead(_8); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 StorageDead(_7); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12 StorageDead(_6); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12 StorageDead(_5); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12 diff --git a/src/test/mir-opt/inst_combine_deref.deep_opt.InstCombine.diff b/src/test/mir-opt/inst_combine_deref.deep_opt.InstCombine.diff new file mode 100644 index 0000000000000..dad98044756bd --- /dev/null +++ b/src/test/mir-opt/inst_combine_deref.deep_opt.InstCombine.diff @@ -0,0 +1,92 @@ +- // MIR for `deep_opt` before InstCombine ++ // MIR for `deep_opt` after InstCombine + + fn deep_opt() -> (u64, u64, u64) { + let mut _0: (u64, u64, u64); // return place in scope 0 at $DIR/inst_combine_deref.rs:10:18: 10:33 + let _1: u64; // in scope 0 at $DIR/inst_combine_deref.rs:11:9: 11:11 + let mut _10: u64; // in scope 0 at $DIR/inst_combine_deref.rs:20:6: 20:8 + let mut _11: u64; // in scope 0 at $DIR/inst_combine_deref.rs:20:10: 20:12 + let mut _12: u64; // in scope 0 at $DIR/inst_combine_deref.rs:20:14: 20:16 + scope 1 { + debug x1 => _1; // in scope 1 at $DIR/inst_combine_deref.rs:11:9: 11:11 + let _2: u64; // in scope 1 at $DIR/inst_combine_deref.rs:12:9: 12:11 + scope 2 { + debug x2 => _2; // in scope 2 at $DIR/inst_combine_deref.rs:12:9: 12:11 + let _3: u64; // in scope 2 at $DIR/inst_combine_deref.rs:13:9: 13:11 + scope 3 { + debug x3 => _3; // in scope 3 at $DIR/inst_combine_deref.rs:13:9: 13:11 + let _4: &u64; // in scope 3 at $DIR/inst_combine_deref.rs:14:9: 14:11 + scope 4 { + debug y1 => _4; // in scope 4 at $DIR/inst_combine_deref.rs:14:9: 14:11 + let _5: &u64; // in scope 4 at $DIR/inst_combine_deref.rs:15:9: 15:11 + scope 5 { + debug y2 => _5; // in scope 5 at $DIR/inst_combine_deref.rs:15:9: 15:11 + let _6: &u64; // in scope 5 at $DIR/inst_combine_deref.rs:16:9: 16:11 + scope 6 { + debug y3 => _6; // in scope 6 at $DIR/inst_combine_deref.rs:16:9: 16:11 + let _7: u64; // in scope 6 at $DIR/inst_combine_deref.rs:17:9: 17:11 + scope 7 { + debug z1 => _7; // in scope 7 at $DIR/inst_combine_deref.rs:17:9: 17:11 + let _8: u64; // in scope 7 at $DIR/inst_combine_deref.rs:18:9: 18:11 + scope 8 { + debug z2 => _8; // in scope 8 at $DIR/inst_combine_deref.rs:18:9: 18:11 + let _9: u64; // in scope 8 at $DIR/inst_combine_deref.rs:19:9: 19:11 + scope 9 { + debug z3 => _9; // in scope 9 at $DIR/inst_combine_deref.rs:19:9: 19:11 + } + } + } + } + } + } + } + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inst_combine_deref.rs:11:9: 11:11 + _1 = const 1_u64; // scope 0 at $DIR/inst_combine_deref.rs:11:14: 11:15 + StorageLive(_2); // scope 1 at $DIR/inst_combine_deref.rs:12:9: 12:11 + _2 = const 2_u64; // scope 1 at $DIR/inst_combine_deref.rs:12:14: 12:15 + StorageLive(_3); // scope 2 at $DIR/inst_combine_deref.rs:13:9: 13:11 + _3 = const 3_u64; // scope 2 at $DIR/inst_combine_deref.rs:13:14: 13:15 + StorageLive(_4); // scope 3 at $DIR/inst_combine_deref.rs:14:9: 14:11 + _4 = &_1; // scope 3 at $DIR/inst_combine_deref.rs:14:14: 14:17 + StorageLive(_5); // scope 4 at $DIR/inst_combine_deref.rs:15:9: 15:11 + _5 = &_2; // scope 4 at $DIR/inst_combine_deref.rs:15:14: 15:17 + StorageLive(_6); // scope 5 at $DIR/inst_combine_deref.rs:16:9: 16:11 + _6 = &_3; // scope 5 at $DIR/inst_combine_deref.rs:16:14: 16:17 + StorageLive(_7); // scope 6 at $DIR/inst_combine_deref.rs:17:9: 17:11 +- _7 = (*_4); // scope 6 at $DIR/inst_combine_deref.rs:17:14: 17:17 ++ _7 = _1; // scope 6 at $DIR/inst_combine_deref.rs:17:14: 17:17 + StorageLive(_8); // scope 7 at $DIR/inst_combine_deref.rs:18:9: 18:11 +- _8 = (*_5); // scope 7 at $DIR/inst_combine_deref.rs:18:14: 18:17 ++ _8 = _2; // scope 7 at $DIR/inst_combine_deref.rs:18:14: 18:17 + StorageLive(_9); // scope 8 at $DIR/inst_combine_deref.rs:19:9: 19:11 +- _9 = (*_6); // scope 8 at $DIR/inst_combine_deref.rs:19:14: 19:17 ++ _9 = _3; // scope 8 at $DIR/inst_combine_deref.rs:19:14: 19:17 + StorageLive(_10); // scope 9 at $DIR/inst_combine_deref.rs:20:6: 20:8 + _10 = _7; // scope 9 at $DIR/inst_combine_deref.rs:20:6: 20:8 + StorageLive(_11); // scope 9 at $DIR/inst_combine_deref.rs:20:10: 20:12 + _11 = _8; // scope 9 at $DIR/inst_combine_deref.rs:20:10: 20:12 + StorageLive(_12); // scope 9 at $DIR/inst_combine_deref.rs:20:14: 20:16 + _12 = _9; // scope 9 at $DIR/inst_combine_deref.rs:20:14: 20:16 + (_0.0: u64) = move _10; // scope 9 at $DIR/inst_combine_deref.rs:20:5: 20:17 + (_0.1: u64) = move _11; // scope 9 at $DIR/inst_combine_deref.rs:20:5: 20:17 + (_0.2: u64) = move _12; // scope 9 at $DIR/inst_combine_deref.rs:20:5: 20:17 + StorageDead(_12); // scope 9 at $DIR/inst_combine_deref.rs:20:16: 20:17 + StorageDead(_11); // scope 9 at $DIR/inst_combine_deref.rs:20:16: 20:17 + StorageDead(_10); // scope 9 at $DIR/inst_combine_deref.rs:20:16: 20:17 + StorageDead(_9); // scope 8 at $DIR/inst_combine_deref.rs:21:1: 21:2 + StorageDead(_8); // scope 7 at $DIR/inst_combine_deref.rs:21:1: 21:2 + StorageDead(_7); // scope 6 at $DIR/inst_combine_deref.rs:21:1: 21:2 + StorageDead(_6); // scope 5 at $DIR/inst_combine_deref.rs:21:1: 21:2 + StorageDead(_5); // scope 4 at $DIR/inst_combine_deref.rs:21:1: 21:2 + StorageDead(_4); // scope 3 at $DIR/inst_combine_deref.rs:21:1: 21:2 + StorageDead(_3); // scope 2 at $DIR/inst_combine_deref.rs:21:1: 21:2 + StorageDead(_2); // scope 1 at $DIR/inst_combine_deref.rs:21:1: 21:2 + StorageDead(_1); // scope 0 at $DIR/inst_combine_deref.rs:21:1: 21:2 + return; // scope 0 at $DIR/inst_combine_deref.rs:21:2: 21:2 + } + } + diff --git a/src/test/mir-opt/inst_combine_deref.do_not_miscompile.InstCombine.diff b/src/test/mir-opt/inst_combine_deref.do_not_miscompile.InstCombine.diff new file mode 100644 index 0000000000000..c32bf256da408 --- /dev/null +++ b/src/test/mir-opt/inst_combine_deref.do_not_miscompile.InstCombine.diff @@ -0,0 +1,85 @@ +- // MIR for `do_not_miscompile` before InstCombine ++ // MIR for `do_not_miscompile` after InstCombine + + fn do_not_miscompile() -> () { + let mut _0: (); // return place in scope 0 at $DIR/inst_combine_deref.rs:53:24: 53:24 + let _1: i32; // in scope 0 at $DIR/inst_combine_deref.rs:54:9: 54:10 + let mut _5: &i32; // in scope 0 at $DIR/inst_combine_deref.rs:58:10: 58:12 + let _6: &i32; // in scope 0 at $DIR/inst_combine_deref.rs:58:10: 58:12 + let _7: (); // in scope 0 at $DIR/inst_combine_deref.rs:59:5: 59:23 + let mut _8: bool; // in scope 0 at $DIR/inst_combine_deref.rs:59:5: 59:23 + let mut _9: bool; // in scope 0 at $DIR/inst_combine_deref.rs:59:13: 59:21 + let mut _10: i32; // in scope 0 at $DIR/inst_combine_deref.rs:59:13: 59:15 + let mut _11: !; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + scope 1 { + debug x => _1; // in scope 1 at $DIR/inst_combine_deref.rs:54:9: 54:10 + let _2: i32; // in scope 1 at $DIR/inst_combine_deref.rs:55:9: 55:10 + scope 2 { + debug a => _2; // in scope 2 at $DIR/inst_combine_deref.rs:55:9: 55:10 + let mut _3: &i32; // in scope 2 at $DIR/inst_combine_deref.rs:56:9: 56:14 + scope 3 { + debug y => _3; // in scope 3 at $DIR/inst_combine_deref.rs:56:9: 56:14 + let _4: &mut &i32; // in scope 3 at $DIR/inst_combine_deref.rs:57:9: 57:10 + scope 4 { + debug z => _4; // in scope 4 at $DIR/inst_combine_deref.rs:57:9: 57:10 + } + } + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inst_combine_deref.rs:54:9: 54:10 + _1 = const 42_i32; // scope 0 at $DIR/inst_combine_deref.rs:54:13: 54:15 + StorageLive(_2); // scope 1 at $DIR/inst_combine_deref.rs:55:9: 55:10 + _2 = const 99_i32; // scope 1 at $DIR/inst_combine_deref.rs:55:13: 55:15 + StorageLive(_3); // scope 2 at $DIR/inst_combine_deref.rs:56:9: 56:14 + _3 = &_1; // scope 2 at $DIR/inst_combine_deref.rs:56:17: 56:19 + StorageLive(_4); // scope 3 at $DIR/inst_combine_deref.rs:57:9: 57:10 + _4 = &mut _3; // scope 3 at $DIR/inst_combine_deref.rs:57:13: 57:19 + StorageLive(_5); // scope 4 at $DIR/inst_combine_deref.rs:58:10: 58:12 + StorageLive(_6); // scope 4 at $DIR/inst_combine_deref.rs:58:10: 58:12 + _6 = &_2; // scope 4 at $DIR/inst_combine_deref.rs:58:10: 58:12 +- _5 = &(*_6); // scope 4 at $DIR/inst_combine_deref.rs:58:10: 58:12 ++ _5 = _6; // scope 4 at $DIR/inst_combine_deref.rs:58:10: 58:12 + (*_4) = move _5; // scope 4 at $DIR/inst_combine_deref.rs:58:5: 58:12 + StorageDead(_5); // scope 4 at $DIR/inst_combine_deref.rs:58:11: 58:12 + StorageDead(_6); // scope 4 at $DIR/inst_combine_deref.rs:58:12: 58:13 + StorageLive(_7); // scope 4 at $DIR/inst_combine_deref.rs:59:5: 59:23 + StorageLive(_8); // scope 4 at $DIR/inst_combine_deref.rs:59:5: 59:23 + StorageLive(_9); // scope 4 at $DIR/inst_combine_deref.rs:59:13: 59:21 + StorageLive(_10); // scope 4 at $DIR/inst_combine_deref.rs:59:13: 59:15 + _10 = (*_3); // scope 4 at $DIR/inst_combine_deref.rs:59:13: 59:15 + _9 = Eq(move _10, const 99_i32); // scope 4 at $DIR/inst_combine_deref.rs:59:13: 59:21 + StorageDead(_10); // scope 4 at $DIR/inst_combine_deref.rs:59:20: 59:21 + _8 = Not(move _9); // scope 4 at $DIR/inst_combine_deref.rs:59:5: 59:23 + StorageDead(_9); // scope 4 at $DIR/inst_combine_deref.rs:59:22: 59:23 + switchInt(_8) -> [false: bb1, otherwise: bb2]; // scope 4 at $DIR/inst_combine_deref.rs:59:5: 59:23 + } + + bb1: { + _7 = const (); // scope 4 at $DIR/inst_combine_deref.rs:59:5: 59:23 + StorageDead(_8); // scope 4 at $DIR/inst_combine_deref.rs:59:22: 59:23 + StorageDead(_7); // scope 4 at $DIR/inst_combine_deref.rs:59:22: 59:23 + _0 = const (); // scope 0 at $DIR/inst_combine_deref.rs:53:24: 60:2 + StorageDead(_4); // scope 3 at $DIR/inst_combine_deref.rs:60:1: 60:2 + StorageDead(_3); // scope 2 at $DIR/inst_combine_deref.rs:60:1: 60:2 + StorageDead(_2); // scope 1 at $DIR/inst_combine_deref.rs:60:1: 60:2 + StorageDead(_1); // scope 0 at $DIR/inst_combine_deref.rs:60:1: 60:2 + return; // scope 0 at $DIR/inst_combine_deref.rs:60:2: 60:2 + } + + 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 + // mir::Constant + // + span: $SRC_DIR/std/src/macros.rs:LL:COL + // + literal: Const { ty: fn(&str) -> ! {std::rt::begin_panic::<&str>}, val: Value(Scalar()) } + // 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 }) + // mir::Constant + // + span: $DIR/inst_combine_deref.rs:1:1: 1:1 + // + literal: 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 }) } + } + } + diff --git a/src/test/mir-opt/inst_combine_deref.dont_opt.InstCombine.diff b/src/test/mir-opt/inst_combine_deref.dont_opt.InstCombine.diff new file mode 100644 index 0000000000000..668766714f93d --- /dev/null +++ b/src/test/mir-opt/inst_combine_deref.dont_opt.InstCombine.diff @@ -0,0 +1,53 @@ +- // MIR for `dont_opt` before InstCombine ++ // MIR for `dont_opt` after InstCombine + + fn dont_opt() -> u64 { + let mut _0: u64; // return place in scope 0 at $DIR/inst_combine_deref.rs:42:18: 42:21 + let _1: i32; // in scope 0 at $DIR/inst_combine_deref.rs:43:9: 43:10 + let mut _5: &i32; // in scope 0 at $DIR/inst_combine_deref.rs:47:10: 47:14 + scope 1 { + debug y => _1; // in scope 1 at $DIR/inst_combine_deref.rs:43:9: 43:10 + let _2: &i32; // in scope 1 at $DIR/inst_combine_deref.rs:44:9: 44:13 + scope 2 { + debug _ref => _2; // in scope 2 at $DIR/inst_combine_deref.rs:44:9: 44:13 + let _3: i32; // in scope 2 at $DIR/inst_combine_deref.rs:45:9: 45:10 + scope 3 { + debug x => _3; // in scope 3 at $DIR/inst_combine_deref.rs:45:9: 45:10 + let mut _4: &i32; // in scope 3 at $DIR/inst_combine_deref.rs:46:9: 46:15 + scope 4 { + debug _1 => _4; // in scope 4 at $DIR/inst_combine_deref.rs:46:9: 46:15 + let _6: i32; // in scope 4 at $DIR/inst_combine_deref.rs:48:9: 48:11 + scope 5 { + debug _4 => _6; // in scope 5 at $DIR/inst_combine_deref.rs:48:9: 48:11 + } + } + } + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inst_combine_deref.rs:43:9: 43:10 + _1 = const 5_i32; // scope 0 at $DIR/inst_combine_deref.rs:43:13: 43:14 + StorageLive(_2); // scope 1 at $DIR/inst_combine_deref.rs:44:9: 44:13 + _2 = &_1; // scope 1 at $DIR/inst_combine_deref.rs:44:16: 44:18 + StorageLive(_3); // scope 2 at $DIR/inst_combine_deref.rs:45:9: 45:10 + _3 = const 5_i32; // scope 2 at $DIR/inst_combine_deref.rs:45:13: 45:14 + StorageLive(_4); // scope 3 at $DIR/inst_combine_deref.rs:46:9: 46:15 + _4 = &_3; // scope 3 at $DIR/inst_combine_deref.rs:46:18: 46:20 + StorageLive(_5); // scope 4 at $DIR/inst_combine_deref.rs:47:10: 47:14 +- _5 = &(*_2); // scope 4 at $DIR/inst_combine_deref.rs:47:10: 47:14 ++ _5 = _2; // scope 4 at $DIR/inst_combine_deref.rs:47:10: 47:14 + _4 = move _5; // scope 4 at $DIR/inst_combine_deref.rs:47:5: 47:14 + StorageDead(_5); // scope 4 at $DIR/inst_combine_deref.rs:47:13: 47:14 + StorageLive(_6); // scope 4 at $DIR/inst_combine_deref.rs:48:9: 48:11 + _6 = (*_4); // scope 4 at $DIR/inst_combine_deref.rs:48:14: 48:17 + _0 = const 0_u64; // scope 5 at $DIR/inst_combine_deref.rs:49:5: 49:6 + StorageDead(_6); // scope 4 at $DIR/inst_combine_deref.rs:50:1: 50:2 + StorageDead(_4); // scope 3 at $DIR/inst_combine_deref.rs:50:1: 50:2 + StorageDead(_3); // scope 2 at $DIR/inst_combine_deref.rs:50:1: 50:2 + StorageDead(_2); // scope 1 at $DIR/inst_combine_deref.rs:50:1: 50:2 + StorageDead(_1); // scope 0 at $DIR/inst_combine_deref.rs:50:1: 50:2 + return; // scope 0 at $DIR/inst_combine_deref.rs:50:2: 50:2 + } + } + diff --git a/src/test/mir-opt/inst_combine_deref.opt_struct.InstCombine.diff b/src/test/mir-opt/inst_combine_deref.opt_struct.InstCombine.diff new file mode 100644 index 0000000000000..e7d8c2e020256 --- /dev/null +++ b/src/test/mir-opt/inst_combine_deref.opt_struct.InstCombine.diff @@ -0,0 +1,44 @@ +- // MIR for `opt_struct` before InstCombine ++ // MIR for `opt_struct` after InstCombine + + fn opt_struct(_1: S) -> u64 { + debug s => _1; // in scope 0 at $DIR/inst_combine_deref.rs:29:15: 29:16 + let mut _0: u64; // return place in scope 0 at $DIR/inst_combine_deref.rs:29:24: 29:27 + let _2: &u64; // in scope 0 at $DIR/inst_combine_deref.rs:30:9: 30:10 + let mut _5: u64; // in scope 0 at $DIR/inst_combine_deref.rs:33:5: 33:7 + let mut _6: u64; // in scope 0 at $DIR/inst_combine_deref.rs:33:10: 33:11 + scope 1 { + debug a => _2; // in scope 1 at $DIR/inst_combine_deref.rs:30:9: 30:10 + let _3: &u64; // in scope 1 at $DIR/inst_combine_deref.rs:31:9: 31:10 + scope 2 { + debug b => _3; // in scope 2 at $DIR/inst_combine_deref.rs:31:9: 31:10 + let _4: u64; // in scope 2 at $DIR/inst_combine_deref.rs:32:9: 32:10 + scope 3 { + debug x => _4; // in scope 3 at $DIR/inst_combine_deref.rs:32:9: 32:10 + } + } + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/inst_combine_deref.rs:30:9: 30:10 + _2 = &(_1.0: u64); // scope 0 at $DIR/inst_combine_deref.rs:30:13: 30:17 + StorageLive(_3); // scope 1 at $DIR/inst_combine_deref.rs:31:9: 31:10 + _3 = &(_1.1: u64); // scope 1 at $DIR/inst_combine_deref.rs:31:13: 31:17 + StorageLive(_4); // scope 2 at $DIR/inst_combine_deref.rs:32:9: 32:10 +- _4 = (*_2); // scope 2 at $DIR/inst_combine_deref.rs:32:13: 32:15 ++ _4 = (_1.0: u64); // scope 2 at $DIR/inst_combine_deref.rs:32:13: 32:15 + StorageLive(_5); // scope 3 at $DIR/inst_combine_deref.rs:33:5: 33:7 +- _5 = (*_3); // scope 3 at $DIR/inst_combine_deref.rs:33:5: 33:7 ++ _5 = (_1.1: u64); // scope 3 at $DIR/inst_combine_deref.rs:33:5: 33:7 + StorageLive(_6); // scope 3 at $DIR/inst_combine_deref.rs:33:10: 33:11 + _6 = _4; // scope 3 at $DIR/inst_combine_deref.rs:33:10: 33:11 + _0 = Add(move _5, move _6); // scope 3 at $DIR/inst_combine_deref.rs:33:5: 33:11 + StorageDead(_6); // scope 3 at $DIR/inst_combine_deref.rs:33:10: 33:11 + StorageDead(_5); // scope 3 at $DIR/inst_combine_deref.rs:33:10: 33:11 + StorageDead(_4); // scope 2 at $DIR/inst_combine_deref.rs:34:1: 34:2 + StorageDead(_3); // scope 1 at $DIR/inst_combine_deref.rs:34:1: 34:2 + StorageDead(_2); // scope 0 at $DIR/inst_combine_deref.rs:34:1: 34:2 + return; // scope 0 at $DIR/inst_combine_deref.rs:34:2: 34:2 + } + } + diff --git a/src/test/mir-opt/inst_combine_deref.rs b/src/test/mir-opt/inst_combine_deref.rs new file mode 100644 index 0000000000000..896ae676c4f47 --- /dev/null +++ b/src/test/mir-opt/inst_combine_deref.rs @@ -0,0 +1,68 @@ +// EMIT_MIR inst_combine_deref.simple_opt.InstCombine.diff +fn simple_opt() -> u64 { + let x = 5; + let y = &x; + let z = *y; + z +} + +// EMIT_MIR inst_combine_deref.deep_opt.InstCombine.diff +fn deep_opt() -> (u64, u64, u64) { + let x1 = 1; + let x2 = 2; + let x3 = 3; + let y1 = &x1; + let y2 = &x2; + let y3 = &x3; + let z1 = *y1; + let z2 = *y2; + let z3 = *y3; + (z1, z2, z3) +} + +struct S { + a: u64, + b: u64, +} + +// EMIT_MIR inst_combine_deref.opt_struct.InstCombine.diff +fn opt_struct(s: S) -> u64 { + let a = &s.a; + let b = &s.b; + let x = *a; + *b + x +} + +// EMIT_MIR inst_combine_deref.dont_opt.InstCombine.diff +// do not optimize a sequence looking like this: +// _1 = &_2; +// _1 = _3; +// _4 = *_1; +// as the _1 = _3 assignment makes it not legal to replace the last statement with _4 = _2 +fn dont_opt() -> u64 { + let y = 5; + let _ref = &y; + let x = 5; + let mut _1 = &x; + _1 = _ref; + let _4 = *_1; + 0 +} + +// EMIT_MIR inst_combine_deref.do_not_miscompile.InstCombine.diff +fn do_not_miscompile() { + let x = 42; + let a = 99; + let mut y = &x; + let z = &mut y; + *z = &a; + assert!(*y == 99); +} + +fn main() { + simple_opt(); + deep_opt(); + opt_struct(S { a: 0, b: 1 }); + dont_opt(); + do_not_miscompile(); +} diff --git a/src/test/mir-opt/inst_combine_deref.simple_opt.InstCombine.diff b/src/test/mir-opt/inst_combine_deref.simple_opt.InstCombine.diff new file mode 100644 index 0000000000000..ea14aefda4bfb --- /dev/null +++ b/src/test/mir-opt/inst_combine_deref.simple_opt.InstCombine.diff @@ -0,0 +1,34 @@ +- // MIR for `simple_opt` before InstCombine ++ // MIR for `simple_opt` after InstCombine + + fn simple_opt() -> u64 { + let mut _0: u64; // return place in scope 0 at $DIR/inst_combine_deref.rs:2:20: 2:23 + let _1: u64; // in scope 0 at $DIR/inst_combine_deref.rs:3:9: 3:10 + scope 1 { + debug x => _1; // in scope 1 at $DIR/inst_combine_deref.rs:3:9: 3:10 + let _2: &u64; // in scope 1 at $DIR/inst_combine_deref.rs:4:9: 4:10 + scope 2 { + debug y => _2; // in scope 2 at $DIR/inst_combine_deref.rs:4:9: 4:10 + let _3: u64; // in scope 2 at $DIR/inst_combine_deref.rs:5:9: 5:10 + scope 3 { + debug z => _3; // in scope 3 at $DIR/inst_combine_deref.rs:5:9: 5:10 + } + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inst_combine_deref.rs:3:9: 3:10 + _1 = const 5_u64; // scope 0 at $DIR/inst_combine_deref.rs:3:13: 3:14 + StorageLive(_2); // scope 1 at $DIR/inst_combine_deref.rs:4:9: 4:10 + _2 = &_1; // scope 1 at $DIR/inst_combine_deref.rs:4:13: 4:15 + StorageLive(_3); // scope 2 at $DIR/inst_combine_deref.rs:5:9: 5:10 +- _3 = (*_2); // scope 2 at $DIR/inst_combine_deref.rs:5:13: 5:15 ++ _3 = _1; // scope 2 at $DIR/inst_combine_deref.rs:5:13: 5:15 + _0 = _3; // scope 3 at $DIR/inst_combine_deref.rs:6:5: 6:6 + StorageDead(_3); // scope 2 at $DIR/inst_combine_deref.rs:7:1: 7:2 + StorageDead(_2); // scope 1 at $DIR/inst_combine_deref.rs:7:1: 7:2 + StorageDead(_1); // scope 0 at $DIR/inst_combine_deref.rs:7:1: 7:2 + return; // scope 0 at $DIR/inst_combine_deref.rs:7:2: 7:2 + } + } + From dfc469ddae5b13a611f70eef27e6d60dbbce3445 Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Mon, 21 Sep 2020 22:15:30 +0200 Subject: [PATCH 0805/1052] Run the test with explicit -O such that Add is generated instead of CheckedAdd This makes the test run deterministic regardless of noopt testruns --- ...st_combine_deref.deep_opt.InstCombine.diff | 130 +++++++++--------- ...e_deref.do_not_miscompile.InstCombine.diff | 100 +++++++------- ...st_combine_deref.dont_opt.InstCombine.diff | 68 ++++----- ..._combine_deref.opt_struct.InstCombine.diff | 58 ++++---- src/test/mir-opt/inst_combine_deref.rs | 1 + ..._combine_deref.simple_opt.InstCombine.diff | 38 ++--- 6 files changed, 198 insertions(+), 197 deletions(-) diff --git a/src/test/mir-opt/inst_combine_deref.deep_opt.InstCombine.diff b/src/test/mir-opt/inst_combine_deref.deep_opt.InstCombine.diff index dad98044756bd..1d20e17a8499b 100644 --- a/src/test/mir-opt/inst_combine_deref.deep_opt.InstCombine.diff +++ b/src/test/mir-opt/inst_combine_deref.deep_opt.InstCombine.diff @@ -2,37 +2,37 @@ + // MIR for `deep_opt` after InstCombine fn deep_opt() -> (u64, u64, u64) { - let mut _0: (u64, u64, u64); // return place in scope 0 at $DIR/inst_combine_deref.rs:10:18: 10:33 - let _1: u64; // in scope 0 at $DIR/inst_combine_deref.rs:11:9: 11:11 - let mut _10: u64; // in scope 0 at $DIR/inst_combine_deref.rs:20:6: 20:8 - let mut _11: u64; // in scope 0 at $DIR/inst_combine_deref.rs:20:10: 20:12 - let mut _12: u64; // in scope 0 at $DIR/inst_combine_deref.rs:20:14: 20:16 + let mut _0: (u64, u64, u64); // return place in scope 0 at $DIR/inst_combine_deref.rs:11:18: 11:33 + let _1: u64; // in scope 0 at $DIR/inst_combine_deref.rs:12:9: 12:11 + let mut _10: u64; // in scope 0 at $DIR/inst_combine_deref.rs:21:6: 21:8 + let mut _11: u64; // in scope 0 at $DIR/inst_combine_deref.rs:21:10: 21:12 + let mut _12: u64; // in scope 0 at $DIR/inst_combine_deref.rs:21:14: 21:16 scope 1 { - debug x1 => _1; // in scope 1 at $DIR/inst_combine_deref.rs:11:9: 11:11 - let _2: u64; // in scope 1 at $DIR/inst_combine_deref.rs:12:9: 12:11 + debug x1 => _1; // in scope 1 at $DIR/inst_combine_deref.rs:12:9: 12:11 + let _2: u64; // in scope 1 at $DIR/inst_combine_deref.rs:13:9: 13:11 scope 2 { - debug x2 => _2; // in scope 2 at $DIR/inst_combine_deref.rs:12:9: 12:11 - let _3: u64; // in scope 2 at $DIR/inst_combine_deref.rs:13:9: 13:11 + debug x2 => _2; // in scope 2 at $DIR/inst_combine_deref.rs:13:9: 13:11 + let _3: u64; // in scope 2 at $DIR/inst_combine_deref.rs:14:9: 14:11 scope 3 { - debug x3 => _3; // in scope 3 at $DIR/inst_combine_deref.rs:13:9: 13:11 - let _4: &u64; // in scope 3 at $DIR/inst_combine_deref.rs:14:9: 14:11 + debug x3 => _3; // in scope 3 at $DIR/inst_combine_deref.rs:14:9: 14:11 + let _4: &u64; // in scope 3 at $DIR/inst_combine_deref.rs:15:9: 15:11 scope 4 { - debug y1 => _4; // in scope 4 at $DIR/inst_combine_deref.rs:14:9: 14:11 - let _5: &u64; // in scope 4 at $DIR/inst_combine_deref.rs:15:9: 15:11 + debug y1 => _4; // in scope 4 at $DIR/inst_combine_deref.rs:15:9: 15:11 + let _5: &u64; // in scope 4 at $DIR/inst_combine_deref.rs:16:9: 16:11 scope 5 { - debug y2 => _5; // in scope 5 at $DIR/inst_combine_deref.rs:15:9: 15:11 - let _6: &u64; // in scope 5 at $DIR/inst_combine_deref.rs:16:9: 16:11 + debug y2 => _5; // in scope 5 at $DIR/inst_combine_deref.rs:16:9: 16:11 + let _6: &u64; // in scope 5 at $DIR/inst_combine_deref.rs:17:9: 17:11 scope 6 { - debug y3 => _6; // in scope 6 at $DIR/inst_combine_deref.rs:16:9: 16:11 - let _7: u64; // in scope 6 at $DIR/inst_combine_deref.rs:17:9: 17:11 + debug y3 => _6; // in scope 6 at $DIR/inst_combine_deref.rs:17:9: 17:11 + let _7: u64; // in scope 6 at $DIR/inst_combine_deref.rs:18:9: 18:11 scope 7 { - debug z1 => _7; // in scope 7 at $DIR/inst_combine_deref.rs:17:9: 17:11 - let _8: u64; // in scope 7 at $DIR/inst_combine_deref.rs:18:9: 18:11 + debug z1 => _7; // in scope 7 at $DIR/inst_combine_deref.rs:18:9: 18:11 + let _8: u64; // in scope 7 at $DIR/inst_combine_deref.rs:19:9: 19:11 scope 8 { - debug z2 => _8; // in scope 8 at $DIR/inst_combine_deref.rs:18:9: 18:11 - let _9: u64; // in scope 8 at $DIR/inst_combine_deref.rs:19:9: 19:11 + debug z2 => _8; // in scope 8 at $DIR/inst_combine_deref.rs:19:9: 19:11 + let _9: u64; // in scope 8 at $DIR/inst_combine_deref.rs:20:9: 20:11 scope 9 { - debug z3 => _9; // in scope 9 at $DIR/inst_combine_deref.rs:19:9: 19:11 + debug z3 => _9; // in scope 9 at $DIR/inst_combine_deref.rs:20:9: 20:11 } } } @@ -44,49 +44,49 @@ } bb0: { - StorageLive(_1); // scope 0 at $DIR/inst_combine_deref.rs:11:9: 11:11 - _1 = const 1_u64; // scope 0 at $DIR/inst_combine_deref.rs:11:14: 11:15 - StorageLive(_2); // scope 1 at $DIR/inst_combine_deref.rs:12:9: 12:11 - _2 = const 2_u64; // scope 1 at $DIR/inst_combine_deref.rs:12:14: 12:15 - StorageLive(_3); // scope 2 at $DIR/inst_combine_deref.rs:13:9: 13:11 - _3 = const 3_u64; // scope 2 at $DIR/inst_combine_deref.rs:13:14: 13:15 - StorageLive(_4); // scope 3 at $DIR/inst_combine_deref.rs:14:9: 14:11 - _4 = &_1; // scope 3 at $DIR/inst_combine_deref.rs:14:14: 14:17 - StorageLive(_5); // scope 4 at $DIR/inst_combine_deref.rs:15:9: 15:11 - _5 = &_2; // scope 4 at $DIR/inst_combine_deref.rs:15:14: 15:17 - StorageLive(_6); // scope 5 at $DIR/inst_combine_deref.rs:16:9: 16:11 - _6 = &_3; // scope 5 at $DIR/inst_combine_deref.rs:16:14: 16:17 - StorageLive(_7); // scope 6 at $DIR/inst_combine_deref.rs:17:9: 17:11 -- _7 = (*_4); // scope 6 at $DIR/inst_combine_deref.rs:17:14: 17:17 -+ _7 = _1; // scope 6 at $DIR/inst_combine_deref.rs:17:14: 17:17 - StorageLive(_8); // scope 7 at $DIR/inst_combine_deref.rs:18:9: 18:11 -- _8 = (*_5); // scope 7 at $DIR/inst_combine_deref.rs:18:14: 18:17 -+ _8 = _2; // scope 7 at $DIR/inst_combine_deref.rs:18:14: 18:17 - StorageLive(_9); // scope 8 at $DIR/inst_combine_deref.rs:19:9: 19:11 -- _9 = (*_6); // scope 8 at $DIR/inst_combine_deref.rs:19:14: 19:17 -+ _9 = _3; // scope 8 at $DIR/inst_combine_deref.rs:19:14: 19:17 - StorageLive(_10); // scope 9 at $DIR/inst_combine_deref.rs:20:6: 20:8 - _10 = _7; // scope 9 at $DIR/inst_combine_deref.rs:20:6: 20:8 - StorageLive(_11); // scope 9 at $DIR/inst_combine_deref.rs:20:10: 20:12 - _11 = _8; // scope 9 at $DIR/inst_combine_deref.rs:20:10: 20:12 - StorageLive(_12); // scope 9 at $DIR/inst_combine_deref.rs:20:14: 20:16 - _12 = _9; // scope 9 at $DIR/inst_combine_deref.rs:20:14: 20:16 - (_0.0: u64) = move _10; // scope 9 at $DIR/inst_combine_deref.rs:20:5: 20:17 - (_0.1: u64) = move _11; // scope 9 at $DIR/inst_combine_deref.rs:20:5: 20:17 - (_0.2: u64) = move _12; // scope 9 at $DIR/inst_combine_deref.rs:20:5: 20:17 - StorageDead(_12); // scope 9 at $DIR/inst_combine_deref.rs:20:16: 20:17 - StorageDead(_11); // scope 9 at $DIR/inst_combine_deref.rs:20:16: 20:17 - StorageDead(_10); // scope 9 at $DIR/inst_combine_deref.rs:20:16: 20:17 - StorageDead(_9); // scope 8 at $DIR/inst_combine_deref.rs:21:1: 21:2 - StorageDead(_8); // scope 7 at $DIR/inst_combine_deref.rs:21:1: 21:2 - StorageDead(_7); // scope 6 at $DIR/inst_combine_deref.rs:21:1: 21:2 - StorageDead(_6); // scope 5 at $DIR/inst_combine_deref.rs:21:1: 21:2 - StorageDead(_5); // scope 4 at $DIR/inst_combine_deref.rs:21:1: 21:2 - StorageDead(_4); // scope 3 at $DIR/inst_combine_deref.rs:21:1: 21:2 - StorageDead(_3); // scope 2 at $DIR/inst_combine_deref.rs:21:1: 21:2 - StorageDead(_2); // scope 1 at $DIR/inst_combine_deref.rs:21:1: 21:2 - StorageDead(_1); // scope 0 at $DIR/inst_combine_deref.rs:21:1: 21:2 - return; // scope 0 at $DIR/inst_combine_deref.rs:21:2: 21:2 + StorageLive(_1); // scope 0 at $DIR/inst_combine_deref.rs:12:9: 12:11 + _1 = const 1_u64; // scope 0 at $DIR/inst_combine_deref.rs:12:14: 12:15 + StorageLive(_2); // scope 1 at $DIR/inst_combine_deref.rs:13:9: 13:11 + _2 = const 2_u64; // scope 1 at $DIR/inst_combine_deref.rs:13:14: 13:15 + StorageLive(_3); // scope 2 at $DIR/inst_combine_deref.rs:14:9: 14:11 + _3 = const 3_u64; // scope 2 at $DIR/inst_combine_deref.rs:14:14: 14:15 + StorageLive(_4); // scope 3 at $DIR/inst_combine_deref.rs:15:9: 15:11 + _4 = &_1; // scope 3 at $DIR/inst_combine_deref.rs:15:14: 15:17 + StorageLive(_5); // scope 4 at $DIR/inst_combine_deref.rs:16:9: 16:11 + _5 = &_2; // scope 4 at $DIR/inst_combine_deref.rs:16:14: 16:17 + StorageLive(_6); // scope 5 at $DIR/inst_combine_deref.rs:17:9: 17:11 + _6 = &_3; // scope 5 at $DIR/inst_combine_deref.rs:17:14: 17:17 + StorageLive(_7); // scope 6 at $DIR/inst_combine_deref.rs:18:9: 18:11 +- _7 = (*_4); // scope 6 at $DIR/inst_combine_deref.rs:18:14: 18:17 ++ _7 = _1; // scope 6 at $DIR/inst_combine_deref.rs:18:14: 18:17 + StorageLive(_8); // scope 7 at $DIR/inst_combine_deref.rs:19:9: 19:11 +- _8 = (*_5); // scope 7 at $DIR/inst_combine_deref.rs:19:14: 19:17 ++ _8 = _2; // scope 7 at $DIR/inst_combine_deref.rs:19:14: 19:17 + StorageLive(_9); // scope 8 at $DIR/inst_combine_deref.rs:20:9: 20:11 +- _9 = (*_6); // scope 8 at $DIR/inst_combine_deref.rs:20:14: 20:17 ++ _9 = _3; // scope 8 at $DIR/inst_combine_deref.rs:20:14: 20:17 + StorageLive(_10); // scope 9 at $DIR/inst_combine_deref.rs:21:6: 21:8 + _10 = _7; // scope 9 at $DIR/inst_combine_deref.rs:21:6: 21:8 + StorageLive(_11); // scope 9 at $DIR/inst_combine_deref.rs:21:10: 21:12 + _11 = _8; // scope 9 at $DIR/inst_combine_deref.rs:21:10: 21:12 + StorageLive(_12); // scope 9 at $DIR/inst_combine_deref.rs:21:14: 21:16 + _12 = _9; // scope 9 at $DIR/inst_combine_deref.rs:21:14: 21:16 + (_0.0: u64) = move _10; // scope 9 at $DIR/inst_combine_deref.rs:21:5: 21:17 + (_0.1: u64) = move _11; // scope 9 at $DIR/inst_combine_deref.rs:21:5: 21:17 + (_0.2: u64) = move _12; // scope 9 at $DIR/inst_combine_deref.rs:21:5: 21:17 + StorageDead(_12); // scope 9 at $DIR/inst_combine_deref.rs:21:16: 21:17 + StorageDead(_11); // scope 9 at $DIR/inst_combine_deref.rs:21:16: 21:17 + StorageDead(_10); // scope 9 at $DIR/inst_combine_deref.rs:21:16: 21:17 + StorageDead(_9); // scope 8 at $DIR/inst_combine_deref.rs:22:1: 22:2 + StorageDead(_8); // scope 7 at $DIR/inst_combine_deref.rs:22:1: 22:2 + StorageDead(_7); // scope 6 at $DIR/inst_combine_deref.rs:22:1: 22:2 + StorageDead(_6); // scope 5 at $DIR/inst_combine_deref.rs:22:1: 22:2 + StorageDead(_5); // scope 4 at $DIR/inst_combine_deref.rs:22:1: 22:2 + StorageDead(_4); // scope 3 at $DIR/inst_combine_deref.rs:22:1: 22:2 + StorageDead(_3); // scope 2 at $DIR/inst_combine_deref.rs:22:1: 22:2 + StorageDead(_2); // scope 1 at $DIR/inst_combine_deref.rs:22:1: 22:2 + StorageDead(_1); // scope 0 at $DIR/inst_combine_deref.rs:22:1: 22:2 + return; // scope 0 at $DIR/inst_combine_deref.rs:22:2: 22:2 } } diff --git a/src/test/mir-opt/inst_combine_deref.do_not_miscompile.InstCombine.diff b/src/test/mir-opt/inst_combine_deref.do_not_miscompile.InstCombine.diff index c32bf256da408..23c18bde2262b 100644 --- a/src/test/mir-opt/inst_combine_deref.do_not_miscompile.InstCombine.diff +++ b/src/test/mir-opt/inst_combine_deref.do_not_miscompile.InstCombine.diff @@ -2,70 +2,70 @@ + // MIR for `do_not_miscompile` after InstCombine fn do_not_miscompile() -> () { - let mut _0: (); // return place in scope 0 at $DIR/inst_combine_deref.rs:53:24: 53:24 - let _1: i32; // in scope 0 at $DIR/inst_combine_deref.rs:54:9: 54:10 - let mut _5: &i32; // in scope 0 at $DIR/inst_combine_deref.rs:58:10: 58:12 - let _6: &i32; // in scope 0 at $DIR/inst_combine_deref.rs:58:10: 58:12 - let _7: (); // in scope 0 at $DIR/inst_combine_deref.rs:59:5: 59:23 - let mut _8: bool; // in scope 0 at $DIR/inst_combine_deref.rs:59:5: 59:23 - let mut _9: bool; // in scope 0 at $DIR/inst_combine_deref.rs:59:13: 59:21 - let mut _10: i32; // in scope 0 at $DIR/inst_combine_deref.rs:59:13: 59:15 + let mut _0: (); // return place in scope 0 at $DIR/inst_combine_deref.rs:54:24: 54:24 + let _1: i32; // in scope 0 at $DIR/inst_combine_deref.rs:55:9: 55:10 + let mut _5: &i32; // in scope 0 at $DIR/inst_combine_deref.rs:59:10: 59:12 + let _6: &i32; // in scope 0 at $DIR/inst_combine_deref.rs:59:10: 59:12 + let _7: (); // in scope 0 at $DIR/inst_combine_deref.rs:60:5: 60:23 + 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 scope 1 { - debug x => _1; // in scope 1 at $DIR/inst_combine_deref.rs:54:9: 54:10 - let _2: i32; // in scope 1 at $DIR/inst_combine_deref.rs:55:9: 55:10 + 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 scope 2 { - debug a => _2; // in scope 2 at $DIR/inst_combine_deref.rs:55:9: 55:10 - let mut _3: &i32; // in scope 2 at $DIR/inst_combine_deref.rs:56:9: 56:14 + debug a => _2; // in scope 2 at $DIR/inst_combine_deref.rs:56:9: 56:10 + let mut _3: &i32; // in scope 2 at $DIR/inst_combine_deref.rs:57:9: 57:14 scope 3 { - debug y => _3; // in scope 3 at $DIR/inst_combine_deref.rs:56:9: 56:14 - let _4: &mut &i32; // in scope 3 at $DIR/inst_combine_deref.rs:57:9: 57:10 + debug y => _3; // in scope 3 at $DIR/inst_combine_deref.rs:57:9: 57:14 + let _4: &mut &i32; // in scope 3 at $DIR/inst_combine_deref.rs:58:9: 58:10 scope 4 { - debug z => _4; // in scope 4 at $DIR/inst_combine_deref.rs:57:9: 57:10 + debug z => _4; // in scope 4 at $DIR/inst_combine_deref.rs:58:9: 58:10 } } } } bb0: { - StorageLive(_1); // scope 0 at $DIR/inst_combine_deref.rs:54:9: 54:10 - _1 = const 42_i32; // scope 0 at $DIR/inst_combine_deref.rs:54:13: 54:15 - StorageLive(_2); // scope 1 at $DIR/inst_combine_deref.rs:55:9: 55:10 - _2 = const 99_i32; // scope 1 at $DIR/inst_combine_deref.rs:55:13: 55:15 - StorageLive(_3); // scope 2 at $DIR/inst_combine_deref.rs:56:9: 56:14 - _3 = &_1; // scope 2 at $DIR/inst_combine_deref.rs:56:17: 56:19 - StorageLive(_4); // scope 3 at $DIR/inst_combine_deref.rs:57:9: 57:10 - _4 = &mut _3; // scope 3 at $DIR/inst_combine_deref.rs:57:13: 57:19 - StorageLive(_5); // scope 4 at $DIR/inst_combine_deref.rs:58:10: 58:12 - StorageLive(_6); // scope 4 at $DIR/inst_combine_deref.rs:58:10: 58:12 - _6 = &_2; // scope 4 at $DIR/inst_combine_deref.rs:58:10: 58:12 -- _5 = &(*_6); // scope 4 at $DIR/inst_combine_deref.rs:58:10: 58:12 -+ _5 = _6; // scope 4 at $DIR/inst_combine_deref.rs:58:10: 58:12 - (*_4) = move _5; // scope 4 at $DIR/inst_combine_deref.rs:58:5: 58:12 - StorageDead(_5); // scope 4 at $DIR/inst_combine_deref.rs:58:11: 58:12 - StorageDead(_6); // scope 4 at $DIR/inst_combine_deref.rs:58:12: 58:13 - StorageLive(_7); // scope 4 at $DIR/inst_combine_deref.rs:59:5: 59:23 - StorageLive(_8); // scope 4 at $DIR/inst_combine_deref.rs:59:5: 59:23 - StorageLive(_9); // scope 4 at $DIR/inst_combine_deref.rs:59:13: 59:21 - StorageLive(_10); // scope 4 at $DIR/inst_combine_deref.rs:59:13: 59:15 - _10 = (*_3); // scope 4 at $DIR/inst_combine_deref.rs:59:13: 59:15 - _9 = Eq(move _10, const 99_i32); // scope 4 at $DIR/inst_combine_deref.rs:59:13: 59:21 - StorageDead(_10); // scope 4 at $DIR/inst_combine_deref.rs:59:20: 59:21 - _8 = Not(move _9); // scope 4 at $DIR/inst_combine_deref.rs:59:5: 59:23 - StorageDead(_9); // scope 4 at $DIR/inst_combine_deref.rs:59:22: 59:23 - switchInt(_8) -> [false: bb1, otherwise: bb2]; // scope 4 at $DIR/inst_combine_deref.rs:59:5: 59:23 + StorageLive(_1); // scope 0 at $DIR/inst_combine_deref.rs:55:9: 55:10 + _1 = const 42_i32; // scope 0 at $DIR/inst_combine_deref.rs:55:13: 55:15 + StorageLive(_2); // scope 1 at $DIR/inst_combine_deref.rs:56:9: 56:10 + _2 = const 99_i32; // scope 1 at $DIR/inst_combine_deref.rs:56:13: 56:15 + StorageLive(_3); // scope 2 at $DIR/inst_combine_deref.rs:57:9: 57:14 + _3 = &_1; // scope 2 at $DIR/inst_combine_deref.rs:57:17: 57:19 + StorageLive(_4); // scope 3 at $DIR/inst_combine_deref.rs:58:9: 58:10 + _4 = &mut _3; // scope 3 at $DIR/inst_combine_deref.rs:58:13: 58:19 + StorageLive(_5); // scope 4 at $DIR/inst_combine_deref.rs:59:10: 59:12 + StorageLive(_6); // scope 4 at $DIR/inst_combine_deref.rs:59:10: 59:12 + _6 = &_2; // scope 4 at $DIR/inst_combine_deref.rs:59:10: 59:12 +- _5 = &(*_6); // scope 4 at $DIR/inst_combine_deref.rs:59:10: 59:12 ++ _5 = _6; // scope 4 at $DIR/inst_combine_deref.rs:59:10: 59:12 + (*_4) = move _5; // scope 4 at $DIR/inst_combine_deref.rs:59:5: 59:12 + StorageDead(_5); // scope 4 at $DIR/inst_combine_deref.rs:59:11: 59:12 + StorageDead(_6); // scope 4 at $DIR/inst_combine_deref.rs:59:12: 59:13 + StorageLive(_7); // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23 + StorageLive(_8); // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23 + StorageLive(_9); // scope 4 at $DIR/inst_combine_deref.rs:60:13: 60:21 + StorageLive(_10); // scope 4 at $DIR/inst_combine_deref.rs:60:13: 60:15 + _10 = (*_3); // scope 4 at $DIR/inst_combine_deref.rs:60:13: 60:15 + _9 = Eq(move _10, const 99_i32); // scope 4 at $DIR/inst_combine_deref.rs:60:13: 60:21 + StorageDead(_10); // scope 4 at $DIR/inst_combine_deref.rs:60:20: 60:21 + _8 = Not(move _9); // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23 + StorageDead(_9); // scope 4 at $DIR/inst_combine_deref.rs:60:22: 60:23 + switchInt(_8) -> [false: bb1, otherwise: bb2]; // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23 } bb1: { - _7 = const (); // scope 4 at $DIR/inst_combine_deref.rs:59:5: 59:23 - StorageDead(_8); // scope 4 at $DIR/inst_combine_deref.rs:59:22: 59:23 - StorageDead(_7); // scope 4 at $DIR/inst_combine_deref.rs:59:22: 59:23 - _0 = const (); // scope 0 at $DIR/inst_combine_deref.rs:53:24: 60:2 - StorageDead(_4); // scope 3 at $DIR/inst_combine_deref.rs:60:1: 60:2 - StorageDead(_3); // scope 2 at $DIR/inst_combine_deref.rs:60:1: 60:2 - StorageDead(_2); // scope 1 at $DIR/inst_combine_deref.rs:60:1: 60:2 - StorageDead(_1); // scope 0 at $DIR/inst_combine_deref.rs:60:1: 60:2 - return; // scope 0 at $DIR/inst_combine_deref.rs:60:2: 60:2 + _7 = const (); // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23 + StorageDead(_8); // scope 4 at $DIR/inst_combine_deref.rs:60:22: 60:23 + StorageDead(_7); // scope 4 at $DIR/inst_combine_deref.rs:60:22: 60:23 + _0 = const (); // scope 0 at $DIR/inst_combine_deref.rs:54:24: 61:2 + StorageDead(_4); // scope 3 at $DIR/inst_combine_deref.rs:61:1: 61:2 + StorageDead(_3); // scope 2 at $DIR/inst_combine_deref.rs:61:1: 61:2 + StorageDead(_2); // scope 1 at $DIR/inst_combine_deref.rs:61:1: 61:2 + StorageDead(_1); // scope 0 at $DIR/inst_combine_deref.rs:61:1: 61:2 + return; // scope 0 at $DIR/inst_combine_deref.rs:61:2: 61:2 } bb2: { diff --git a/src/test/mir-opt/inst_combine_deref.dont_opt.InstCombine.diff b/src/test/mir-opt/inst_combine_deref.dont_opt.InstCombine.diff index 668766714f93d..69036491a10b7 100644 --- a/src/test/mir-opt/inst_combine_deref.dont_opt.InstCombine.diff +++ b/src/test/mir-opt/inst_combine_deref.dont_opt.InstCombine.diff @@ -2,23 +2,23 @@ + // MIR for `dont_opt` after InstCombine fn dont_opt() -> u64 { - let mut _0: u64; // return place in scope 0 at $DIR/inst_combine_deref.rs:42:18: 42:21 - let _1: i32; // in scope 0 at $DIR/inst_combine_deref.rs:43:9: 43:10 - let mut _5: &i32; // in scope 0 at $DIR/inst_combine_deref.rs:47:10: 47:14 + let mut _0: u64; // return place in scope 0 at $DIR/inst_combine_deref.rs:43:18: 43:21 + let _1: i32; // in scope 0 at $DIR/inst_combine_deref.rs:44:9: 44:10 + let mut _5: &i32; // in scope 0 at $DIR/inst_combine_deref.rs:48:10: 48:14 scope 1 { - debug y => _1; // in scope 1 at $DIR/inst_combine_deref.rs:43:9: 43:10 - let _2: &i32; // in scope 1 at $DIR/inst_combine_deref.rs:44:9: 44:13 + debug y => _1; // in scope 1 at $DIR/inst_combine_deref.rs:44:9: 44:10 + let _2: &i32; // in scope 1 at $DIR/inst_combine_deref.rs:45:9: 45:13 scope 2 { - debug _ref => _2; // in scope 2 at $DIR/inst_combine_deref.rs:44:9: 44:13 - let _3: i32; // in scope 2 at $DIR/inst_combine_deref.rs:45:9: 45:10 + debug _ref => _2; // in scope 2 at $DIR/inst_combine_deref.rs:45:9: 45:13 + let _3: i32; // in scope 2 at $DIR/inst_combine_deref.rs:46:9: 46:10 scope 3 { - debug x => _3; // in scope 3 at $DIR/inst_combine_deref.rs:45:9: 45:10 - let mut _4: &i32; // in scope 3 at $DIR/inst_combine_deref.rs:46:9: 46:15 + debug x => _3; // in scope 3 at $DIR/inst_combine_deref.rs:46:9: 46:10 + let mut _4: &i32; // in scope 3 at $DIR/inst_combine_deref.rs:47:9: 47:15 scope 4 { - debug _1 => _4; // in scope 4 at $DIR/inst_combine_deref.rs:46:9: 46:15 - let _6: i32; // in scope 4 at $DIR/inst_combine_deref.rs:48:9: 48:11 + debug _1 => _4; // in scope 4 at $DIR/inst_combine_deref.rs:47:9: 47:15 + let _6: i32; // in scope 4 at $DIR/inst_combine_deref.rs:49:9: 49:11 scope 5 { - debug _4 => _6; // in scope 5 at $DIR/inst_combine_deref.rs:48:9: 48:11 + debug _4 => _6; // in scope 5 at $DIR/inst_combine_deref.rs:49:9: 49:11 } } } @@ -26,28 +26,28 @@ } bb0: { - StorageLive(_1); // scope 0 at $DIR/inst_combine_deref.rs:43:9: 43:10 - _1 = const 5_i32; // scope 0 at $DIR/inst_combine_deref.rs:43:13: 43:14 - StorageLive(_2); // scope 1 at $DIR/inst_combine_deref.rs:44:9: 44:13 - _2 = &_1; // scope 1 at $DIR/inst_combine_deref.rs:44:16: 44:18 - StorageLive(_3); // scope 2 at $DIR/inst_combine_deref.rs:45:9: 45:10 - _3 = const 5_i32; // scope 2 at $DIR/inst_combine_deref.rs:45:13: 45:14 - StorageLive(_4); // scope 3 at $DIR/inst_combine_deref.rs:46:9: 46:15 - _4 = &_3; // scope 3 at $DIR/inst_combine_deref.rs:46:18: 46:20 - StorageLive(_5); // scope 4 at $DIR/inst_combine_deref.rs:47:10: 47:14 -- _5 = &(*_2); // scope 4 at $DIR/inst_combine_deref.rs:47:10: 47:14 -+ _5 = _2; // scope 4 at $DIR/inst_combine_deref.rs:47:10: 47:14 - _4 = move _5; // scope 4 at $DIR/inst_combine_deref.rs:47:5: 47:14 - StorageDead(_5); // scope 4 at $DIR/inst_combine_deref.rs:47:13: 47:14 - StorageLive(_6); // scope 4 at $DIR/inst_combine_deref.rs:48:9: 48:11 - _6 = (*_4); // scope 4 at $DIR/inst_combine_deref.rs:48:14: 48:17 - _0 = const 0_u64; // scope 5 at $DIR/inst_combine_deref.rs:49:5: 49:6 - StorageDead(_6); // scope 4 at $DIR/inst_combine_deref.rs:50:1: 50:2 - StorageDead(_4); // scope 3 at $DIR/inst_combine_deref.rs:50:1: 50:2 - StorageDead(_3); // scope 2 at $DIR/inst_combine_deref.rs:50:1: 50:2 - StorageDead(_2); // scope 1 at $DIR/inst_combine_deref.rs:50:1: 50:2 - StorageDead(_1); // scope 0 at $DIR/inst_combine_deref.rs:50:1: 50:2 - return; // scope 0 at $DIR/inst_combine_deref.rs:50:2: 50:2 + StorageLive(_1); // scope 0 at $DIR/inst_combine_deref.rs:44:9: 44:10 + _1 = const 5_i32; // scope 0 at $DIR/inst_combine_deref.rs:44:13: 44:14 + StorageLive(_2); // scope 1 at $DIR/inst_combine_deref.rs:45:9: 45:13 + _2 = &_1; // scope 1 at $DIR/inst_combine_deref.rs:45:16: 45:18 + StorageLive(_3); // scope 2 at $DIR/inst_combine_deref.rs:46:9: 46:10 + _3 = const 5_i32; // scope 2 at $DIR/inst_combine_deref.rs:46:13: 46:14 + StorageLive(_4); // scope 3 at $DIR/inst_combine_deref.rs:47:9: 47:15 + _4 = &_3; // scope 3 at $DIR/inst_combine_deref.rs:47:18: 47:20 + StorageLive(_5); // scope 4 at $DIR/inst_combine_deref.rs:48:10: 48:14 +- _5 = &(*_2); // scope 4 at $DIR/inst_combine_deref.rs:48:10: 48:14 ++ _5 = _2; // scope 4 at $DIR/inst_combine_deref.rs:48:10: 48:14 + _4 = move _5; // scope 4 at $DIR/inst_combine_deref.rs:48:5: 48:14 + StorageDead(_5); // scope 4 at $DIR/inst_combine_deref.rs:48:13: 48:14 + StorageLive(_6); // scope 4 at $DIR/inst_combine_deref.rs:49:9: 49:11 + _6 = (*_4); // scope 4 at $DIR/inst_combine_deref.rs:49:14: 49:17 + _0 = const 0_u64; // scope 5 at $DIR/inst_combine_deref.rs:50:5: 50:6 + StorageDead(_6); // scope 4 at $DIR/inst_combine_deref.rs:51:1: 51:2 + StorageDead(_4); // scope 3 at $DIR/inst_combine_deref.rs:51:1: 51:2 + StorageDead(_3); // scope 2 at $DIR/inst_combine_deref.rs:51:1: 51:2 + StorageDead(_2); // scope 1 at $DIR/inst_combine_deref.rs:51:1: 51:2 + StorageDead(_1); // scope 0 at $DIR/inst_combine_deref.rs:51:1: 51:2 + return; // scope 0 at $DIR/inst_combine_deref.rs:51:2: 51:2 } } diff --git a/src/test/mir-opt/inst_combine_deref.opt_struct.InstCombine.diff b/src/test/mir-opt/inst_combine_deref.opt_struct.InstCombine.diff index e7d8c2e020256..c867543d05ea3 100644 --- a/src/test/mir-opt/inst_combine_deref.opt_struct.InstCombine.diff +++ b/src/test/mir-opt/inst_combine_deref.opt_struct.InstCombine.diff @@ -2,43 +2,43 @@ + // MIR for `opt_struct` after InstCombine fn opt_struct(_1: S) -> u64 { - debug s => _1; // in scope 0 at $DIR/inst_combine_deref.rs:29:15: 29:16 - let mut _0: u64; // return place in scope 0 at $DIR/inst_combine_deref.rs:29:24: 29:27 - let _2: &u64; // in scope 0 at $DIR/inst_combine_deref.rs:30:9: 30:10 - let mut _5: u64; // in scope 0 at $DIR/inst_combine_deref.rs:33:5: 33:7 - let mut _6: u64; // in scope 0 at $DIR/inst_combine_deref.rs:33:10: 33:11 + debug s => _1; // in scope 0 at $DIR/inst_combine_deref.rs:30:15: 30:16 + let mut _0: u64; // return place in scope 0 at $DIR/inst_combine_deref.rs:30:24: 30:27 + let _2: &u64; // in scope 0 at $DIR/inst_combine_deref.rs:31:9: 31:10 + let mut _5: u64; // in scope 0 at $DIR/inst_combine_deref.rs:34:5: 34:7 + let mut _6: u64; // in scope 0 at $DIR/inst_combine_deref.rs:34:10: 34:11 scope 1 { - debug a => _2; // in scope 1 at $DIR/inst_combine_deref.rs:30:9: 30:10 - let _3: &u64; // in scope 1 at $DIR/inst_combine_deref.rs:31:9: 31:10 + debug a => _2; // in scope 1 at $DIR/inst_combine_deref.rs:31:9: 31:10 + let _3: &u64; // in scope 1 at $DIR/inst_combine_deref.rs:32:9: 32:10 scope 2 { - debug b => _3; // in scope 2 at $DIR/inst_combine_deref.rs:31:9: 31:10 - let _4: u64; // in scope 2 at $DIR/inst_combine_deref.rs:32:9: 32:10 + debug b => _3; // in scope 2 at $DIR/inst_combine_deref.rs:32:9: 32:10 + let _4: u64; // in scope 2 at $DIR/inst_combine_deref.rs:33:9: 33:10 scope 3 { - debug x => _4; // in scope 3 at $DIR/inst_combine_deref.rs:32:9: 32:10 + debug x => _4; // in scope 3 at $DIR/inst_combine_deref.rs:33:9: 33:10 } } } bb0: { - StorageLive(_2); // scope 0 at $DIR/inst_combine_deref.rs:30:9: 30:10 - _2 = &(_1.0: u64); // scope 0 at $DIR/inst_combine_deref.rs:30:13: 30:17 - StorageLive(_3); // scope 1 at $DIR/inst_combine_deref.rs:31:9: 31:10 - _3 = &(_1.1: u64); // scope 1 at $DIR/inst_combine_deref.rs:31:13: 31:17 - StorageLive(_4); // scope 2 at $DIR/inst_combine_deref.rs:32:9: 32:10 -- _4 = (*_2); // scope 2 at $DIR/inst_combine_deref.rs:32:13: 32:15 -+ _4 = (_1.0: u64); // scope 2 at $DIR/inst_combine_deref.rs:32:13: 32:15 - StorageLive(_5); // scope 3 at $DIR/inst_combine_deref.rs:33:5: 33:7 -- _5 = (*_3); // scope 3 at $DIR/inst_combine_deref.rs:33:5: 33:7 -+ _5 = (_1.1: u64); // scope 3 at $DIR/inst_combine_deref.rs:33:5: 33:7 - StorageLive(_6); // scope 3 at $DIR/inst_combine_deref.rs:33:10: 33:11 - _6 = _4; // scope 3 at $DIR/inst_combine_deref.rs:33:10: 33:11 - _0 = Add(move _5, move _6); // scope 3 at $DIR/inst_combine_deref.rs:33:5: 33:11 - StorageDead(_6); // scope 3 at $DIR/inst_combine_deref.rs:33:10: 33:11 - StorageDead(_5); // scope 3 at $DIR/inst_combine_deref.rs:33:10: 33:11 - StorageDead(_4); // scope 2 at $DIR/inst_combine_deref.rs:34:1: 34:2 - StorageDead(_3); // scope 1 at $DIR/inst_combine_deref.rs:34:1: 34:2 - StorageDead(_2); // scope 0 at $DIR/inst_combine_deref.rs:34:1: 34:2 - return; // scope 0 at $DIR/inst_combine_deref.rs:34:2: 34:2 + StorageLive(_2); // scope 0 at $DIR/inst_combine_deref.rs:31:9: 31:10 + _2 = &(_1.0: u64); // scope 0 at $DIR/inst_combine_deref.rs:31:13: 31:17 + StorageLive(_3); // scope 1 at $DIR/inst_combine_deref.rs:32:9: 32:10 + _3 = &(_1.1: u64); // scope 1 at $DIR/inst_combine_deref.rs:32:13: 32:17 + StorageLive(_4); // scope 2 at $DIR/inst_combine_deref.rs:33:9: 33:10 +- _4 = (*_2); // scope 2 at $DIR/inst_combine_deref.rs:33:13: 33:15 ++ _4 = (_1.0: u64); // scope 2 at $DIR/inst_combine_deref.rs:33:13: 33:15 + StorageLive(_5); // scope 3 at $DIR/inst_combine_deref.rs:34:5: 34:7 +- _5 = (*_3); // scope 3 at $DIR/inst_combine_deref.rs:34:5: 34:7 ++ _5 = (_1.1: u64); // scope 3 at $DIR/inst_combine_deref.rs:34:5: 34:7 + StorageLive(_6); // scope 3 at $DIR/inst_combine_deref.rs:34:10: 34:11 + _6 = _4; // scope 3 at $DIR/inst_combine_deref.rs:34:10: 34:11 + _0 = Add(move _5, move _6); // scope 3 at $DIR/inst_combine_deref.rs:34:5: 34:11 + StorageDead(_6); // scope 3 at $DIR/inst_combine_deref.rs:34:10: 34:11 + StorageDead(_5); // scope 3 at $DIR/inst_combine_deref.rs:34:10: 34:11 + StorageDead(_4); // scope 2 at $DIR/inst_combine_deref.rs:35:1: 35:2 + StorageDead(_3); // scope 1 at $DIR/inst_combine_deref.rs:35:1: 35:2 + StorageDead(_2); // scope 0 at $DIR/inst_combine_deref.rs:35:1: 35:2 + return; // scope 0 at $DIR/inst_combine_deref.rs:35:2: 35:2 } } diff --git a/src/test/mir-opt/inst_combine_deref.rs b/src/test/mir-opt/inst_combine_deref.rs index 896ae676c4f47..3be8c2f3ac732 100644 --- a/src/test/mir-opt/inst_combine_deref.rs +++ b/src/test/mir-opt/inst_combine_deref.rs @@ -1,3 +1,4 @@ +// compile-flags: -O // EMIT_MIR inst_combine_deref.simple_opt.InstCombine.diff fn simple_opt() -> u64 { let x = 5; diff --git a/src/test/mir-opt/inst_combine_deref.simple_opt.InstCombine.diff b/src/test/mir-opt/inst_combine_deref.simple_opt.InstCombine.diff index ea14aefda4bfb..f52dfe379ca30 100644 --- a/src/test/mir-opt/inst_combine_deref.simple_opt.InstCombine.diff +++ b/src/test/mir-opt/inst_combine_deref.simple_opt.InstCombine.diff @@ -2,33 +2,33 @@ + // MIR for `simple_opt` after InstCombine fn simple_opt() -> u64 { - let mut _0: u64; // return place in scope 0 at $DIR/inst_combine_deref.rs:2:20: 2:23 - let _1: u64; // in scope 0 at $DIR/inst_combine_deref.rs:3:9: 3:10 + let mut _0: u64; // return place in scope 0 at $DIR/inst_combine_deref.rs:3:20: 3:23 + let _1: u64; // in scope 0 at $DIR/inst_combine_deref.rs:4:9: 4:10 scope 1 { - debug x => _1; // in scope 1 at $DIR/inst_combine_deref.rs:3:9: 3:10 - let _2: &u64; // in scope 1 at $DIR/inst_combine_deref.rs:4:9: 4:10 + debug x => _1; // in scope 1 at $DIR/inst_combine_deref.rs:4:9: 4:10 + let _2: &u64; // in scope 1 at $DIR/inst_combine_deref.rs:5:9: 5:10 scope 2 { - debug y => _2; // in scope 2 at $DIR/inst_combine_deref.rs:4:9: 4:10 - let _3: u64; // in scope 2 at $DIR/inst_combine_deref.rs:5:9: 5:10 + debug y => _2; // in scope 2 at $DIR/inst_combine_deref.rs:5:9: 5:10 + let _3: u64; // in scope 2 at $DIR/inst_combine_deref.rs:6:9: 6:10 scope 3 { - debug z => _3; // in scope 3 at $DIR/inst_combine_deref.rs:5:9: 5:10 + debug z => _3; // in scope 3 at $DIR/inst_combine_deref.rs:6:9: 6:10 } } } bb0: { - StorageLive(_1); // scope 0 at $DIR/inst_combine_deref.rs:3:9: 3:10 - _1 = const 5_u64; // scope 0 at $DIR/inst_combine_deref.rs:3:13: 3:14 - StorageLive(_2); // scope 1 at $DIR/inst_combine_deref.rs:4:9: 4:10 - _2 = &_1; // scope 1 at $DIR/inst_combine_deref.rs:4:13: 4:15 - StorageLive(_3); // scope 2 at $DIR/inst_combine_deref.rs:5:9: 5:10 -- _3 = (*_2); // scope 2 at $DIR/inst_combine_deref.rs:5:13: 5:15 -+ _3 = _1; // scope 2 at $DIR/inst_combine_deref.rs:5:13: 5:15 - _0 = _3; // scope 3 at $DIR/inst_combine_deref.rs:6:5: 6:6 - StorageDead(_3); // scope 2 at $DIR/inst_combine_deref.rs:7:1: 7:2 - StorageDead(_2); // scope 1 at $DIR/inst_combine_deref.rs:7:1: 7:2 - StorageDead(_1); // scope 0 at $DIR/inst_combine_deref.rs:7:1: 7:2 - return; // scope 0 at $DIR/inst_combine_deref.rs:7:2: 7:2 + StorageLive(_1); // scope 0 at $DIR/inst_combine_deref.rs:4:9: 4:10 + _1 = const 5_u64; // scope 0 at $DIR/inst_combine_deref.rs:4:13: 4:14 + StorageLive(_2); // scope 1 at $DIR/inst_combine_deref.rs:5:9: 5:10 + _2 = &_1; // scope 1 at $DIR/inst_combine_deref.rs:5:13: 5:15 + StorageLive(_3); // scope 2 at $DIR/inst_combine_deref.rs:6:9: 6:10 +- _3 = (*_2); // scope 2 at $DIR/inst_combine_deref.rs:6:13: 6:15 ++ _3 = _1; // scope 2 at $DIR/inst_combine_deref.rs:6:13: 6:15 + _0 = _3; // scope 3 at $DIR/inst_combine_deref.rs:7:5: 7:6 + StorageDead(_3); // scope 2 at $DIR/inst_combine_deref.rs:8:1: 8:2 + StorageDead(_2); // scope 1 at $DIR/inst_combine_deref.rs:8:1: 8:2 + StorageDead(_1); // scope 0 at $DIR/inst_combine_deref.rs:8:1: 8:2 + return; // scope 0 at $DIR/inst_combine_deref.rs:8:2: 8:2 } } From 8c9cb06c2ec287e4b9d2bce79390b444752c3686 Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Fri, 10 Jul 2020 23:53:25 +0200 Subject: [PATCH 0806/1052] Deny unsafe op in unsafe fns without the unsafe keyword, first part for std/thread --- library/std/src/thread/local.rs | 99 +++++++++++++++++++++++---------- library/std/src/thread/mod.rs | 28 +++++++--- 2 files changed, 91 insertions(+), 36 deletions(-) diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 60a05dc5d545b..991631d91f0b2 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -288,7 +288,11 @@ mod lazy { } pub unsafe fn get(&self) -> Option<&'static T> { - (*self.inner.get()).as_ref() + // SAFETY: No reference is ever handed out to the inner cell nor + // mutable reference to the Option inside said cell. This make it + // safe to hand a reference, though the lifetime of 'static + // is itself unsafe, making the get method unsafe. + unsafe { (*self.inner.get()).as_ref() } } pub unsafe fn initialize T>(&self, init: F) -> &'static T { @@ -297,6 +301,8 @@ mod lazy { let value = init(); let ptr = self.inner.get(); + // SAFETY: + // // note that this can in theory just be `*ptr = Some(value)`, but due to // the compiler will currently codegen that pattern with something like: // @@ -309,22 +315,31 @@ mod lazy { // value (an aliasing violation). To avoid setting the "I'm running a // destructor" flag we just use `mem::replace` which should sequence the // operations a little differently and make this safe to call. - let _ = mem::replace(&mut *ptr, Some(value)); - - // After storing `Some` we want to get a reference to the contents of - // what we just stored. While we could use `unwrap` here and it should - // always work it empirically doesn't seem to always get optimized away, - // which means that using something like `try_with` can pull in - // panicking code and cause a large size bloat. - match *ptr { - Some(ref x) => x, - None => hint::unreachable_unchecked(), + unsafe { + let _ = mem::replace(&mut *ptr, Some(value)); + } + + // SAFETY: the *ptr operation is made safe by the `mem::replace` + // call above that made sure a valid value is present behind it. + unsafe { + // After storing `Some` we want to get a reference to the contents of + // what we just stored. While we could use `unwrap` here and it should + // always work it empirically doesn't seem to always get optimized away, + // which means that using something like `try_with` can pull in + // panicking code and cause a large size bloat. + match *ptr { + Some(ref x) => x, + None => hint::unreachable_unchecked(), + } } } #[allow(unused)] pub unsafe fn take(&mut self) -> Option { - (*self.inner.get()).take() + // SAFETY: The other methods hand out references while taking &self. + // As such, calling this method when such references are still alive + // will fail because it takes a &mut self, conflicting with them. + unsafe { (*self.inner.get()).take() } } } } @@ -413,9 +428,17 @@ pub mod fast { } pub unsafe fn get T>(&self, init: F) -> Option<&'static T> { - match self.inner.get() { - Some(val) => Some(val), - None => self.try_initialize(init), + // SAFETY: See the definitions of `LazyKeyInner::get` and + // `try_initialize` for more informations. + // + // The call to `get` is made safe because no mutable references are + // ever handed out and the `try_initialize` is dependant on the + // passed `init` function. + unsafe { + match self.inner.get() { + Some(val) => Some(val), + None => self.try_initialize(init), + } } } @@ -428,8 +451,10 @@ pub mod fast { // LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722 #[inline(never)] unsafe fn try_initialize T>(&self, init: F) -> Option<&'static T> { - if !mem::needs_drop::() || self.try_register_dtor() { - Some(self.inner.initialize(init)) + // SAFETY: See comment above. + if !mem::needs_drop::() || unsafe { self.try_register_dtor() } { + // SAFETY: See comment above. + Some(unsafe { self.inner.initialize(init) }) } else { None } @@ -441,8 +466,12 @@ pub mod fast { unsafe fn try_register_dtor(&self) -> bool { match self.dtor_state.get() { DtorState::Unregistered => { - // dtor registration happens before initialization. - register_dtor(self as *const _ as *mut u8, destroy_value::); + // SAFETY: dtor registration happens before initialization. + // Passing `self` as a pointer while using `destroy_value` + // is safe because the function will build a pointer to a + // Key, which is the type of self and so find the correct + // size. + unsafe { register_dtor(self as *const _ as *mut u8, destroy_value::) }; self.dtor_state.set(DtorState::Registered); true } @@ -458,13 +487,21 @@ pub mod fast { unsafe extern "C" fn destroy_value(ptr: *mut u8) { let ptr = ptr as *mut Key; + // SAFETY: + // + // The pointer `ptr` has been built just above and comes from + // `try_register_dtor` where it is originally a Key coming from `self`, + // making it non-NUL and of the correct type. + // // Right before we run the user destructor be sure to set the // `Option` to `None`, and `dtor_state` to `RunningOrHasRun`. This // causes future calls to `get` to run `try_initialize_drop` again, // which will now fail, and return `None`. - let value = (*ptr).inner.take(); - (*ptr).dtor_state.set(DtorState::RunningOrHasRun); - drop(value); + unsafe { + let value = (*ptr).inner.take(); + (*ptr).dtor_state.set(DtorState::RunningOrHasRun); + drop(value); + } } } @@ -533,11 +570,15 @@ pub mod os { ptr }; - Some((*ptr).inner.initialize(init)) + // SAFETY: ptr has been ensured as non-NUL just above an so can be + // dereferenced safely. + unsafe { Some((*ptr).inner.initialize(init)) } } } unsafe extern "C" fn destroy_value(ptr: *mut u8) { + // SAFETY: + // // The OS TLS ensures that this key contains a NULL value when this // destructor starts to run. We set it back to a sentinel value of 1 to // ensure that any future calls to `get` for this thread will return @@ -545,10 +586,12 @@ pub mod os { // // Note that to prevent an infinite loop we reset it back to null right // before we return from the destructor ourselves. - let ptr = Box::from_raw(ptr as *mut Value); - let key = ptr.key; - key.os.set(1 as *mut u8); - drop(ptr); - key.os.set(ptr::null_mut()); + unsafe { + let ptr = Box::from_raw(ptr as *mut Value); + let key = ptr.key; + key.os.set(1 as *mut u8); + drop(ptr); + key.os.set(ptr::null_mut()); + } } } diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 6d6be8560aa36..8c353e2484ef2 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -144,6 +144,7 @@ //! [`with`]: LocalKey::with #![stable(feature = "rust1", since = "1.0.0")] +#![deny(unsafe_op_in_unsafe_fn)] #[cfg(all(test, not(target_os = "emscripten")))] mod tests; @@ -456,14 +457,23 @@ impl Builder { imp::Thread::set_name(name); } - thread_info::set(imp::guard::current(), their_thread); + // SAFETY: the stack guard passed is the one for the current thread. + // This means the current thread's stack and the new thread's stack + // are properly set and protected from each other. + thread_info::set(unsafe { imp::guard::current() }, their_thread); let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| { crate::sys_common::backtrace::__rust_begin_short_backtrace(f) })); - *their_packet.get() = Some(try_result); + // SAFETY: `their_packet` as been built just above and moved by the + // closure (it is an Arc<...>) and `my_packet` will be stored in the + // same `JoinInner` as this closure meaning the mutation will be + // safe (not modify it and affect a value far away). + unsafe { *their_packet.get() = Some(try_result) }; }; Ok(JoinHandle(JoinInner { + // SAFETY: + // // `imp::Thread::new` takes a closure with a `'static` lifetime, since it's passed // through FFI or otherwise used with low-level threading primitives that have no // notion of or way to enforce lifetimes. @@ -475,12 +485,14 @@ impl Builder { // Similarly, the `sys` implementation must guarantee that no references to the closure // exist after the thread has terminated, which is signaled by `Thread::join` // returning. - native: Some(imp::Thread::new( - stack_size, - mem::transmute::, Box>(Box::new( - main, - )), - )?), + native: unsafe { + Some(imp::Thread::new( + stack_size, + mem::transmute::, Box>( + Box::new(main), + ), + )?) + }, thread: my_thread, packet: Packet(my_packet), })) From a83b79ec31df3a467753c3e5b41cf457af544c7b Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Sat, 11 Jul 2020 00:15:24 +0200 Subject: [PATCH 0807/1052] Finished documenting all unsafe op inside unsafe fn --- library/std/src/thread/local.rs | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 991631d91f0b2..281e1ef6741a5 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -539,20 +539,28 @@ pub mod os { } pub unsafe fn get(&'static self, init: fn() -> T) -> Option<&'static T> { - let ptr = self.os.get() as *mut Value; + // SAFETY: No mutable references are ever handed out meaning getting + // the value is ok. + let ptr = unsafe { self.os.get() as *mut Value }; if ptr as usize > 1 { - if let Some(ref value) = (*ptr).inner.get() { + // SAFETY: the check ensured the pointer is safe (its destructor + // is not running) + it is coming from a trusted source (self). + if let Some(ref value) = unsafe { (*ptr).inner.get() } { return Some(value); } } - self.try_initialize(init) + // SAFETY: At this point we are sure we have no value and so + // initializing (or trying to) is safe. + unsafe { self.try_initialize(init) } } // `try_initialize` is only called once per os thread local variable, // except in corner cases where thread_local dtors reference other // thread_local's, or it is being recursively initialized. unsafe fn try_initialize(&'static self, init: fn() -> T) -> Option<&'static T> { - let ptr = self.os.get() as *mut Value; + // SAFETY: No mutable references are ever handed out meaning getting + // the value is ok. + let ptr = unsafe { self.os.get() as *mut Value }; if ptr as usize == 1 { // destructor is running return None; @@ -563,7 +571,11 @@ pub mod os { // local copy, so do that now. let ptr: Box> = box Value { inner: LazyKeyInner::new(), key: self }; let ptr = Box::into_raw(ptr); - self.os.set(ptr as *mut u8); + // SAFETY: At this point we are sure there is no value inside + // ptr so setting it will not affect anyone else. + unsafe { + self.os.set(ptr as *mut u8); + } ptr } else { // recursive initialization From 5d29954b2f2c3e079372bbaaee2ed64c1674046b Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Sat, 29 Aug 2020 20:10:05 +0200 Subject: [PATCH 0808/1052] Improve some SAFETY comments following suggestions --- library/std/src/thread/local.rs | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 281e1ef6741a5..54efff2a92bbf 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -315,12 +315,23 @@ mod lazy { // value (an aliasing violation). To avoid setting the "I'm running a // destructor" flag we just use `mem::replace` which should sequence the // operations a little differently and make this safe to call. + // + // `ptr` can be dereferenced safely since it was obtained from + // `UnsafeCell::get`, which should not return a non-aligned or NUL pointer. + // What's more a `LazyKeyInner` can only be created with `new`, which ensures + // `inner` is correctly initialized and all calls to methods on `LazyKeyInner` + // will leave `inner` initialized too. unsafe { let _ = mem::replace(&mut *ptr, Some(value)); } - // SAFETY: the *ptr operation is made safe by the `mem::replace` - // call above that made sure a valid value is present behind it. + // SAFETY: the `*ptr` operation is made safe by the `mem::replace` + // call above combined with `ptr` being correct from the beginning + // (see previous SAFETY: comment above). + // + // Plus, with the call to `mem::replace` it is guaranteed there is + // a `Some` behind `ptr`, not a `None` so `unreachable_unchecked` + // will never be reached. unsafe { // After storing `Some` we want to get a reference to the contents of // what we just stored. While we could use `unwrap` here and it should @@ -337,8 +348,8 @@ mod lazy { #[allow(unused)] pub unsafe fn take(&mut self) -> Option { // SAFETY: The other methods hand out references while taking &self. - // As such, calling this method when such references are still alive - // will fail because it takes a &mut self, conflicting with them. + // As such, callers of this method must ensure no `&` and `&mut` are + // available and used at the same time. unsafe { (*self.inner.get()).take() } } } @@ -451,9 +462,9 @@ pub mod fast { // LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722 #[inline(never)] unsafe fn try_initialize T>(&self, init: F) -> Option<&'static T> { - // SAFETY: See comment above. + // SAFETY: See comment above (this function doc). if !mem::needs_drop::() || unsafe { self.try_register_dtor() } { - // SAFETY: See comment above. + // SAFETY: See comment above (his function doc). Some(unsafe { self.inner.initialize(init) }) } else { None From 3afadaad4f087c86b1a8509109f544214ecad45f Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Sun, 20 Sep 2020 17:31:55 +0200 Subject: [PATCH 0809/1052] Fix accordingly to review --- library/std/src/thread/local.rs | 42 ++++++++++++++++----------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 54efff2a92bbf..cc9cad2162b1b 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -288,13 +288,15 @@ mod lazy { } pub unsafe fn get(&self) -> Option<&'static T> { - // SAFETY: No reference is ever handed out to the inner cell nor - // mutable reference to the Option inside said cell. This make it - // safe to hand a reference, though the lifetime of 'static - // is itself unsafe, making the get method unsafe. + // SAFETY: The caller must ensure no reference is ever handed out to + // the inner cell nor mutable reference to the Option inside said + // cell. This make it safe to hand a reference, though the lifetime + // of 'static is itself unsafe, making the get method unsafe. unsafe { (*self.inner.get()).as_ref() } } + /// The caller must ensure that no reference is active: this method + /// needs unique access. pub unsafe fn initialize T>(&self, init: F) -> &'static T { // Execute the initialization up front, *then* move it into our slot, // just in case initialization fails. @@ -316,20 +318,13 @@ mod lazy { // destructor" flag we just use `mem::replace` which should sequence the // operations a little differently and make this safe to call. // - // `ptr` can be dereferenced safely since it was obtained from - // `UnsafeCell::get`, which should not return a non-aligned or NUL pointer. - // What's more a `LazyKeyInner` can only be created with `new`, which ensures - // `inner` is correctly initialized and all calls to methods on `LazyKeyInner` - // will leave `inner` initialized too. + // The precondition also ensures that we are the only one accessing + // `self` at the moment so replacing is fine. unsafe { let _ = mem::replace(&mut *ptr, Some(value)); } - // SAFETY: the `*ptr` operation is made safe by the `mem::replace` - // call above combined with `ptr` being correct from the beginning - // (see previous SAFETY: comment above). - // - // Plus, with the call to `mem::replace` it is guaranteed there is + // SAFETY: With the call to `mem::replace` it is guaranteed there is // a `Some` behind `ptr`, not a `None` so `unreachable_unchecked` // will never be reached. unsafe { @@ -345,11 +340,12 @@ mod lazy { } } + /// The other methods hand out references while taking &self. + /// As such, callers of this method must ensure no `&` and `&mut` are + /// available and used at the same time. #[allow(unused)] pub unsafe fn take(&mut self) -> Option { - // SAFETY: The other methods hand out references while taking &self. - // As such, callers of this method must ensure no `&` and `&mut` are - // available and used at the same time. + // SAFETY: See doc comment for this method. unsafe { (*self.inner.get()).take() } } } @@ -442,9 +438,10 @@ pub mod fast { // SAFETY: See the definitions of `LazyKeyInner::get` and // `try_initialize` for more informations. // - // The call to `get` is made safe because no mutable references are - // ever handed out and the `try_initialize` is dependant on the - // passed `init` function. + // The caller must ensure no mutable references are ever active to + // the inner cell or the inner T when this is called. + // The `try_initialize` is dependant on the passed `init` function + // for this. unsafe { match self.inner.get() { Some(val) => Some(val), @@ -549,9 +546,10 @@ pub mod os { Key { os: OsStaticKey::new(Some(destroy_value::)), marker: marker::PhantomData } } + /// It is a requirement for the caller to ensure that no mutable + /// reference is active when this method is called. pub unsafe fn get(&'static self, init: fn() -> T) -> Option<&'static T> { - // SAFETY: No mutable references are ever handed out meaning getting - // the value is ok. + // SAFETY: See the documentation for this method. let ptr = unsafe { self.os.get() as *mut Value }; if ptr as usize > 1 { // SAFETY: the check ensured the pointer is safe (its destructor From d01bd19573a14d53a035bae704bdcdab0680a283 Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Mon, 21 Sep 2020 23:08:48 +0200 Subject: [PATCH 0810/1052] Fix missing unsafe block for target arch wasm32 --- library/std/src/thread/local.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index cc9cad2162b1b..7226692fa0c98 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -377,10 +377,17 @@ pub mod statik { } pub unsafe fn get(&self, init: fn() -> T) -> Option<&'static T> { - let value = match self.inner.get() { - Some(ref value) => value, - None => self.inner.initialize(init), + // SAFETY: The caller must ensure no reference is ever handed out to + // the inner cell nor mutable reference to the Option inside said + // cell. This make it safe to hand a reference, though the lifetime + // of 'static is itself unsafe, making the get method unsafe. + let value = unsafe { + match self.inner.get() { + Some(ref value) => value, + None => self.inner.initialize(init), + } }; + Some(value) } } From 2f893e458a20a159fcf93a9a5b0435ae3ed0a67e Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 21 Sep 2020 23:25:52 +0200 Subject: [PATCH 0811/1052] review --- .../rustc_middle/src/mir/interpret/error.rs | 6 ++++++ .../src/traits/const_evaluatable.rs | 21 +++++++------------ .../const_evaluatable_checked/closures.stderr | 9 +++----- .../let-bindings.stderr | 18 ++++++---------- 4 files changed, 23 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 059925088ce1d..97a13ee8e20e9 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -23,6 +23,12 @@ pub enum ErrorHandled { TooGeneric, } +impl From for ErrorHandled { + fn from(err: ErrorReported) -> ErrorHandled { + ErrorHandled::Reported(err) + } +} + CloneTypeFoldableAndLiftImpls! { ErrorHandled, } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 12082475c85d4..0cfcaca906033 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -32,9 +32,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( ) -> Result<(), ErrorHandled> { debug!("is_const_evaluatable({:?}, {:?})", def, substs); if infcx.tcx.features().const_evaluatable_checked { - if let Some(ct) = - AbstractConst::new(infcx.tcx, def, substs).map_err(ErrorHandled::Reported)? - { + if let Some(ct) = AbstractConst::new(infcx.tcx, def, substs)? { for pred in param_env.caller_bounds() { match pred.skip_binders() { ty::PredicateAtom::ConstEvaluatable(b_def, b_substs) => { @@ -42,8 +40,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( if b_def == def && b_substs == substs { debug!("is_const_evaluatable: caller_bound ~~> ok"); return Ok(()); - } else if AbstractConst::new(infcx.tcx, b_def, b_substs) - .map_err(ErrorHandled::Reported)? + } else if AbstractConst::new(infcx.tcx, b_def, b_substs)? .map_or(false, |b_ct| try_unify(infcx.tcx, ct, b_ct)) { debug!("is_const_evaluatable: abstract_const ~~> ok"); @@ -153,14 +150,12 @@ struct AbstractConstBuilder<'a, 'tcx> { impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { fn error(&mut self, span: Option, msg: &str) -> Result { - let mut err = - self.tcx.sess.struct_span_err(self.body.span, "overly complex generic constant"); - if let Some(span) = span { - err.span_note(span, msg); - } else { - err.note(msg); - } - err.help("consider moving this anonymous constant into a `const` function").emit(); + self.tcx + .sess + .struct_span_err(self.body.span, "overly complex generic constant") + .span_label(span.unwrap_or(self.body.span), msg) + .help("consider moving this anonymous constant into a `const` function") + .emit(); Err(ErrorReported) } diff --git a/src/test/ui/const-generics/const_evaluatable_checked/closures.stderr b/src/test/ui/const-generics/const_evaluatable_checked/closures.stderr index 7bb23f1488d93..9f0b7252e8326 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/closures.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/closures.stderr @@ -2,13 +2,10 @@ error: overly complex generic constant --> $DIR/closures.rs:3:35 | LL | fn test() -> [u8; N + (|| 42)()] {} - | ^^^^^^^^^^^^^ + | ^^^^-------^^ + | | + | unsupported rvalue | -note: unsupported rvalue - --> $DIR/closures.rs:3:39 - | -LL | fn test() -> [u8; N + (|| 42)()] {} - | ^^^^^^^ = help: consider moving this anonymous constant into a `const` function error: aborting due to previous error diff --git a/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr index 95fcde52af820..5749defb3e12c 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr @@ -2,26 +2,20 @@ error: overly complex generic constant --> $DIR/let-bindings.rs:6:68 | LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^-^^^^^^^^^^^^^ + | | + | unsupported statement | -note: unsupported statement - --> $DIR/let-bindings.rs:6:74 - | -LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - | ^ = help: consider moving this anonymous constant into a `const` function error: overly complex generic constant --> $DIR/let-bindings.rs:6:35 | LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^-^^^^^^^^^^^^^ + | | + | unsupported statement | -note: unsupported statement - --> $DIR/let-bindings.rs:6:41 - | -LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - | ^ = help: consider moving this anonymous constant into a `const` function error: aborting due to 2 previous errors From d452744100203c9f75202079ce7c8ad8aa1bdf02 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 21 Sep 2020 23:48:39 +0200 Subject: [PATCH 0812/1052] lint missing docs for extern items --- compiler/rustc_lint/src/builtin.rs | 13 +++++++++++++ src/test/ui/lint/lint-missing-doc.rs | 19 ++++++++++++++++++- src/test/ui/lint/lint-missing-doc.stderr | 20 +++++++++++++++++++- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index c35b6a9aaf4e9..abd899e8db4d3 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -613,6 +613,19 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { ); } + fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'_>) { + let def_id = cx.tcx.hir().local_def_id(foreign_item.hir_id); + let (article, desc) = cx.tcx.article_and_description(def_id.to_def_id()); + self.check_missing_docs_attrs( + cx, + Some(foreign_item.hir_id), + &foreign_item.attrs, + foreign_item.span, + article, + desc, + ); + } + fn check_struct_field(&mut self, cx: &LateContext<'_>, sf: &hir::StructField<'_>) { if !sf.is_positional() { self.check_missing_docs_attrs( diff --git a/src/test/ui/lint/lint-missing-doc.rs b/src/test/ui/lint/lint-missing-doc.rs index bab6f4e9e5e15..2297257919ee1 100644 --- a/src/test/ui/lint/lint-missing-doc.rs +++ b/src/test/ui/lint/lint-missing-doc.rs @@ -2,7 +2,7 @@ // injected intrinsics by the compiler. #![deny(missing_docs)] #![allow(dead_code)] -#![feature(associated_type_defaults)] +#![feature(associated_type_defaults, extern_types)] //! Some garbage docs for the crate here #![doc="More garbage"] @@ -183,4 +183,21 @@ pub mod public_interface { pub use internal_impl::globbed::*; } +extern "C" { + /// dox + pub fn extern_fn_documented(f: f32) -> f32; + pub fn extern_fn_undocumented(f: f32) -> f32; + //~^ ERROR: missing documentation for a function + + /// dox + pub static EXTERN_STATIC_DOCUMENTED: u8; + pub static EXTERN_STATIC_UNDOCUMENTED: u8; + //~^ ERROR: missing documentation for a static + + /// dox + pub type ExternTyDocumented; + pub type ExternTyUndocumented; + //~^ ERROR: missing documentation for a foreign type +} + fn main() {} diff --git a/src/test/ui/lint/lint-missing-doc.stderr b/src/test/ui/lint/lint-missing-doc.stderr index 21da4fae4c161..56f8fc10e8623 100644 --- a/src/test/ui/lint/lint-missing-doc.stderr +++ b/src/test/ui/lint/lint-missing-doc.stderr @@ -118,5 +118,23 @@ error: missing documentation for a function LL | pub fn also_undocumented1() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 19 previous errors +error: missing documentation for a function + --> $DIR/lint-missing-doc.rs:189:5 + | +LL | pub fn extern_fn_undocumented(f: f32) -> f32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: missing documentation for a static + --> $DIR/lint-missing-doc.rs:194:5 + | +LL | pub static EXTERN_STATIC_UNDOCUMENTED: u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: missing documentation for a foreign type + --> $DIR/lint-missing-doc.rs:199:5 + | +LL | pub type ExternTyUndocumented; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 22 previous errors From d9d02fa168016b5b5b2033a2964a723f447f94b0 Mon Sep 17 00:00:00 2001 From: blitzerr Date: Sun, 20 Sep 2020 20:14:44 -0700 Subject: [PATCH 0813/1052] Changing the alloc() to accept &self instead of &mut self --- library/alloc/src/alloc.rs | 4 ++-- library/alloc/src/raw_vec/tests.rs | 15 ++++++++------- library/core/src/alloc/mod.rs | 4 ++-- library/std/src/alloc.rs | 4 ++-- src/test/ui/allocator/custom.rs | 2 +- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 341c6816197c7..7d872b1a66bb9 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -145,7 +145,7 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { impl Global { #[inline] - fn alloc_impl(&mut self, layout: Layout, zeroed: bool) -> Result, AllocErr> { + fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result, AllocErr> { match layout.size() { 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)), // SAFETY: `layout` is non-zero in size, @@ -208,7 +208,7 @@ impl Global { #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl AllocRef for Global { #[inline] - fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + fn alloc(&self, layout: Layout) -> Result, AllocErr> { self.alloc_impl(layout, false) } diff --git a/library/alloc/src/raw_vec/tests.rs b/library/alloc/src/raw_vec/tests.rs index cadd913aa6bf2..f348710d61a77 100644 --- a/library/alloc/src/raw_vec/tests.rs +++ b/library/alloc/src/raw_vec/tests.rs @@ -1,4 +1,5 @@ use super::*; +use std::cell::Cell; #[test] fn allocator_param() { @@ -17,17 +18,17 @@ fn allocator_param() { // A dumb allocator that consumes a fixed amount of fuel // before allocation attempts start failing. struct BoundedAlloc { - fuel: usize, + fuel: Cell, } unsafe impl AllocRef for BoundedAlloc { - fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + fn alloc(&self, layout: Layout) -> Result, AllocErr> { let size = layout.size(); - if size > self.fuel { + if size > self.fuel.get() { return Err(AllocErr); } match Global.alloc(layout) { ok @ Ok(_) => { - self.fuel -= size; + self.fuel.update(|old| old - size); ok } err @ Err(_) => err, @@ -38,11 +39,11 @@ fn allocator_param() { } } - let a = BoundedAlloc { fuel: 500 }; + let a = BoundedAlloc { fuel: Cell::new(500) }; let mut v: RawVec = RawVec::with_capacity_in(50, a); - assert_eq!(v.alloc.fuel, 450); + assert_eq!(v.alloc.fuel.get(), 450); v.reserve(50, 150); // (causes a realloc, thus using 50 + 150 = 200 units of fuel) - assert_eq!(v.alloc.fuel, 250); + assert_eq!(v.alloc.fuel.get(), 250); } #[test] diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index c1fda2fce641f..b7dd249d09361 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -109,7 +109,7 @@ pub unsafe trait AllocRef { /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. /// /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html - fn alloc(&mut self, layout: Layout) -> Result, AllocErr>; + fn alloc(&self, layout: Layout) -> Result, AllocErr>; /// Behaves like `alloc`, but also ensures that the returned memory is zero-initialized. /// @@ -348,7 +348,7 @@ where A: AllocRef + ?Sized, { #[inline] - fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + fn alloc(&self, layout: Layout) -> Result, AllocErr> { (**self).alloc(layout) } diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index 770c97899f002..86ae4cf4dd213 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -133,7 +133,7 @@ pub struct System; impl System { #[inline] - fn alloc_impl(&mut self, layout: Layout, zeroed: bool) -> Result, AllocErr> { + fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result, AllocErr> { match layout.size() { 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)), // SAFETY: `layout` is non-zero in size, @@ -202,7 +202,7 @@ impl System { #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl AllocRef for System { #[inline] - fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + fn alloc(&self, layout: Layout) -> Result, AllocErr> { self.alloc_impl(layout, false) } diff --git a/src/test/ui/allocator/custom.rs b/src/test/ui/allocator/custom.rs index a6c2317c73669..603f59ab06927 100644 --- a/src/test/ui/allocator/custom.rs +++ b/src/test/ui/allocator/custom.rs @@ -18,7 +18,7 @@ struct A; unsafe impl alloc::GlobalAlloc for A { unsafe fn alloc(&self, layout: Layout) -> *mut u8 { HITS.fetch_add(1, Ordering::SeqCst); - System.alloc(layout) + AllocRef::alloc(&System, layout).unwrap().as_mut_ptr() } unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { From 7e443a1ffc587858c16aeac1dda3d2dffce0ff5f Mon Sep 17 00:00:00 2001 From: blitzerr Date: Mon, 21 Sep 2020 15:52:35 -0700 Subject: [PATCH 0814/1052] Added feature flag to use cell_update --- library/alloc/src/raw_vec/tests.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/alloc/src/raw_vec/tests.rs b/library/alloc/src/raw_vec/tests.rs index f348710d61a77..41d6c98b48196 100644 --- a/library/alloc/src/raw_vec/tests.rs +++ b/library/alloc/src/raw_vec/tests.rs @@ -1,6 +1,10 @@ +#![feature(cell_update)] + use super::*; use std::cell::Cell; + + #[test] fn allocator_param() { use crate::alloc::AllocErr; From 219003bd2ee6778333cf92405c6ea8591ecc8816 Mon Sep 17 00:00:00 2001 From: blitzerr Date: Mon, 21 Sep 2020 16:55:07 -0700 Subject: [PATCH 0815/1052] replaced cell::update with cell::[g|s]et --- library/alloc/src/raw_vec/tests.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/library/alloc/src/raw_vec/tests.rs b/library/alloc/src/raw_vec/tests.rs index 41d6c98b48196..2ed9d3685c69f 100644 --- a/library/alloc/src/raw_vec/tests.rs +++ b/library/alloc/src/raw_vec/tests.rs @@ -1,10 +1,6 @@ -#![feature(cell_update)] - use super::*; use std::cell::Cell; - - #[test] fn allocator_param() { use crate::alloc::AllocErr; @@ -32,7 +28,7 @@ fn allocator_param() { } match Global.alloc(layout) { ok @ Ok(_) => { - self.fuel.update(|old| old - size); + self.fuel.set(self.fuel.get() - size); ok } err @ Err(_) => err, From 01a771a7d8c16fc344152525e6fe16b3b72de57a Mon Sep 17 00:00:00 2001 From: Ishi Tatsuyuki Date: Tue, 22 Sep 2020 14:24:55 +0900 Subject: [PATCH 0816/1052] Add debug assertions against slow path reference results --- .../src/thir/pattern/_match.rs | 39 ++++++++++++++++--- .../rustc_mir_build/src/thir/pattern/mod.rs | 8 ++-- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/_match.rs b/compiler/rustc_mir_build/src/thir/pattern/_match.rs index ff14ffc2a11bd..3f13af0586913 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/_match.rs @@ -416,7 +416,7 @@ impl<'tcx> Pat<'tcx> { /// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]` /// works well. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] crate struct PatStack<'p, 'tcx>(SmallVec<[&'p Pat<'tcx>; 2]>); impl<'p, 'tcx> PatStack<'p, 'tcx> { @@ -506,7 +506,7 @@ impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> { /// Depending on the match patterns, the specialization process might be able to use a fast path. /// Tracks whether we can use the fast path and the lookup table needed in those cases. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] enum SpecializationCache { /// Patterns consist of only enum variants. /// Variant patterns does not intersect with each other (in contrast to range patterns), @@ -523,7 +523,7 @@ enum SpecializationCache { } /// A 2D matrix. -#[derive(Clone)] +#[derive(Clone, PartialEq)] crate struct Matrix<'p, 'tcx> { patterns: Vec>, cache: SpecializationCache, @@ -622,7 +622,19 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { fn specialize_wildcard(&self) -> Self { match &self.cache { SpecializationCache::Variants { wilds, .. } => { - wilds.iter().filter_map(|&i| self.patterns[i].specialize_wildcard()).collect() + let result = + wilds.iter().filter_map(|&i| self.patterns[i].specialize_wildcard()).collect(); + // When debug assertions are enabled, check the results against the "slow path" + // result. + debug_assert_eq!( + result, + Self { + patterns: self.patterns.clone(), + cache: SpecializationCache::Incompatible + } + .specialize_wildcard() + ); + result } SpecializationCache::Incompatible => { self.patterns.iter().filter_map(|r| r.specialize_wildcard()).collect() @@ -639,7 +651,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { ) -> Matrix<'p, 'tcx> { match &self.cache { SpecializationCache::Variants { lookup, wilds } => { - if let Constructor::Variant(id) = constructor { + let result: Self = if let Constructor::Variant(id) = constructor { lookup .get(id) // Default to `wilds` for absent keys. See `update_cache` for an explanation. @@ -655,7 +667,22 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { .collect() } else { unreachable!() - } + }; + // When debug assertions are enabled, check the results against the "slow path" + // result. + debug_assert_eq!( + result, + Matrix { + patterns: self.patterns.clone(), + cache: SpecializationCache::Incompatible + } + .specialize_constructor( + cx, + constructor, + ctor_wild_subpatterns + ) + ); + result } SpecializationCache::Incompatible => self .patterns diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index d617f4a6aa684..718ed78889f09 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -39,19 +39,19 @@ crate enum PatternError { NonConstPath(Span), } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq)] crate enum BindingMode { ByValue, ByRef(BorrowKind), } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] crate struct FieldPat<'tcx> { crate field: Field, crate pattern: Pat<'tcx>, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] crate struct Pat<'tcx> { crate ty: Ty<'tcx>, crate span: Span, @@ -116,7 +116,7 @@ crate struct Ascription<'tcx> { crate user_ty_span: Span, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] crate enum PatKind<'tcx> { Wild, From 2a40b6366245ddb38f4562da0b4f665f4d0e45d9 Mon Sep 17 00:00:00 2001 From: Imbolc Date: Tue, 22 Sep 2020 09:15:53 +0300 Subject: [PATCH 0817/1052] Update addr.rs I little clarification --- library/std/src/net/addr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/net/addr.rs b/library/std/src/net/addr.rs index 499b1137dcba5..a52e23de76ff4 100644 --- a/library/std/src/net/addr.rs +++ b/library/std/src/net/addr.rs @@ -747,7 +747,7 @@ impl hash::Hash for SocketAddrV6 { /// /// * `(`[`&str`]`, `[`u16`]`)`: the string should be either a string representation /// of an [`IpAddr`] address as expected by [`FromStr`] implementation or a host -/// name. +/// name. The second [`u16`] value of the tuple represents a port. /// /// * [`&str`]: the string should be either a string representation of a /// [`SocketAddr`] as expected by its [`FromStr`] implementation or a string like From 4a6bc77a0160a4540dea03e39642c373ca9f2a69 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Tue, 22 Sep 2020 14:26:15 +0800 Subject: [PATCH 0818/1052] Liballoc bench vec use mem take not replace --- library/alloc/benches/vec.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/alloc/benches/vec.rs b/library/alloc/benches/vec.rs index b295342f3610e..687efa8e9e777 100644 --- a/library/alloc/benches/vec.rs +++ b/library/alloc/benches/vec.rs @@ -241,7 +241,7 @@ fn bench_extend_recycle(b: &mut Bencher) { let mut data = vec![0; 1000]; b.iter(|| { - let tmp = std::mem::replace(&mut data, Vec::new()); + let tmp = std::mem::take(&mut data); let mut to_extend = black_box(Vec::new()); to_extend.extend(tmp.into_iter()); data = black_box(to_extend); @@ -500,7 +500,7 @@ fn bench_in_place_recycle(b: &mut Bencher) { let mut data = vec![0; 1000]; b.iter(|| { - let tmp = std::mem::replace(&mut data, Vec::new()); + let tmp = std::mem::take(&mut data); data = black_box( tmp.into_iter() .enumerate() @@ -520,7 +520,7 @@ fn bench_in_place_zip_recycle(b: &mut Bencher) { rng.fill_bytes(&mut subst[..]); b.iter(|| { - let tmp = std::mem::replace(&mut data, Vec::new()); + let tmp = std::mem::take(&mut data); let mangled = tmp .into_iter() .zip(subst.iter().copied()) From 731113b8eeef206ff27b77cb9f0dc49e2762a1b4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 22 Sep 2020 09:04:30 +0200 Subject: [PATCH 0819/1052] Miri: more informative deallocation error messages --- compiler/rustc_mir/src/interpret/memory.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir/src/interpret/memory.rs b/compiler/rustc_mir/src/interpret/memory.rs index 86e242c67d520..f3e373813ca53 100644 --- a/compiler/rustc_mir/src/interpret/memory.rs +++ b/compiler/rustc_mir/src/interpret/memory.rs @@ -285,9 +285,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { None => { // Deallocating global memory -- always an error return Err(match self.tcx.get_global_alloc(ptr.alloc_id) { - Some(GlobalAlloc::Function(..)) => err_ub_format!("deallocating a function"), + Some(GlobalAlloc::Function(..)) => { + err_ub_format!("deallocating {}, which is a function", ptr.alloc_id) + } Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => { - err_ub_format!("deallocating static memory") + err_ub_format!("deallocating {}, which is static memory", ptr.alloc_id) } None => err_ub!(PointerUseAfterFree(ptr.alloc_id)), } @@ -297,7 +299,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { if alloc_kind != kind { throw_ub_format!( - "deallocating {} memory using {} deallocation operation", + "deallocating {}, which is {} memory, using {} deallocation operation", + ptr.alloc_id, alloc_kind, kind ); @@ -305,7 +308,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { if let Some((size, align)) = old_size_and_align { if size != alloc.size || align != alloc.align { throw_ub_format!( - "incorrect layout on deallocation: allocation has size {} and alignment {}, but gave size {} and alignment {}", + "incorrect layout on deallocation: {} has size {} and alignment {}, but gave size {} and alignment {}", + ptr.alloc_id, alloc.size.bytes(), alloc.align.bytes(), size.bytes(), From 0082d201f1ea8ce106f1c71562d5f2d0d2e35513 Mon Sep 17 00:00:00 2001 From: follower Date: Tue, 22 Sep 2020 20:54:07 +1200 Subject: [PATCH 0820/1052] Typo fix: "satsify" -> "satisfy" --- library/alloc/src/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 8c0b6af54829b..d3845cbbc5e06 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -412,7 +412,7 @@ impl Vec { /// (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 satsify the [`dealloc`] requirement that memory must be + /// 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. From 2f5192280f57ab859a2414ff2e9b6f6398d3feb7 Mon Sep 17 00:00:00 2001 From: Federico Ponzi Date: Tue, 22 Sep 2020 09:54:36 +0100 Subject: [PATCH 0821/1052] enable unstable open_options_ext_as_flags feature in doc comments --- library/std/src/sys/unix/ext/fs.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/sys/unix/ext/fs.rs b/library/std/src/sys/unix/ext/fs.rs index afcd80abb9d27..15831c632ea3b 100644 --- a/library/std/src/sys/unix/ext/fs.rs +++ b/library/std/src/sys/unix/ext/fs.rs @@ -357,6 +357,7 @@ pub trait OpenOptionsExt { /// /// ```no_run /// # #![feature(rustc_private)] + /// #![feature(open_options_ext_as_flags)] /// extern crate libc; /// use std::ffi::CString; /// use std::fs::OpenOptions; From 143557ec56124c246d6cf4c37398e657f84536e1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 21 Sep 2020 17:32:53 +0200 Subject: [PATCH 0822/1052] Add missing examples on Vec iter types --- library/alloc/src/vec.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 9dbea0dc9e68b..b1f3b11ab9fd2 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -2797,6 +2797,13 @@ where /// /// This `struct` is created by the `into_iter` method on [`Vec`] (provided /// by the [`IntoIterator`] trait). +/// +/// # Example +/// +/// ``` +/// let v = vec![0, 1, 2]; +/// let iter: std::vec::IntoIter<_> = v.into_iter(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { buf: NonNull, @@ -3040,6 +3047,13 @@ impl AsIntoIter for IntoIter { /// /// This `struct` is created by [`Vec::drain`]. /// See its documentation for more. +/// +/// # Example +/// +/// ``` +/// let mut v = vec![0, 1, 2]; +/// let iter: std::vec::Drain<_> = v.drain(..); +/// ``` #[stable(feature = "drain", since = "1.6.0")] pub struct Drain<'a, T: 'a> { /// Index of tail to preserve @@ -3169,6 +3183,14 @@ impl FusedIterator for Drain<'_, T> {} /// /// This struct is created by [`Vec::splice()`]. /// See its documentation for more. +/// +/// # Example +/// +/// ``` +/// let mut v = vec![0, 1, 2]; +/// let new = [7, 8]; +/// let iter: std::vec::Splice<_> = v.splice(1.., new.iter().cloned()); +/// ``` #[derive(Debug)] #[stable(feature = "vec_splice", since = "1.21.0")] pub struct Splice<'a, I: Iterator + 'a> { @@ -3285,6 +3307,15 @@ impl Drain<'_, T> { /// /// This struct is created by [`Vec::drain_filter`]. /// See its documentation for more. +/// +/// # Example +/// +/// ``` +/// #![feature(drain_filter)] +/// +/// let mut v = vec![0, 1, 2]; +/// let iter: std::vec::DrainFilter<_, _> = v.drain_filter(|x| *x % 2 == 0); +/// ``` #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] #[derive(Debug)] pub struct DrainFilter<'a, T, F> From a13239dac2b4b50e389a3e12c638d164e620ea2f Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Thu, 19 Mar 2020 15:47:22 +0100 Subject: [PATCH 0823/1052] generic ret hardening test --- .../x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs diff --git a/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs new file mode 100644 index 0000000000000..5ca5dd6f27282 --- /dev/null +++ b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs @@ -0,0 +1,13 @@ +// Test LVI ret hardening on generic rust code + +// assembly-output: emit-asm +// compile-flags: --crate-type staticlib +// only-x86_64-fortanix-unknown-sgx + +#[no_mangle] +pub extern fn myret() {} +// CHECK: myret: +// CHECK: popq [[REGISTER:%[a-z]+]] +// CHECK-NEXT: lfence +// CHECK-NEXT: jmpq *[[REGISTER]] + From cd31f40b6f59c8966a09e7f1e2d6c3c5ed1570f1 Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Thu, 19 Mar 2020 15:47:50 +0100 Subject: [PATCH 0824/1052] generic load hardening test --- ...64-fortanix-unknown-sgx-lvi-generic-load.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs diff --git a/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs new file mode 100644 index 0000000000000..87ebb71dce9a3 --- /dev/null +++ b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs @@ -0,0 +1,18 @@ +// Test LVI load hardening on SGX enclave code + +// assembly-output: emit-asm +// compile-flags: --crate-type staticlib +// only-x86_64-fortanix-unknown-sgx + +#[no_mangle] +pub extern fn plus_one(r: &mut u64) { + *r = *r + 1; +} + +// CHECK: plus_one +// CHECK: lfence +// CHECK-NEXT: addq +// CHECK: popq [[REGISTER:%[a-z]+]] +// CHECK-NEXT: lfence +// CHECK-NEXT: jmpq *[[REGISTER]] + From 3ffd403c6b97f181c189a8eb5fbd30e3e7a95b43 Mon Sep 17 00:00:00 2001 From: blitzerr Date: Tue, 22 Sep 2020 06:22:02 -0700 Subject: [PATCH 0825/1052] removing &mut self for other methods of AllocRef --- library/alloc/src/alloc.rs | 4 ++-- library/alloc/src/raw_vec.rs | 2 +- library/alloc/src/raw_vec/tests.rs | 2 +- library/alloc/tests/heap.rs | 2 +- library/core/src/alloc/mod.rs | 8 ++++---- library/std/src/alloc.rs | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 7d872b1a66bb9..462bcd15fa941 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -213,12 +213,12 @@ unsafe impl AllocRef for Global { } #[inline] - fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + fn alloc_zeroed(&self, layout: Layout) -> Result, AllocErr> { self.alloc_impl(layout, true) } #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { if layout.size() != 0 { // SAFETY: `layout` is non-zero in size, // other conditions must be upheld by the caller diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 62675665f037f..5b4a4957f6cb1 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -169,7 +169,7 @@ impl RawVec { Self::allocate_in(capacity, AllocInit::Zeroed, alloc) } - fn allocate_in(capacity: usize, init: AllocInit, mut alloc: A) -> Self { + fn allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Self { if mem::size_of::() == 0 { Self::new_in(alloc) } else { diff --git a/library/alloc/src/raw_vec/tests.rs b/library/alloc/src/raw_vec/tests.rs index 2ed9d3685c69f..e4c8b3709dfee 100644 --- a/library/alloc/src/raw_vec/tests.rs +++ b/library/alloc/src/raw_vec/tests.rs @@ -34,7 +34,7 @@ fn allocator_param() { err @ Err(_) => err, } } - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { unsafe { Global.dealloc(ptr, layout) } } } diff --git a/library/alloc/tests/heap.rs b/library/alloc/tests/heap.rs index cbde2a7e28e8f..a7239a4b14fae 100644 --- a/library/alloc/tests/heap.rs +++ b/library/alloc/tests/heap.rs @@ -11,7 +11,7 @@ fn std_heap_overaligned_request() { check_overalign_requests(Global) } -fn check_overalign_requests(mut allocator: T) { +fn check_overalign_requests(allocator: T) { for &align in &[4, 8, 16, 32] { // less than and bigger than `MIN_ALIGN` for &size in &[align / 2, align - 1] { diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index b7dd249d09361..5f9092fe7037e 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -126,7 +126,7 @@ pub unsafe trait AllocRef { /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. /// /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html - fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + fn alloc_zeroed(&self, layout: Layout) -> Result, AllocErr> { let ptr = self.alloc(layout)?; // SAFETY: `alloc` returns a valid memory block unsafe { ptr.as_non_null_ptr().as_ptr().write_bytes(0, ptr.len()) } @@ -142,7 +142,7 @@ pub unsafe trait AllocRef { /// /// [*currently allocated*]: #currently-allocated-memory /// [*fit*]: #memory-fitting - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout); + unsafe fn dealloc(&self, ptr: NonNull, layout: Layout); /// Attempts to extend the memory block. /// @@ -353,12 +353,12 @@ where } #[inline] - fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + fn alloc_zeroed(&self, layout: Layout) -> Result, AllocErr> { (**self).alloc_zeroed(layout) } #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { // SAFETY: the safety contract must be upheld by the caller unsafe { (**self).dealloc(ptr, layout) } } diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index 86ae4cf4dd213..f41aa28b5ecb5 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -207,12 +207,12 @@ unsafe impl AllocRef for System { } #[inline] - fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + fn alloc_zeroed(&self, layout: Layout) -> Result, AllocErr> { self.alloc_impl(layout, true) } #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { if layout.size() != 0 { // SAFETY: `layout` is non-zero in size, // other conditions must be upheld by the caller From 05c3a2b07dc66fabc874181ce1eebea192cb4b56 Mon Sep 17 00:00:00 2001 From: est31 Date: Tue, 22 Sep 2020 15:30:09 +0200 Subject: [PATCH 0826/1052] Add #[track_caller] to more panicking Cell functions Continuation of #74526 Adds the #[track_caller] attribute to almost all panicking Cell functions. The ones that borrow two Cells in their function body are spared, because the panic location helps pinpoint which of the two borrows failed. You'd need to have full debuginfo and backtraces enabled together with column info in order to be able to discern the cases. Column info is only available on non-Windows platforms. --- library/core/src/cell.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index cbbfcb4611321..8d37cffeef556 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -700,6 +700,7 @@ impl RefCell { /// ``` #[inline] #[stable(feature = "refcell_replace", since = "1.24.0")] + #[track_caller] pub fn replace(&self, t: T) -> T { mem::replace(&mut *self.borrow_mut(), t) } @@ -722,6 +723,7 @@ impl RefCell { /// ``` #[inline] #[stable(feature = "refcell_replace_swap", since = "1.35.0")] + #[track_caller] pub fn replace_with T>(&self, f: F) -> T { let mut_borrow = &mut *self.borrow_mut(); let replacement = f(mut_borrow); @@ -1056,6 +1058,7 @@ impl Clone for RefCell { /// /// Panics if the value is currently mutably borrowed. #[inline] + #[track_caller] fn clone(&self) -> RefCell { RefCell::new(self.borrow().clone()) } From 14736ca20b2e5f60981743c6ee2dfa62db818767 Mon Sep 17 00:00:00 2001 From: blitzerr Date: Tue, 22 Sep 2020 08:51:20 -0700 Subject: [PATCH 0827/1052] fixing the custom.rs --- src/test/ui/allocator/custom.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/allocator/custom.rs b/src/test/ui/allocator/custom.rs index 603f59ab06927..f54ef1f0bc152 100644 --- a/src/test/ui/allocator/custom.rs +++ b/src/test/ui/allocator/custom.rs @@ -23,7 +23,7 @@ unsafe impl alloc::GlobalAlloc for A { unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { HITS.fetch_add(1, Ordering::SeqCst); - System.dealloc(ptr, layout) + AllocRef::dealloc(&System, ptr, layout) } } From 5ab714fdfe00db1dbac1adf2f56a850768d478b4 Mon Sep 17 00:00:00 2001 From: Imbolc Date: Tue, 22 Sep 2020 19:09:27 +0300 Subject: [PATCH 0828/1052] Update library/std/src/net/addr.rs Co-authored-by: Ivan Tham --- library/std/src/net/addr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/net/addr.rs b/library/std/src/net/addr.rs index a52e23de76ff4..16320ac3fe792 100644 --- a/library/std/src/net/addr.rs +++ b/library/std/src/net/addr.rs @@ -747,7 +747,7 @@ impl hash::Hash for SocketAddrV6 { /// /// * `(`[`&str`]`, `[`u16`]`)`: the string should be either a string representation /// of an [`IpAddr`] address as expected by [`FromStr`] implementation or a host -/// name. The second [`u16`] value of the tuple represents a port. +/// name. [`u16`] is the port number. /// /// * [`&str`]: the string should be either a string representation of a /// [`SocketAddr`] as expected by its [`FromStr`] implementation or a string like From 4622ceb5e02a717afd2380bc416b0a19897731ee Mon Sep 17 00:00:00 2001 From: Imbolc Date: Tue, 22 Sep 2020 19:09:35 +0300 Subject: [PATCH 0829/1052] Update library/std/src/net/addr.rs Co-authored-by: Ivan Tham --- library/std/src/net/addr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/net/addr.rs b/library/std/src/net/addr.rs index 16320ac3fe792..e213963d25046 100644 --- a/library/std/src/net/addr.rs +++ b/library/std/src/net/addr.rs @@ -745,7 +745,7 @@ impl hash::Hash for SocketAddrV6 { /// `(`[`Ipv4Addr`]`, `[`u16`]`)`, `(`[`Ipv6Addr`]`, `[`u16`]`)`: /// [`to_socket_addrs`] constructs a [`SocketAddr`] trivially. /// -/// * `(`[`&str`]`, `[`u16`]`)`: the string should be either a string representation +/// * `(`[`&str`]`, `[`u16`]`)`: [`&str`] should be either a string representation /// of an [`IpAddr`] address as expected by [`FromStr`] implementation or a host /// name. [`u16`] is the port number. /// From 3dd28c78c3c3f0fad72bfa41dd9655ce9d7b4bd5 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 17 Sep 2020 11:10:36 -0700 Subject: [PATCH 0830/1052] Useful derives on `ops::Status` --- compiler/rustc_mir/src/transform/check_consts/ops.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index 032cbc23a3f52..61171c870367c 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -51,6 +51,7 @@ pub fn non_const(ccx: &ConstCx<'_, '_>, op: O, span: Span) { op.emit_error(ccx, span); } +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Status { Allowed, Unstable(Symbol), From 110e59e70e21b2c93dc0cd48f22dea292cf62b75 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 17 Sep 2020 11:02:56 -0700 Subject: [PATCH 0831/1052] Update library functions with stability attributes This may not be strictly minimal, but all unstable functions also need a `rustc_const_unstable` attribute. --- library/alloc/src/borrow.rs | 2 ++ library/alloc/src/lib.rs | 2 ++ library/alloc/src/raw_vec.rs | 1 + library/alloc/tests/lib.rs | 1 + library/core/src/alloc/layout.rs | 1 + library/core/src/future/mod.rs | 1 + library/core/src/lib.rs | 2 ++ library/proc_macro/src/bridge/client.rs | 5 +++++ library/proc_macro/src/bridge/scoped_cell.rs | 1 + library/proc_macro/src/lib.rs | 1 + library/std/src/lib.rs | 2 ++ library/std/src/sys_common/thread_local_key.rs | 1 + library/std/src/thread/local.rs | 2 ++ 13 files changed, 22 insertions(+) diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs index e7260f3956c38..f801c1ac75bc3 100644 --- a/library/alloc/src/borrow.rs +++ b/library/alloc/src/borrow.rs @@ -217,6 +217,7 @@ impl Cow<'_, B> { /// assert!(!bull.is_borrowed()); /// ``` #[unstable(feature = "cow_is_borrowed", issue = "65143")] + #[rustc_const_unstable(feature = "const_cow_is_borrowed", issue = "65143")] pub const fn is_borrowed(&self) -> bool { match *self { Borrowed(_) => true, @@ -239,6 +240,7 @@ impl Cow<'_, B> { /// assert!(!bull.is_owned()); /// ``` #[unstable(feature = "cow_is_borrowed", issue = "65143")] + #[rustc_const_unstable(feature = "const_cow_is_borrowed", issue = "65143")] pub const fn is_owned(&self) -> bool { !self.is_borrowed() } diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 5ae4b7cf36adc..b33cb3ad8e839 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -86,9 +86,11 @@ #![feature(cfg_target_has_atomic)] #![feature(coerce_unsized)] #![feature(const_btree_new)] +#![feature(const_fn)] #![feature(const_generics)] #![feature(const_in_array_repeat_expressions)] #![feature(cow_is_borrowed)] +#![feature(const_cow_is_borrowed)] #![feature(dispatch_from_dyn)] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index e33dddc4f9841..e6da599006000 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -150,6 +150,7 @@ impl RawVec { impl RawVec { /// Like `new`, but parameterized over the choice of allocator for /// the returned `RawVec`. + #[allow_internal_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 } diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 3ee0cfbe74759..cff8ff9ac7ad9 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -1,6 +1,7 @@ #![feature(allocator_api)] #![feature(box_syntax)] #![feature(cow_is_borrowed)] +#![feature(const_cow_is_borrowed)] #![feature(drain_filter)] #![feature(exact_size_is_empty)] #![feature(new_uninit)] diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index a5ddf7619b6dc..a3fbed2ec1254 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -177,6 +177,7 @@ impl Layout { /// sentinel value. Types that lazily allocate must track initialization by /// some other means. #[unstable(feature = "alloc_layout_extra", issue = "55724")] + #[rustc_const_unstable(feature = "alloc_layout_extra", issue = "55724")] #[inline] pub const fn dangling(&self) -> NonNull { // SAFETY: align is guaranteed to be non-zero diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs index bec3adfa98422..fa5655ca35f41 100644 --- a/library/core/src/future/mod.rs +++ b/library/core/src/future/mod.rs @@ -56,6 +56,7 @@ unsafe impl Sync for ResumeTy {} #[lang = "from_generator"] #[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] +#[rustc_const_unstable(feature = "gen_future", issue = "50547")] #[inline] pub const fn from_generator(gen: T) -> impl Future where diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 9de0f76cbdd2c..86eda843c5bc3 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -75,11 +75,13 @@ #![feature(const_float_bits_conv)] #![feature(const_overflowing_int_methods)] #![feature(const_int_unchecked_arith)] +#![feature(const_mut_refs)] #![feature(const_int_pow)] #![feature(constctlz)] #![feature(const_panic)] #![feature(const_pin)] #![feature(const_fn_union)] +#![feature(const_fn)] #![feature(const_generics)] #![feature(const_option)] #![feature(const_precise_live_drops)] diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index 39daad4da127d..ba3d4c075e11f 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -401,6 +401,7 @@ fn run_client DecodeMut<'a, 's, ()>, R: Encode<()>>( } impl Client crate::TokenStream> { + #[allow_internal_unstable(const_fn)] pub const fn expand1(f: fn(crate::TokenStream) -> crate::TokenStream) -> Self { extern "C" fn run( bridge: Bridge<'_>, @@ -413,6 +414,7 @@ impl Client crate::TokenStream> { } impl Client crate::TokenStream> { + #[allow_internal_unstable(const_fn)] pub const fn expand2( f: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream, ) -> Self { @@ -457,6 +459,7 @@ impl ProcMacro { } } + #[allow_internal_unstable(const_fn)] pub const fn custom_derive( trait_name: &'static str, attributes: &'static [&'static str], @@ -465,6 +468,7 @@ impl ProcMacro { ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) } } + #[allow_internal_unstable(const_fn)] pub const fn attr( name: &'static str, expand: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream, @@ -472,6 +476,7 @@ impl ProcMacro { ProcMacro::Attr { name, client: Client::expand2(expand) } } + #[allow_internal_unstable(const_fn)] pub const fn bang( name: &'static str, expand: fn(crate::TokenStream) -> crate::TokenStream, diff --git a/library/proc_macro/src/bridge/scoped_cell.rs b/library/proc_macro/src/bridge/scoped_cell.rs index 2cde1f65adf9c..daa577f74bac3 100644 --- a/library/proc_macro/src/bridge/scoped_cell.rs +++ b/library/proc_macro/src/bridge/scoped_cell.rs @@ -35,6 +35,7 @@ impl<'a, 'b, T: LambdaL> DerefMut for RefMutL<'a, 'b, T> { pub struct ScopedCell(Cell<>::Out>); impl ScopedCell { + #[allow_internal_unstable(const_fn)] pub const fn new(value: >::Out) -> Self { ScopedCell(Cell::new(value)) } diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index c5a871e09a6ea..f81ffd2bb9429 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -20,6 +20,7 @@ )] #![feature(nll)] #![feature(staged_api)] +#![feature(const_fn)] #![feature(allow_internal_unstable)] #![feature(decl_macro)] #![feature(extern_types)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 70533189d8e0b..309657e70424b 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -237,6 +237,7 @@ #![feature(concat_idents)] #![feature(const_cstr_unchecked)] #![feature(const_fn_transmute)] +#![feature(const_fn)] #![feature(const_ipv6)] #![feature(const_raw_ptr_deref)] #![feature(const_ipv4)] @@ -306,6 +307,7 @@ #![feature(str_internals)] #![feature(test)] #![feature(thread_local)] +#![feature(thread_local_internals)] #![feature(toowned_clone_into)] #![feature(total_cmp)] #![feature(trace_macros)] diff --git a/library/std/src/sys_common/thread_local_key.rs b/library/std/src/sys_common/thread_local_key.rs index 3a2218854a730..676eadd1fac3b 100644 --- a/library/std/src/sys_common/thread_local_key.rs +++ b/library/std/src/sys_common/thread_local_key.rs @@ -117,6 +117,7 @@ pub struct Key { pub const INIT: StaticKey = StaticKey::new(None); impl StaticKey { + #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] pub const fn new(dtor: Option) -> StaticKey { StaticKey { key: atomic::AtomicUsize::new(0), dtor } } diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 60a05dc5d545b..784b376fcdc06 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -225,6 +225,7 @@ impl LocalKey { reason = "recently added to create a key", issue = "none" )] + #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] pub const unsafe fn new(inner: unsafe fn() -> Option<&'static T>) -> LocalKey { LocalKey { inner } } @@ -497,6 +498,7 @@ pub mod os { } impl Key { + #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] pub const fn new() -> Key { Key { os: OsStaticKey::new(Some(destroy_value::)), marker: marker::PhantomData } } From a173c5c1b3e1beb418c3adf9198c5ffd64dfb12a Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 17 Sep 2020 11:05:51 -0700 Subject: [PATCH 0832/1052] Add const-stability helpers --- .../src/transform/check_consts/mod.rs | 38 +++++++++++++++++++ .../src/transform/check_consts/ops.rs | 4 +- .../check_consts/post_drop_elaboration.rs | 11 +++--- .../src/transform/check_consts/validation.rs | 2 +- 4 files changed, 45 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/mod.rs b/compiler/rustc_mir/src/transform/check_consts/mod.rs index c1b4cb5f1a8d5..b49945f3f9dfd 100644 --- a/compiler/rustc_mir/src/transform/check_consts/mod.rs +++ b/compiler/rustc_mir/src/transform/check_consts/mod.rs @@ -51,6 +51,12 @@ impl ConstCx<'mir, 'tcx> { pub fn const_kind(&self) -> hir::ConstContext { self.const_kind.expect("`const_kind` must not be called on a non-const fn") } + + pub fn is_const_stable_const_fn(&self) -> bool { + self.const_kind == Some(hir::ConstContext::ConstFn) + && self.tcx.features().staged_api + && is_const_stable(self.tcx, self.def_id.to_def_id()) + } } /// Returns `true` if this `DefId` points to one of the official `panic` lang items. @@ -63,3 +69,35 @@ pub fn allow_internal_unstable(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: S attr::allow_internal_unstable(&tcx.sess, attrs) .map_or(false, |mut features| features.any(|name| name == feature_gate)) } + +// Returns `true` if the given `const fn` is "const-stable". +// +// Const-stability is only relevant for `const fn` within a `staged_api` crate. Only "const-stable" +// functions can be called in a const-context by users of the stable compiler. "const-stable" +// functions are subject to more stringent restrictions than "const-unstable" functions: They +// cannot use unstable features and can only call other "const-stable" functions. +pub fn is_const_stable(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { + use attr::{ConstStability, Stability, StabilityLevel}; + + // Const-stability is only relevant for `const fn`. + assert!(tcx.is_const_fn_raw(def_id)); + + // Functions with `#[rustc_const_unstable]` are const-unstable. + match tcx.lookup_const_stability(def_id) { + Some(ConstStability { level: StabilityLevel::Unstable { .. }, .. }) => return false, + Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => return true, + None => {} + } + + // Functions with `#[unstable]` are const-unstable. + // + // FIXME(ecstaticmorse): We should keep const-stability attributes wholly separate from normal stability + // attributes. `#[unstable]` should be irrelevant. + if let Some(Stability { level: StabilityLevel::Unstable { .. }, .. }) = + tcx.lookup_stability(def_id) + { + return false; + } + + true +} diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index 61171c870367c..2dfd7e2171cec 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -18,9 +18,7 @@ pub fn non_const(ccx: &ConstCx<'_, '_>, op: O, span: Span) { Status::Allowed => return, Status::Unstable(gate) if ccx.tcx.features().enabled(gate) => { - let unstable_in_stable = ccx.const_kind() == hir::ConstContext::ConstFn - && ccx.tcx.features().enabled(sym::staged_api) - && !ccx.tcx.has_attr(ccx.def_id.to_def_id(), sym::rustc_const_unstable) + let unstable_in_stable = ccx.is_const_stable_const_fn() && !super::allow_internal_unstable(ccx.tcx, ccx.def_id.to_def_id(), gate); if unstable_in_stable { diff --git a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs index 0228f2d7de023..e34511211c679 100644 --- a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs +++ b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs @@ -11,13 +11,13 @@ use super::ConstCx; /// Returns `true` if we should use the more precise live drop checker that runs after drop /// elaboration. -pub fn checking_enabled(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool { +pub fn checking_enabled(ccx: &ConstCx<'_, '_>) -> bool { // Const-stable functions must always use the stable live drop checker. - if tcx.features().staged_api && !tcx.has_attr(def_id.to_def_id(), sym::rustc_const_unstable) { + if ccx.is_const_stable_const_fn() { return false; } - tcx.features().const_precise_live_drops + ccx.tcx.features().const_precise_live_drops } /// Look for live drops in a const context. @@ -30,12 +30,11 @@ pub fn check_live_drops(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &mir::Body< return; } - if !checking_enabled(tcx, def_id) { + let ccx = ConstCx { body, tcx, def_id, const_kind, param_env: tcx.param_env(def_id) }; + if !checking_enabled(&ccx) { return; } - let ccx = ConstCx { body, tcx, def_id, const_kind, param_env: tcx.param_env(def_id) }; - let mut visitor = CheckLiveDrops { ccx: &ccx, qualifs: Qualifs::default() }; visitor.visit_body(body); diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 0501302b7610a..af9d7cc1aa529 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -551,7 +551,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { | TerminatorKind::DropAndReplace { place: dropped_place, .. } => { // If we are checking live drops after drop-elaboration, don't emit duplicate // errors here. - if super::post_drop_elaboration::checking_enabled(self.tcx, self.def_id) { + if super::post_drop_elaboration::checking_enabled(self.ccx) { return; } From 7fb9587a3ce4c689f7cab3aa5112aad9d421301f Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 17 Sep 2020 11:08:43 -0700 Subject: [PATCH 0833/1052] Return `true` if `check_const` emits an error --- .../src/transform/check_consts/ops.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index 2dfd7e2171cec..66b81b3d111fc 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -10,12 +10,12 @@ use rustc_span::{Span, Symbol}; use super::ConstCx; -/// Emits an error if `op` is not allowed in the given const context. -pub fn non_const(ccx: &ConstCx<'_, '_>, op: O, span: Span) { +/// Emits an error and returns `true` if `op` is not allowed in the given const context. +pub fn non_const(ccx: &ConstCx<'_, '_>, op: O, span: Span) -> bool { debug!("illegal_op: op={:?}", op); let gate = match op.status_in_item(ccx) { - Status::Allowed => return, + Status::Allowed => return false, Status::Unstable(gate) if ccx.tcx.features().enabled(gate) => { let unstable_in_stable = ccx.is_const_stable_const_fn() @@ -23,18 +23,21 @@ pub fn non_const(ccx: &ConstCx<'_, '_>, op: O, span: Span) { if unstable_in_stable { ccx.tcx.sess - .struct_span_err(span, &format!("`#[feature({})]` cannot be depended on in a const-stable function", gate.as_str())) + .struct_span_err( + span, + &format!("const-stable function cannot use `#[feature({})]`", gate.as_str()), + ) .span_suggestion( ccx.body.span, "if it is not part of the public API, make this function unstably const", concat!(r#"#[rustc_const_unstable(feature = "...", issue = "...")]"#, '\n').to_owned(), Applicability::HasPlaceholders, ) - .help("otherwise `#[allow_internal_unstable]` can be used to bypass stability checks") + .note("otherwise `#[allow_internal_unstable]` can be used to bypass stability checks") .emit(); } - return; + return unstable_in_stable; } Status::Unstable(gate) => Some(gate), @@ -43,10 +46,11 @@ pub fn non_const(ccx: &ConstCx<'_, '_>, op: O, span: Span) { if ccx.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you { ccx.tcx.sess.miri_unleashed_feature(span, gate); - return; + return false; } op.emit_error(ccx, span); + true } #[derive(Clone, Copy, Debug, PartialEq, Eq)] From bfc10a89c3a1cf2398b4cd8de342577ea96fe98a Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 17 Sep 2020 11:09:52 -0700 Subject: [PATCH 0834/1052] Allow errors to abort const checking when emitted This is a hack for parity with `qualify_min_const_fn`, which only emitted a single error. --- .../src/transform/check_consts/ops.rs | 2 ++ .../src/transform/check_consts/validation.rs | 24 +++++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index 66b81b3d111fc..1f0c93eed551e 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -62,6 +62,8 @@ pub enum Status { /// An operation that is not *always* allowed in a const context. pub trait NonConstOp: std::fmt::Debug { + const STOPS_CONST_CHECKING: bool = false; + /// Returns an enum indicating whether this operation is allowed within the given item. fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status { Status::Forbidden diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index af9d7cc1aa529..2c6e12e40bc70 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -176,6 +176,8 @@ pub struct Validator<'mir, 'tcx> { /// The span of the current statement. span: Span, + + const_checking_stopped: bool, } impl Deref for Validator<'mir, 'tcx> { @@ -188,7 +190,12 @@ impl Deref for Validator<'mir, 'tcx> { impl Validator<'mir, 'tcx> { pub fn new(ccx: &'mir ConstCx<'mir, 'tcx>) -> Self { - Validator { span: ccx.body.span, ccx, qualifs: Default::default() } + Validator { + span: ccx.body.span, + ccx, + qualifs: Default::default(), + const_checking_stopped: false, + } } pub fn check_body(&mut self) { @@ -226,13 +233,22 @@ impl Validator<'mir, 'tcx> { /// Emits an error if an expression cannot be evaluated in the current context. pub fn check_op(&mut self, op: impl NonConstOp) { - ops::non_const(self.ccx, op, self.span); + self.check_op_spanned(op, self.span); } /// Emits an error at the given `span` if an expression cannot be evaluated in the current /// context. - pub fn check_op_spanned(&mut self, op: impl NonConstOp, span: Span) { - ops::non_const(self.ccx, op, span); + pub fn check_op_spanned(&mut self, op: O, span: Span) { + // HACK: This is for strict equivalence with the old `qualify_min_const_fn` pass, which + // only emitted one error per function. It should be removed and the test output updated. + if self.const_checking_stopped { + return; + } + + let err_emitted = ops::non_const(self.ccx, op, span); + if err_emitted && O::STOPS_CONST_CHECKING { + self.const_checking_stopped = true; + } } fn check_static(&mut self, def_id: DefId, span: Span) { From 5ee5429e006af853827718fca42d6741ff26236e Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 17 Sep 2020 11:12:13 -0700 Subject: [PATCH 0835/1052] Add structured errors for `qualify_min_const_fn` checks --- .../src/transform/check_consts/ops.rs | 223 +++++++++++++++++- 1 file changed, 220 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index 1f0c93eed551e..b35c041ef53dd 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -98,6 +98,34 @@ pub trait NonConstOp: std::fmt::Debug { } } +#[derive(Debug)] +pub struct Abort; +impl NonConstOp for Abort { + const STOPS_CONST_CHECKING: bool = true; + + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + mcf_status_in_item(ccx) + } + + fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { + mcf_emit_error(ccx, span, "abort is not stable in const fn") + } +} + +#[derive(Debug)] +pub struct NonPrimitiveOp; +impl NonConstOp for NonPrimitiveOp { + const STOPS_CONST_CHECKING: bool = true; + + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + mcf_status_in_item(ccx) + } + + fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { + mcf_emit_error(ccx, span, "only int, `bool` and `char` operations are stable in const fn") + } +} + /// A function call where the callee is a pointer. #[derive(Debug)] pub struct FnCallIndirect; @@ -130,7 +158,8 @@ impl NonConstOp for FnCallNonConst { /// /// Contains the name of the feature that would allow the use of this function. #[derive(Debug)] -pub struct FnCallUnstable(pub DefId, pub Symbol); +pub struct FnCallUnstable(pub DefId, pub Option); + impl NonConstOp for FnCallUnstable { fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { let FnCallUnstable(def_id, feature) = *self; @@ -139,13 +168,51 @@ impl NonConstOp for FnCallUnstable { span, &format!("`{}` is not yet stable as a const fn", ccx.tcx.def_path_str(def_id)), ); - if nightly_options::is_nightly_build() { - err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature)); + + if ccx.is_const_stable_const_fn() { + err.help("Const-stable functions can only call other const-stable functions"); + } else if nightly_options::is_nightly_build() { + if let Some(feature) = feature { + err.help(&format!( + "add `#![feature({})]` to the crate attributes to enable", + feature + )); + } } err.emit(); } } +#[derive(Debug)] +pub struct FnPtrCast; +impl NonConstOp for FnPtrCast { + const STOPS_CONST_CHECKING: bool = true; + + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + mcf_status_in_item(ccx) + } + + fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { + mcf_emit_error(ccx, span, "function pointer casts are not allowed in const fn"); + } +} + +#[derive(Debug)] +pub struct Generator; +impl NonConstOp for Generator { + const STOPS_CONST_CHECKING: bool = true; + + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + // FIXME: This means generator-only MIR is only forbidden in const fn. This is for + // compatibility with the old code. Such MIR should be forbidden everywhere. + mcf_status_in_item(ccx) + } + + fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { + mcf_emit_error(ccx, span, "const fn generators are unstable"); + } +} + #[derive(Debug)] pub struct HeapAllocation; impl NonConstOp for HeapAllocation { @@ -408,6 +475,24 @@ impl NonConstOp for ThreadLocalAccess { } } +#[derive(Debug)] +pub struct Transmute; +impl NonConstOp for Transmute { + const STOPS_CONST_CHECKING: bool = true; + + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + if ccx.const_kind() != hir::ConstContext::ConstFn { + Status::Allowed + } else { + Status::Unstable(sym::const_fn_transmute) + } + } + + fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { + mcf_emit_error(ccx, span, "can only call `transmute` from const items, not `const fn`"); + } +} + #[derive(Debug)] pub struct UnionAccess; impl NonConstOp for UnionAccess { @@ -430,3 +515,135 @@ impl NonConstOp for UnionAccess { .emit(); } } + +/// See [#64992]. +/// +/// [#64992]: https://github.com/rust-lang/rust/issues/64992 +#[derive(Debug)] +pub struct UnsizingCast; +impl NonConstOp for UnsizingCast { + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + if ccx.const_kind() != hir::ConstContext::ConstFn { + Status::Allowed + } else { + Status::Unstable(sym::const_fn_transmute) + } + } + + fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { + mcf_emit_error( + ccx, + span, + "unsizing casts to types besides slices are not allowed in const fn", + ); + } +} + +pub mod ty { + use super::*; + + #[derive(Debug)] + pub struct MutRef; + impl NonConstOp for MutRef { + const STOPS_CONST_CHECKING: bool = true; + + fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_mut_refs) + } + + fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { + mcf_emit_error(ccx, span, "mutable references in const fn are unstable"); + } + } + + #[derive(Debug)] + pub struct FnPtr; + impl NonConstOp for FnPtr { + const STOPS_CONST_CHECKING: bool = true; + + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + // FIXME: This attribute a hack to allow the specialization of the `futures` API. See + // #59739. We should have a proper feature gate for this. + if ccx.tcx.has_attr(ccx.def_id.to_def_id(), sym::rustc_allow_const_fn_ptr) { + Status::Allowed + } else { + mcf_status_in_item(ccx) + } + } + + fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { + mcf_emit_error(ccx, span, "function pointers in const fn are unstable"); + } + } + + #[derive(Debug)] + pub struct ImplTrait; + impl NonConstOp for ImplTrait { + const STOPS_CONST_CHECKING: bool = true; + + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + mcf_status_in_item(ccx) + } + + fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { + mcf_emit_error(ccx, span, "`impl Trait` in const fn is unstable"); + } + } + + #[derive(Debug)] + pub struct TraitBound; + impl NonConstOp for TraitBound { + const STOPS_CONST_CHECKING: bool = true; + + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + mcf_status_in_item(ccx) + } + + fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { + mcf_emit_error( + ccx, + span, + "trait bounds other than `Sized` on const fn parameters are unstable", + ); + } + } + + /// A trait bound with the `?const Trait` opt-out + #[derive(Debug)] + pub struct TraitBoundNotConst; + impl NonConstOp for TraitBoundNotConst { + const STOPS_CONST_CHECKING: bool = true; + + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_trait_bound_opt_out) + } + + fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_trait_bound_opt_out, + span, + "`?const Trait` syntax is unstable", + ) + .emit() + } + } +} + +fn mcf_status_in_item(ccx: &ConstCx<'_, '_>) -> Status { + if ccx.const_kind() != hir::ConstContext::ConstFn { + Status::Allowed + } else { + Status::Unstable(sym::const_fn) + } +} + +fn mcf_emit_error(ccx: &ConstCx<'_, '_>, span: Span, msg: &str) { + struct_span_err!(ccx.tcx.sess, span, E0723, "{}", msg) + .note( + "see issue #57563 \ + for more information", + ) + .help("add `#![feature(const_fn)]` to the crate attributes to enable") + .emit(); +} From 3569bb63231979c89b71736cd8b9399aad249784 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 17 Sep 2020 11:14:11 -0700 Subject: [PATCH 0836/1052] Update const-checker to replicate `qualify_min_const_fn` --- .../check_consts/post_drop_elaboration.rs | 2 +- .../src/transform/check_consts/validation.rs | 339 ++++++++++++++---- 2 files changed, 268 insertions(+), 73 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs index e34511211c679..0c171bbc464a2 100644 --- a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs +++ b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs @@ -2,7 +2,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::{self, BasicBlock, Location}; use rustc_middle::ty::TyCtxt; -use rustc_span::{sym, Span}; +use rustc_span::Span; use super::ops; use super::qualifs::{NeedsDrop, Qualif}; diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 2c6e12e40bc70..55f49ab2be16b 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -7,19 +7,21 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::cast::CastTy; -use rustc_middle::ty::{self, Instance, InstanceDef, TyCtxt}; -use rustc_span::Span; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::{ + self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt, TypeAndMut, +}; +use rustc_span::{sym, Span}; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; use rustc_trait_selection::traits::{self, TraitEngine}; -use std::borrow::Cow; use std::ops::Deref; use super::ops::{self, NonConstOp}; use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop}; use super::resolver::FlowSensitiveAnalysis; use super::{is_lang_panic_fn, ConstCx, Qualif}; -use crate::const_eval::{is_const_fn, is_unstable_const_fn}; +use crate::const_eval::is_unstable_const_fn; use crate::dataflow::impls::MaybeMutBorrowedLocals; use crate::dataflow::{self, Analysis}; @@ -199,26 +201,51 @@ impl Validator<'mir, 'tcx> { } pub fn check_body(&mut self) { - let ConstCx { tcx, body, def_id, const_kind, .. } = *self.ccx; - - let use_min_const_fn_checks = (const_kind == Some(hir::ConstContext::ConstFn) - && crate::const_eval::is_min_const_fn(tcx, def_id.to_def_id())) - && !tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you; - - if use_min_const_fn_checks { - // Enforce `min_const_fn` for stable `const fn`s. - use crate::transform::qualify_min_const_fn::is_min_const_fn; - if let Err((span, err)) = is_min_const_fn(tcx, def_id.to_def_id(), &body) { - error_min_const_fn_violation(tcx, span, err); - return; + let ConstCx { tcx, body, def_id, .. } = *self.ccx; + + // HACK: This function has side-effects???? Make sure we call it. + let _ = crate::const_eval::is_min_const_fn(tcx, def_id.to_def_id()); + + // The local type and predicate checks are not free and only relevant for `const fn`s. + if self.const_kind() == hir::ConstContext::ConstFn { + // Prevent const trait methods from being annotated as `stable`. + // FIXME: Do this as part of stability checking. + if self.is_const_stable_const_fn() { + let hir_id = tcx.hir().local_def_id_to_hir_id(self.def_id); + if crate::const_eval::is_parent_const_impl_raw(tcx, hir_id) { + struct_span_err!( + self.ccx.tcx.sess, + self.span, + E0723, + "trait methods cannot be stable const fn" + ) + .emit(); + } + } + + self.check_item_predicates(); + + for local in &body.local_decls { + if local.internal { + continue; + } + + self.span = local.source_info.span; + self.check_local_or_return_ty(local.ty); } + + // impl trait is gone in MIR, so check the return type of a const fn by its signature + // instead of the type of the return place. + self.span = body.local_decls[RETURN_PLACE].source_info.span; + let return_ty = tcx.fn_sig(def_id).output(); + self.check_local_or_return_ty(return_ty.skip_binder()); } self.visit_body(&body); // Ensure that the end result is `Sync` in a non-thread local `static`. - let should_check_for_sync = const_kind - == Some(hir::ConstContext::Static(hir::Mutability::Not)) + let should_check_for_sync = self.const_kind() + == hir::ConstContext::Static(hir::Mutability::Not) && !tcx.is_thread_local_static(def_id.to_def_id()); if should_check_for_sync { @@ -258,6 +285,100 @@ impl Validator<'mir, 'tcx> { ); self.check_op_spanned(ops::StaticAccess, span) } + + fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>) { + for ty in ty.walk() { + let ty = match ty.unpack() { + GenericArgKind::Type(ty) => ty, + + // No constraints on lifetimes or constants, except potentially + // constants' types, but `walk` will get to them as well. + GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue, + }; + + match *ty.kind() { + ty::Ref(_, _, hir::Mutability::Mut) => self.check_op(ops::ty::MutRef), + ty::Opaque(..) => self.check_op(ops::ty::ImplTrait), + ty::FnPtr(..) => self.check_op(ops::ty::FnPtr), + + ty::Dynamic(preds, _) => { + for pred in preds.iter() { + match pred.skip_binder() { + ty::ExistentialPredicate::AutoTrait(_) + | ty::ExistentialPredicate::Projection(_) => { + self.check_op(ops::ty::TraitBound) + } + ty::ExistentialPredicate::Trait(trait_ref) => { + if Some(trait_ref.def_id) != self.tcx.lang_items().sized_trait() { + self.check_op(ops::ty::TraitBound) + } + } + } + } + } + _ => {} + } + } + } + + fn check_item_predicates(&mut self) { + let ConstCx { tcx, def_id, .. } = *self.ccx; + + let mut current = def_id.to_def_id(); + loop { + let predicates = tcx.predicates_of(current); + for (predicate, _) in predicates.predicates { + match predicate.skip_binders() { + ty::PredicateAtom::RegionOutlives(_) + | ty::PredicateAtom::TypeOutlives(_) + | ty::PredicateAtom::WellFormed(_) + | ty::PredicateAtom::Projection(_) + | ty::PredicateAtom::ConstEvaluatable(..) + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => continue, + ty::PredicateAtom::ObjectSafe(_) => { + bug!("object safe predicate on function: {:#?}", predicate) + } + ty::PredicateAtom::ClosureKind(..) => { + bug!("closure kind predicate on function: {:#?}", predicate) + } + ty::PredicateAtom::Subtype(_) => { + bug!("subtype predicate on function: {:#?}", predicate) + } + ty::PredicateAtom::Trait(pred, constness) => { + if Some(pred.def_id()) == tcx.lang_items().sized_trait() { + continue; + } + match pred.self_ty().kind() { + ty::Param(p) => { + let generics = tcx.generics_of(current); + let def = generics.type_param(p, tcx); + let span = tcx.def_span(def.def_id); + + if constness == hir::Constness::Const { + self.check_op_spanned(ops::ty::TraitBound, span); + } else if !tcx.features().const_fn + || self.ccx.is_const_stable_const_fn() + { + // HACK: We shouldn't need the conditional above, but trait + // bounds on containing impl blocks are wrongly being marked as + // "not-const". + self.check_op_spanned(ops::ty::TraitBound, span); + } + } + // other kinds of bounds are either tautologies + // or cause errors in other passes + _ => continue, + } + } + } + } + match predicates.parent { + Some(parent) => current = parent, + None => break, + } + } + } } impl Visitor<'tcx> for Validator<'mir, 'tcx> { @@ -325,11 +446,6 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { Rvalue::Use(_) | Rvalue::Repeat(..) - | Rvalue::UnaryOp(UnOp::Neg, _) - | Rvalue::UnaryOp(UnOp::Not, _) - | Rvalue::NullaryOp(NullOp::SizeOf, _) - | Rvalue::CheckedBinaryOp(..) - | Rvalue::Cast(CastKind::Pointer(_), ..) | Rvalue::Discriminant(..) | Rvalue::Len(_) | Rvalue::Aggregate(..) => {} @@ -379,6 +495,35 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } } + Rvalue::Cast( + CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer), + _, + _, + ) => {} + + Rvalue::Cast( + CastKind::Pointer( + PointerCast::UnsafeFnPointer + | PointerCast::ClosureFnPointer(_) + | PointerCast::ReifyFnPointer, + ), + _, + _, + ) => self.check_op(ops::FnPtrCast), + + Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, cast_ty) => { + if let Some(TypeAndMut { ty, .. }) = cast_ty.builtin_deref(true) { + let unsized_ty = self.tcx.struct_tail_erasing_lifetimes(ty, self.param_env); + + // Casting/coercing things to slices is fine. + if let ty::Slice(_) | ty::Str = unsized_ty.kind() { + return; + } + } + + self.check_op(ops::UnsizingCast); + } + Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => { let operand_ty = operand.ty(self.body, self.tcx); let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); @@ -389,8 +534,23 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } } - Rvalue::BinaryOp(op, ref lhs, _) => { - if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind() { + Rvalue::NullaryOp(NullOp::SizeOf, _) => {} + Rvalue::NullaryOp(NullOp::Box, _) => self.check_op(ops::HeapAllocation), + + Rvalue::UnaryOp(_, ref operand) => { + let ty = operand.ty(self.body, self.tcx); + if !(ty.is_integral() || ty.is_bool()) { + self.check_op(ops::NonPrimitiveOp) + } + } + + Rvalue::BinaryOp(op, ref lhs, ref rhs) + | Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => { + let lhs_ty = lhs.ty(self.body, self.tcx); + let rhs_ty = rhs.ty(self.body, self.tcx); + + if let ty::RawPtr(_) | ty::FnPtr(..) = lhs_ty.kind() { + assert_eq!(lhs_ty, rhs_ty); assert!( op == BinOp::Eq || op == BinOp::Ne @@ -403,10 +563,12 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { self.check_op(ops::RawPtrComparison); } - } - Rvalue::NullaryOp(NullOp::Box, _) => { - self.check_op(ops::HeapAllocation); + if !(lhs_ty.is_integral() || lhs_ty.is_bool() || lhs_ty.is_char()) + || !(rhs_ty.is_integral() || rhs_ty.is_bool() || rhs_ty.is_char()) + { + self.check_op(ops::NonPrimitiveOp) + } } } } @@ -507,14 +669,19 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + use rustc_target::spec::abi::Abi::RustIntrinsic; + trace!("visit_terminator: terminator={:?} location={:?}", terminator, location); self.super_terminator(terminator, location); match &terminator.kind { TerminatorKind::Call { func, .. } => { - let fn_ty = func.ty(self.body, self.tcx); + let ConstCx { tcx, body, def_id: caller, param_env, .. } = *self.ccx; + let caller = caller.to_def_id(); + + let fn_ty = func.ty(body, tcx); - let (def_id, substs) = match *fn_ty.kind() { + let (mut callee, substs) = match *fn_ty.kind() { ty::FnDef(def_id, substs) => (def_id, substs), ty::FnPtr(_) => { @@ -526,38 +693,78 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } }; - // At this point, we are calling a function whose `DefId` is known... - if is_const_fn(self.tcx, def_id) { - return; - } - - // See if this is a trait method for a concrete type whose impl of that trait is - // `const`. if self.tcx.features().const_trait_impl { - let instance = Instance::resolve(self.tcx, self.param_env, def_id, substs); - debug!("Resolving ({:?}) -> {:?}", def_id, instance); + let instance = Instance::resolve(tcx, param_env, callee, substs); + debug!("Resolving ({:?}) -> {:?}", callee, instance); if let Ok(Some(func)) = instance { if let InstanceDef::Item(def) = func.def { - if is_const_fn(self.tcx, def.did) { - return; - } + callee = def.did; } } } - if is_lang_panic_fn(self.tcx, def_id) { + // At this point, we are calling a function, `callee`, whose `DefId` is known... + + if is_lang_panic_fn(tcx, callee) { self.check_op(ops::Panic); - } else if let Some(feature) = is_unstable_const_fn(self.tcx, def_id) { - // Exempt unstable const fns inside of macros or functions with - // `#[allow_internal_unstable]`. - use crate::transform::qualify_min_const_fn::lib_feature_allowed; - if !self.span.allows_unstable(feature) - && !lib_feature_allowed(self.tcx, self.def_id.to_def_id(), feature) - { - self.check_op(ops::FnCallUnstable(def_id, feature)); + return; + } + + // HACK: This is to "unstabilize" the `transmute` intrinsic + // within const fns. `transmute` is allowed in all other const contexts. + // This won't really scale to more intrinsics or functions. Let's allow const + // transmutes in const fn before we add more hacks to this. + if tcx.fn_sig(callee).abi() == RustIntrinsic + && tcx.item_name(callee) == sym::transmute + { + self.check_op(ops::Transmute); + return; + } + + if !tcx.is_const_fn_raw(callee) { + self.check_op(ops::FnCallNonConst(callee)); + return; + } + + // If the `const fn` we are trying to call is not const-stable, ensure that we have + // the proper feature gate enabled. + if let Some(gate) = is_unstable_const_fn(tcx, callee) { + if self.span.allows_unstable(gate) { + return; + } + + // Calling an unstable function *always* requires that the corresponding gate + // be enabled, even if the function has `#[allow_internal_unstable(the_gate)]`. + if !tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == gate) { + self.check_op(ops::FnCallUnstable(callee, Some(gate))); + return; + } + + // If this crate is not using stability attributes, or the caller is not claiming to be a + // stable `const fn`, that is all that is required. + if !self.ccx.is_const_stable_const_fn() { + return; + } + + // Otherwise, we are something const-stable calling a const-unstable fn. + + if super::allow_internal_unstable(tcx, caller, gate) { + return; + } + + self.check_op(ops::FnCallUnstable(callee, Some(gate))); + return; + } + + // FIXME(ecstaticmorse); For compatibility, we consider `unstable` callees that + // have no `rustc_const_stable` attributes to be const-unstable as well. This + // should be fixed later. + let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none() + && tcx.lookup_stability(callee).map_or(false, |s| s.level.is_unstable()); + if callee_is_unstable_unmarked { + if self.ccx.is_const_stable_const_fn() { + self.check_op(ops::FnCallUnstable(callee, None)); } - } else { - self.check_op(ops::FnCallNonConst(def_id)); } } @@ -598,37 +805,25 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } } - TerminatorKind::InlineAsm { .. } => { - self.check_op(ops::InlineAsm); + TerminatorKind::InlineAsm { .. } => self.check_op(ops::InlineAsm), + TerminatorKind::Abort => self.check_op(ops::Abort), + + TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => { + self.check_op(ops::Generator) } - // FIXME: Some of these are only caught by `min_const_fn`, but should error here - // instead. - TerminatorKind::Abort - | TerminatorKind::Assert { .. } + TerminatorKind::Assert { .. } | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::GeneratorDrop | TerminatorKind::Goto { .. } | TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Unreachable - | TerminatorKind::Yield { .. } => {} + | TerminatorKind::Unreachable => {} } } } -fn error_min_const_fn_violation(tcx: TyCtxt<'_>, span: Span, msg: Cow<'_, str>) { - struct_span_err!(tcx.sess, span, E0723, "{}", msg) - .note( - "see issue #57563 \ - for more information", - ) - .help("add `#![feature(const_fn)]` to the crate attributes to enable") - .emit(); -} - fn check_return_ty_is_sync(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, hir_id: HirId) { let ty = body.return_ty(); tcx.infer_ctxt().enter(|infcx| { From ef6d4277ed319de88d078e09a1d449eebc409327 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 17 Sep 2020 10:32:07 -0700 Subject: [PATCH 0837/1052] Bless tests --- .../const-extern-fn-call-extern-fn.rs | 4 +- .../const-extern-fn-call-extern-fn.stderr | 12 +--- .../const-extern-fn-min-const-fn.rs | 2 +- .../const-extern-fn-min-const-fn.stderr | 9 +-- .../ui/consts/const-fn-not-safe-for-const.rs | 2 +- .../feature-gate-const_mut_refs.rs | 3 +- src/test/ui/consts/const_let_assign3.rs | 2 +- src/test/ui/consts/const_let_assign3.stderr | 13 ++-- .../min_const_fn/bad_const_fn_body_ice.rs | 5 +- .../min_const_fn/bad_const_fn_body_ice.stderr | 26 ++++++-- .../ui/consts/min_const_fn/min_const_fn.rs | 20 +++--- .../consts/min_const_fn/min_const_fn.stderr | 40 ++++++------ .../min_const_fn_libstd_stability.rs | 9 +-- .../min_const_fn_libstd_stability.stderr | 27 ++++---- .../min_const_fn/min_const_fn_unsafe_bad.rs | 2 +- .../min_const_fn_unsafe_bad.stderr | 9 ++- .../min_const_unsafe_fn_libstd_stability.rs | 9 +-- ...in_const_unsafe_fn_libstd_stability.stderr | 27 ++++---- .../min_const_unsafe_fn_libstd_stability2.rs | 6 +- ...n_const_unsafe_fn_libstd_stability2.stderr | 16 ++--- .../consts/miri_unleashed/abi-mismatch.stderr | 10 +++ src/test/ui/consts/unsizing-cast-non-null.rs | 2 +- .../ui/consts/unsizing-cast-non-null.stderr | 2 +- .../ui/consts/unstable-const-fn-in-libcore.rs | 1 + .../unstable-const-fn-in-libcore.stderr | 6 +- src/test/ui/parser/fn-header-semantic-fail.rs | 3 + .../ui/parser/fn-header-semantic-fail.stderr | 64 +++++++++++++------ .../const-check-fns-in-const-impl.rs | 2 +- .../const-check-fns-in-const-impl.stderr | 7 +- .../feature-gate.gated.stderr | 2 +- .../const-trait-bound-opt-out/feature-gate.rs | 1 + .../feature-gate.stock.stderr | 2 +- .../ui/rfc-2632-const-trait-impl/stability.rs | 2 +- .../stability.stderr | 8 +-- src/test/ui/unsafe/ranged_ints2_const.rs | 4 +- 35 files changed, 200 insertions(+), 159 deletions(-) diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs index 6469a65700dad..e18e0a83573ee 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs @@ -7,7 +7,7 @@ extern "C" { const extern fn bar() { unsafe { regular_in_block(); - //~^ ERROR: can only call other `const fn` within a `const fn` + //~^ ERROR: calls in constant functions } } @@ -16,7 +16,7 @@ extern fn regular() {} const extern fn foo() { unsafe { regular(); - //~^ ERROR: can only call other `const fn` within a `const fn` + //~^ ERROR: calls in constant functions } } diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr index a9e2bcdbdd150..348387ff5f827 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr @@ -1,21 +1,15 @@ -error[E0723]: can only call other `const fn` within a `const fn`, but `regular_in_block` is not stable as `const fn` +error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants --> $DIR/const-extern-fn-call-extern-fn.rs:9:9 | LL | regular_in_block(); | ^^^^^^^^^^^^^^^^^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: can only call other `const fn` within a `const fn`, but `regular` is not stable as `const fn` +error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants --> $DIR/const-extern-fn-call-extern-fn.rs:18:9 | LL | regular(); | ^^^^^^^^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0723`. +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs index 2854c08665716..e0b9e5f33759e 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs @@ -6,7 +6,7 @@ const unsafe extern "C" fn closure() -> fn() { || {} } const unsafe extern fn use_float() { 1.0 + 1.0; } //~^ ERROR only int, `bool` and `char` operations are stable in const fn const extern "C" fn ptr_cast(val: *const u8) { val as usize; } -//~^ ERROR casting pointers to ints is unstable in const fn +//~^ ERROR casting pointers to integers fn main() {} diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr index 146d119fc8f7f..5ca44b3fa7e65 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr @@ -16,15 +16,16 @@ LL | const unsafe extern fn use_float() { 1.0 + 1.0; } = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: casting pointers to ints is unstable in const fn +error[E0658]: casting pointers to integers in constant functions is unstable --> $DIR/const-extern-fn-min-const-fn.rs:8:48 | LL | const extern "C" fn ptr_cast(val: *const u8) { val as usize; } | ^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0723`. +Some errors have detailed explanations: E0658, E0723. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/const-fn-not-safe-for-const.rs b/src/test/ui/consts/const-fn-not-safe-for-const.rs index 085ff5c58e60c..0446ece421eff 100644 --- a/src/test/ui/consts/const-fn-not-safe-for-const.rs +++ b/src/test/ui/consts/const-fn-not-safe-for-const.rs @@ -1,6 +1,6 @@ // Test that we can't call random fns in a const fn or do other bad things. -#![feature(const_fn, const_transmute)] +#![feature(const_fn, const_fn_transmute)] use std::mem::transmute; diff --git a/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs index 2207599815ee8..f31543af590d6 100644 --- a/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs +++ b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs @@ -2,6 +2,7 @@ fn main() { foo(&mut 5); } -const fn foo(x: &mut i32) -> i32 { //~ ERROR mutable references in const fn are unstable +const fn foo(x: &mut i32) -> i32 { //~ ERROR mutable references in const fn *x + 1 + } diff --git a/src/test/ui/consts/const_let_assign3.rs b/src/test/ui/consts/const_let_assign3.rs index f993a427b4899..9d5ccb880aa1b 100644 --- a/src/test/ui/consts/const_let_assign3.rs +++ b/src/test/ui/consts/const_let_assign3.rs @@ -6,8 +6,8 @@ struct S { impl S { const fn foo(&mut self, x: u32) { + //~^ ERROR mutable references self.state = x; - //~^ contains unimplemented expression } } diff --git a/src/test/ui/consts/const_let_assign3.stderr b/src/test/ui/consts/const_let_assign3.stderr index dd05a4c0bb069..785d9c8c2a5fb 100644 --- a/src/test/ui/consts/const_let_assign3.stderr +++ b/src/test/ui/consts/const_let_assign3.stderr @@ -1,10 +1,11 @@ -error[E0019]: constant function contains unimplemented expression type - --> $DIR/const_let_assign3.rs:9:9 +error[E0723]: mutable references in const fn are unstable + --> $DIR/const_let_assign3.rs:8:18 | -LL | self.state = x; - | ^^^^^^^^^^^^^^ +LL | const fn foo(&mut self, x: u32) { + | ^^^^^^^^^ | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + = note: see issue #57563 for more information + = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0764]: mutable references are not allowed in constants --> $DIR/const_let_assign3.rs:16:5 @@ -28,5 +29,5 @@ LL | *y = 42; error: aborting due to 4 previous errors -Some errors have detailed explanations: E0019, E0764. +Some errors have detailed explanations: E0019, E0723, E0764. For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs index 3e42cb8c1b074..589085871fba9 100644 --- a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs +++ b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs @@ -1,5 +1,8 @@ const fn foo(a: i32) -> Vec { - vec![1, 2, 3] //~ ERROR heap allocations are not allowed in const fn + vec![1, 2, 3] + //~^ ERROR allocations are not allowed + //~| ERROR unimplemented expression type + //~| ERROR calls in constant functions } fn main() {} diff --git a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr index 39b223062e986..0f16890141f6b 100644 --- a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr +++ b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr @@ -1,13 +1,29 @@ -error[E0723]: heap allocations are not allowed in const fn +error[E0010]: allocations are not allowed in constant functions + --> $DIR/bad_const_fn_body_ice.rs:2:5 + | +LL | vec![1, 2, 3] + | ^^^^^^^^^^^^^ allocation not allowed in constant functions + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0019]: constant function contains unimplemented expression type + --> $DIR/bad_const_fn_body_ice.rs:2:5 + | +LL | vec![1, 2, 3] + | ^^^^^^^^^^^^^ + | + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants --> $DIR/bad_const_fn_body_ice.rs:2:5 | LL | vec![1, 2, 3] | ^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to previous error +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0723`. +Some errors have detailed explanations: E0010, E0015, E0019. +For more information about an error, try `rustc --explain E0010`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs index 2ebd9dd10c512..5dd70acb6ff1c 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs @@ -78,25 +78,25 @@ const fn foo11(t: T) -> T { t } const fn foo11_2(t: T) -> T { t } //~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable const fn foo19(f: f32) -> f32 { f * 2.0 } -//~^ ERROR only int, `bool` and `char` operations are stable in const fn +//~^ ERROR int, `bool` and `char` operations const fn foo19_2(f: f32) -> f32 { 2.0 - f } -//~^ ERROR only int, `bool` and `char` operations are stable in const fn +//~^ ERROR int, `bool` and `char` operations const fn foo19_3(f: f32) -> f32 { -f } -//~^ ERROR only int and `bool` operations are stable in const fn +//~^ ERROR int, `bool` and `char` operations const fn foo19_4(f: f32, g: f32) -> f32 { f / g } -//~^ ERROR only int, `bool` and `char` operations are stable in const fn +//~^ ERROR int, `bool` and `char` operations static BAR: u32 = 42; -const fn foo25() -> u32 { BAR } //~ ERROR cannot access `static` items in const fn -const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot access `static` items +const fn foo25() -> u32 { BAR } //~ ERROR cannot refer to statics +const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot refer to statics const fn foo30(x: *const u32) -> usize { x as usize } -//~^ ERROR casting pointers to ints is unstable +//~^ ERROR casting pointers to integers const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } } -//~^ ERROR casting pointers to ints is unstable +//~^ ERROR casting pointers to integers const fn foo30_2(x: *mut u32) -> usize { x as usize } -//~^ ERROR casting pointers to ints is unstable +//~^ ERROR casting pointers to integers const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } } -//~^ ERROR casting pointers to ints is unstable +//~^ ERROR casting pointers to integers const fn foo30_6() -> bool { let x = true; x } const fn inc(x: &mut i32) { *x += 1 } //~^ ERROR mutable references in const fn are unstable diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr index 9b55b6c6f3bbc..d4498f061c64b 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr @@ -94,7 +94,7 @@ LL | const fn foo19_2(f: f32) -> f32 { 2.0 - f } = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: only int and `bool` operations are stable in const fn +error[E0723]: only int, `bool` and `char` operations are stable in const fn --> $DIR/min_const_fn.rs:84:35 | LL | const fn foo19_3(f: f32) -> f32 { -f } @@ -112,59 +112,57 @@ LL | const fn foo19_4(f: f32, g: f32) -> f32 { f / g } = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: cannot access `static` items in const fn +error[E0013]: constant functions cannot refer to statics --> $DIR/min_const_fn.rs:90:27 | LL | const fn foo25() -> u32 { BAR } | ^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: consider extracting the value of the `static` to a `const`, and referring to that -error[E0723]: cannot access `static` items in const fn +error[E0013]: constant functions cannot refer to statics --> $DIR/min_const_fn.rs:91:37 | LL | const fn foo26() -> &'static u32 { &BAR } | ^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: consider extracting the value of the `static` to a `const`, and referring to that -error[E0723]: casting pointers to ints is unstable in const fn +error[E0658]: casting pointers to integers in constant functions is unstable --> $DIR/min_const_fn.rs:92:42 | LL | const fn foo30(x: *const u32) -> usize { x as usize } | ^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable -error[E0723]: casting pointers to ints is unstable in const fn +error[E0658]: casting pointers to integers in constant functions is unstable --> $DIR/min_const_fn.rs:94:63 | LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } } | ^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable -error[E0723]: casting pointers to ints is unstable in const fn +error[E0658]: casting pointers to integers in constant functions is unstable --> $DIR/min_const_fn.rs:96:42 | LL | const fn foo30_2(x: *mut u32) -> usize { x as usize } | ^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable -error[E0723]: casting pointers to ints is unstable in const fn +error[E0658]: casting pointers to integers in constant functions is unstable --> $DIR/min_const_fn.rs:98:63 | LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } } | ^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable error[E0723]: mutable references in const fn are unstable --> $DIR/min_const_fn.rs:101:14 @@ -267,5 +265,5 @@ LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo } error: aborting due to 30 previous errors -Some errors have detailed explanations: E0493, E0723. -For more information about an error, try `rustc --explain E0493`. +Some errors have detailed explanations: E0013, E0493, E0658, E0723. +For more information about an error, try `rustc --explain E0013`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs index df10f3496c3c8..b83fdf7c656cd 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs @@ -13,7 +13,7 @@ const fn foo() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const fn bar() -> u32 { foo() } //~ ERROR can only call other `const fn` +const fn bar() -> u32 { foo() } //~ ERROR not yet stable as a const fn #[unstable(feature = "rust1", issue = "none")] const fn foo2() -> u32 { 42 } @@ -21,12 +21,13 @@ const fn foo2() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const fn bar2() -> u32 { foo2() } //~ ERROR can only call other `const fn` +const fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // conformity is required, even with `const_fn` feature gate -const fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` operations +const fn bar3() -> u32 { (5f32 + 6f32) as u32 } +//~^ ERROR const-stable function cannot use `#[feature(const_fn)]` // check whether this function cannot be called even with the feature gate active #[unstable(feature = "foo2", issue = "none")] @@ -35,6 +36,6 @@ const fn foo2_gated() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `const fn` +const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR not yet stable as a const fn fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr index bef4f240eeb8b..a1f1f6f52ab2a 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr @@ -1,39 +1,38 @@ -error[E0723]: can only call other `const fn` within a `const fn`, but `foo` is not stable as `const fn` +error: `foo` is not yet stable as a const fn --> $DIR/min_const_fn_libstd_stability.rs:16:25 | LL | const fn bar() -> u32 { foo() } | ^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions -error[E0723]: can only call other `const fn` within a `const fn`, but `foo2` is not stable as `const fn` +error: `foo2` is not yet stable as a const fn --> $DIR/min_const_fn_libstd_stability.rs:24:26 | LL | const fn bar2() -> u32 { foo2() } | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions -error[E0723]: only int, `bool` and `char` operations are stable in const fn +error: const-stable function cannot use `#[feature(const_fn)]` --> $DIR/min_const_fn_libstd_stability.rs:29:26 | LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 } | ^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: otherwise `#[allow_internal_unstable]` can be used to bypass stability checks +help: if it is not part of the public API, make this function unstably const + | +LL | #[rustc_const_unstable(feature = "...", issue = "...")] + | -error[E0723]: can only call other `const fn` within a `const fn`, but `foo2_gated` is not stable as `const fn` - --> $DIR/min_const_fn_libstd_stability.rs:38:32 +error: `foo2_gated` is not yet stable as a const fn + --> $DIR/min_const_fn_libstd_stability.rs:39:32 | LL | const fn bar2_gated() -> u32 { foo2_gated() } | ^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs index 6462d736ad194..0c8af5a199aa0 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs @@ -12,5 +12,5 @@ fn main() {} const unsafe fn no_union() { union Foo { x: (), y: () } Foo { x: () }.y - //~^ accessing union fields is unstable + //~^ unions in const fn } diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr index 427ecff5c6d1a..322052c28fab1 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr @@ -25,16 +25,15 @@ LL | const unsafe fn bad_const_unsafe_deref_raw_ref(x: *mut usize) -> &'static u = note: see issue #51911 for more information = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable -error[E0723]: accessing union fields is unstable +error[E0658]: unions in const fn are unstable --> $DIR/min_const_fn_unsafe_bad.rs:14:5 | LL | Foo { x: () }.y | ^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #51909 for more information + = help: add `#![feature(const_fn_union)]` to the crate attributes to enable error: aborting due to 4 previous errors -Some errors have detailed explanations: E0658, E0723. -For more information about an error, try `rustc --explain E0658`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs index 12b41ee2b0d6a..902ed435e31bc 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs @@ -13,7 +13,7 @@ const unsafe fn foo() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other `const fn` +const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR not yet stable as a const fn #[unstable(feature = "rust1", issue = "none")] const unsafe fn foo2() -> u32 { 42 } @@ -21,12 +21,13 @@ const unsafe fn foo2() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR can only call other `const fn` +const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR not yet stable as a const fn #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // conformity is required, even with `const_fn` feature gate -const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` op +const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } +//~^ ERROR const-stable function cannot use `#[feature(const_fn)]` // check whether this function cannot be called even with the feature gate active #[unstable(feature = "foo2", issue = "none")] @@ -36,6 +37,6 @@ const unsafe fn foo2_gated() -> u32 { 42 } #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } -//~^ ERROR can only call other `const fn` +//~^ ERROR not yet stable as a const fn fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr index c5ff340dfc6b7..2741a86440487 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr @@ -1,39 +1,38 @@ -error[E0723]: can only call other `const fn` within a `const fn`, but `foo` is not stable as `const fn` +error: `foo` is not yet stable as a const fn --> $DIR/min_const_unsafe_fn_libstd_stability.rs:16:41 | LL | const unsafe fn bar() -> u32 { unsafe { foo() } } | ^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions -error[E0723]: can only call other `const fn` within a `const fn`, but `foo2` is not stable as `const fn` +error: `foo2` is not yet stable as a const fn --> $DIR/min_const_unsafe_fn_libstd_stability.rs:24:42 | LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions -error[E0723]: only int, `bool` and `char` operations are stable in const fn +error: const-stable function cannot use `#[feature(const_fn)]` --> $DIR/min_const_unsafe_fn_libstd_stability.rs:29:33 | LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } | ^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: otherwise `#[allow_internal_unstable]` can be used to bypass stability checks +help: if it is not part of the public API, make this function unstably const + | +LL | #[rustc_const_unstable(feature = "...", issue = "...")] + | -error[E0723]: can only call other `const fn` within a `const fn`, but `foo2_gated` is not stable as `const fn` - --> $DIR/min_const_unsafe_fn_libstd_stability.rs:38:48 +error: `foo2_gated` is not yet stable as a const fn + --> $DIR/min_const_unsafe_fn_libstd_stability.rs:39:48 | LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } | ^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs index 44a6209498737..d17dcb281153c 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs @@ -13,7 +13,7 @@ const fn foo() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `const fn` +const unsafe fn bar() -> u32 { foo() } //~ ERROR not yet stable as a const fn #[unstable(feature = "rust1", issue = "none")] const fn foo2() -> u32 { 42 } @@ -21,7 +21,7 @@ const fn foo2() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `const fn` +const unsafe fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn // check whether this function cannot be called even with the feature gate active #[unstable(feature = "foo2", issue = "none")] @@ -30,6 +30,6 @@ const fn foo2_gated() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `const fn` +const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR not yet stable as a const fn fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr index 31ad12c955113..891c34a888a70 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr @@ -1,30 +1,26 @@ -error[E0723]: can only call other `const fn` within a `const fn`, but `foo` is not stable as `const fn` +error: `foo` is not yet stable as a const fn --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:16:32 | LL | const unsafe fn bar() -> u32 { foo() } | ^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions -error[E0723]: can only call other `const fn` within a `const fn`, but `foo2` is not stable as `const fn` +error: `foo2` is not yet stable as a const fn --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:24:33 | LL | const unsafe fn bar2() -> u32 { foo2() } | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions -error[E0723]: can only call other `const fn` within a `const fn`, but `foo2_gated` is not stable as `const fn` +error: `foo2_gated` is not yet stable as a const fn --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:33:39 | LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } | ^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr b/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr index eb250081d6a72..93b67fd7b1428 100644 --- a/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr +++ b/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr @@ -12,6 +12,16 @@ LL | static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern " warning: skipping const checks | +help: skipping check for `const_fn` feature + --> $DIR/abi-mismatch.rs:9:23 + | +LL | const fn call_rust_fn(my_fn: extern "Rust" fn()) { + | ^^^^^ +help: skipping check for `const_fn` feature + --> $DIR/abi-mismatch.rs:10:5 + | +LL | my_fn(); + | ^^^^^ help: skipping check that does not even have a feature gate --> $DIR/abi-mismatch.rs:10:5 | diff --git a/src/test/ui/consts/unsizing-cast-non-null.rs b/src/test/ui/consts/unsizing-cast-non-null.rs index 67d9f6baca5b4..af6bc2d85fdd6 100644 --- a/src/test/ui/consts/unsizing-cast-non-null.rs +++ b/src/test/ui/consts/unsizing-cast-non-null.rs @@ -4,7 +4,7 @@ use std::ptr::NonNull; pub const fn dangling_slice() -> NonNull<[T]> { NonNull::<[T; 0]>::dangling() - //~^ ERROR: unsizing casts are only allowed for references right now + //~^ ERROR: unsizing casts to types besides slices } fn main() {} diff --git a/src/test/ui/consts/unsizing-cast-non-null.stderr b/src/test/ui/consts/unsizing-cast-non-null.stderr index 6575355daadd7..dc08ccd02b646 100644 --- a/src/test/ui/consts/unsizing-cast-non-null.stderr +++ b/src/test/ui/consts/unsizing-cast-non-null.stderr @@ -1,4 +1,4 @@ -error[E0723]: unsizing casts are only allowed for references right now +error[E0723]: unsizing casts to types besides slices are not allowed in const fn --> $DIR/unsizing-cast-non-null.rs:6:5 | LL | NonNull::<[T; 0]>::dangling() diff --git a/src/test/ui/consts/unstable-const-fn-in-libcore.rs b/src/test/ui/consts/unstable-const-fn-in-libcore.rs index 29d3dc18fa7cc..43951c6854b1a 100644 --- a/src/test/ui/consts/unstable-const-fn-in-libcore.rs +++ b/src/test/ui/consts/unstable-const-fn-in-libcore.rs @@ -6,6 +6,7 @@ #![stable(feature = "core", since = "1.6.0")] #![feature(rustc_const_unstable)] #![feature(staged_api)] +#![feature(const_fn)] enum Opt { Some(T), diff --git a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr index be797cae7ca97..928605356a16e 100644 --- a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr +++ b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr @@ -1,11 +1,11 @@ error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants - --> $DIR/unstable-const-fn-in-libcore.rs:23:26 + --> $DIR/unstable-const-fn-in-libcore.rs:24:26 | LL | Opt::None => f(), | ^^^ error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/unstable-const-fn-in-libcore.rs:18:53 + --> $DIR/unstable-const-fn-in-libcore.rs:19:53 | LL | const fn unwrap_or_else T>(self, f: F) -> T { | ^ constant functions cannot evaluate destructors @@ -14,7 +14,7 @@ LL | } | - value is dropped here error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/unstable-const-fn-in-libcore.rs:18:47 + --> $DIR/unstable-const-fn-in-libcore.rs:19:47 | LL | const fn unwrap_or_else T>(self, f: F) -> T { | ^^^^ constant functions cannot evaluate destructors diff --git a/src/test/ui/parser/fn-header-semantic-fail.rs b/src/test/ui/parser/fn-header-semantic-fail.rs index c327667f4cdc7..6d3fc3ce2f171 100644 --- a/src/test/ui/parser/fn-header-semantic-fail.rs +++ b/src/test/ui/parser/fn-header-semantic-fail.rs @@ -12,6 +12,7 @@ fn main() { extern "C" fn ff4() {} // OK. const async unsafe extern "C" fn ff5() {} // OK. //~^ ERROR functions cannot be both `const` and `async` + //~| ERROR `from_generator` is not yet stable as a const fn trait X { async fn ft1(); //~ ERROR functions in traits cannot be declared `async` @@ -34,6 +35,7 @@ fn main() { const async unsafe extern "C" fn ft5() {} //~^ ERROR functions in traits cannot be declared `async` //~| ERROR functions in traits cannot be declared const + //~| ERROR `from_generator` is not yet stable as a const fn //~| ERROR method `ft5` has an incompatible type for trait //~| ERROR functions cannot be both `const` and `async` } @@ -45,6 +47,7 @@ fn main() { extern "C" fn fi4() {} // OK. const async unsafe extern "C" fn fi5() {} //~^ ERROR functions cannot be both `const` and `async` + //~| ERROR `from_generator` is not yet stable as a const fn } extern { diff --git a/src/test/ui/parser/fn-header-semantic-fail.stderr b/src/test/ui/parser/fn-header-semantic-fail.stderr index 4193b3ee695bc..f1e21884040f0 100644 --- a/src/test/ui/parser/fn-header-semantic-fail.stderr +++ b/src/test/ui/parser/fn-header-semantic-fail.stderr @@ -8,7 +8,7 @@ LL | const async unsafe extern "C" fn ff5() {} // OK. | `const` because of this error[E0706]: functions in traits cannot be declared `async` - --> $DIR/fn-header-semantic-fail.rs:17:9 + --> $DIR/fn-header-semantic-fail.rs:18:9 | LL | async fn ft1(); | -----^^^^^^^^^^ @@ -19,19 +19,19 @@ LL | async fn ft1(); = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait error[E0379]: functions in traits cannot be declared const - --> $DIR/fn-header-semantic-fail.rs:19:9 + --> $DIR/fn-header-semantic-fail.rs:20:9 | LL | const fn ft3(); | ^^^^^ functions in traits cannot be const error[E0379]: functions in traits cannot be declared const - --> $DIR/fn-header-semantic-fail.rs:21:9 + --> $DIR/fn-header-semantic-fail.rs:22:9 | LL | const async unsafe extern "C" fn ft5(); | ^^^^^ functions in traits cannot be const error[E0706]: functions in traits cannot be declared `async` - --> $DIR/fn-header-semantic-fail.rs:21:9 + --> $DIR/fn-header-semantic-fail.rs:22:9 | LL | const async unsafe extern "C" fn ft5(); | ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -42,7 +42,7 @@ LL | const async unsafe extern "C" fn ft5(); = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait error: functions cannot be both `const` and `async` - --> $DIR/fn-header-semantic-fail.rs:21:9 + --> $DIR/fn-header-semantic-fail.rs:22:9 | LL | const async unsafe extern "C" fn ft5(); | ^^^^^-^^^^^---------------------------- @@ -51,7 +51,7 @@ LL | const async unsafe extern "C" fn ft5(); | `const` because of this error[E0706]: functions in traits cannot be declared `async` - --> $DIR/fn-header-semantic-fail.rs:29:9 + --> $DIR/fn-header-semantic-fail.rs:30:9 | LL | async fn ft1() {} | -----^^^^^^^^^^^^ @@ -62,19 +62,19 @@ LL | async fn ft1() {} = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait error[E0379]: functions in traits cannot be declared const - --> $DIR/fn-header-semantic-fail.rs:32:9 + --> $DIR/fn-header-semantic-fail.rs:33:9 | LL | const fn ft3() {} | ^^^^^ functions in traits cannot be const error[E0379]: functions in traits cannot be declared const - --> $DIR/fn-header-semantic-fail.rs:34:9 + --> $DIR/fn-header-semantic-fail.rs:35:9 | LL | const async unsafe extern "C" fn ft5() {} | ^^^^^ functions in traits cannot be const error[E0706]: functions in traits cannot be declared `async` - --> $DIR/fn-header-semantic-fail.rs:34:9 + --> $DIR/fn-header-semantic-fail.rs:35:9 | LL | const async unsafe extern "C" fn ft5() {} | ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | const async unsafe extern "C" fn ft5() {} = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait error: functions cannot be both `const` and `async` - --> $DIR/fn-header-semantic-fail.rs:34:9 + --> $DIR/fn-header-semantic-fail.rs:35:9 | LL | const async unsafe extern "C" fn ft5() {} | ^^^^^-^^^^^------------------------------ @@ -94,7 +94,7 @@ LL | const async unsafe extern "C" fn ft5() {} | `const` because of this error: functions cannot be both `const` and `async` - --> $DIR/fn-header-semantic-fail.rs:46:9 + --> $DIR/fn-header-semantic-fail.rs:48:9 | LL | const async unsafe extern "C" fn fi5() {} | ^^^^^-^^^^^------------------------------ @@ -103,7 +103,7 @@ LL | const async unsafe extern "C" fn fi5() {} | `const` because of this error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:51:18 + --> $DIR/fn-header-semantic-fail.rs:54:18 | LL | extern { | ------ in this `extern` block @@ -113,7 +113,7 @@ LL | async fn fe1(); | help: remove the qualifiers: `fn` error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:52:19 + --> $DIR/fn-header-semantic-fail.rs:55:19 | LL | extern { | ------ in this `extern` block @@ -124,7 +124,7 @@ LL | unsafe fn fe2(); | help: remove the qualifiers: `fn` error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:53:18 + --> $DIR/fn-header-semantic-fail.rs:56:18 | LL | extern { | ------ in this `extern` block @@ -135,7 +135,7 @@ LL | const fn fe3(); | help: remove the qualifiers: `fn` error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:54:23 + --> $DIR/fn-header-semantic-fail.rs:57:23 | LL | extern { | ------ in this `extern` block @@ -146,7 +146,7 @@ LL | extern "C" fn fe4(); | help: remove the qualifiers: `fn` error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:55:42 + --> $DIR/fn-header-semantic-fail.rs:58:42 | LL | extern { | ------ in this `extern` block @@ -157,7 +157,7 @@ LL | const async unsafe extern "C" fn fe5(); | help: remove the qualifiers: `fn` error: functions cannot be both `const` and `async` - --> $DIR/fn-header-semantic-fail.rs:55:9 + --> $DIR/fn-header-semantic-fail.rs:58:9 | LL | const async unsafe extern "C" fn fe5(); | ^^^^^-^^^^^---------------------------- @@ -165,8 +165,16 @@ LL | const async unsafe extern "C" fn fe5(); | | `async` because of this | `const` because of this +error: `from_generator` is not yet stable as a const fn + --> $DIR/fn-header-semantic-fail.rs:13:44 + | +LL | const async unsafe extern "C" fn ff5() {} // OK. + | ^^ + | + = help: add `#![feature(gen_future)]` to the crate attributes to enable + error[E0053]: method `ft1` has an incompatible type for trait - --> $DIR/fn-header-semantic-fail.rs:29:24 + --> $DIR/fn-header-semantic-fail.rs:30:24 | LL | async fn ft1(); | - type in trait @@ -181,7 +189,7 @@ LL | async fn ft1() {} found fn pointer `fn() -> impl Future` error[E0053]: method `ft5` has an incompatible type for trait - --> $DIR/fn-header-semantic-fail.rs:34:48 + --> $DIR/fn-header-semantic-fail.rs:35:48 | LL | const async unsafe extern "C" fn ft5(); | - type in trait @@ -195,7 +203,23 @@ LL | const async unsafe extern "C" fn ft5() {} = note: expected fn pointer `unsafe extern "C" fn()` found fn pointer `unsafe extern "C" fn() -> impl Future` -error: aborting due to 20 previous errors +error: `from_generator` is not yet stable as a const fn + --> $DIR/fn-header-semantic-fail.rs:35:48 + | +LL | const async unsafe extern "C" fn ft5() {} + | ^^ + | + = help: add `#![feature(gen_future)]` to the crate attributes to enable + +error: `from_generator` is not yet stable as a const fn + --> $DIR/fn-header-semantic-fail.rs:48:48 + | +LL | const async unsafe extern "C" fn fi5() {} + | ^^ + | + = help: add `#![feature(gen_future)]` to the crate attributes to enable + +error: aborting due to 23 previous errors Some errors have detailed explanations: E0053, E0379, E0706. For more information about an error, try `rustc --explain E0053`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs index 3278f35bad2b2..fc85e98ef5326 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs @@ -10,7 +10,7 @@ fn non_const() {} impl const T for S { fn foo() { non_const() } - //~^ ERROR can only call other `const fn` + //~^ ERROR calls in constant functions } fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr index b50dd03a86138..c6c78c7d1e895 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr @@ -1,12 +1,9 @@ -error[E0723]: can only call other `const fn` within a `const fn`, but `non_const` is not stable as `const fn` +error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants --> $DIR/const-check-fns-in-const-impl.rs:12:16 | LL | fn foo() { non_const() } | ^^^^^^^^^^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable error: aborting due to previous error -For more information about this error, try `rustc --explain E0723`. +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr index 3994bd97c308e..58041454d5901 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr @@ -1,5 +1,5 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/feature-gate.rs:16:1 + --> $DIR/feature-gate.rs:17:1 | LL | fn main() {} | ^^^^^^^^^ diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs index d600b53e44875..3506237d1f1d5 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs @@ -4,6 +4,7 @@ #![cfg_attr(gated, feature(const_trait_bound_opt_out))] #![allow(incomplete_features)] #![feature(rustc_attrs)] +#![feature(const_fn)] trait T { const CONST: i32; diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr index a1e1c3249af36..8ae8b8868dded 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr @@ -1,5 +1,5 @@ error[E0658]: `?const` on trait bounds is experimental - --> $DIR/feature-gate.rs:12:29 + --> $DIR/feature-gate.rs:13:29 | LL | const fn get_assoc_const() -> i32 { ::CONST } | ^^^^^^ diff --git a/src/test/ui/rfc-2632-const-trait-impl/stability.rs b/src/test/ui/rfc-2632-const-trait-impl/stability.rs index 03a6fb51503b5..454fde34a2cdc 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/stability.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/stability.rs @@ -30,7 +30,7 @@ impl const std::ops::Add for Int { #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn foo() -> Int { Int(1i32) + Int(2i32) - //~^ ERROR can only call other `const fn` within a `const fn` + //~^ ERROR not yet stable as a const fn } // ok diff --git a/src/test/ui/rfc-2632-const-trait-impl/stability.stderr b/src/test/ui/rfc-2632-const-trait-impl/stability.stderr index ddef7a3aafc93..54d7cfd5d7973 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/stability.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/stability.stderr @@ -6,18 +6,14 @@ LL | | LL | | Int(self.0 - rhs.0) LL | | } | |_____^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: can only call other `const fn` within a `const fn`, but `::add` is not stable as `const fn` +error: `::add` is not yet stable as a const fn --> $DIR/stability.rs:32:5 | LL | Int(1i32) + Int(2i32) | ^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions error: aborting due to 2 previous errors diff --git a/src/test/ui/unsafe/ranged_ints2_const.rs b/src/test/ui/unsafe/ranged_ints2_const.rs index 788f49f743cda..65e0d79308ca3 100644 --- a/src/test/ui/unsafe/ranged_ints2_const.rs +++ b/src/test/ui/unsafe/ranged_ints2_const.rs @@ -8,13 +8,13 @@ fn main() { const fn foo() -> NonZero { let mut x = unsafe { NonZero(1) }; - let y = &mut x.0; //~ ERROR references in const fn are unstable + let y = &mut x.0; //~ ERROR mutable references //~^ ERROR mutation of layout constrained field is unsafe unsafe { NonZero(1) } } const fn bar() -> NonZero { let mut x = unsafe { NonZero(1) }; - let y = unsafe { &mut x.0 }; //~ ERROR mutable references in const fn are unstable + let y = unsafe { &mut x.0 }; //~ ERROR mutable references unsafe { NonZero(1) } } From 9be3d106c39b292af064cdd8998b34d6d1b9ab04 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 17 Sep 2020 12:48:09 -0700 Subject: [PATCH 0838/1052] Bless compile-fail --- src/test/compile-fail/consts/const-fn-error.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/test/compile-fail/consts/const-fn-error.rs b/src/test/compile-fail/consts/const-fn-error.rs index 7dbf7d1a38691..644748786036d 100644 --- a/src/test/compile-fail/consts/const-fn-error.rs +++ b/src/test/compile-fail/consts/const-fn-error.rs @@ -5,9 +5,7 @@ const X : usize = 2; const fn f(x: usize) -> usize { let mut sum = 0; for i in 0..x { - //~^ ERROR E0015 - //~| ERROR E0015 - //~| ERROR E0658 + //~^ ERROR mutable references //~| ERROR E0080 //~| ERROR E0744 sum += i; From d60e204e0adb899de3bc1e4a87a04a1cb56238b5 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 18 Sep 2020 09:17:13 -0700 Subject: [PATCH 0839/1052] Use the same name everywhere for `is_const_stable_const_fn` --- compiler/rustc_mir/src/transform/check_consts/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/mod.rs b/compiler/rustc_mir/src/transform/check_consts/mod.rs index b49945f3f9dfd..8d4efd8ae8052 100644 --- a/compiler/rustc_mir/src/transform/check_consts/mod.rs +++ b/compiler/rustc_mir/src/transform/check_consts/mod.rs @@ -55,7 +55,7 @@ impl ConstCx<'mir, 'tcx> { pub fn is_const_stable_const_fn(&self) -> bool { self.const_kind == Some(hir::ConstContext::ConstFn) && self.tcx.features().staged_api - && is_const_stable(self.tcx, self.def_id.to_def_id()) + && is_const_stable_const_fn(self.tcx, self.def_id.to_def_id()) } } @@ -72,11 +72,13 @@ pub fn allow_internal_unstable(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: S // Returns `true` if the given `const fn` is "const-stable". // +// Panics if the given `DefId` does not refer to a `const fn`. +// // Const-stability is only relevant for `const fn` within a `staged_api` crate. Only "const-stable" // functions can be called in a const-context by users of the stable compiler. "const-stable" // functions are subject to more stringent restrictions than "const-unstable" functions: They // cannot use unstable features and can only call other "const-stable" functions. -pub fn is_const_stable(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { +pub fn is_const_stable_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { use attr::{ConstStability, Stability, StabilityLevel}; // Const-stability is only relevant for `const fn`. From 08e3822d9a5ce2f403c67c2d0e374f601fbf1aaf Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 18 Sep 2020 09:19:36 -0700 Subject: [PATCH 0840/1052] Replace missing comment --- compiler/rustc_mir/src/transform/check_consts/validation.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 55f49ab2be16b..7ea3c1d5a6f85 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -693,6 +693,8 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } }; + // Resolve a trait method call to its concrete implementation, which may be in a + // `const` trait impl. if self.tcx.features().const_trait_impl { let instance = Instance::resolve(tcx, param_env, callee, substs); debug!("Resolving ({:?}) -> {:?}", callee, instance); From 883a7a5c05c24439e5c540a25e8e1ea952362bfc Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 22 Sep 2020 10:16:03 -0700 Subject: [PATCH 0841/1052] Rebase LLVM onto 11.0.0-rc3 --- .gitmodules | 2 +- src/llvm-project | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 8f4d3768c21e8..d460b6508f620 100644 --- a/.gitmodules +++ b/.gitmodules @@ -37,7 +37,7 @@ [submodule "src/llvm-project"] path = src/llvm-project url = https://github.com/rust-lang/llvm-project.git - branch = rustc/11.0-2020-08-20 + branch = rustc/11.0-2020-09-22 [submodule "src/doc/embedded-book"] path = src/doc/embedded-book url = https://github.com/rust-embedded/book.git diff --git a/src/llvm-project b/src/llvm-project index a78defc24c739..7075196da1aa3 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit a78defc24c73930246db65fcabbca86a3df684c4 +Subproject commit 7075196da1aa3527f7c87943607e25f3cf24997a From 6044836284190f1ed63623deb531457c720e73d2 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Tue, 22 Sep 2020 10:21:45 -0700 Subject: [PATCH 0842/1052] Add `#![feature(const_fn_transmute)]` to `rustc_ast` --- compiler/rustc_ast/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 76b84d9da8334..480a5d2f18eca 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -7,6 +7,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] #![feature(box_syntax)] #![feature(const_fn)] // For the `transmute` in `P::new` +#![feature(const_fn_transmute)] #![feature(const_panic)] #![feature(crate_visibility_modifier)] #![feature(label_break_value)] From 186d148b4cd67223fde15b421086e74a95501096 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Tue, 22 Sep 2020 10:21:58 -0700 Subject: [PATCH 0843/1052] Use correct feature gate for unsizing casts --- compiler/rustc_mir/src/transform/check_consts/ops.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index b35c041ef53dd..e14dcf92b89d2 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -523,11 +523,7 @@ impl NonConstOp for UnionAccess { pub struct UnsizingCast; impl NonConstOp for UnsizingCast { fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { - if ccx.const_kind() != hir::ConstContext::ConstFn { - Status::Allowed - } else { - Status::Unstable(sym::const_fn_transmute) - } + mcf_status_in_item(ccx) } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { From 4b6a4821b71221a46576100a5ab3fc92011fad16 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 22 Sep 2020 20:19:00 +0200 Subject: [PATCH 0844/1052] Fix dest prop miscompilation around references --- compiler/rustc_mir/src/transform/dest_prop.rs | 2 +- src/test/ui/issues/issue-77002.rs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/issues/issue-77002.rs diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs index 46cbced2d54bc..97d261760772b 100644 --- a/compiler/rustc_mir/src/transform/dest_prop.rs +++ b/compiler/rustc_mir/src/transform/dest_prop.rs @@ -905,7 +905,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindAssignments<'a, 'tcx> { // FIXME: This can be smarter and take `StorageDead` into account (which // invalidates borrows). if self.ever_borrowed_locals.contains(dest.local) - && self.ever_borrowed_locals.contains(src.local) + || self.ever_borrowed_locals.contains(src.local) { return; } diff --git a/src/test/ui/issues/issue-77002.rs b/src/test/ui/issues/issue-77002.rs new file mode 100644 index 0000000000000..c7dd3cf810938 --- /dev/null +++ b/src/test/ui/issues/issue-77002.rs @@ -0,0 +1,16 @@ +// compile-flags: -Zmir-opt-level=2 -Copt-level=0 +// run-pass + +type M = [i64; 2]; + +fn f(a: &M) -> M { + let mut b: M = M::default(); + b[0] = a[0] * a[0]; + b +} + +fn main() { + let mut a: M = [1, 1]; + a = f(&a); + assert_eq!(a[0], 1); +} From 928a29fd41b5757ff183ee0befa410f12f955f7c Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 22 Sep 2020 20:59:05 +0200 Subject: [PATCH 0845/1052] Bless mir-opt tests --- ...allocation3.main.ConstProp.after.32bit.mir | 4 +- ...allocation3.main.ConstProp.after.64bit.mir | 4 +- .../simple.nrvo.DestinationPropagation.diff | 18 +- .../issue_73223.main.PreCodegen.32bit.diff | 170 +++++++++--------- .../issue_73223.main.PreCodegen.64bit.diff | 170 +++++++++--------- 5 files changed, 188 insertions(+), 178 deletions(-) diff --git a/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir b/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir index 19d6c51bc75f3..99d3a278d6922 100644 --- a/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir +++ b/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir @@ -24,10 +24,10 @@ fn main() -> () { } alloc0 (static: FOO, size: 4, align: 4) { - ╾─alloc3──╼ │ ╾──╼ + ╾─alloc9──╼ │ ╾──╼ } -alloc3 (size: 168, align: 1) { +alloc9 (size: 168, align: 1) { 0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................ 0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾─alloc4──╼ │ ............╾──╼ 0x20 │ 01 ef cd ab 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ diff --git a/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir b/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir index 94388b08c0ec0..d6e49892d4c6a 100644 --- a/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir +++ b/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir @@ -24,10 +24,10 @@ fn main() -> () { } alloc0 (static: FOO, size: 8, align: 8) { - ╾───────alloc3────────╼ │ ╾──────╼ + ╾───────alloc9────────╼ │ ╾──────╼ } -alloc3 (size: 180, align: 1) { +alloc9 (size: 180, align: 1) { 0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................ 0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾──alloc4── │ ............╾─── 0x20 │ ──────────╼ 01 ef cd ab 00 00 00 00 00 00 00 00 │ ───╼............ diff --git a/src/test/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.diff index 1277c51f2a050..3475d41b50fbd 100644 --- a/src/test/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.diff +++ b/src/test/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.diff @@ -10,22 +10,18 @@ let mut _5: &mut [u8; 1024]; // in scope 0 at $DIR/simple.rs:6:10: 6:18 let mut _6: &mut [u8; 1024]; // in scope 0 at $DIR/simple.rs:6:10: 6:18 scope 1 { -- debug buf => _2; // in scope 1 at $DIR/simple.rs:5:9: 5:16 -+ debug buf => _0; // in scope 1 at $DIR/simple.rs:5:9: 5:16 + debug buf => _2; // in scope 1 at $DIR/simple.rs:5:9: 5:16 } bb0: { -- StorageLive(_2); // scope 0 at $DIR/simple.rs:5:9: 5:16 -- _2 = [const 0_u8; 1024]; // scope 0 at $DIR/simple.rs:5:19: 5:28 -+ nop; // scope 0 at $DIR/simple.rs:5:9: 5:16 -+ _0 = [const 0_u8; 1024]; // scope 0 at $DIR/simple.rs:5:19: 5:28 + StorageLive(_2); // scope 0 at $DIR/simple.rs:5:9: 5:16 + _2 = [const 0_u8; 1024]; // scope 0 at $DIR/simple.rs:5:19: 5:28 StorageLive(_3); // scope 1 at $DIR/simple.rs:6:5: 6:19 StorageLive(_4); // scope 1 at $DIR/simple.rs:6:5: 6:9 _4 = _1; // scope 1 at $DIR/simple.rs:6:5: 6:9 StorageLive(_5); // scope 1 at $DIR/simple.rs:6:10: 6:18 StorageLive(_6); // scope 1 at $DIR/simple.rs:6:10: 6:18 -- _6 = &mut _2; // scope 1 at $DIR/simple.rs:6:10: 6:18 -+ _6 = &mut _0; // scope 1 at $DIR/simple.rs:6:10: 6:18 + _6 = &mut _2; // scope 1 at $DIR/simple.rs:6:10: 6:18 _5 = &mut (*_6); // scope 1 at $DIR/simple.rs:6:10: 6:18 _3 = move _4(move _5) -> bb1; // scope 1 at $DIR/simple.rs:6:5: 6:19 } @@ -35,10 +31,8 @@ StorageDead(_4); // scope 1 at $DIR/simple.rs:6:18: 6:19 StorageDead(_6); // scope 1 at $DIR/simple.rs:6:19: 6:20 StorageDead(_3); // scope 1 at $DIR/simple.rs:6:19: 6:20 -- _0 = _2; // scope 1 at $DIR/simple.rs:7:5: 7:8 -- StorageDead(_2); // scope 0 at $DIR/simple.rs:8:1: 8:2 -+ nop; // scope 1 at $DIR/simple.rs:7:5: 7:8 -+ nop; // scope 0 at $DIR/simple.rs:8:1: 8:2 + _0 = _2; // scope 1 at $DIR/simple.rs:7:5: 7:8 + StorageDead(_2); // scope 0 at $DIR/simple.rs:8:1: 8:2 return; // scope 0 at $DIR/simple.rs:8:2: 8:2 } } diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff index a8662b96566cc..99ea92299c61a 100644 --- a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff +++ b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff @@ -3,59 +3,61 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:1:11: 1:11 - let _1: i32; // in scope 0 at $DIR/issue-73223.rs:2:9: 2:14 - let mut _2: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + let mut _1: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + let _2: i32; // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15 let mut _4: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _5: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _6: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _7: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _8: &std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let _9: std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _10: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let _11: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _12: (&&i32, &&i32); // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let _13: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _14: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _7: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _8: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _9: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _10: &std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let _11: std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _12: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let _13: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _14: (&&i32, &&i32); // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL let _15: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _16: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _16: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _17: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _18: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL scope 1 { - debug split => _1; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14 + debug split => _2; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14 let _3: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14 scope 3 { debug _prev => _3; // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14 + let _5: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let _6: &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 => _15; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + debug left_val => _5; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + debug right_val => _6; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 5 { - debug arg0 => _20; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - debug arg1 => _23; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + debug arg0 => _21; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + debug arg1 => _24; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 6 { - debug x => _20; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - debug f => _19; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _18: 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 _19: 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 _20: &&i32; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL + debug x => _21; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug f => _20; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + let mut _19: 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 _20: 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 _21: &&i32; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL } scope 8 { - debug x => _23; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - debug f => _22; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _21: 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 _22: 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 _23: &&i32; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL + debug x => _24; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug f => _23; // in scope 8 at $SRC_DIR/core/src/fmt/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 8 at $SRC_DIR/std/src/macros.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 8 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _24: &&i32; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL } } scope 10 { - debug pieces => (_9.0: &[&str]); // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - debug args => _25; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _24: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _25: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL + debug pieces => _25; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug args => _27; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + let mut _25: &[&str]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _26: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _27: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL } } } } scope 2 { - debug v => _1; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15 + debug v => _2; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15 } scope 7 { } @@ -63,14 +65,14 @@ } bb0: { - StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - _1 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 - StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 - ((_3 as Some).0: i32) = _1; // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 + StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + ((_1 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + discriminant(_1) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + _2 = ((_1 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 + ((_3 as Some).0: i32) = _2; // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 discriminant(_3) = 1; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 - (_4.0: &i32) = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_4.0: &i32) = &_2; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_4.1: &i32) = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // ty::Const // + ty: &i32 @@ -78,93 +80,99 @@ // 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[0]), const_param_did: None }, [], Some(promoted[1])) } - _13 = (_4.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _15 = (_4.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_5); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_6); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _5 = (_4.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _6 = (_4.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_7); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _7 = (*_13); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _6 = Eq(move _7, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_7); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _5 = Not(move _6); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_6); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - switchInt(_5) -> [false: bb1, otherwise: bb2]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_8); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _9 = (*_5); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _8 = Eq(move _9, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _7 = Not(move _8); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_8); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + switchInt(_7) -> [false: bb1, otherwise: bb2]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL } bb1: { - StorageDead(_5); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_7); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _0 = const (); // scope 0 at $DIR/issue-73223.rs:1:11: 9:2 return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 } bb2: { - (_9.0: &[&str]) = const main::promoted[0] as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_11); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + _25 = const main::promoted[0] as &[&str] (Pointer(Unsize)); // 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[0]), 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[0]), const_param_did: None }, [], Some(promoted[0])) } - StorageLive(_11); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - (_12.0: &&i32) = &_13; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_14); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _14 = &_15; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_12.1: &&i32) = move _14; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageDead(_14); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _20 = (_12.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _23 = (_12.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _19 = <&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 + StorageLive(_13); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + StorageLive(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _15 = _5; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_14.0: &&i32) = &_15; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _16 = &_6; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_14.1: &&i32) = move _16; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + StorageDead(_16); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + _21 = (_14.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _24 = (_14.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _20 = <&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()) } - StorageLive(_18); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _18 = transmute:: 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 _19) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageLive(_19); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _19 = transmute:: 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 _20) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/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:: 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()) } } bb3: { - (_16.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _20) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_17.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _21) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/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()) } } bb4: { - (_16.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _18; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_18); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _22 = <&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 + (_17.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _19; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_19); // scope 7 at $SRC_DIR/core/src/fmt/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()) } - StorageLive(_21); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _21 = transmute:: 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 _22) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageLive(_22); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _22 = transmute:: 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) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/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:: 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()) } } bb5: { - (_17.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _23) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_18.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _24) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/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()) } } bb6: { - (_17.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _21; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_21); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _11 = [move _16, move _17]; // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL + (_18.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 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_22); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _13 = [move _17, move _18]; // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL + _12 = &_13; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + _27 = move _12 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + StorageLive(_26); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + discriminant(_26) = 0; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_11.0: &[&str]) = move _25; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_11.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _26; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_11.2: &[std::fmt::ArgumentV1]) = move _27; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_26); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _10 = &_11; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _25 = move _10 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageLive(_24); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - discriminant(_24) = 0; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_9.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _24; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_9.2: &[std::fmt::ArgumentV1]) = move _25; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_24); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _8 = &_9; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - begin_panic_fmt(move _8); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + begin_panic_fmt(move _10); // scope 4 at $SRC_DIR/std/src/macros.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()) } diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff index a8662b96566cc..99ea92299c61a 100644 --- a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff +++ b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff @@ -3,59 +3,61 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:1:11: 1:11 - let _1: i32; // in scope 0 at $DIR/issue-73223.rs:2:9: 2:14 - let mut _2: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + let mut _1: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + let _2: i32; // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15 let mut _4: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _5: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _6: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _7: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _8: &std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let _9: std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _10: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let _11: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _12: (&&i32, &&i32); // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let _13: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _14: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _7: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _8: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _9: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _10: &std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let _11: std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _12: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let _13: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _14: (&&i32, &&i32); // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL let _15: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _16: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _16: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _17: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _18: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL scope 1 { - debug split => _1; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14 + debug split => _2; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14 let _3: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14 scope 3 { debug _prev => _3; // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14 + let _5: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let _6: &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 => _15; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + debug left_val => _5; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + debug right_val => _6; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 5 { - debug arg0 => _20; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - debug arg1 => _23; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + debug arg0 => _21; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + debug arg1 => _24; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 6 { - debug x => _20; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - debug f => _19; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _18: 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 _19: 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 _20: &&i32; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL + debug x => _21; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug f => _20; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + let mut _19: 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 _20: 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 _21: &&i32; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL } scope 8 { - debug x => _23; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - debug f => _22; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _21: 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 _22: 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 _23: &&i32; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL + debug x => _24; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug f => _23; // in scope 8 at $SRC_DIR/core/src/fmt/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 8 at $SRC_DIR/std/src/macros.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 8 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _24: &&i32; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL } } scope 10 { - debug pieces => (_9.0: &[&str]); // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - debug args => _25; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _24: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _25: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL + debug pieces => _25; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug args => _27; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + let mut _25: &[&str]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _26: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _27: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL } } } } scope 2 { - debug v => _1; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15 + debug v => _2; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15 } scope 7 { } @@ -63,14 +65,14 @@ } bb0: { - StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - _1 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 - StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 - ((_3 as Some).0: i32) = _1; // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 + StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + ((_1 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + discriminant(_1) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + _2 = ((_1 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 + ((_3 as Some).0: i32) = _2; // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 discriminant(_3) = 1; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 - (_4.0: &i32) = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_4.0: &i32) = &_2; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_4.1: &i32) = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // ty::Const // + ty: &i32 @@ -78,93 +80,99 @@ // 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[0]), const_param_did: None }, [], Some(promoted[1])) } - _13 = (_4.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _15 = (_4.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_5); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_6); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _5 = (_4.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _6 = (_4.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_7); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _7 = (*_13); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _6 = Eq(move _7, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_7); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _5 = Not(move _6); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_6); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - switchInt(_5) -> [false: bb1, otherwise: bb2]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_8); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _9 = (*_5); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _8 = Eq(move _9, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _7 = Not(move _8); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_8); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + switchInt(_7) -> [false: bb1, otherwise: bb2]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL } bb1: { - StorageDead(_5); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_7); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _0 = const (); // scope 0 at $DIR/issue-73223.rs:1:11: 9:2 return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 } bb2: { - (_9.0: &[&str]) = const main::promoted[0] as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_11); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + _25 = const main::promoted[0] as &[&str] (Pointer(Unsize)); // 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[0]), 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[0]), const_param_did: None }, [], Some(promoted[0])) } - StorageLive(_11); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - (_12.0: &&i32) = &_13; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_14); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _14 = &_15; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_12.1: &&i32) = move _14; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageDead(_14); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _20 = (_12.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _23 = (_12.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _19 = <&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 + StorageLive(_13); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + StorageLive(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _15 = _5; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_14.0: &&i32) = &_15; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _16 = &_6; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_14.1: &&i32) = move _16; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + StorageDead(_16); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + _21 = (_14.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _24 = (_14.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _20 = <&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()) } - StorageLive(_18); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _18 = transmute:: 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 _19) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageLive(_19); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _19 = transmute:: 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 _20) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/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:: 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()) } } bb3: { - (_16.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _20) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_17.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _21) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/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()) } } bb4: { - (_16.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _18; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_18); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _22 = <&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 + (_17.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _19; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_19); // scope 7 at $SRC_DIR/core/src/fmt/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()) } - StorageLive(_21); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _21 = transmute:: 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 _22) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageLive(_22); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _22 = transmute:: 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) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/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:: 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()) } } bb5: { - (_17.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _23) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_18.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _24) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/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()) } } bb6: { - (_17.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _21; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_21); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _11 = [move _16, move _17]; // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL + (_18.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 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_22); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _13 = [move _17, move _18]; // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL + _12 = &_13; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + _27 = move _12 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + StorageLive(_26); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + discriminant(_26) = 0; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_11.0: &[&str]) = move _25; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_11.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _26; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_11.2: &[std::fmt::ArgumentV1]) = move _27; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_26); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _10 = &_11; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _25 = move _10 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageLive(_24); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - discriminant(_24) = 0; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_9.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _24; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_9.2: &[std::fmt::ArgumentV1]) = move _25; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_24); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _8 = &_9; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - begin_panic_fmt(move _8); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + begin_panic_fmt(move _10); // scope 4 at $SRC_DIR/std/src/macros.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()) } From 179f63dafcf9463b48d82e8698a844e18bf94370 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 22 Sep 2020 21:35:43 +0200 Subject: [PATCH 0846/1052] add array from_ref --- library/core/src/array/mod.rs | 14 ++++++++++++++ library/core/tests/array.rs | 17 ++++++++++++++++- library/core/tests/lib.rs | 1 + 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index c1d3aca6fdd4f..5730074bf2747 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -19,6 +19,20 @@ mod iter; #[unstable(feature = "array_value_iter", issue = "65798")] pub use iter::IntoIter; +/// Converts a reference to `T` into a reference to an array of length 1 (without copying). +#[unstable(feature = "array_from_ref", issue = "none")] +pub fn from_ref(s: &T) -> &[T; 1] { + // SAFETY: Converting `&T` to `&[T; 1]` is sound. + unsafe { &*(s as *const T).cast::<[T; 1]>() } +} + +/// Converts a mutable reference to `T` into a mutable reference to an array of length 1 (without copying). +#[unstable(feature = "array_from_ref", issue = "none")] +pub fn from_mut(s: &mut T) -> &mut [T; 1] { + // SAFETY: Converting `&mut T` to `&mut [T; 1]` is sound. + unsafe { &mut *(s as *mut T).cast::<[T; 1]>() } +} + /// Utility trait implemented only on arrays of fixed size /// /// This trait can be used to implement other traits on fixed-size arrays diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs index 5aba1a5d958d1..dbcea2747a00d 100644 --- a/library/core/tests/array.rs +++ b/library/core/tests/array.rs @@ -1,4 +1,4 @@ -use core::array::{FixedSizeArray, IntoIter}; +use core::array::{self, FixedSizeArray, IntoIter}; use core::convert::TryFrom; #[test] @@ -19,6 +19,21 @@ fn fixed_size_array() { assert_eq!(FixedSizeArray::as_mut_slice(&mut empty_zero_sized).len(), 0); } +#[test] +fn array_from_ref() { + let value: String = "Hello World!".into(); + let arr: &[String; 1] = array::from_ref(&value); + assert_eq!(&[value.clone()], arr); +} + +#[test] +fn array_from_mut() { + let mut value: String = "Hello World".into(); + let arr: &mut [String; 1] = array::from_mut(&mut value); + arr[0].push_str("!"); + assert_eq!(&value, "Hello World!"); +} + #[test] fn array_try_from() { macro_rules! test { diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 7e75c7cf47bf6..d8b36beb3e085 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -1,5 +1,6 @@ #![feature(alloc_layout_extra)] #![feature(array_chunks)] +#![feature(array_from_ref)] #![feature(array_methods)] #![feature(array_map)] #![feature(array_windows)] From 438d229b25921e0b1d4b731586cff27a2e79e99f Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 22 Sep 2020 21:25:32 +0200 Subject: [PATCH 0847/1052] dead_code: look at trait impls even if they don't contain items --- compiler/rustc_passes/src/dead.rs | 5 ++++- .../ui/const-generics/issues/issue-70225.rs | 21 +++++++++++++++++++ src/test/ui/lint/dead-code/trait-impl.rs | 19 +++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/const-generics/issues/issue-70225.rs create mode 100644 src/test/ui/lint/dead-code/trait-impl.rs diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index fe6653e98da89..98ded4189cf19 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -369,7 +369,7 @@ fn has_allow_dead_code_or_lang_attr( // - This is because lang items are always callable from elsewhere. // or // 2) We are not sure to be live or not -// * Implementation of a trait method +// * Implementations of traits and trait methods struct LifeSeeder<'k, 'tcx> { worklist: Vec, krate: &'k hir::Crate<'k>, @@ -415,6 +415,9 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { } } hir::ItemKind::Impl { ref of_trait, items, .. } => { + if of_trait.is_some() { + self.worklist.push(item.hir_id); + } for impl_item_ref in items { let impl_item = self.krate.impl_item(impl_item_ref.id); if of_trait.is_some() diff --git a/src/test/ui/const-generics/issues/issue-70225.rs b/src/test/ui/const-generics/issues/issue-70225.rs new file mode 100644 index 0000000000000..8f8d753d0a75f --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-70225.rs @@ -0,0 +1,21 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] +#![deny(dead_code)] + +// We previously incorrectly linted `L` as unused here. +const L: usize = 3; + +fn main() { + let p = Printer {}; + p.print(); +} + +trait Print { + fn print(&self) -> usize { + 3 + } +} + +struct Printer {} +impl Print for Printer {} diff --git a/src/test/ui/lint/dead-code/trait-impl.rs b/src/test/ui/lint/dead-code/trait-impl.rs new file mode 100644 index 0000000000000..92e389a938ab3 --- /dev/null +++ b/src/test/ui/lint/dead-code/trait-impl.rs @@ -0,0 +1,19 @@ +// check-pass +#![deny(dead_code)] + +enum Foo { + Bar, +} + +fn main() { + let p = [0; 0]; + p.bar(); +} + +trait Bar { + fn bar(&self) -> usize { + 3 + } +} + +impl Bar for [u32; Foo::Bar as usize] {} From 290dca17819479069a15c2ba46d8f6197a002a2e Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Sun, 13 Sep 2020 16:04:45 +0200 Subject: [PATCH 0848/1052] MIR pass to remove unneeded drops on types not needing drop This is heavily dependent on MIR inlining running to actually see the drop statement --- compiler/rustc_mir/src/transform/mod.rs | 2 + .../src/transform/remove_unneeded_drops.rs | 57 +++++++++++++++++++ ...annot_opt_generic.RemoveUnneededDrops.diff | 32 +++++++++++ ...ed_drops.dont_opt.RemoveUnneededDrops.diff | 32 +++++++++++ ...nneeded_drops.opt.RemoveUnneededDrops.diff | 29 ++++++++++ ....opt_generic_copy.RemoveUnneededDrops.diff | 29 ++++++++++ src/test/mir-opt/remove_unneeded_drops.rs | 28 +++++++++ 7 files changed, 209 insertions(+) create mode 100644 compiler/rustc_mir/src/transform/remove_unneeded_drops.rs create mode 100644 src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff create mode 100644 src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff create mode 100644 src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff create mode 100644 src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff create mode 100644 src/test/mir-opt/remove_unneeded_drops.rs diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index abe2dc496a630..17ef98c176df2 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -38,6 +38,7 @@ pub mod nrvo; pub mod promote_consts; pub mod qualify_min_const_fn; pub mod remove_noop_landing_pads; +pub mod remove_unneeded_drops; pub mod required_consts; pub mod rustc_peek; pub mod simplify; @@ -461,6 +462,7 @@ fn run_optimization_passes<'tcx>( // The main optimizations that we do on MIR. let optimizations: &[&dyn MirPass<'tcx>] = &[ + &remove_unneeded_drops::RemoveUnneededDrops::new(def_id), &match_branches::MatchBranchSimplification, // inst combine is after MatchBranchSimplification to clean up Ne(_1, false) &instcombine::InstCombine, diff --git a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs new file mode 100644 index 0000000000000..0f023d71dd1da --- /dev/null +++ b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs @@ -0,0 +1,57 @@ +//! This pass replaces a drop of a type that does not need dropping, with a goto + +use crate::transform::{MirPass, MirSource}; +use rustc_hir::def_id::LocalDefId; +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +pub struct RemoveUnneededDrops { + def_id: LocalDefId, +} + +impl RemoveUnneededDrops { + pub fn new(def_id: LocalDefId) -> Self { + Self { def_id } + } +} + +impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { + fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { + trace!("Running SimplifyComparisonIntegral on {:?}", source); + let mut opt_finder = RemoveUnneededDropsOptimizationFinder { + tcx, + body, + optimizations: vec![], + def_id: self.def_id, + }; + opt_finder.visit_body(body); + for (loc, target) in opt_finder.optimizations { + let terminator = body.basic_blocks_mut()[loc.block].terminator_mut(); + debug!("SUCCESS: replacing `drop` with goto({:?})", target); + terminator.kind = TerminatorKind::Goto { target }; + } + } +} + +impl<'a, 'tcx> Visitor<'tcx> for RemoveUnneededDropsOptimizationFinder<'a, 'tcx> { + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + match terminator.kind { + TerminatorKind::Drop { place, target, .. } => { + let ty = place.ty(self.body, self.tcx); + let needs_drop = ty.ty.needs_drop(self.tcx, self.tcx.param_env(self.def_id)); + if !needs_drop { + self.optimizations.push((location, target)); + } + } + _ => {} + } + self.super_terminator(terminator, location); + } +} +pub struct RemoveUnneededDropsOptimizationFinder<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + optimizations: Vec<(Location, BasicBlock)>, + def_id: LocalDefId, +} diff --git a/src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff new file mode 100644 index 0000000000000..545ad2794ee17 --- /dev/null +++ b/src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff @@ -0,0 +1,32 @@ +- // MIR for `cannot_opt_generic` before RemoveUnneededDrops ++ // MIR for `cannot_opt_generic` after RemoveUnneededDrops + + fn cannot_opt_generic(_1: T) -> () { + debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:19:26: 19:27 + let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:19:32: 19:32 + let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:20:5: 20:12 + let mut _3: T; // in scope 0 at $DIR/remove_unneeded_drops.rs:20:10: 20:11 + scope 1 { + debug _x => _3; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:20:5: 20:12 + StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:20:10: 20:11 + _3 = move _1; // scope 0 at $DIR/remove_unneeded_drops.rs:20:10: 20:11 + _2 = const (); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + drop(_3) -> [return: bb2, unwind: bb1]; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb1 (cleanup): { + resume; // scope 0 at $DIR/remove_unneeded_drops.rs:19:1: 21:2 + } + + bb2: { + StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:20:11: 20:12 + StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:20:12: 20:13 + _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:19:32: 21:2 + return; // scope 0 at $DIR/remove_unneeded_drops.rs:21:2: 21:2 + } + } + diff --git a/src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff new file mode 100644 index 0000000000000..78d65d13bd1bf --- /dev/null +++ b/src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff @@ -0,0 +1,32 @@ +- // MIR for `dont_opt` before RemoveUnneededDrops ++ // MIR for `dont_opt` after RemoveUnneededDrops + + fn dont_opt(_1: Vec) -> () { + debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:7:13: 7:14 + let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:7:27: 7:27 + let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:8:5: 8:12 + let mut _3: std::vec::Vec; // in scope 0 at $DIR/remove_unneeded_drops.rs:8:10: 8:11 + scope 1 { + debug _x => _3; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:8:5: 8:12 + StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:8:10: 8:11 + _3 = move _1; // scope 0 at $DIR/remove_unneeded_drops.rs:8:10: 8:11 + _2 = const (); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + drop(_3) -> [return: bb2, unwind: bb1]; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb1 (cleanup): { + resume; // scope 0 at $DIR/remove_unneeded_drops.rs:7:1: 9:2 + } + + bb2: { + StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:8:11: 8:12 + StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:8:12: 8:13 + _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:7:27: 9:2 + return; // scope 0 at $DIR/remove_unneeded_drops.rs:9:2: 9:2 + } + } + diff --git a/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff new file mode 100644 index 0000000000000..34193ccc5c7e7 --- /dev/null +++ b/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff @@ -0,0 +1,29 @@ +- // MIR for `opt` before RemoveUnneededDrops ++ // MIR for `opt` after RemoveUnneededDrops + + fn opt(_1: bool) -> () { + debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:2:8: 2:9 + let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:2:17: 2:17 + let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:3:5: 3:12 + let mut _3: bool; // in scope 0 at $DIR/remove_unneeded_drops.rs:3:10: 3:11 + scope 1 { + debug _x => _3; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:3:5: 3:12 + StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:3:10: 3:11 + _3 = _1; // scope 0 at $DIR/remove_unneeded_drops.rs:3:10: 3:11 + _2 = const (); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL +- drop(_3) -> bb1; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL ++ goto -> bb1; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb1: { + StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:3:11: 3:12 + StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:3:12: 3:13 + _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:2:17: 4:2 + return; // scope 0 at $DIR/remove_unneeded_drops.rs:4:2: 4:2 + } + } + diff --git a/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff new file mode 100644 index 0000000000000..2e6c8c8a78a72 --- /dev/null +++ b/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff @@ -0,0 +1,29 @@ +- // MIR for `opt_generic_copy` before RemoveUnneededDrops ++ // MIR for `opt_generic_copy` after RemoveUnneededDrops + + fn opt_generic_copy(_1: T) -> () { + debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:12:30: 12:31 + let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:12:36: 12:36 + let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:13:5: 13:12 + let mut _3: T; // in scope 0 at $DIR/remove_unneeded_drops.rs:13:10: 13:11 + scope 1 { + debug _x => _3; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:13:5: 13:12 + StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:13:10: 13:11 + _3 = _1; // scope 0 at $DIR/remove_unneeded_drops.rs:13:10: 13:11 + _2 = const (); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL +- drop(_3) -> bb1; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL ++ goto -> bb1; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb1: { + StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:13:11: 13:12 + StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:13:12: 13:13 + _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:12:36: 14:2 + return; // scope 0 at $DIR/remove_unneeded_drops.rs:14:2: 14:2 + } + } + diff --git a/src/test/mir-opt/remove_unneeded_drops.rs b/src/test/mir-opt/remove_unneeded_drops.rs new file mode 100644 index 0000000000000..17d7e79a1eb0a --- /dev/null +++ b/src/test/mir-opt/remove_unneeded_drops.rs @@ -0,0 +1,28 @@ +// EMIT_MIR remove_unneeded_drops.opt.RemoveUnneededDrops.diff +fn opt(x: bool) { + drop(x); +} + +// EMIT_MIR remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff +fn dont_opt(x: Vec) { + drop(x); +} + +// EMIT_MIR remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff +fn opt_generic_copy(x: T) { + drop(x); +} + +// EMIT_MIR remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff +// since the pass is not running on monomorphisized code, +// we can't (but probably should) optimize this +fn cannot_opt_generic(x: T) { + drop(x); +} + +fn main() { + opt(true); + opt_generic_copy(42); + cannot_opt_generic(42); + dont_opt(vec![true]); +} From b4bdaa14f2a4ab14812502e1b12a2effe1c92a2a Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Mon, 14 Sep 2020 22:56:39 +0200 Subject: [PATCH 0849/1052] Suggestion from review Co-authored-by: Andreas Jonson --- compiler/rustc_mir/src/transform/remove_unneeded_drops.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs index 0f023d71dd1da..393b0f923b910 100644 --- a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs +++ b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs @@ -18,7 +18,7 @@ impl RemoveUnneededDrops { impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { - trace!("Running SimplifyComparisonIntegral on {:?}", source); + trace!("Running RemoveUnneededDrops on {:?}", source); let mut opt_finder = RemoveUnneededDropsOptimizationFinder { tcx, body, From d3338dcf4de915fedc39ca46cb9944250bcb1a9e Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Sat, 19 Sep 2020 13:52:55 +0200 Subject: [PATCH 0850/1052] Get LocalDefId from source instead of passing in --- compiler/rustc_mir/src/transform/mod.rs | 2 +- .../rustc_mir/src/transform/remove_unneeded_drops.rs | 12 ++---------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index 17ef98c176df2..f48ad039b4ff9 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -462,7 +462,7 @@ fn run_optimization_passes<'tcx>( // The main optimizations that we do on MIR. let optimizations: &[&dyn MirPass<'tcx>] = &[ - &remove_unneeded_drops::RemoveUnneededDrops::new(def_id), + &remove_unneeded_drops::RemoveUnneededDrops, &match_branches::MatchBranchSimplification, // inst combine is after MatchBranchSimplification to clean up Ne(_1, false) &instcombine::InstCombine, diff --git a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs index 393b0f923b910..505133219b863 100644 --- a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs +++ b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs @@ -6,15 +6,7 @@ use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; -pub struct RemoveUnneededDrops { - def_id: LocalDefId, -} - -impl RemoveUnneededDrops { - pub fn new(def_id: LocalDefId) -> Self { - Self { def_id } - } -} +pub struct RemoveUnneededDrops; impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { @@ -23,7 +15,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { tcx, body, optimizations: vec![], - def_id: self.def_id, + def_id: source.def_id().expect_local(), }; opt_finder.visit_body(body); for (loc, target) in opt_finder.optimizations { From f472303a93699f4d6465ada0ab7e9a999c34b0ec Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Sat, 19 Sep 2020 14:25:53 +0200 Subject: [PATCH 0851/1052] The optimization should also apply for DropAndReplace --- compiler/rustc_mir/src/transform/remove_unneeded_drops.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs index 505133219b863..b8ad816f75831 100644 --- a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs +++ b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs @@ -29,7 +29,8 @@ impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { impl<'a, 'tcx> Visitor<'tcx> for RemoveUnneededDropsOptimizationFinder<'a, 'tcx> { fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { match terminator.kind { - TerminatorKind::Drop { place, target, .. } => { + TerminatorKind::Drop { place, target, .. } + | TerminatorKind::DropAndReplace { place, target, .. } => { let ty = place.ty(self.body, self.tcx); let needs_drop = ty.ty.needs_drop(self.tcx, self.tcx.param_env(self.def_id)); if !needs_drop { From b6f51d6d6ab441993cd54f5069e67ccd0ef4520b Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Sat, 19 Sep 2020 15:21:39 +0200 Subject: [PATCH 0852/1052] cleanup cfg after optimization --- .../rustc_mir/src/transform/remove_unneeded_drops.rs | 9 +++++++++ .../remove_unneeded_drops.opt.RemoveUnneededDrops.diff | 7 +++---- ...eeded_drops.opt_generic_copy.RemoveUnneededDrops.diff | 7 +++---- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs index b8ad816f75831..f027f5e33a187 100644 --- a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs +++ b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs @@ -6,6 +6,8 @@ use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; +use super::simplify::simplify_cfg; + pub struct RemoveUnneededDrops; impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { @@ -18,11 +20,18 @@ impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { def_id: source.def_id().expect_local(), }; opt_finder.visit_body(body); + let should_simplify = !opt_finder.optimizations.is_empty(); for (loc, target) in opt_finder.optimizations { let terminator = body.basic_blocks_mut()[loc.block].terminator_mut(); debug!("SUCCESS: replacing `drop` with goto({:?})", target); terminator.kind = TerminatorKind::Goto { target }; } + + // if we applied optimizations, we potentially have some cfg to cleanup to + // make it easier for further passes + if should_simplify { + simplify_cfg(body); + } } } diff --git a/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff index 34193ccc5c7e7..eba839cf0a48b 100644 --- a/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff +++ b/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff @@ -16,10 +16,9 @@ _3 = _1; // scope 0 at $DIR/remove_unneeded_drops.rs:3:10: 3:11 _2 = const (); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - drop(_3) -> bb1; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL -+ goto -> bb1; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - } - - bb1: { +- } +- +- bb1: { StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:3:11: 3:12 StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:3:12: 3:13 _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:2:17: 4:2 diff --git a/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff index 2e6c8c8a78a72..840b1ba30fb9b 100644 --- a/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff +++ b/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff @@ -16,10 +16,9 @@ _3 = _1; // scope 0 at $DIR/remove_unneeded_drops.rs:13:10: 13:11 _2 = const (); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - drop(_3) -> bb1; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL -+ goto -> bb1; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - } - - bb1: { +- } +- +- bb1: { StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:13:11: 13:12 StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:13:12: 13:13 _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:12:36: 14:2 From ff241633f4ac520ec2409a30679c13b1302f53ba Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Mon, 21 Sep 2020 22:06:54 +0200 Subject: [PATCH 0853/1052] rebless after rebase --- .../mir-opt/dest-prop/cycle.main.DestinationPropagation.diff | 4 ---- .../mir-opt/dest-prop/union.main.DestinationPropagation.diff | 4 ---- 2 files changed, 8 deletions(-) diff --git a/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff index dd717c1b9c324..881c296cee77a 100644 --- a/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff +++ b/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff @@ -57,10 +57,6 @@ - _6 = _1; // scope 3 at $DIR/cycle.rs:14:10: 14:11 + _6 = _4; // scope 3 at $DIR/cycle.rs:14:10: 14:11 _5 = const (); // scope 4 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - drop(_6) -> bb2; // scope 4 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - } - - bb2: { StorageDead(_6); // scope 3 at $DIR/cycle.rs:14:11: 14:12 StorageDead(_5); // scope 3 at $DIR/cycle.rs:14:12: 14:13 _0 = const (); // scope 0 at $DIR/cycle.rs:8:11: 15:2 diff --git a/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff index 871f6e35043ec..f15e7bcb2fba6 100644 --- a/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff +++ b/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff @@ -32,10 +32,6 @@ StorageLive(_4); // scope 1 at $DIR/union.rs:15:10: 15:26 _4 = (_1.0: u32); // scope 2 at $DIR/union.rs:15:19: 15:24 _3 = const (); // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - drop(_4) -> bb2; // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - } - - bb2: { StorageDead(_4); // scope 1 at $DIR/union.rs:15:26: 15:27 StorageDead(_3); // scope 1 at $DIR/union.rs:15:27: 15:28 _0 = const (); // scope 0 at $DIR/union.rs:8:11: 16:2 From b6e72837fd36f65f7ff73dcf6e915971296a9af8 Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Tue, 22 Sep 2020 23:36:08 +0200 Subject: [PATCH 0854/1052] Use Self more in core/src/cmp.rs --- library/core/src/cmp.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index dde442aa7b52d..ee79a94cc66ab 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -726,19 +726,19 @@ impl PartialOrd for Ordering { /// } /// /// impl PartialOrd for Person { -/// fn partial_cmp(&self, other: &Person) -> Option { +/// fn partial_cmp(&self, other: &Self) -> Option { /// Some(self.cmp(other)) /// } /// } /// /// impl Ord for Person { -/// fn cmp(&self, other: &Person) -> Ordering { +/// fn cmp(&self, other: &Self) -> Ordering { /// self.height.cmp(&other.height) /// } /// } /// /// impl PartialEq for Person { -/// fn eq(&self, other: &Person) -> bool { +/// fn eq(&self, other: &Self) -> bool { /// self.height == other.height /// } /// } From 87a5dec4db20aa4e45b0db63f762681de084ad58 Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Wed, 23 Sep 2020 00:16:16 +0200 Subject: [PATCH 0855/1052] Use Self more in core in doc when possible --- library/core/src/marker.rs | 4 +- library/core/src/ops/arith.rs | 22 +++++------ library/core/src/ops/bit.rs | 69 ++++++++++++++++++----------------- library/core/src/ops/mod.rs | 12 +++--- 4 files changed, 55 insertions(+), 52 deletions(-) diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 9340b591ebd70..cdf742057b7b6 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -643,9 +643,9 @@ macro_rules! impls { /// } /// /// impl ExternalResource { -/// fn new() -> ExternalResource { +/// fn new() -> Self { /// let size_of_res = mem::size_of::(); -/// ExternalResource { +/// Self { /// resource_handle: foreign_lib::new(size_of_res), /// resource_type: PhantomData, /// } diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs index bdf93baa1b8f9..19f86ced5007c 100644 --- a/library/core/src/ops/arith.rs +++ b/library/core/src/ops/arith.rs @@ -128,10 +128,10 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// } /// /// impl Sub for Point { -/// type Output = Point; +/// type Output = Self; /// -/// fn sub(self, other: Point) -> Point { -/// Point { +/// fn sub(self, other: Self) -> Self::Output { +/// Self { /// x: self.x - other.x, /// y: self.y - other.y, /// } @@ -241,7 +241,7 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// // Reduce to lowest terms by dividing by the greatest common /// // divisor. /// let gcd = gcd(numerator, denominator); -/// Rational { +/// Self { /// numerator: numerator / gcd, /// denominator: denominator / gcd, /// } @@ -255,7 +255,7 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// fn mul(self, rhs: Self) -> Self { /// let numerator = self.numerator * rhs.numerator; /// let denominator = self.denominator * rhs.denominator; -/// Rational::new(numerator, denominator) +/// Self::new(numerator, denominator) /// } /// } /// @@ -291,7 +291,7 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// type Output = Self; /// /// fn mul(self, rhs: Scalar) -> Self::Output { -/// Vector { value: self.value.iter().map(|v| v * rhs.value).collect() } +/// Self { value: self.value.iter().map(|v| v * rhs.value).collect() } /// } /// } /// @@ -369,7 +369,7 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// // Reduce to lowest terms by dividing by the greatest common /// // divisor. /// let gcd = gcd(numerator, denominator); -/// Rational { +/// Self { /// numerator: numerator / gcd, /// denominator: denominator / gcd, /// } @@ -387,7 +387,7 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// /// let numerator = self.numerator * rhs.denominator; /// let denominator = self.denominator * rhs.numerator; -/// Rational::new(numerator, denominator) +/// Self::new(numerator, denominator) /// } /// } /// @@ -423,7 +423,7 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// type Output = Self; /// /// fn div(self, rhs: Scalar) -> Self::Output { -/// Vector { value: self.value.iter().map(|v| v / rhs.value).collect() } +/// Self { value: self.value.iter().map(|v| v / rhs.value).collect() } /// } /// } /// @@ -515,7 +515,7 @@ div_impl_float! { f32 f64 } /// let len = self.slice.len(); /// let rem = len % modulus; /// let start = len - rem; -/// SplitSlice {slice: &self.slice[start..]} +/// Self {slice: &self.slice[start..]} /// } /// } /// @@ -615,7 +615,7 @@ rem_impl_float! { f32 f64 } /// } /// /// impl Neg for Sign { -/// type Output = Sign; +/// type Output = Self; /// /// fn neg(self) -> Self::Output { /// match self { diff --git a/library/core/src/ops/bit.rs b/library/core/src/ops/bit.rs index 3d71e0b0002c2..6120da50c3cdf 100644 --- a/library/core/src/ops/bit.rs +++ b/library/core/src/ops/bit.rs @@ -15,7 +15,7 @@ /// } /// /// impl Not for Answer { -/// type Output = Answer; +/// type Output = Self; /// /// fn not(self) -> Self::Output { /// match self { @@ -85,7 +85,7 @@ not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// /// // rhs is the "right-hand side" of the expression `a & b` /// fn bitand(self, rhs: Self) -> Self::Output { -/// Scalar(self.0 & rhs.0) +/// Self(self.0 & rhs.0) /// } /// } /// @@ -106,10 +106,13 @@ not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// impl BitAnd for BooleanVector { /// type Output = Self; /// -/// fn bitand(self, BooleanVector(rhs): Self) -> Self::Output { -/// let BooleanVector(lhs) = self; +/// fn bitand(self, Self(rhs): Self) -> Self::Output { +/// let Self(lhs) = self; /// assert_eq!(lhs.len(), rhs.len()); -/// BooleanVector(lhs.iter().zip(rhs.iter()).map(|(x, y)| *x && *y).collect()) +/// Self(lhs.iter() +/// .zip(rhs.iter()) +/// .map(|(x, y)| *x && *y) +/// .collect()) /// } /// } /// @@ -179,8 +182,8 @@ bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// type Output = Self; /// /// // rhs is the "right-hand side" of the expression `a | b` -/// fn bitor(self, rhs: Self) -> Self { -/// Scalar(self.0 | rhs.0) +/// fn bitor(self, rhs: Self) -> Self::Output { +/// Self(self.0 | rhs.0) /// } /// } /// @@ -201,10 +204,10 @@ bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// impl BitOr for BooleanVector { /// type Output = Self; /// -/// fn bitor(self, BooleanVector(rhs): Self) -> Self::Output { -/// let BooleanVector(lhs) = self; +/// fn bitor(self, Self(rhs): Self) -> Self::Output { +/// let Self(lhs) = self; /// assert_eq!(lhs.len(), rhs.len()); -/// BooleanVector(lhs.iter().zip(rhs.iter()).map(|(x, y)| *x || *y).collect()) +/// Self(lhs.iter().zip(rhs.iter()).map(|(x, y)| *x || *y).collect()) /// } /// } /// @@ -275,7 +278,7 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// /// // rhs is the "right-hand side" of the expression `a ^ b` /// fn bitxor(self, rhs: Self) -> Self::Output { -/// Scalar(self.0 ^ rhs.0) +/// Self(self.0 ^ rhs.0) /// } /// } /// @@ -296,13 +299,13 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// impl BitXor for BooleanVector { /// type Output = Self; /// -/// fn bitxor(self, BooleanVector(rhs): Self) -> Self::Output { -/// let BooleanVector(lhs) = self; +/// fn bitxor(self, Self(rhs): Self) -> Self::Output { +/// let Self(lhs) = self; /// assert_eq!(lhs.len(), rhs.len()); -/// BooleanVector(lhs.iter() -/// .zip(rhs.iter()) -/// .map(|(x, y)| (*x || *y) && !(*x && *y)) -/// .collect()) +/// Self(lhs.iter() +/// .zip(rhs.iter()) +/// .map(|(x, y)| (*x || *y) && !(*x && *y)) +/// .collect()) /// } /// } /// @@ -375,9 +378,9 @@ bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// impl Shl for Scalar { /// type Output = Self; /// -/// fn shl(self, Scalar(rhs): Self) -> Scalar { -/// let Scalar(lhs) = self; -/// Scalar(lhs << rhs) +/// fn shl(self, Self(rhs): Self) -> Self::Output { +/// let Self(lhs) = self; +/// Self(lhs << rhs) /// } /// } /// @@ -400,10 +403,10 @@ bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// fn shl(self, rhs: usize) -> Self::Output { /// // Rotate the vector by `rhs` places. /// let (a, b) = self.vec.split_at(rhs); -/// let mut spun_vector: Vec = vec![]; +/// let mut spun_vector = vec![]; /// spun_vector.extend_from_slice(b); /// spun_vector.extend_from_slice(a); -/// SpinVector { vec: spun_vector } +/// Self { vec: spun_vector } /// } /// } /// @@ -493,9 +496,9 @@ shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } /// impl Shr for Scalar { /// type Output = Self; /// -/// fn shr(self, Scalar(rhs): Self) -> Scalar { -/// let Scalar(lhs) = self; -/// Scalar(lhs >> rhs) +/// fn shr(self, Self(rhs): Self) -> Self::Output { +/// let Self(lhs) = self; +/// Self(lhs >> rhs) /// } /// } /// @@ -518,10 +521,10 @@ shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } /// fn shr(self, rhs: usize) -> Self::Output { /// // Rotate the vector by `rhs` places. /// let (a, b) = self.vec.split_at(self.vec.len() - rhs); -/// let mut spun_vector: Vec = vec![]; +/// let mut spun_vector = vec![]; /// spun_vector.extend_from_slice(b); /// spun_vector.extend_from_slice(a); -/// SpinVector { vec: spun_vector } +/// Self { vec: spun_vector } /// } /// } /// @@ -606,7 +609,7 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } /// impl BitAndAssign for Scalar { /// // rhs is the "right-hand side" of the expression `a &= b` /// fn bitand_assign(&mut self, rhs: Self) { -/// *self = Scalar(self.0 & rhs.0) +/// *self = Self(self.0 & rhs.0) /// } /// } /// @@ -640,11 +643,11 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } /// // `rhs` is the "right-hand side" of the expression `a &= b`. /// fn bitand_assign(&mut self, rhs: Self) { /// assert_eq!(self.0.len(), rhs.0.len()); -/// *self = BooleanVector(self.0 -/// .iter() -/// .zip(rhs.0.iter()) -/// .map(|(x, y)| *x && *y) -/// .collect()); +/// *self = Self(self.0 +/// .iter() +/// .zip(rhs.0.iter()) +/// .map(|(x, y)| *x && *y) +/// .collect()); /// } /// } /// diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index 2a4186f9d5db9..354ad6b7b7333 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -49,18 +49,18 @@ //! } //! //! impl Add for Point { -//! type Output = Point; +//! type Output = Self; //! -//! fn add(self, other: Point) -> Point { -//! Point {x: self.x + other.x, y: self.y + other.y} +//! fn add(self, other: Self) -> Self { +//! Self {x: self.x + other.x, y: self.y + other.y} //! } //! } //! //! impl Sub for Point { -//! type Output = Point; +//! type Output = Self; //! -//! fn sub(self, other: Point) -> Point { -//! Point {x: self.x - other.x, y: self.y - other.y} +//! fn sub(self, other: Self) -> Self { +//! Self {x: self.x - other.x, y: self.y - other.y} //! } //! } //! From c07890543d13b36180dfbc0b6b6632c2c1dfff3f Mon Sep 17 00:00:00 2001 From: LingMan Date: Wed, 23 Sep 2020 00:29:56 +0200 Subject: [PATCH 0856/1052] Don't use an if guard to check equality with a constant Match on it directly instead --- compiler/rustc_attr/src/builtin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 9951c25200129..1808eb270baa9 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -301,7 +301,7 @@ where .emit(); }; match issue.parse() { - Ok(num) if num == 0 => { + Ok(0) => { emit_diag( "`issue` must not be \"0\", \ use \"none\" instead", From ec4e9cd12a380bb61791c489baaaae2e9454546d Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Wed, 23 Sep 2020 00:31:37 +0200 Subject: [PATCH 0857/1052] Use Self in alloc --- library/alloc/src/collections/binary_heap.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index ea75fa2196502..f2852b1cc2b80 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -30,7 +30,7 @@ //! // Explicitly implement the trait so the queue becomes a min-heap //! // instead of a max-heap. //! impl Ord for State { -//! fn cmp(&self, other: &State) -> Ordering { +//! fn cmp(&self, other: &Self) -> Ordering { //! // Notice that the we flip the ordering on costs. //! // In case of a tie we compare positions - this step is necessary //! // to make implementations of `PartialEq` and `Ord` consistent. @@ -41,7 +41,7 @@ //! //! // `PartialOrd` needs to be implemented as well. //! impl PartialOrd for State { -//! fn partial_cmp(&self, other: &State) -> Option { +//! fn partial_cmp(&self, other: &Self) -> Option { //! Some(self.cmp(other)) //! } //! } From d76b80768c4e5f1ee879af12db30d8930e50f70d Mon Sep 17 00:00:00 2001 From: LingMan Date: Wed, 23 Sep 2020 01:09:24 +0200 Subject: [PATCH 0858/1052] Merge two almost identical match arms --- compiler/rustc_builtin_macros/src/format_foreign.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs index b39423b86e7b5..ff81b5eca13a7 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -518,8 +518,7 @@ pub mod printf { .and_then(|end| end.at_next_cp()) .map(|end| (next.slice_between(end).unwrap(), end)); let end = match end { - Some(("32", end)) => end, - Some(("64", end)) => end, + Some(("32" | "64", end)) => end, _ => next, }; state = Type; From 9b2c8d866ebe746207472ba5da7c1fd79c856faa Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Wed, 23 Sep 2020 08:39:19 +1000 Subject: [PATCH 0859/1052] revert const_type_id stabilization This reverts commit e3856616ee2a894c7811a7017d98fafa7ba84dd8. --- library/core/src/any.rs | 2 +- library/core/src/intrinsics.rs | 2 +- library/core/src/lib.rs | 1 + src/test/ui/consts/const-typeid-of-rpass.rs | 1 + src/test/ui/consts/issue-73976-monomorphic.rs | 1 + src/test/ui/consts/issue-73976-polymorphic.rs | 1 + src/test/ui/consts/issue-73976-polymorphic.stderr | 8 ++++---- 7 files changed, 10 insertions(+), 6 deletions(-) diff --git a/library/core/src/any.rs b/library/core/src/any.rs index d79b9a33b5aa8..88ff2a632fd49 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -435,7 +435,7 @@ impl TypeId { /// assert_eq!(is_string(&"cookie monster".to_string()), true); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_type_id", since = "1.46.0")] + #[rustc_const_unstable(feature = "const_type_id", issue = "63084")] pub const fn of() -> TypeId { TypeId { t: intrinsics::type_id::() } } diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index abb9bfec127be..b8c0519f659c1 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -807,7 +807,7 @@ extern "rust-intrinsic" { /// crate it is invoked in. /// /// The stabilized version of this intrinsic is [`crate::any::TypeId::of`]. - #[rustc_const_stable(feature = "const_type_id", since = "1.46.0")] + #[rustc_const_unstable(feature = "const_type_id", issue = "63084")] pub fn type_id() -> u64; /// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited: diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 9de0f76cbdd2c..a0d1f0165c4c2 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -90,6 +90,7 @@ #![feature(const_slice_ptr_len)] #![feature(const_size_of_val)] #![feature(const_align_of_val)] +#![feature(const_type_id)] #![feature(const_type_name)] #![feature(const_likely)] #![feature(const_unreachable_unchecked)] diff --git a/src/test/ui/consts/const-typeid-of-rpass.rs b/src/test/ui/consts/const-typeid-of-rpass.rs index c49141050b20f..89d57ae4f98e6 100644 --- a/src/test/ui/consts/const-typeid-of-rpass.rs +++ b/src/test/ui/consts/const-typeid-of-rpass.rs @@ -1,4 +1,5 @@ // run-pass +#![feature(const_type_id)] #![feature(core_intrinsics)] use std::any::TypeId; diff --git a/src/test/ui/consts/issue-73976-monomorphic.rs b/src/test/ui/consts/issue-73976-monomorphic.rs index 1db0fdc87c37e..7706a97f23b48 100644 --- a/src/test/ui/consts/issue-73976-monomorphic.rs +++ b/src/test/ui/consts/issue-73976-monomorphic.rs @@ -5,6 +5,7 @@ // will be properly rejected. This test will ensure that monomorphic use of these // would not be wrongly rejected in patterns. +#![feature(const_type_id)] #![feature(const_type_name)] use std::any::{self, TypeId}; diff --git a/src/test/ui/consts/issue-73976-polymorphic.rs b/src/test/ui/consts/issue-73976-polymorphic.rs index b3d8610ff5173..787462da9f960 100644 --- a/src/test/ui/consts/issue-73976-polymorphic.rs +++ b/src/test/ui/consts/issue-73976-polymorphic.rs @@ -5,6 +5,7 @@ // This test case should either run-pass or be rejected at compile time. // Currently we just disallow this usage and require pattern is monomorphic. +#![feature(const_type_id)] #![feature(const_type_name)] use std::any::{self, TypeId}; diff --git a/src/test/ui/consts/issue-73976-polymorphic.stderr b/src/test/ui/consts/issue-73976-polymorphic.stderr index 250f1536d85fc..442ad23f2cc42 100644 --- a/src/test/ui/consts/issue-73976-polymorphic.stderr +++ b/src/test/ui/consts/issue-73976-polymorphic.stderr @@ -1,23 +1,23 @@ error: constant pattern depends on a generic parameter - --> $DIR/issue-73976-polymorphic.rs:19:37 + --> $DIR/issue-73976-polymorphic.rs:20:37 | LL | matches!(GetTypeId::::VALUE, GetTypeId::::VALUE) | ^^^^^^^^^^^^^^^^^^^^^ error: constant pattern depends on a generic parameter - --> $DIR/issue-73976-polymorphic.rs:31:42 + --> $DIR/issue-73976-polymorphic.rs:32:42 | LL | matches!(GetTypeNameLen::::VALUE, GetTypeNameLen::::VALUE) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: constant pattern depends on a generic parameter - --> $DIR/issue-73976-polymorphic.rs:19:37 + --> $DIR/issue-73976-polymorphic.rs:20:37 | LL | matches!(GetTypeId::::VALUE, GetTypeId::::VALUE) | ^^^^^^^^^^^^^^^^^^^^^ error: constant pattern depends on a generic parameter - --> $DIR/issue-73976-polymorphic.rs:31:42 + --> $DIR/issue-73976-polymorphic.rs:32:42 | LL | matches!(GetTypeNameLen::::VALUE, GetTypeNameLen::::VALUE) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ From 9f27f3796d3487411ab035803a0757d69040649c Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 22 Sep 2020 17:20:15 -0700 Subject: [PATCH 0860/1052] Include libunwind in the rust-src component. --- src/bootstrap/dist.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index cf73e570fa56f..55ca25ffe060a 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1022,7 +1022,7 @@ impl Step for Src { copy_src_dirs( builder, &builder.src, - &["library"], + &["library", "src/llvm-project/libunwind"], &[ // not needed and contains symlinks which rustup currently // chokes on when unpacking. From a7a20860537ddd05f802598866681a6f9cc3413c Mon Sep 17 00:00:00 2001 From: Avi Dessauer Date: Sun, 17 May 2020 23:00:19 -0400 Subject: [PATCH 0861/1052] Stability annotations on generic trait parameters --- compiler/rustc_metadata/src/rmeta/encoder.rs | 4 ++ compiler/rustc_middle/src/middle/stability.rs | 40 ++++++++--- compiler/rustc_passes/src/stability.rs | 68 ++++++++++++++----- compiler/rustc_typeck/src/astconv/mod.rs | 11 ++- .../rustc_typeck/src/check/method/probe.rs | 2 +- .../auxiliary/unstable_generic_param.rs | 41 +++++++++++ .../generics-default-stability.rs | 59 ++++++++++++++++ .../generics-default-stability.stderr | 27 ++++++++ 8 files changed, 226 insertions(+), 26 deletions(-) create mode 100644 src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs create mode 100644 src/test/ui/stability-attribute/generics-default-stability.rs create mode 100644 src/test/ui/stability-attribute/generics-default-stability.stderr diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index eb091d86b82c6..9ef17a934232c 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1756,6 +1756,9 @@ impl EncodeContext<'a, 'tcx> { EntryKind::TypeParam, default.is_some(), ); + if default.is_some() { + self.encode_stability(def_id.to_def_id()); + } } GenericParamKind::Const { .. } => { self.encode_info_for_generic_param( @@ -1763,6 +1766,7 @@ impl EncodeContext<'a, 'tcx> { EntryKind::ConstParam, true, ); + // FIXME(const_generics:defaults) } } } diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 27658d50d4582..4c0e513e75ce1 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -293,9 +293,15 @@ impl<'tcx> TyCtxt<'tcx> { /// If `id` is `Some(_)`, this function will also check if the item at `def_id` has been /// deprecated. If the item is indeed deprecated, we will emit a deprecation lint attached to /// `id`. - pub fn eval_stability(self, def_id: DefId, id: Option, span: Span) -> EvalResult { + pub fn eval_stability( + self, + def_id: DefId, + id: Option, + span: Span, + check_deprecation: bool, + ) -> EvalResult { // Deprecated attributes apply in-crate and cross-crate. - if let Some(id) = id { + if let (Some(id), true) = (id, check_deprecation) { if let Some(depr_entry) = self.lookup_deprecation_entry(def_id) { let parent_def_id = self.hir().local_def_id(self.hir().get_parent_item(id)); let skip = self @@ -395,21 +401,39 @@ impl<'tcx> TyCtxt<'tcx> { /// Additionally, this function will also check if the item is deprecated. If so, and `id` is /// not `None`, a deprecated lint attached to `id` will be emitted. pub fn check_stability(self, def_id: DefId, id: Option, span: Span) { + self.check_stability_internal(def_id, id, span, true, |span, def_id| { + // The API could be uncallable for other reasons, for example when a private module + // was referenced. + self.sess.delay_span_bug(span, &format!("encountered unmarked API: {:?}", def_id)); + }) + } + + /// Checks if an item is stable or error out. + /// + /// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not + /// exist, emits an error. + /// + /// Additionally when `inherit_dep` is `true`, this function will also check if the item is deprecated. If so, and `id` is + /// not `None`, a deprecated lint attached to `id` will be emitted. + pub fn check_stability_internal( + self, + def_id: DefId, + id: Option, + span: Span, + check_deprecation: bool, + unmarked: impl FnOnce(Span, DefId) -> (), + ) { let soft_handler = |lint, span, msg: &_| { self.struct_span_lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, |lint| { lint.build(msg).emit() }) }; - match self.eval_stability(def_id, id, span) { + match self.eval_stability(def_id, id, span, check_deprecation) { EvalResult::Allow => {} EvalResult::Deny { feature, reason, issue, is_soft } => { report_unstable(self.sess, feature, reason, issue, is_soft, span, soft_handler) } - EvalResult::Unmarked => { - // The API could be uncallable for other reasons, for example when a private module - // was referenced. - self.sess.delay_span_bug(span, &format!("encountered unmarked API: {:?}", def_id)); - } + EvalResult::Unmarked => unmarked(span, def_id), } } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 4ca52f405fb94..d658a58aeab1a 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -56,6 +56,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { attrs: &[Attribute], item_sp: Span, kind: AnnotationKind, + inherit_deprecation: bool, visit_children: F, ) where F: FnOnce(&mut Self), @@ -63,7 +64,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { debug!("annotate(id = {:?}, attrs = {:?})", hir_id, attrs); let mut did_error = false; if !self.tcx.features().staged_api { - did_error = self.forbid_staged_api_attrs(hir_id, attrs); + did_error = self.forbid_staged_api_attrs(hir_id, attrs, inherit_deprecation); } let depr = @@ -80,9 +81,11 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { let depr_entry = DeprecationEntry::local(depr.clone(), hir_id); self.index.depr_map.insert(hir_id, depr_entry); } else if let Some(parent_depr) = self.parent_depr.clone() { - is_deprecated = true; - info!("tagging child {:?} as deprecated from parent", hir_id); - self.index.depr_map.insert(hir_id, parent_depr); + if inherit_deprecation { + is_deprecated = true; + info!("tagging child {:?} as deprecated from parent", hir_id); + self.index.depr_map.insert(hir_id, parent_depr); + } } if self.tcx.features().staged_api { @@ -186,7 +189,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if stab.is_none() { debug!("annotate: stab not found, parent = {:?}", self.parent_stab); if let Some(stab) = self.parent_stab { - if stab.level.is_unstable() { + if inherit_deprecation && stab.level.is_unstable() { self.index.stab_map.insert(hir_id, stab); } } @@ -237,7 +240,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } // returns true if an error occurred, used to suppress some spurious errors - fn forbid_staged_api_attrs(&mut self, hir_id: HirId, attrs: &[Attribute]) -> bool { + fn forbid_staged_api_attrs(&mut self, hir_id: HirId, attrs: &[Attribute], inherit_deprecation: bool) -> bool { // Emit errors for non-staged-api crates. let unstable_attrs = [ sym::unstable, @@ -265,7 +268,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { // Propagate unstability. This can happen even for non-staged-api crates in case // -Zforce-unstable-if-unmarked is set. if let Some(stab) = self.parent_stab { - if stab.level.is_unstable() { + if inherit_deprecation && stab.level.is_unstable() { self.index.stab_map.insert(hir_id, stab); } } @@ -301,18 +304,25 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } hir::ItemKind::Struct(ref sd, _) => { if let Some(ctor_hir_id) = sd.ctor_hir_id() { - self.annotate(ctor_hir_id, &i.attrs, i.span, AnnotationKind::Required, |_| {}) + self.annotate( + ctor_hir_id, + &i.attrs, + i.span, + AnnotationKind::Required, + true, + |_| {}, + ) } } _ => {} } - self.annotate(i.hir_id, &i.attrs, i.span, kind, |v| intravisit::walk_item(v, i)); + self.annotate(i.hir_id, &i.attrs, i.span, kind, true, |v| intravisit::walk_item(v, i)); self.in_trait_impl = orig_in_trait_impl; } fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) { - self.annotate(ti.hir_id, &ti.attrs, ti.span, AnnotationKind::Required, |v| { + self.annotate(ti.hir_id, &ti.attrs, ti.span, AnnotationKind::Required, true, |v| { intravisit::walk_trait_item(v, ti); }); } @@ -320,15 +330,22 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) { let kind = if self.in_trait_impl { AnnotationKind::Prohibited } else { AnnotationKind::Required }; - self.annotate(ii.hir_id, &ii.attrs, ii.span, kind, |v| { + self.annotate(ii.hir_id, &ii.attrs, ii.span, kind, true, |v| { intravisit::walk_impl_item(v, ii); }); } fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, item_id: HirId) { - self.annotate(var.id, &var.attrs, var.span, AnnotationKind::Required, |v| { + self.annotate(var.id, &var.attrs, var.span, AnnotationKind::Required, true, |v| { if let Some(ctor_hir_id) = var.data.ctor_hir_id() { - v.annotate(ctor_hir_id, &var.attrs, var.span, AnnotationKind::Required, |_| {}); + v.annotate( + ctor_hir_id, + &var.attrs, + var.span, + AnnotationKind::Required, + true, + |_| {}, + ); } intravisit::walk_variant(v, var, g, item_id) @@ -336,19 +353,33 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } fn visit_struct_field(&mut self, s: &'tcx StructField<'tcx>) { - self.annotate(s.hir_id, &s.attrs, s.span, AnnotationKind::Required, |v| { + self.annotate(s.hir_id, &s.attrs, s.span, AnnotationKind::Required, true, |v| { intravisit::walk_struct_field(v, s); }); } fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) { - self.annotate(i.hir_id, &i.attrs, i.span, AnnotationKind::Required, |v| { + self.annotate(i.hir_id, &i.attrs, i.span, AnnotationKind::Required, true, |v| { intravisit::walk_foreign_item(v, i); }); } fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) { - self.annotate(md.hir_id, &md.attrs, md.span, AnnotationKind::Required, |_| {}); + self.annotate(md.hir_id, &md.attrs, md.span, AnnotationKind::Required, true, |_| {}); + } + + fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { + let kind = match &p.kind { + // FIXME(const_generics:defaults) + hir::GenericParamKind::Type { default, .. } if default.is_some() => { + AnnotationKind::Container + } + _ => AnnotationKind::Prohibited, + }; + + self.annotate(p.hir_id, &p.attrs, p.span, kind, false, |v| { + intravisit::walk_generic_param(v, p); + }); } } @@ -422,6 +453,10 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) { self.check_missing_stability(md.hir_id, md.span); } + + // Note that we don't need to `check_missing_stability` for default generic parameters, + // as we assume that any default generic parameters without attributes are automatically + // stable (assuming they have not inherited instability from their parent). } fn new_index(tcx: TyCtxt<'tcx>) -> Index<'tcx> { @@ -484,6 +519,7 @@ fn new_index(tcx: TyCtxt<'tcx>) -> Index<'tcx> { &krate.item.attrs, krate.item.span, AnnotationKind::Required, + true, |v| intravisit::walk_crate(v, krate), ); } diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index a743dc1cd2086..c4f1ee2e6f6d6 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -360,7 +360,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { self.ast_region_to_region(<, Some(param)).into() } - (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { + (GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => { + if *has_default { + tcx.check_stability_internal( + param.def_id, + Some(arg.id()), + arg.span(), + false, + |_, _| (), + ) + } if let (hir::TyKind::Infer, false) = (&ty.kind, self.allow_ty_infer()) { inferred_params.push(ty.span); tcx.ty_error().into() diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index 8a62031ec887c..07e75594195ea 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -1227,7 +1227,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { if let Some(uc) = unstable_candidates { applicable_candidates.retain(|&(p, _)| { if let stability::EvalResult::Deny { feature, .. } = - self.tcx.eval_stability(p.item.def_id, None, self.span) + self.tcx.eval_stability(p.item.def_id, None, self.span, true) { uc.push((p, feature)); return false; diff --git a/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs b/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs new file mode 100644 index 0000000000000..7596fa07cbad4 --- /dev/null +++ b/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs @@ -0,0 +1,41 @@ +#![crate_type = "lib"] +#![feature(staged_api)] + +#![stable(feature = "stable_test_feature", since = "1.0.0")] + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub trait Trait1<#[unstable(feature = "unstable_default", issue = "none")] T = ()> { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + fn foo() -> T; +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub trait Trait2<#[unstable(feature = "unstable_default", issue = "none")] T = usize> { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + fn foo() -> T; +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub trait Trait3 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + fn foo() -> T; +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct Struct1<#[unstable(feature = "unstable_default", issue = "none")] T = usize> { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub field: T, +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct Struct2 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub field: T, +} + + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const STRUCT1: Struct1 = Struct1 { field: 1 }; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const STRUCT2: Struct2 = Struct2 { field: 1 }; diff --git a/src/test/ui/stability-attribute/generics-default-stability.rs b/src/test/ui/stability-attribute/generics-default-stability.rs new file mode 100644 index 0000000000000..b8d6ad631022b --- /dev/null +++ b/src/test/ui/stability-attribute/generics-default-stability.rs @@ -0,0 +1,59 @@ +// aux-build:unstable_generic_param.rs + +extern crate unstable_generic_param; + +use unstable_generic_param::*; + +struct R; + +impl Trait1 for S { + fn foo() -> () { () } // ok +} + +struct S; + +impl Trait1 for S { //~ ERROR use of unstable library feature 'unstable_default' + fn foo() -> usize { 0 } +} + +impl Trait1 for S { //~ ERROR use of unstable library feature 'unstable_default' + fn foo() -> isize { 0 } +} + +impl Trait2 for S { //~ ERROR use of unstable library feature 'unstable_default' + fn foo() -> usize { 0 } +} + +impl Trait3 for S { + fn foo() -> usize { 0 } // ok +} + +fn main() { + // let _ = S; + + // let _ = Struct1 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default' + // let _: Struct1 = Struct1 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default' + // let _: Struct1 = Struct1 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default' + + // let _ = STRUCT1; // ok + // let _: Struct1 = STRUCT1; // ok + // let _: Struct1 = STRUCT1; //~ ERROR use of unstable library feature 'unstable_default' + // let _: Struct1 = STRUCT1; //~ ERROR use of unstable library feature 'unstable_default' + // let _ = STRUCT1.field; // ok + // let _: usize = STRUCT1.field; //~ ERROR use of unstable library feature 'unstable_default' + // let _ = STRUCT1.field + 1; //~ ERROR use of unstable library feature 'unstable_default' + // let _ = STRUCT1.field + 1usize; //~ ERROR use of unstable library feature 'unstable_default' + + // let _ = Struct2 { field: 1 }; // ok + // let _: Struct2 = Struct2 { field: 1 }; // ok + // let _: Struct2 = Struct2 { field: 1 }; // ok + + // let _ = STRUCT2; + // let _: Struct2 = STRUCT2; // ok + // let _: Struct2 = STRUCT2; // ok + // let _: Struct2 = STRUCT2; // ok + // let _ = STRUCT2.field; // ok + // let _: usize = STRUCT2.field; // ok + // let _ = STRUCT2.field + 1; // ok + // let _ = STRUCT2.field + 1usize; // ok +} diff --git a/src/test/ui/stability-attribute/generics-default-stability.stderr b/src/test/ui/stability-attribute/generics-default-stability.stderr new file mode 100644 index 0000000000000..1b7f4b85b59ba --- /dev/null +++ b/src/test/ui/stability-attribute/generics-default-stability.stderr @@ -0,0 +1,27 @@ +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:15:13 + | +LL | impl Trait1 for S { + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:19:13 + | +LL | impl Trait1 for S { + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:23:13 + | +LL | impl Trait2 for S { + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. From a9d6da576bbc4b80337c14cb3d0fcb2967a934f4 Mon Sep 17 00:00:00 2001 From: Avi Dessauer Date: Sat, 23 May 2020 16:19:18 -0400 Subject: [PATCH 0862/1052] ignore-tidy-linelength generic default stab test Co-authored-by: Tim Diekmann <21277928+TimDiekmann@users.noreply.github.com> --- src/test/ui/stability-attribute/generics-default-stability.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/ui/stability-attribute/generics-default-stability.rs b/src/test/ui/stability-attribute/generics-default-stability.rs index b8d6ad631022b..b699ff5aae437 100644 --- a/src/test/ui/stability-attribute/generics-default-stability.rs +++ b/src/test/ui/stability-attribute/generics-default-stability.rs @@ -1,3 +1,4 @@ +// ignore-tidy-linelength // aux-build:unstable_generic_param.rs extern crate unstable_generic_param; From 8b81a17d7353a75e4b2d29f96c2c0c8fb1713fec Mon Sep 17 00:00:00 2001 From: Avi Dessauer Date: Sat, 23 May 2020 18:12:33 -0400 Subject: [PATCH 0863/1052] Uncomment struct tests --- .../generics-default-stability.rs | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/test/ui/stability-attribute/generics-default-stability.rs b/src/test/ui/stability-attribute/generics-default-stability.rs index b699ff5aae437..4d08e6f5b138a 100644 --- a/src/test/ui/stability-attribute/generics-default-stability.rs +++ b/src/test/ui/stability-attribute/generics-default-stability.rs @@ -30,31 +30,31 @@ impl Trait3 for S { } fn main() { - // let _ = S; - - // let _ = Struct1 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default' - // let _: Struct1 = Struct1 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default' - // let _: Struct1 = Struct1 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default' - - // let _ = STRUCT1; // ok - // let _: Struct1 = STRUCT1; // ok - // let _: Struct1 = STRUCT1; //~ ERROR use of unstable library feature 'unstable_default' - // let _: Struct1 = STRUCT1; //~ ERROR use of unstable library feature 'unstable_default' - // let _ = STRUCT1.field; // ok - // let _: usize = STRUCT1.field; //~ ERROR use of unstable library feature 'unstable_default' - // let _ = STRUCT1.field + 1; //~ ERROR use of unstable library feature 'unstable_default' - // let _ = STRUCT1.field + 1usize; //~ ERROR use of unstable library feature 'unstable_default' - - // let _ = Struct2 { field: 1 }; // ok - // let _: Struct2 = Struct2 { field: 1 }; // ok - // let _: Struct2 = Struct2 { field: 1 }; // ok - - // let _ = STRUCT2; - // let _: Struct2 = STRUCT2; // ok - // let _: Struct2 = STRUCT2; // ok - // let _: Struct2 = STRUCT2; // ok - // let _ = STRUCT2.field; // ok - // let _: usize = STRUCT2.field; // ok - // let _ = STRUCT2.field + 1; // ok - // let _ = STRUCT2.field + 1usize; // ok + let _ = S; + + let _ = Struct1 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default' + let _: Struct1 = Struct1 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default' + let _: Struct1 = Struct1 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default' + + let _ = STRUCT1; // ok + let _: Struct1 = STRUCT1; // ok + let _: Struct1 = STRUCT1; //~ ERROR use of unstable library feature 'unstable_default' + let _: Struct1 = STRUCT1; //~ ERROR use of unstable library feature 'unstable_default' + let _ = STRUCT1.field; // ok + let _: usize = STRUCT1.field; //~ ERROR use of unstable library feature 'unstable_default' + let _ = STRUCT1.field + 1; //~ ERROR use of unstable library feature 'unstable_default' + let _ = STRUCT1.field + 1usize; //~ ERROR use of unstable library feature 'unstable_default' + + let _ = Struct2 { field: 1 }; // ok + let _: Struct2 = Struct2 { field: 1 }; // ok + let _: Struct2 = Struct2 { field: 1 }; // ok + + let _ = STRUCT2; + let _: Struct2 = STRUCT2; // ok + let _: Struct2 = STRUCT2; // ok + let _: Struct2 = STRUCT2; // ok + let _ = STRUCT2.field; // ok + let _: usize = STRUCT2.field; // ok + let _ = STRUCT2.field + 1; // ok + let _ = STRUCT2.field + 1usize; // ok } From 88b77b6534d5353a16e597451a22322cc7d92063 Mon Sep 17 00:00:00 2001 From: Avi Dessauer Date: Tue, 26 May 2020 16:38:47 -0400 Subject: [PATCH 0864/1052] Comment out broken tests --- .../generics-default-stability.rs | 10 +++--- .../generics-default-stability.stderr | 32 ++++++++++++++++--- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/test/ui/stability-attribute/generics-default-stability.rs b/src/test/ui/stability-attribute/generics-default-stability.rs index 4d08e6f5b138a..f99ce6da198c8 100644 --- a/src/test/ui/stability-attribute/generics-default-stability.rs +++ b/src/test/ui/stability-attribute/generics-default-stability.rs @@ -32,8 +32,8 @@ impl Trait3 for S { fn main() { let _ = S; - let _ = Struct1 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default' - let _: Struct1 = Struct1 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default' + let _ = Struct1 { field: 1 }; // ERROR use of unstable library feature 'unstable_default' + let _: Struct1 = Struct1 { field: 1 }; // ERROR use of unstable library feature 'unstable_default' let _: Struct1 = Struct1 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default' let _ = STRUCT1; // ok @@ -41,9 +41,9 @@ fn main() { let _: Struct1 = STRUCT1; //~ ERROR use of unstable library feature 'unstable_default' let _: Struct1 = STRUCT1; //~ ERROR use of unstable library feature 'unstable_default' let _ = STRUCT1.field; // ok - let _: usize = STRUCT1.field; //~ ERROR use of unstable library feature 'unstable_default' - let _ = STRUCT1.field + 1; //~ ERROR use of unstable library feature 'unstable_default' - let _ = STRUCT1.field + 1usize; //~ ERROR use of unstable library feature 'unstable_default' + let _: usize = STRUCT1.field; // ERROR use of unstable library feature 'unstable_default' + let _ = STRUCT1.field + 1; // ERROR use of unstable library feature 'unstable_default' + let _ = STRUCT1.field + 1usize; // ERROR use of unstable library feature 'unstable_default' let _ = Struct2 { field: 1 }; // ok let _: Struct2 = Struct2 { field: 1 }; // ok diff --git a/src/test/ui/stability-attribute/generics-default-stability.stderr b/src/test/ui/stability-attribute/generics-default-stability.stderr index 1b7f4b85b59ba..00ddc873cfb38 100644 --- a/src/test/ui/stability-attribute/generics-default-stability.stderr +++ b/src/test/ui/stability-attribute/generics-default-stability.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature 'unstable_default' - --> $DIR/generics-default-stability.rs:15:13 + --> $DIR/generics-default-stability.rs:16:13 | LL | impl Trait1 for S { | ^^^^^ @@ -7,7 +7,7 @@ LL | impl Trait1 for S { = help: add `#![feature(unstable_default)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_default' - --> $DIR/generics-default-stability.rs:19:13 + --> $DIR/generics-default-stability.rs:20:13 | LL | impl Trait1 for S { | ^^^^^ @@ -15,13 +15,37 @@ LL | impl Trait1 for S { = help: add `#![feature(unstable_default)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_default' - --> $DIR/generics-default-stability.rs:23:13 + --> $DIR/generics-default-stability.rs:24:13 | LL | impl Trait2 for S { | ^^^^^ | = help: add `#![feature(unstable_default)]` to the crate attributes to enable -error: aborting due to 3 previous errors +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:37:20 + | +LL | let _: Struct1 = Struct1 { field: 1 }; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:41:20 + | +LL | let _: Struct1 = STRUCT1; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:42:20 + | +LL | let _: Struct1 = STRUCT1; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0658`. From eb7abb9e32a2ba10d0c083b13bb1a2dcd1d22b5d Mon Sep 17 00:00:00 2001 From: Avi Dessauer Date: Mon, 1 Jun 2020 11:51:35 -0400 Subject: [PATCH 0865/1052] Unstable default types leak in public fields --- .../generics-default-stability.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/test/ui/stability-attribute/generics-default-stability.rs b/src/test/ui/stability-attribute/generics-default-stability.rs index f99ce6da198c8..bacbc64ab4748 100644 --- a/src/test/ui/stability-attribute/generics-default-stability.rs +++ b/src/test/ui/stability-attribute/generics-default-stability.rs @@ -32,18 +32,22 @@ impl Trait3 for S { fn main() { let _ = S; - let _ = Struct1 { field: 1 }; // ERROR use of unstable library feature 'unstable_default' - let _: Struct1 = Struct1 { field: 1 }; // ERROR use of unstable library feature 'unstable_default' let _: Struct1 = Struct1 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default' let _ = STRUCT1; // ok let _: Struct1 = STRUCT1; // ok let _: Struct1 = STRUCT1; //~ ERROR use of unstable library feature 'unstable_default' - let _: Struct1 = STRUCT1; //~ ERROR use of unstable library feature 'unstable_default' - let _ = STRUCT1.field; // ok - let _: usize = STRUCT1.field; // ERROR use of unstable library feature 'unstable_default' - let _ = STRUCT1.field + 1; // ERROR use of unstable library feature 'unstable_default' - let _ = STRUCT1.field + 1usize; // ERROR use of unstable library feature 'unstable_default' + let _: Struct1 = STRUCT1; //~ ERROR use of unstable library feature 'unstable_default' + + // Instability is not enforced for generic type parameters used in public fields. + // Note how the unstable type default `usize` leaks, + // and can be used without the 'unstable_default' feature. + let _ = STRUCT1.field; + let _ = Struct1 { field: 1 }; + let _: Struct1 = Struct1 { field: 1 }; + let _: usize = STRUCT1.field; + let _ = STRUCT1.field + 1; + let _ = STRUCT1.field + 1usize; let _ = Struct2 { field: 1 }; // ok let _: Struct2 = Struct2 { field: 1 }; // ok From cb7264b22a45b993df57bd17e869a472a5c12b47 Mon Sep 17 00:00:00 2001 From: Avi Dessauer Date: Sat, 20 Jun 2020 17:33:04 -0400 Subject: [PATCH 0866/1052] Fix tests --- .../ui/stability-attribute/generics-default-stability.rs | 4 ++-- .../stability-attribute/generics-default-stability.stderr | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/ui/stability-attribute/generics-default-stability.rs b/src/test/ui/stability-attribute/generics-default-stability.rs index bacbc64ab4748..7f3f90c192628 100644 --- a/src/test/ui/stability-attribute/generics-default-stability.rs +++ b/src/test/ui/stability-attribute/generics-default-stability.rs @@ -37,7 +37,7 @@ fn main() { let _ = STRUCT1; // ok let _: Struct1 = STRUCT1; // ok let _: Struct1 = STRUCT1; //~ ERROR use of unstable library feature 'unstable_default' - let _: Struct1 = STRUCT1; //~ ERROR use of unstable library feature 'unstable_default' + let _: Struct1 = Struct1 { field: 0 }; //~ ERROR use of unstable library feature 'unstable_default' // Instability is not enforced for generic type parameters used in public fields. // Note how the unstable type default `usize` leaks, @@ -56,7 +56,7 @@ fn main() { let _ = STRUCT2; let _: Struct2 = STRUCT2; // ok let _: Struct2 = STRUCT2; // ok - let _: Struct2 = STRUCT2; // ok + let _: Struct2 = Struct2 { field: 0 }; // ok let _ = STRUCT2.field; // ok let _: usize = STRUCT2.field; // ok let _ = STRUCT2.field + 1; // ok diff --git a/src/test/ui/stability-attribute/generics-default-stability.stderr b/src/test/ui/stability-attribute/generics-default-stability.stderr index 00ddc873cfb38..6b405b557699f 100644 --- a/src/test/ui/stability-attribute/generics-default-stability.stderr +++ b/src/test/ui/stability-attribute/generics-default-stability.stderr @@ -23,7 +23,7 @@ LL | impl Trait2 for S { = help: add `#![feature(unstable_default)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_default' - --> $DIR/generics-default-stability.rs:37:20 + --> $DIR/generics-default-stability.rs:35:20 | LL | let _: Struct1 = Struct1 { field: 1 }; | ^^^^^ @@ -31,7 +31,7 @@ LL | let _: Struct1 = Struct1 { field: 1 }; = help: add `#![feature(unstable_default)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_default' - --> $DIR/generics-default-stability.rs:41:20 + --> $DIR/generics-default-stability.rs:39:20 | LL | let _: Struct1 = STRUCT1; | ^^^^^ @@ -39,9 +39,9 @@ LL | let _: Struct1 = STRUCT1; = help: add `#![feature(unstable_default)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_default' - --> $DIR/generics-default-stability.rs:42:20 + --> $DIR/generics-default-stability.rs:40:20 | -LL | let _: Struct1 = STRUCT1; +LL | let _: Struct1 = Struct1 { field: 0 }; | ^^^^^ | = help: add `#![feature(unstable_default)]` to the crate attributes to enable From f665ccd3a2f5e58c6ac3828e34f5c8e94f71811c Mon Sep 17 00:00:00 2001 From: Avi Dessauer Date: Mon, 22 Jun 2020 00:08:54 -0400 Subject: [PATCH 0867/1052] Add more tests --- .../auxiliary/unstable_generic_param.rs | 10 +++++++ .../generics-default-stability-where.rs | 12 +++++++++ .../generics-default-stability-where.stderr | 11 ++++++++ .../generics-default-stability.rs | 15 +++++++++++ .../generics-default-stability.stderr | 26 ++++++++++++++++++- 5 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/stability-attribute/generics-default-stability-where.rs create mode 100644 src/test/ui/stability-attribute/generics-default-stability-where.stderr diff --git a/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs b/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs index 7596fa07cbad4..c38fb92905b3f 100644 --- a/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs +++ b/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs @@ -33,9 +33,19 @@ pub struct Struct2 { pub field: T, } +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct Struct3 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub field1: A, + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub field2: B, +} #[stable(feature = "stable_test_feature", since = "1.0.0")] pub const STRUCT1: Struct1 = Struct1 { field: 1 }; #[stable(feature = "stable_test_feature", since = "1.0.0")] pub const STRUCT2: Struct2 = Struct2 { field: 1 }; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const STRUCT3: Struct3 = Struct3 { field1: 1, field2: 2 }; diff --git a/src/test/ui/stability-attribute/generics-default-stability-where.rs b/src/test/ui/stability-attribute/generics-default-stability-where.rs new file mode 100644 index 0000000000000..3fd14e25d0ef2 --- /dev/null +++ b/src/test/ui/stability-attribute/generics-default-stability-where.rs @@ -0,0 +1,12 @@ +// ignore-tidy-linelength +// aux-build:unstable_generic_param.rs + +extern crate unstable_generic_param; + +use unstable_generic_param::*; + +impl Trait3 for T where T: Trait2 { //~ ERROR use of unstable library feature 'unstable_default' + fn foo() -> usize { T::foo() } +} + +fn main() {} diff --git a/src/test/ui/stability-attribute/generics-default-stability-where.stderr b/src/test/ui/stability-attribute/generics-default-stability-where.stderr new file mode 100644 index 0000000000000..19fa09f311ba8 --- /dev/null +++ b/src/test/ui/stability-attribute/generics-default-stability-where.stderr @@ -0,0 +1,11 @@ +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability-where.rs:8:45 + | +LL | impl Trait3 for T where T: Trait2 { + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/stability-attribute/generics-default-stability.rs b/src/test/ui/stability-attribute/generics-default-stability.rs index 7f3f90c192628..063058c0f53fc 100644 --- a/src/test/ui/stability-attribute/generics-default-stability.rs +++ b/src/test/ui/stability-attribute/generics-default-stability.rs @@ -61,4 +61,19 @@ fn main() { let _: usize = STRUCT2.field; // ok let _ = STRUCT2.field + 1; // ok let _ = STRUCT2.field + 1usize; // ok + + let _ = STRUCT3; + let _: Struct3 = STRUCT3; // ok + let _: Struct3 = STRUCT3; //~ ERROR use of unstable library feature 'unstable_default' + let _: Struct3 = STRUCT3; // ok + let _: Struct3 = Struct3 { field1: 0, field2: 0 }; //~ ERROR use of unstable library feature 'unstable_default' + let _: Struct3 = Struct3 { field1: 0, field2: 0 }; //~ ERROR use of unstable library feature 'unstable_default' + let _ = STRUCT3.field1; // ok + let _: isize = STRUCT3.field1; // ok + let _ = STRUCT3.field1 + 1; // ok + // Note the aforementioned leak. + let _: usize = STRUCT3.field2; // ok + let _: Struct3 = Struct3 { field1: 0, field2: 0 }; // ok + let _ = STRUCT3.field2 + 1; // ok + let _ = STRUCT3.field2 + 1usize; // ok } diff --git a/src/test/ui/stability-attribute/generics-default-stability.stderr b/src/test/ui/stability-attribute/generics-default-stability.stderr index 6b405b557699f..eadcd2641d058 100644 --- a/src/test/ui/stability-attribute/generics-default-stability.stderr +++ b/src/test/ui/stability-attribute/generics-default-stability.stderr @@ -46,6 +46,30 @@ LL | let _: Struct1 = Struct1 { field: 0 }; | = help: add `#![feature(unstable_default)]` to the crate attributes to enable -error: aborting due to 6 previous errors +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:67:27 + | +LL | let _: Struct3 = STRUCT3; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:69:27 + | +LL | let _: Struct3 = Struct3 { field1: 0, field2: 0 }; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:70:27 + | +LL | let _: Struct3 = Struct3 { field1: 0, field2: 0 }; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0658`. From a1892f1a798f8b0c24136d0be65fa4cc23e0ff74 Mon Sep 17 00:00:00 2001 From: Avi Dessauer Date: Thu, 25 Jun 2020 15:53:47 -0400 Subject: [PATCH 0868/1052] Test stability on default parameter of deprecated --- .../auxiliary/unstable_generic_param.rs | 20 +++ .../generics-default-stability.rs | 27 ++++ .../generics-default-stability.stderr | 124 +++++++++++++++++- 3 files changed, 170 insertions(+), 1 deletion(-) diff --git a/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs b/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs index c38fb92905b3f..64d725e55edb8 100644 --- a/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs +++ b/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs @@ -41,6 +41,20 @@ pub struct Struct3 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub field: A, +} + +#[rustc_deprecated(since = "1.1.0", reason = "test")] +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct Struct5<#[unstable(feature = "unstable_default", issue = "none")] A = usize> { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub field: A, +} + #[stable(feature = "stable_test_feature", since = "1.0.0")] pub const STRUCT1: Struct1 = Struct1 { field: 1 }; @@ -49,3 +63,9 @@ pub const STRUCT2: Struct2 = Struct2 { field: 1 }; #[stable(feature = "stable_test_feature", since = "1.0.0")] pub const STRUCT3: Struct3 = Struct3 { field1: 1, field2: 2 }; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const STRUCT4: Struct4 = Struct4 { field: 1 }; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const STRUCT5: Struct5 = Struct5 { field: 1 }; diff --git a/src/test/ui/stability-attribute/generics-default-stability.rs b/src/test/ui/stability-attribute/generics-default-stability.rs index 063058c0f53fc..de178eee1d769 100644 --- a/src/test/ui/stability-attribute/generics-default-stability.rs +++ b/src/test/ui/stability-attribute/generics-default-stability.rs @@ -76,4 +76,31 @@ fn main() { let _: Struct3 = Struct3 { field1: 0, field2: 0 }; // ok let _ = STRUCT3.field2 + 1; // ok let _ = STRUCT3.field2 + 1usize; // ok + + let _ = STRUCT4; + let _: Struct4 = Struct4 { field: 1 }; + //~^ use of deprecated item 'unstable_generic_param::Struct4': test [deprecated] + //~^^ use of deprecated item 'unstable_generic_param::Struct4': test [deprecated] + //~^^^ use of deprecated item 'unstable_generic_param::Struct4::field': test [deprecated] + let _ = STRUCT4; + let _: Struct4 = STRUCT4; //~ use of deprecated item 'unstable_generic_param::Struct4': test [deprecated] + let _: Struct4 = STRUCT4; //~ use of deprecated item 'unstable_generic_param::Struct4': test [deprecated] + let _: Struct4 = Struct4 { field: 0 }; + //~^ use of deprecated item 'unstable_generic_param::Struct4': test [deprecated] + //~^^ use of deprecated item 'unstable_generic_param::Struct4': test [deprecated] + //~^^^ use of deprecated item 'unstable_generic_param::Struct4::field': test [deprecated] + + let _ = STRUCT5; + let _: Struct5 = Struct5 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated item 'unstable_generic_param::Struct5': test [deprecated] + //~^^ use of deprecated item 'unstable_generic_param::Struct5': test [deprecated] + //~^^^ use of deprecated item 'unstable_generic_param::Struct5::field': test [deprecated] + let _ = STRUCT5; + let _: Struct5 = STRUCT5; //~ use of deprecated item 'unstable_generic_param::Struct5': test [deprecated] + let _: Struct5 = STRUCT5; //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated item 'unstable_generic_param::Struct5': test [deprecated] + let _: Struct5 = Struct5 { field: 0 }; //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated item 'unstable_generic_param::Struct5': test [deprecated] + //~^^ use of deprecated item 'unstable_generic_param::Struct5': test [deprecated] + //~^^^ use of deprecated item 'unstable_generic_param::Struct5::field': test [deprecated] } diff --git a/src/test/ui/stability-attribute/generics-default-stability.stderr b/src/test/ui/stability-attribute/generics-default-stability.stderr index eadcd2641d058..2bc98cc009587 100644 --- a/src/test/ui/stability-attribute/generics-default-stability.stderr +++ b/src/test/ui/stability-attribute/generics-default-stability.stderr @@ -22,6 +22,80 @@ LL | impl Trait2 for S { | = help: add `#![feature(unstable_default)]` to the crate attributes to enable +warning: use of deprecated item 'unstable_generic_param::Struct4': test + --> $DIR/generics-default-stability.rs:81:29 + | +LL | let _: Struct4 = Struct4 { field: 1 }; + | ^^^^^^^ + | + = note: `#[warn(deprecated)]` on by default + +warning: use of deprecated item 'unstable_generic_param::Struct4': test + --> $DIR/generics-default-stability.rs:81:12 + | +LL | let _: Struct4 = Struct4 { field: 1 }; + | ^^^^^^^^^^^^^^ + +warning: use of deprecated item 'unstable_generic_param::Struct4': test + --> $DIR/generics-default-stability.rs:86:12 + | +LL | let _: Struct4 = STRUCT4; + | ^^^^^^^ + +warning: use of deprecated item 'unstable_generic_param::Struct4': test + --> $DIR/generics-default-stability.rs:87:12 + | +LL | let _: Struct4 = STRUCT4; + | ^^^^^^^^^^^^^^ + +warning: use of deprecated item 'unstable_generic_param::Struct4': test + --> $DIR/generics-default-stability.rs:88:29 + | +LL | let _: Struct4 = Struct4 { field: 0 }; + | ^^^^^^^ + +warning: use of deprecated item 'unstable_generic_param::Struct4': test + --> $DIR/generics-default-stability.rs:88:12 + | +LL | let _: Struct4 = Struct4 { field: 0 }; + | ^^^^^^^^^^^^^^ + +warning: use of deprecated item 'unstable_generic_param::Struct5': test + --> $DIR/generics-default-stability.rs:94:29 + | +LL | let _: Struct5 = Struct5 { field: 1 }; + | ^^^^^^^ + +warning: use of deprecated item 'unstable_generic_param::Struct5': test + --> $DIR/generics-default-stability.rs:94:12 + | +LL | let _: Struct5 = Struct5 { field: 1 }; + | ^^^^^^^^^^^^^^ + +warning: use of deprecated item 'unstable_generic_param::Struct5': test + --> $DIR/generics-default-stability.rs:99:12 + | +LL | let _: Struct5 = STRUCT5; + | ^^^^^^^ + +warning: use of deprecated item 'unstable_generic_param::Struct5': test + --> $DIR/generics-default-stability.rs:100:12 + | +LL | let _: Struct5 = STRUCT5; + | ^^^^^^^^^^^^^^ + +warning: use of deprecated item 'unstable_generic_param::Struct5': test + --> $DIR/generics-default-stability.rs:102:29 + | +LL | let _: Struct5 = Struct5 { field: 0 }; + | ^^^^^^^ + +warning: use of deprecated item 'unstable_generic_param::Struct5': test + --> $DIR/generics-default-stability.rs:102:12 + | +LL | let _: Struct5 = Struct5 { field: 0 }; + | ^^^^^^^^^^^^^^ + error[E0658]: use of unstable library feature 'unstable_default' --> $DIR/generics-default-stability.rs:35:20 | @@ -70,6 +144,54 @@ LL | let _: Struct3 = Struct3 { field1: 0, field2: 0 }; | = help: add `#![feature(unstable_default)]` to the crate attributes to enable -error: aborting due to 9 previous errors +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:94:20 + | +LL | let _: Struct5 = Struct5 { field: 1 }; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:100:20 + | +LL | let _: Struct5 = STRUCT5; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:102:20 + | +LL | let _: Struct5 = Struct5 { field: 0 }; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +warning: use of deprecated item 'unstable_generic_param::Struct4::field': test + --> $DIR/generics-default-stability.rs:81:39 + | +LL | let _: Struct4 = Struct4 { field: 1 }; + | ^^^^^^^^ + +warning: use of deprecated item 'unstable_generic_param::Struct4::field': test + --> $DIR/generics-default-stability.rs:88:39 + | +LL | let _: Struct4 = Struct4 { field: 0 }; + | ^^^^^^^^ + +warning: use of deprecated item 'unstable_generic_param::Struct5::field': test + --> $DIR/generics-default-stability.rs:94:39 + | +LL | let _: Struct5 = Struct5 { field: 1 }; + | ^^^^^^^^ + +warning: use of deprecated item 'unstable_generic_param::Struct5::field': test + --> $DIR/generics-default-stability.rs:102:39 + | +LL | let _: Struct5 = Struct5 { field: 0 }; + | ^^^^^^^^ + +error: aborting due to 12 previous errors; 16 warnings emitted For more information about this error, try `rustc --explain E0658`. From 3947591ee82702f124af9248463036155b83b907 Mon Sep 17 00:00:00 2001 From: Avi Dessauer Date: Tue, 30 Jun 2020 19:05:14 -0400 Subject: [PATCH 0869/1052] Remove now unneeded check_stability argument --- compiler/rustc_middle/src/middle/stability.rs | 23 +++++++------------ compiler/rustc_typeck/src/astconv/mod.rs | 1 - .../rustc_typeck/src/check/method/probe.rs | 2 +- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 4c0e513e75ce1..0fb73db83e8c5 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -293,15 +293,9 @@ impl<'tcx> TyCtxt<'tcx> { /// If `id` is `Some(_)`, this function will also check if the item at `def_id` has been /// deprecated. If the item is indeed deprecated, we will emit a deprecation lint attached to /// `id`. - pub fn eval_stability( - self, - def_id: DefId, - id: Option, - span: Span, - check_deprecation: bool, - ) -> EvalResult { + pub fn eval_stability(self, def_id: DefId, id: Option, span: Span) -> EvalResult { // Deprecated attributes apply in-crate and cross-crate. - if let (Some(id), true) = (id, check_deprecation) { + if let Some(id) = id { if let Some(depr_entry) = self.lookup_deprecation_entry(def_id) { let parent_def_id = self.hir().local_def_id(self.hir().get_parent_item(id)); let skip = self @@ -398,10 +392,10 @@ impl<'tcx> TyCtxt<'tcx> { /// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not /// exist, emits an error. /// - /// Additionally, this function will also check if the item is deprecated. If so, and `id` is - /// not `None`, a deprecated lint attached to `id` will be emitted. + /// This function will also check if the item is deprecated. + /// If so, and `id` is not `None`, a deprecated lint attached to `id` will be emitted. pub fn check_stability(self, def_id: DefId, id: Option, span: Span) { - self.check_stability_internal(def_id, id, span, true, |span, def_id| { + self.check_stability_internal(def_id, id, span, |span, def_id| { // The API could be uncallable for other reasons, for example when a private module // was referenced. self.sess.delay_span_bug(span, &format!("encountered unmarked API: {:?}", def_id)); @@ -413,14 +407,13 @@ impl<'tcx> TyCtxt<'tcx> { /// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not /// exist, emits an error. /// - /// Additionally when `inherit_dep` is `true`, this function will also check if the item is deprecated. If so, and `id` is - /// not `None`, a deprecated lint attached to `id` will be emitted. + /// This function will also check if the item is deprecated. + /// If so, and `id` is not `None`, a deprecated lint attached to `id` will be emitted. pub fn check_stability_internal( self, def_id: DefId, id: Option, span: Span, - check_deprecation: bool, unmarked: impl FnOnce(Span, DefId) -> (), ) { let soft_handler = |lint, span, msg: &_| { @@ -428,7 +421,7 @@ impl<'tcx> TyCtxt<'tcx> { lint.build(msg).emit() }) }; - match self.eval_stability(def_id, id, span, check_deprecation) { + match self.eval_stability(def_id, id, span) { EvalResult::Allow => {} EvalResult::Deny { feature, reason, issue, is_soft } => { report_unstable(self.sess, feature, reason, issue, is_soft, span, soft_handler) diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index c4f1ee2e6f6d6..ad4c28928fc63 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -366,7 +366,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { param.def_id, Some(arg.id()), arg.span(), - false, |_, _| (), ) } diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index 07e75594195ea..8a62031ec887c 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -1227,7 +1227,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { if let Some(uc) = unstable_candidates { applicable_candidates.retain(|&(p, _)| { if let stability::EvalResult::Deny { feature, .. } = - self.tcx.eval_stability(p.item.def_id, None, self.span, true) + self.tcx.eval_stability(p.item.def_id, None, self.span) { uc.push((p, feature)); return false; From 19e90843a4eb99d528dea62f793ad6d523c4af6c Mon Sep 17 00:00:00 2001 From: Avi Dessauer Date: Sun, 5 Jul 2020 19:02:30 -0400 Subject: [PATCH 0870/1052] Add documentation --- compiler/rustc_middle/src/middle/stability.rs | 7 +- compiler/rustc_passes/src/stability.rs | 117 +++++++++++++----- compiler/rustc_typeck/src/astconv/mod.rs | 2 +- 3 files changed, 90 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 0fb73db83e8c5..28d139faa59b0 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -395,7 +395,7 @@ impl<'tcx> TyCtxt<'tcx> { /// This function will also check if the item is deprecated. /// If so, and `id` is not `None`, a deprecated lint attached to `id` will be emitted. pub fn check_stability(self, def_id: DefId, id: Option, span: Span) { - self.check_stability_internal(def_id, id, span, |span, def_id| { + self.check_optional_stability(def_id, id, span, |span, def_id| { // The API could be uncallable for other reasons, for example when a private module // was referenced. self.sess.delay_span_bug(span, &format!("encountered unmarked API: {:?}", def_id)); @@ -409,7 +409,10 @@ impl<'tcx> TyCtxt<'tcx> { /// /// This function will also check if the item is deprecated. /// If so, and `id` is not `None`, a deprecated lint attached to `id` will be emitted. - pub fn check_stability_internal( + /// + /// The `unmarked` closure is called definitions without a stability annotation. + /// This is needed for generic parameters, since they may not be marked when used in a staged_api crate. + pub fn check_optional_stability( self, def_id: DefId, id: Option, diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index d658a58aeab1a..d34363e057726 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -37,6 +37,20 @@ enum AnnotationKind { Container, } +/// Inheriting deprecations Nested items causes duplicate warnings. +/// Inheriting the deprecation of `Foo` onto the parameter `T`, would cause a duplicate warnings. +#[derive(PartialEq, Copy, Clone)] +enum InheritDeprecation { + Yes, + No, +} + +impl InheritDeprecation { + fn yes(&self) -> bool { + *self == InheritDeprecation::Yes + } +} + // A private tree-walker for producing an Index. struct Annotator<'a, 'tcx> { tcx: TyCtxt<'tcx>, @@ -56,7 +70,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { attrs: &[Attribute], item_sp: Span, kind: AnnotationKind, - inherit_deprecation: bool, + inherit_deprecation: InheritDeprecation, visit_children: F, ) where F: FnOnce(&mut Self), @@ -81,7 +95,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { let depr_entry = DeprecationEntry::local(depr.clone(), hir_id); self.index.depr_map.insert(hir_id, depr_entry); } else if let Some(parent_depr) = self.parent_depr.clone() { - if inherit_deprecation { + if inherit_deprecation.yes() { is_deprecated = true; info!("tagging child {:?} as deprecated from parent", hir_id); self.index.depr_map.insert(hir_id, parent_depr); @@ -189,7 +203,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if stab.is_none() { debug!("annotate: stab not found, parent = {:?}", self.parent_stab); if let Some(stab) = self.parent_stab { - if inherit_deprecation && stab.level.is_unstable() { + if inherit_deprecation.yes() && stab.level.is_unstable() { self.index.stab_map.insert(hir_id, stab); } } @@ -240,7 +254,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } // returns true if an error occurred, used to suppress some spurious errors - fn forbid_staged_api_attrs(&mut self, hir_id: HirId, attrs: &[Attribute], inherit_deprecation: bool) -> bool { + fn forbid_staged_api_attrs(&mut self, hir_id: HirId, attrs: &[Attribute], inherit_deprecation: InheritDeprecation) -> bool { // Emit errors for non-staged-api crates. let unstable_attrs = [ sym::unstable, @@ -268,7 +282,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { // Propagate unstability. This can happen even for non-staged-api crates in case // -Zforce-unstable-if-unmarked is set. if let Some(stab) = self.parent_stab { - if inherit_deprecation && stab.level.is_unstable() { + if inherit_deprecation.yes() && stab.level.is_unstable() { self.index.stab_map.insert(hir_id, stab); } } @@ -309,7 +323,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { &i.attrs, i.span, AnnotationKind::Required, - true, + InheritDeprecation::Yes, |_| {}, ) } @@ -317,55 +331,92 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { _ => {} } - self.annotate(i.hir_id, &i.attrs, i.span, kind, true, |v| intravisit::walk_item(v, i)); + self.annotate(i.hir_id, &i.attrs, i.span, kind, InheritDeprecation::Yes, |v| { + intravisit::walk_item(v, i) + }); self.in_trait_impl = orig_in_trait_impl; } fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) { - self.annotate(ti.hir_id, &ti.attrs, ti.span, AnnotationKind::Required, true, |v| { - intravisit::walk_trait_item(v, ti); - }); + self.annotate( + ti.hir_id, + &ti.attrs, + ti.span, + AnnotationKind::Required, + InheritDeprecation::Yes, + |v| { + intravisit::walk_trait_item(v, ti); + }, + ); } fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) { let kind = if self.in_trait_impl { AnnotationKind::Prohibited } else { AnnotationKind::Required }; - self.annotate(ii.hir_id, &ii.attrs, ii.span, kind, true, |v| { + self.annotate(ii.hir_id, &ii.attrs, ii.span, kind, InheritDeprecation::Yes, |v| { intravisit::walk_impl_item(v, ii); }); } fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, item_id: HirId) { - self.annotate(var.id, &var.attrs, var.span, AnnotationKind::Required, true, |v| { - if let Some(ctor_hir_id) = var.data.ctor_hir_id() { - v.annotate( - ctor_hir_id, - &var.attrs, - var.span, - AnnotationKind::Required, - true, - |_| {}, - ); - } + self.annotate( + var.id, + &var.attrs, + var.span, + AnnotationKind::Required, + InheritDeprecation::Yes, + |v| { + if let Some(ctor_hir_id) = var.data.ctor_hir_id() { + v.annotate( + ctor_hir_id, + &var.attrs, + var.span, + AnnotationKind::Required, + InheritDeprecation::Yes, + |_| {}, + ); + } - intravisit::walk_variant(v, var, g, item_id) - }) + intravisit::walk_variant(v, var, g, item_id) + }, + ) } fn visit_struct_field(&mut self, s: &'tcx StructField<'tcx>) { - self.annotate(s.hir_id, &s.attrs, s.span, AnnotationKind::Required, true, |v| { - intravisit::walk_struct_field(v, s); - }); + self.annotate( + s.hir_id, + &s.attrs, + s.span, + AnnotationKind::Required, + InheritDeprecation::Yes, + |v| { + intravisit::walk_struct_field(v, s); + }, + ); } fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) { - self.annotate(i.hir_id, &i.attrs, i.span, AnnotationKind::Required, true, |v| { - intravisit::walk_foreign_item(v, i); - }); + self.annotate( + i.hir_id, + &i.attrs, + i.span, + AnnotationKind::Required, + InheritDeprecation::Yes, + |v| { + intravisit::walk_foreign_item(v, i); + }, + ); } fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) { - self.annotate(md.hir_id, &md.attrs, md.span, AnnotationKind::Required, true, |_| {}); + self.annotate( + md.hir_id, + &md.attrs, + md.span, + AnnotationKind::Required, + InheritDeprecation::Yes, + |_| {}, + ); } fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { @@ -377,7 +428,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { _ => AnnotationKind::Prohibited, }; - self.annotate(p.hir_id, &p.attrs, p.span, kind, false, |v| { + self.annotate(p.hir_id, &p.attrs, p.span, kind, InheritDeprecation::No, |v| { intravisit::walk_generic_param(v, p); }); } @@ -519,7 +570,7 @@ fn new_index(tcx: TyCtxt<'tcx>) -> Index<'tcx> { &krate.item.attrs, krate.item.span, AnnotationKind::Required, - true, + InheritDeprecation::Yes, |v| intravisit::walk_crate(v, krate), ); } diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index ad4c28928fc63..3c95184c35feb 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -362,7 +362,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } (GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => { if *has_default { - tcx.check_stability_internal( + tcx.check_optional_stability( param.def_id, Some(arg.id()), arg.span(), From 41eec9065aef513cc41d8e2297c4f469fd7029b7 Mon Sep 17 00:00:00 2001 From: Avi Dessauer Date: Wed, 8 Jul 2020 15:31:48 -0400 Subject: [PATCH 0871/1052] Update src/librustc_passes/stability.rs Co-authored-by: varkor --- compiler/rustc_passes/src/stability.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index d34363e057726..dd453f2855420 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -37,8 +37,12 @@ enum AnnotationKind { Container, } -/// Inheriting deprecations Nested items causes duplicate warnings. -/// Inheriting the deprecation of `Foo` onto the parameter `T`, would cause a duplicate warnings. +/// Whether to inherit deprecation flags for nested items. In most cases, we do want to inherit +/// deprecation, because nested items rarely have individual deprecation attributes, and so +/// should be treated as deprecated if their parent is. However, default generic parameters +/// have separate deprecation attributes from their parents, so we do not wish to inherit +/// deprecation in this case. For example, inheriting deprecation for `T` in `Foo` +/// would cause a duplicate warning arising from both `Foo` and `T` being deprecated. #[derive(PartialEq, Copy, Clone)] enum InheritDeprecation { Yes, From 9eb595705e754c970de76375060455bc3f576296 Mon Sep 17 00:00:00 2001 From: Avi Dessauer Date: Wed, 8 Jul 2020 15:32:11 -0400 Subject: [PATCH 0872/1052] Update src/librustc_typeck/astconv.rs Co-authored-by: varkor --- compiler/rustc_typeck/src/astconv/mod.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 3c95184c35feb..46b8b2e14c736 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -366,7 +366,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { param.def_id, Some(arg.id()), arg.span(), - |_, _| (), + |_, _| { + // Default generic parameters may not be marked + // with stability attributes, i.e. when the + // default parameter was defined at the same time + // as the rest of the type. As such, we ignore missing + // stability attributes. + }, ) } if let (hir::TyKind::Infer, false) = (&ty.kind, self.allow_ty_infer()) { From 25dba40cbee4161709fba653c5f3915a7ac87537 Mon Sep 17 00:00:00 2001 From: Avi Dessauer Date: Wed, 8 Jul 2020 15:32:58 -0400 Subject: [PATCH 0873/1052] Update src/librustc_middle/middle/stability.rs Co-authored-by: varkor --- compiler/rustc_middle/src/middle/stability.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 28d139faa59b0..7e2415fd544d4 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -402,16 +402,10 @@ impl<'tcx> TyCtxt<'tcx> { }) } - /// Checks if an item is stable or error out. - /// - /// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not - /// exist, emits an error. - /// - /// This function will also check if the item is deprecated. - /// If so, and `id` is not `None`, a deprecated lint attached to `id` will be emitted. - /// - /// The `unmarked` closure is called definitions without a stability annotation. - /// This is needed for generic parameters, since they may not be marked when used in a staged_api crate. + /// Like `check_stability`, except that we permit items to have custom behaviour for + /// missing stability attributes (not necessarily just emit a `bug!`). This is necessary + /// for default generic parameters, which only have stability attributes if they were + /// added after the type on which they're defined. pub fn check_optional_stability( self, def_id: DefId, From 2793da3f39033d7f0b2c07a3556d68ccd4d03d4e Mon Sep 17 00:00:00 2001 From: Avi Dessauer Date: Wed, 8 Jul 2020 15:51:31 -0400 Subject: [PATCH 0874/1052] Update src/librustc_passes/stability.rs Co-authored-by: varkor --- compiler/rustc_passes/src/stability.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index dd453f2855420..5b0df9e884ff6 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -43,7 +43,6 @@ enum AnnotationKind { /// have separate deprecation attributes from their parents, so we do not wish to inherit /// deprecation in this case. For example, inheriting deprecation for `T` in `Foo` /// would cause a duplicate warning arising from both `Foo` and `T` being deprecated. -#[derive(PartialEq, Copy, Clone)] enum InheritDeprecation { Yes, No, @@ -51,7 +50,7 @@ enum InheritDeprecation { impl InheritDeprecation { fn yes(&self) -> bool { - *self == InheritDeprecation::Yes + matches!(self, InheritDeprecation::Yes) } } From af19d4492124a9681c1e3bc9c9effe1641ad7d20 Mon Sep 17 00:00:00 2001 From: Avi Dessauer Date: Sat, 11 Jul 2020 19:08:05 -0400 Subject: [PATCH 0875/1052] Add test case demonstrating leak --- .../generics-default-stability.rs | 2 + .../generics-default-stability.stderr | 44 +++++++++---------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/test/ui/stability-attribute/generics-default-stability.rs b/src/test/ui/stability-attribute/generics-default-stability.rs index de178eee1d769..c44f3c32bbee3 100644 --- a/src/test/ui/stability-attribute/generics-default-stability.rs +++ b/src/test/ui/stability-attribute/generics-default-stability.rs @@ -44,6 +44,8 @@ fn main() { // and can be used without the 'unstable_default' feature. let _ = STRUCT1.field; let _ = Struct1 { field: 1 }; + let _ = Struct1 { field: () }; + let _ = Struct1 { field: 1isize }; let _: Struct1 = Struct1 { field: 1 }; let _: usize = STRUCT1.field; let _ = STRUCT1.field + 1; diff --git a/src/test/ui/stability-attribute/generics-default-stability.stderr b/src/test/ui/stability-attribute/generics-default-stability.stderr index 2bc98cc009587..87ebe65dcfcfc 100644 --- a/src/test/ui/stability-attribute/generics-default-stability.stderr +++ b/src/test/ui/stability-attribute/generics-default-stability.stderr @@ -23,7 +23,7 @@ LL | impl Trait2 for S { = help: add `#![feature(unstable_default)]` to the crate attributes to enable warning: use of deprecated item 'unstable_generic_param::Struct4': test - --> $DIR/generics-default-stability.rs:81:29 + --> $DIR/generics-default-stability.rs:83:29 | LL | let _: Struct4 = Struct4 { field: 1 }; | ^^^^^^^ @@ -31,67 +31,67 @@ LL | let _: Struct4 = Struct4 { field: 1 }; = note: `#[warn(deprecated)]` on by default warning: use of deprecated item 'unstable_generic_param::Struct4': test - --> $DIR/generics-default-stability.rs:81:12 + --> $DIR/generics-default-stability.rs:83:12 | LL | let _: Struct4 = Struct4 { field: 1 }; | ^^^^^^^^^^^^^^ warning: use of deprecated item 'unstable_generic_param::Struct4': test - --> $DIR/generics-default-stability.rs:86:12 + --> $DIR/generics-default-stability.rs:88:12 | LL | let _: Struct4 = STRUCT4; | ^^^^^^^ warning: use of deprecated item 'unstable_generic_param::Struct4': test - --> $DIR/generics-default-stability.rs:87:12 + --> $DIR/generics-default-stability.rs:89:12 | LL | let _: Struct4 = STRUCT4; | ^^^^^^^^^^^^^^ warning: use of deprecated item 'unstable_generic_param::Struct4': test - --> $DIR/generics-default-stability.rs:88:29 + --> $DIR/generics-default-stability.rs:90:29 | LL | let _: Struct4 = Struct4 { field: 0 }; | ^^^^^^^ warning: use of deprecated item 'unstable_generic_param::Struct4': test - --> $DIR/generics-default-stability.rs:88:12 + --> $DIR/generics-default-stability.rs:90:12 | LL | let _: Struct4 = Struct4 { field: 0 }; | ^^^^^^^^^^^^^^ warning: use of deprecated item 'unstable_generic_param::Struct5': test - --> $DIR/generics-default-stability.rs:94:29 + --> $DIR/generics-default-stability.rs:96:29 | LL | let _: Struct5 = Struct5 { field: 1 }; | ^^^^^^^ warning: use of deprecated item 'unstable_generic_param::Struct5': test - --> $DIR/generics-default-stability.rs:94:12 + --> $DIR/generics-default-stability.rs:96:12 | LL | let _: Struct5 = Struct5 { field: 1 }; | ^^^^^^^^^^^^^^ warning: use of deprecated item 'unstable_generic_param::Struct5': test - --> $DIR/generics-default-stability.rs:99:12 + --> $DIR/generics-default-stability.rs:101:12 | LL | let _: Struct5 = STRUCT5; | ^^^^^^^ warning: use of deprecated item 'unstable_generic_param::Struct5': test - --> $DIR/generics-default-stability.rs:100:12 + --> $DIR/generics-default-stability.rs:102:12 | LL | let _: Struct5 = STRUCT5; | ^^^^^^^^^^^^^^ warning: use of deprecated item 'unstable_generic_param::Struct5': test - --> $DIR/generics-default-stability.rs:102:29 + --> $DIR/generics-default-stability.rs:104:29 | LL | let _: Struct5 = Struct5 { field: 0 }; | ^^^^^^^ warning: use of deprecated item 'unstable_generic_param::Struct5': test - --> $DIR/generics-default-stability.rs:102:12 + --> $DIR/generics-default-stability.rs:104:12 | LL | let _: Struct5 = Struct5 { field: 0 }; | ^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL | let _: Struct1 = Struct1 { field: 0 }; = help: add `#![feature(unstable_default)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_default' - --> $DIR/generics-default-stability.rs:67:27 + --> $DIR/generics-default-stability.rs:69:27 | LL | let _: Struct3 = STRUCT3; | ^^^^^ @@ -129,7 +129,7 @@ LL | let _: Struct3 = STRUCT3; = help: add `#![feature(unstable_default)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_default' - --> $DIR/generics-default-stability.rs:69:27 + --> $DIR/generics-default-stability.rs:71:27 | LL | let _: Struct3 = Struct3 { field1: 0, field2: 0 }; | ^^^^^ @@ -137,7 +137,7 @@ LL | let _: Struct3 = Struct3 { field1: 0, field2: 0 }; = help: add `#![feature(unstable_default)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_default' - --> $DIR/generics-default-stability.rs:70:27 + --> $DIR/generics-default-stability.rs:72:27 | LL | let _: Struct3 = Struct3 { field1: 0, field2: 0 }; | ^^^^^ @@ -145,7 +145,7 @@ LL | let _: Struct3 = Struct3 { field1: 0, field2: 0 }; = help: add `#![feature(unstable_default)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_default' - --> $DIR/generics-default-stability.rs:94:20 + --> $DIR/generics-default-stability.rs:96:20 | LL | let _: Struct5 = Struct5 { field: 1 }; | ^^^^^ @@ -153,7 +153,7 @@ LL | let _: Struct5 = Struct5 { field: 1 }; = help: add `#![feature(unstable_default)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_default' - --> $DIR/generics-default-stability.rs:100:20 + --> $DIR/generics-default-stability.rs:102:20 | LL | let _: Struct5 = STRUCT5; | ^^^^^ @@ -161,7 +161,7 @@ LL | let _: Struct5 = STRUCT5; = help: add `#![feature(unstable_default)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_default' - --> $DIR/generics-default-stability.rs:102:20 + --> $DIR/generics-default-stability.rs:104:20 | LL | let _: Struct5 = Struct5 { field: 0 }; | ^^^^^ @@ -169,25 +169,25 @@ LL | let _: Struct5 = Struct5 { field: 0 }; = help: add `#![feature(unstable_default)]` to the crate attributes to enable warning: use of deprecated item 'unstable_generic_param::Struct4::field': test - --> $DIR/generics-default-stability.rs:81:39 + --> $DIR/generics-default-stability.rs:83:39 | LL | let _: Struct4 = Struct4 { field: 1 }; | ^^^^^^^^ warning: use of deprecated item 'unstable_generic_param::Struct4::field': test - --> $DIR/generics-default-stability.rs:88:39 + --> $DIR/generics-default-stability.rs:90:39 | LL | let _: Struct4 = Struct4 { field: 0 }; | ^^^^^^^^ warning: use of deprecated item 'unstable_generic_param::Struct5::field': test - --> $DIR/generics-default-stability.rs:94:39 + --> $DIR/generics-default-stability.rs:96:39 | LL | let _: Struct5 = Struct5 { field: 1 }; | ^^^^^^^^ warning: use of deprecated item 'unstable_generic_param::Struct5::field': test - --> $DIR/generics-default-stability.rs:102:39 + --> $DIR/generics-default-stability.rs:104:39 | LL | let _: Struct5 = Struct5 { field: 0 }; | ^^^^^^^^ From 7616b30bff843ff279fae9ae4eea44b87d46b310 Mon Sep 17 00:00:00 2001 From: Avi Dessauer Date: Sat, 11 Jul 2020 19:24:04 -0400 Subject: [PATCH 0876/1052] Add unstable default feature enabled test --- .../auxiliary/unstable_generic_param.rs | 6 ++ .../generics-default-stability.rs | 4 ++ .../generics-default-stability.stderr | 56 +++++++++---------- 3 files changed, 38 insertions(+), 28 deletions(-) diff --git a/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs b/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs index 64d725e55edb8..82eed9a38f9e5 100644 --- a/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs +++ b/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs @@ -55,6 +55,12 @@ pub struct Struct5<#[unstable(feature = "unstable_default", issue = "none")] A = pub field: A, } +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct Struct6<#[unstable(feature = "unstable_default6", issue = "none")] T = usize> { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub field: T, +} + #[stable(feature = "stable_test_feature", since = "1.0.0")] pub const STRUCT1: Struct1 = Struct1 { field: 1 }; diff --git a/src/test/ui/stability-attribute/generics-default-stability.rs b/src/test/ui/stability-attribute/generics-default-stability.rs index c44f3c32bbee3..26f7692209f9c 100644 --- a/src/test/ui/stability-attribute/generics-default-stability.rs +++ b/src/test/ui/stability-attribute/generics-default-stability.rs @@ -1,5 +1,6 @@ // ignore-tidy-linelength // aux-build:unstable_generic_param.rs +#![feature(unstable_default6)] extern crate unstable_generic_param; @@ -105,4 +106,7 @@ fn main() { //~^ use of deprecated item 'unstable_generic_param::Struct5': test [deprecated] //~^^ use of deprecated item 'unstable_generic_param::Struct5': test [deprecated] //~^^^ use of deprecated item 'unstable_generic_param::Struct5::field': test [deprecated] + + let _: Struct6 = Struct6 { field: 1 }; // ok + let _: Struct6 = Struct6 { field: 0 }; // ok } diff --git a/src/test/ui/stability-attribute/generics-default-stability.stderr b/src/test/ui/stability-attribute/generics-default-stability.stderr index 87ebe65dcfcfc..d9e195c21d608 100644 --- a/src/test/ui/stability-attribute/generics-default-stability.stderr +++ b/src/test/ui/stability-attribute/generics-default-stability.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature 'unstable_default' - --> $DIR/generics-default-stability.rs:16:13 + --> $DIR/generics-default-stability.rs:17:13 | LL | impl Trait1 for S { | ^^^^^ @@ -7,7 +7,7 @@ LL | impl Trait1 for S { = help: add `#![feature(unstable_default)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_default' - --> $DIR/generics-default-stability.rs:20:13 + --> $DIR/generics-default-stability.rs:21:13 | LL | impl Trait1 for S { | ^^^^^ @@ -15,7 +15,7 @@ LL | impl Trait1 for S { = help: add `#![feature(unstable_default)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_default' - --> $DIR/generics-default-stability.rs:24:13 + --> $DIR/generics-default-stability.rs:25:13 | LL | impl Trait2 for S { | ^^^^^ @@ -23,7 +23,7 @@ LL | impl Trait2 for S { = help: add `#![feature(unstable_default)]` to the crate attributes to enable warning: use of deprecated item 'unstable_generic_param::Struct4': test - --> $DIR/generics-default-stability.rs:83:29 + --> $DIR/generics-default-stability.rs:84:29 | LL | let _: Struct4 = Struct4 { field: 1 }; | ^^^^^^^ @@ -31,73 +31,73 @@ LL | let _: Struct4 = Struct4 { field: 1 }; = note: `#[warn(deprecated)]` on by default warning: use of deprecated item 'unstable_generic_param::Struct4': test - --> $DIR/generics-default-stability.rs:83:12 + --> $DIR/generics-default-stability.rs:84:12 | LL | let _: Struct4 = Struct4 { field: 1 }; | ^^^^^^^^^^^^^^ warning: use of deprecated item 'unstable_generic_param::Struct4': test - --> $DIR/generics-default-stability.rs:88:12 + --> $DIR/generics-default-stability.rs:89:12 | LL | let _: Struct4 = STRUCT4; | ^^^^^^^ warning: use of deprecated item 'unstable_generic_param::Struct4': test - --> $DIR/generics-default-stability.rs:89:12 + --> $DIR/generics-default-stability.rs:90:12 | LL | let _: Struct4 = STRUCT4; | ^^^^^^^^^^^^^^ warning: use of deprecated item 'unstable_generic_param::Struct4': test - --> $DIR/generics-default-stability.rs:90:29 + --> $DIR/generics-default-stability.rs:91:29 | LL | let _: Struct4 = Struct4 { field: 0 }; | ^^^^^^^ warning: use of deprecated item 'unstable_generic_param::Struct4': test - --> $DIR/generics-default-stability.rs:90:12 + --> $DIR/generics-default-stability.rs:91:12 | LL | let _: Struct4 = Struct4 { field: 0 }; | ^^^^^^^^^^^^^^ warning: use of deprecated item 'unstable_generic_param::Struct5': test - --> $DIR/generics-default-stability.rs:96:29 + --> $DIR/generics-default-stability.rs:97:29 | LL | let _: Struct5 = Struct5 { field: 1 }; | ^^^^^^^ warning: use of deprecated item 'unstable_generic_param::Struct5': test - --> $DIR/generics-default-stability.rs:96:12 + --> $DIR/generics-default-stability.rs:97:12 | LL | let _: Struct5 = Struct5 { field: 1 }; | ^^^^^^^^^^^^^^ warning: use of deprecated item 'unstable_generic_param::Struct5': test - --> $DIR/generics-default-stability.rs:101:12 + --> $DIR/generics-default-stability.rs:102:12 | LL | let _: Struct5 = STRUCT5; | ^^^^^^^ warning: use of deprecated item 'unstable_generic_param::Struct5': test - --> $DIR/generics-default-stability.rs:102:12 + --> $DIR/generics-default-stability.rs:103:12 | LL | let _: Struct5 = STRUCT5; | ^^^^^^^^^^^^^^ warning: use of deprecated item 'unstable_generic_param::Struct5': test - --> $DIR/generics-default-stability.rs:104:29 + --> $DIR/generics-default-stability.rs:105:29 | LL | let _: Struct5 = Struct5 { field: 0 }; | ^^^^^^^ warning: use of deprecated item 'unstable_generic_param::Struct5': test - --> $DIR/generics-default-stability.rs:104:12 + --> $DIR/generics-default-stability.rs:105:12 | LL | let _: Struct5 = Struct5 { field: 0 }; | ^^^^^^^^^^^^^^ error[E0658]: use of unstable library feature 'unstable_default' - --> $DIR/generics-default-stability.rs:35:20 + --> $DIR/generics-default-stability.rs:36:20 | LL | let _: Struct1 = Struct1 { field: 1 }; | ^^^^^ @@ -105,7 +105,7 @@ LL | let _: Struct1 = Struct1 { field: 1 }; = help: add `#![feature(unstable_default)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_default' - --> $DIR/generics-default-stability.rs:39:20 + --> $DIR/generics-default-stability.rs:40:20 | LL | let _: Struct1 = STRUCT1; | ^^^^^ @@ -113,7 +113,7 @@ LL | let _: Struct1 = STRUCT1; = help: add `#![feature(unstable_default)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_default' - --> $DIR/generics-default-stability.rs:40:20 + --> $DIR/generics-default-stability.rs:41:20 | LL | let _: Struct1 = Struct1 { field: 0 }; | ^^^^^ @@ -121,7 +121,7 @@ LL | let _: Struct1 = Struct1 { field: 0 }; = help: add `#![feature(unstable_default)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_default' - --> $DIR/generics-default-stability.rs:69:27 + --> $DIR/generics-default-stability.rs:70:27 | LL | let _: Struct3 = STRUCT3; | ^^^^^ @@ -129,7 +129,7 @@ LL | let _: Struct3 = STRUCT3; = help: add `#![feature(unstable_default)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_default' - --> $DIR/generics-default-stability.rs:71:27 + --> $DIR/generics-default-stability.rs:72:27 | LL | let _: Struct3 = Struct3 { field1: 0, field2: 0 }; | ^^^^^ @@ -137,7 +137,7 @@ LL | let _: Struct3 = Struct3 { field1: 0, field2: 0 }; = help: add `#![feature(unstable_default)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_default' - --> $DIR/generics-default-stability.rs:72:27 + --> $DIR/generics-default-stability.rs:73:27 | LL | let _: Struct3 = Struct3 { field1: 0, field2: 0 }; | ^^^^^ @@ -145,7 +145,7 @@ LL | let _: Struct3 = Struct3 { field1: 0, field2: 0 }; = help: add `#![feature(unstable_default)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_default' - --> $DIR/generics-default-stability.rs:96:20 + --> $DIR/generics-default-stability.rs:97:20 | LL | let _: Struct5 = Struct5 { field: 1 }; | ^^^^^ @@ -153,7 +153,7 @@ LL | let _: Struct5 = Struct5 { field: 1 }; = help: add `#![feature(unstable_default)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_default' - --> $DIR/generics-default-stability.rs:102:20 + --> $DIR/generics-default-stability.rs:103:20 | LL | let _: Struct5 = STRUCT5; | ^^^^^ @@ -161,7 +161,7 @@ LL | let _: Struct5 = STRUCT5; = help: add `#![feature(unstable_default)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_default' - --> $DIR/generics-default-stability.rs:104:20 + --> $DIR/generics-default-stability.rs:105:20 | LL | let _: Struct5 = Struct5 { field: 0 }; | ^^^^^ @@ -169,25 +169,25 @@ LL | let _: Struct5 = Struct5 { field: 0 }; = help: add `#![feature(unstable_default)]` to the crate attributes to enable warning: use of deprecated item 'unstable_generic_param::Struct4::field': test - --> $DIR/generics-default-stability.rs:83:39 + --> $DIR/generics-default-stability.rs:84:39 | LL | let _: Struct4 = Struct4 { field: 1 }; | ^^^^^^^^ warning: use of deprecated item 'unstable_generic_param::Struct4::field': test - --> $DIR/generics-default-stability.rs:90:39 + --> $DIR/generics-default-stability.rs:91:39 | LL | let _: Struct4 = Struct4 { field: 0 }; | ^^^^^^^^ warning: use of deprecated item 'unstable_generic_param::Struct5::field': test - --> $DIR/generics-default-stability.rs:96:39 + --> $DIR/generics-default-stability.rs:97:39 | LL | let _: Struct5 = Struct5 { field: 1 }; | ^^^^^^^^ warning: use of deprecated item 'unstable_generic_param::Struct5::field': test - --> $DIR/generics-default-stability.rs:104:39 + --> $DIR/generics-default-stability.rs:105:39 | LL | let _: Struct5 = Struct5 { field: 0 }; | ^^^^^^^^ From a73e7d0a4df305e8b8237163e5ac7755cf488af8 Mon Sep 17 00:00:00 2001 From: Avi Dessauer Date: Sun, 12 Jul 2020 20:56:37 -0400 Subject: [PATCH 0877/1052] Test unstable Alloc param on Box --- .../auxiliary/unstable_generic_param.rs | 36 ++++++++++++++++++- .../generics-default-stability.rs | 6 ++++ .../generics-default-stability.stderr | 10 +++++- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs b/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs index 82eed9a38f9e5..b26908c25e304 100644 --- a/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs +++ b/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs @@ -1,6 +1,5 @@ #![crate_type = "lib"] #![feature(staged_api)] - #![stable(feature = "stable_test_feature", since = "1.0.0")] #[stable(feature = "stable_test_feature", since = "1.0.0")] @@ -75,3 +74,38 @@ pub const STRUCT4: Struct4 = Struct4 { field: 1 }; #[stable(feature = "stable_test_feature", since = "1.0.0")] pub const STRUCT5: Struct5 = Struct5 { field: 1 }; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub trait Alloc {} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct System {} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +impl Alloc for System {} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct Box1 { + ptr: *mut T, + alloc: A, +} + +impl Box1 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub fn new(mut t: T) -> Self { + unsafe { Self { ptr: &mut t, alloc: System {} } } + } +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct Box2 { + ptr: *mut T, + alloc: A, +} + +impl Box2 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub fn new(mut t: T) -> Self { + Self { ptr: &mut t, alloc: System {} } + } +} diff --git a/src/test/ui/stability-attribute/generics-default-stability.rs b/src/test/ui/stability-attribute/generics-default-stability.rs index 26f7692209f9c..d412aceb3a28c 100644 --- a/src/test/ui/stability-attribute/generics-default-stability.rs +++ b/src/test/ui/stability-attribute/generics-default-stability.rs @@ -109,4 +109,10 @@ fn main() { let _: Struct6 = Struct6 { field: 1 }; // ok let _: Struct6 = Struct6 { field: 0 }; // ok + + let _: Box1 = Box1::new(1); //~ ERROR use of unstable library feature 'box_alloc_param' + let _: Box1 = Box1::new(1); // ok + + let _: Box2 = Box2::new(1); // ok + let _: Box2 = Box2::new(1); // ok } diff --git a/src/test/ui/stability-attribute/generics-default-stability.stderr b/src/test/ui/stability-attribute/generics-default-stability.stderr index d9e195c21d608..37a809f8bca65 100644 --- a/src/test/ui/stability-attribute/generics-default-stability.stderr +++ b/src/test/ui/stability-attribute/generics-default-stability.stderr @@ -168,6 +168,14 @@ LL | let _: Struct5 = Struct5 { field: 0 }; | = help: add `#![feature(unstable_default)]` to the crate attributes to enable +error[E0658]: use of unstable library feature 'box_alloc_param' + --> $DIR/generics-default-stability.rs:113:24 + | +LL | let _: Box1 = Box1::new(1); + | ^^^^^^ + | + = help: add `#![feature(box_alloc_param)]` to the crate attributes to enable + warning: use of deprecated item 'unstable_generic_param::Struct4::field': test --> $DIR/generics-default-stability.rs:84:39 | @@ -192,6 +200,6 @@ warning: use of deprecated item 'unstable_generic_param::Struct5::field': test LL | let _: Struct5 = Struct5 { field: 0 }; | ^^^^^^^^ -error: aborting due to 12 previous errors; 16 warnings emitted +error: aborting due to 13 previous errors; 16 warnings emitted For more information about this error, try `rustc --explain E0658`. From d281620d8f630346ea96c8c65b9fd7f5b7f1da9e Mon Sep 17 00:00:00 2001 From: Avi Dessauer Date: Sun, 12 Jul 2020 21:02:47 -0400 Subject: [PATCH 0878/1052] Test removing unstable default parameter --- .../auxiliary/unstable_generic_param.rs | 12 ++++++++++++ .../generics-default-stability.rs | 2 ++ 2 files changed, 14 insertions(+) diff --git a/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs b/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs index b26908c25e304..b5490381a46b6 100644 --- a/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs +++ b/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs @@ -109,3 +109,15 @@ impl Box2 { Self { ptr: &mut t, alloc: System {} } } } + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct Box3 { + ptr: *mut T, +} + +impl Box3 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub fn new(mut t: T) -> Self { + Self { ptr: &mut t } + } +} diff --git a/src/test/ui/stability-attribute/generics-default-stability.rs b/src/test/ui/stability-attribute/generics-default-stability.rs index d412aceb3a28c..b68336da1a5f7 100644 --- a/src/test/ui/stability-attribute/generics-default-stability.rs +++ b/src/test/ui/stability-attribute/generics-default-stability.rs @@ -115,4 +115,6 @@ fn main() { let _: Box2 = Box2::new(1); // ok let _: Box2 = Box2::new(1); // ok + + let _: Box3 = Box3::new(1); // ok } From 6c056d346562eebf8535e2a4415c353a911b6280 Mon Sep 17 00:00:00 2001 From: Robin Schoonover Date: Tue, 22 Sep 2020 20:34:38 -0600 Subject: [PATCH 0879/1052] Satisfy rc_buffer lint in Constant::Binary byte string by copying data We can avoid the data copy again by fixing rustc_ast::ast::LitKind later. --- clippy_lints/src/consts.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index 3ee022e4e68a0..0000d39263ed3 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -21,7 +21,7 @@ pub enum Constant { /// A `String` (e.g., "abc"). Str(String), /// A binary string (e.g., `b"abc"`). - Binary(Lrc>), + Binary(Lrc<[u8]>), /// A single `char` (e.g., `'a'`). Char(char), /// An integer's bit representation. @@ -155,7 +155,7 @@ pub fn lit_to_constant(lit: &LitKind, ty: Option>) -> Constant { match *lit { LitKind::Str(ref is, _) => Constant::Str(is.to_string()), LitKind::Byte(b) => Constant::Int(u128::from(b)), - LitKind::ByteStr(ref s) => Constant::Binary(Lrc::clone(s)), + LitKind::ByteStr(ref s) => Constant::Binary(Lrc::from(s.as_slice())), LitKind::Char(c) => Constant::Char(c), LitKind::Int(n, _) => Constant::Int(n), LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty { From 3f1b4b39e3dbff49d3298af1acaa526310b255a7 Mon Sep 17 00:00:00 2001 From: Jacob Hughes Date: Tue, 22 Sep 2020 22:54:52 -0400 Subject: [PATCH 0880/1052] Fix compilation & test failures --- compiler/rustc_passes/src/stability.rs | 10 ++++-- .../generics-default-stability.rs | 32 +++++++++---------- .../generics-default-stability.stderr | 32 +++++++++---------- 3 files changed, 40 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 5b0df9e884ff6..b807dff5fd25d 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -43,6 +43,7 @@ enum AnnotationKind { /// have separate deprecation attributes from their parents, so we do not wish to inherit /// deprecation in this case. For example, inheriting deprecation for `T` in `Foo` /// would cause a duplicate warning arising from both `Foo` and `T` being deprecated. +#[derive(Clone)] enum InheritDeprecation { Yes, No, @@ -81,7 +82,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { debug!("annotate(id = {:?}, attrs = {:?})", hir_id, attrs); let mut did_error = false; if !self.tcx.features().staged_api { - did_error = self.forbid_staged_api_attrs(hir_id, attrs, inherit_deprecation); + did_error = self.forbid_staged_api_attrs(hir_id, attrs, inherit_deprecation.clone()); } let depr = @@ -257,7 +258,12 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } // returns true if an error occurred, used to suppress some spurious errors - fn forbid_staged_api_attrs(&mut self, hir_id: HirId, attrs: &[Attribute], inherit_deprecation: InheritDeprecation) -> bool { + fn forbid_staged_api_attrs( + &mut self, + hir_id: HirId, + attrs: &[Attribute], + inherit_deprecation: InheritDeprecation, + ) -> bool { // Emit errors for non-staged-api crates. let unstable_attrs = [ sym::unstable, diff --git a/src/test/ui/stability-attribute/generics-default-stability.rs b/src/test/ui/stability-attribute/generics-default-stability.rs index b68336da1a5f7..461b1d405cb10 100644 --- a/src/test/ui/stability-attribute/generics-default-stability.rs +++ b/src/test/ui/stability-attribute/generics-default-stability.rs @@ -82,30 +82,30 @@ fn main() { let _ = STRUCT4; let _: Struct4 = Struct4 { field: 1 }; - //~^ use of deprecated item 'unstable_generic_param::Struct4': test [deprecated] - //~^^ use of deprecated item 'unstable_generic_param::Struct4': test [deprecated] - //~^^^ use of deprecated item 'unstable_generic_param::Struct4::field': test [deprecated] + //~^ use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] + //~^^ use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] + //~^^^ use of deprecated field `unstable_generic_param::Struct4::field`: test [deprecated] let _ = STRUCT4; - let _: Struct4 = STRUCT4; //~ use of deprecated item 'unstable_generic_param::Struct4': test [deprecated] - let _: Struct4 = STRUCT4; //~ use of deprecated item 'unstable_generic_param::Struct4': test [deprecated] + let _: Struct4 = STRUCT4; //~ use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] + let _: Struct4 = STRUCT4; //~ use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] let _: Struct4 = Struct4 { field: 0 }; - //~^ use of deprecated item 'unstable_generic_param::Struct4': test [deprecated] - //~^^ use of deprecated item 'unstable_generic_param::Struct4': test [deprecated] - //~^^^ use of deprecated item 'unstable_generic_param::Struct4::field': test [deprecated] + //~^ use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] + //~^^ use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] + //~^^^ use of deprecated field `unstable_generic_param::Struct4::field`: test [deprecated] let _ = STRUCT5; let _: Struct5 = Struct5 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default' - //~^ use of deprecated item 'unstable_generic_param::Struct5': test [deprecated] - //~^^ use of deprecated item 'unstable_generic_param::Struct5': test [deprecated] - //~^^^ use of deprecated item 'unstable_generic_param::Struct5::field': test [deprecated] + //~^ use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] + //~^^ use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] + //~^^^ use of deprecated field `unstable_generic_param::Struct5::field`: test [deprecated] let _ = STRUCT5; - let _: Struct5 = STRUCT5; //~ use of deprecated item 'unstable_generic_param::Struct5': test [deprecated] + let _: Struct5 = STRUCT5; //~ use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] let _: Struct5 = STRUCT5; //~ ERROR use of unstable library feature 'unstable_default' - //~^ use of deprecated item 'unstable_generic_param::Struct5': test [deprecated] + //~^ use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] let _: Struct5 = Struct5 { field: 0 }; //~ ERROR use of unstable library feature 'unstable_default' - //~^ use of deprecated item 'unstable_generic_param::Struct5': test [deprecated] - //~^^ use of deprecated item 'unstable_generic_param::Struct5': test [deprecated] - //~^^^ use of deprecated item 'unstable_generic_param::Struct5::field': test [deprecated] + //~^ use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] + //~^^ use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] + //~^^^ use of deprecated field `unstable_generic_param::Struct5::field`: test [deprecated] let _: Struct6 = Struct6 { field: 1 }; // ok let _: Struct6 = Struct6 { field: 0 }; // ok diff --git a/src/test/ui/stability-attribute/generics-default-stability.stderr b/src/test/ui/stability-attribute/generics-default-stability.stderr index 37a809f8bca65..d9b238f8841bd 100644 --- a/src/test/ui/stability-attribute/generics-default-stability.stderr +++ b/src/test/ui/stability-attribute/generics-default-stability.stderr @@ -22,7 +22,7 @@ LL | impl Trait2 for S { | = help: add `#![feature(unstable_default)]` to the crate attributes to enable -warning: use of deprecated item 'unstable_generic_param::Struct4': test +warning: use of deprecated struct `unstable_generic_param::Struct4`: test --> $DIR/generics-default-stability.rs:84:29 | LL | let _: Struct4 = Struct4 { field: 1 }; @@ -30,67 +30,67 @@ LL | let _: Struct4 = Struct4 { field: 1 }; | = note: `#[warn(deprecated)]` on by default -warning: use of deprecated item 'unstable_generic_param::Struct4': test +warning: use of deprecated struct `unstable_generic_param::Struct4`: test --> $DIR/generics-default-stability.rs:84:12 | LL | let _: Struct4 = Struct4 { field: 1 }; | ^^^^^^^^^^^^^^ -warning: use of deprecated item 'unstable_generic_param::Struct4': test +warning: use of deprecated struct `unstable_generic_param::Struct4`: test --> $DIR/generics-default-stability.rs:89:12 | LL | let _: Struct4 = STRUCT4; | ^^^^^^^ -warning: use of deprecated item 'unstable_generic_param::Struct4': test +warning: use of deprecated struct `unstable_generic_param::Struct4`: test --> $DIR/generics-default-stability.rs:90:12 | LL | let _: Struct4 = STRUCT4; | ^^^^^^^^^^^^^^ -warning: use of deprecated item 'unstable_generic_param::Struct4': test +warning: use of deprecated struct `unstable_generic_param::Struct4`: test --> $DIR/generics-default-stability.rs:91:29 | LL | let _: Struct4 = Struct4 { field: 0 }; | ^^^^^^^ -warning: use of deprecated item 'unstable_generic_param::Struct4': test +warning: use of deprecated struct `unstable_generic_param::Struct4`: test --> $DIR/generics-default-stability.rs:91:12 | LL | let _: Struct4 = Struct4 { field: 0 }; | ^^^^^^^^^^^^^^ -warning: use of deprecated item 'unstable_generic_param::Struct5': test +warning: use of deprecated struct `unstable_generic_param::Struct5`: test --> $DIR/generics-default-stability.rs:97:29 | LL | let _: Struct5 = Struct5 { field: 1 }; | ^^^^^^^ -warning: use of deprecated item 'unstable_generic_param::Struct5': test +warning: use of deprecated struct `unstable_generic_param::Struct5`: test --> $DIR/generics-default-stability.rs:97:12 | LL | let _: Struct5 = Struct5 { field: 1 }; | ^^^^^^^^^^^^^^ -warning: use of deprecated item 'unstable_generic_param::Struct5': test +warning: use of deprecated struct `unstable_generic_param::Struct5`: test --> $DIR/generics-default-stability.rs:102:12 | LL | let _: Struct5 = STRUCT5; | ^^^^^^^ -warning: use of deprecated item 'unstable_generic_param::Struct5': test +warning: use of deprecated struct `unstable_generic_param::Struct5`: test --> $DIR/generics-default-stability.rs:103:12 | LL | let _: Struct5 = STRUCT5; | ^^^^^^^^^^^^^^ -warning: use of deprecated item 'unstable_generic_param::Struct5': test +warning: use of deprecated struct `unstable_generic_param::Struct5`: test --> $DIR/generics-default-stability.rs:105:29 | LL | let _: Struct5 = Struct5 { field: 0 }; | ^^^^^^^ -warning: use of deprecated item 'unstable_generic_param::Struct5': test +warning: use of deprecated struct `unstable_generic_param::Struct5`: test --> $DIR/generics-default-stability.rs:105:12 | LL | let _: Struct5 = Struct5 { field: 0 }; @@ -176,25 +176,25 @@ LL | let _: Box1 = Box1::new(1); | = help: add `#![feature(box_alloc_param)]` to the crate attributes to enable -warning: use of deprecated item 'unstable_generic_param::Struct4::field': test +warning: use of deprecated field `unstable_generic_param::Struct4::field`: test --> $DIR/generics-default-stability.rs:84:39 | LL | let _: Struct4 = Struct4 { field: 1 }; | ^^^^^^^^ -warning: use of deprecated item 'unstable_generic_param::Struct4::field': test +warning: use of deprecated field `unstable_generic_param::Struct4::field`: test --> $DIR/generics-default-stability.rs:91:39 | LL | let _: Struct4 = Struct4 { field: 0 }; | ^^^^^^^^ -warning: use of deprecated item 'unstable_generic_param::Struct5::field': test +warning: use of deprecated field `unstable_generic_param::Struct5::field`: test --> $DIR/generics-default-stability.rs:97:39 | LL | let _: Struct5 = Struct5 { field: 1 }; | ^^^^^^^^ -warning: use of deprecated item 'unstable_generic_param::Struct5::field': test +warning: use of deprecated field `unstable_generic_param::Struct5::field`: test --> $DIR/generics-default-stability.rs:105:39 | LL | let _: Struct5 = Struct5 { field: 0 }; From 15f08d6ddfa1d6e50f783196bd63cacf7d015b3e Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 22 Sep 2020 23:07:30 -0400 Subject: [PATCH 0881/1052] Revert "Function to convert OpenOptions to c_int" --- library/std/src/sys/unix/ext/fs.rs | 29 ----------------------------- library/std/src/sys/unix/fs.rs | 6 ------ 2 files changed, 35 deletions(-) diff --git a/library/std/src/sys/unix/ext/fs.rs b/library/std/src/sys/unix/ext/fs.rs index 83cbe25d41bde..4b9f4ceb29c49 100644 --- a/library/std/src/sys/unix/ext/fs.rs +++ b/library/std/src/sys/unix/ext/fs.rs @@ -348,31 +348,6 @@ pub trait OpenOptionsExt { /// ``` #[stable(feature = "open_options_ext", since = "1.10.0")] fn custom_flags(&mut self, flags: i32) -> &mut Self; - - /// Get the flags as [`libc::c_int`]. - /// - /// This method allows the reuse of the OpenOptions as flags argument for [`libc::open`]. - /// - /// [`libc::c_int`]: https://docs.rs/libc/*/libc/type.c_int.html - /// [`libc::open`]: https://docs.rs/libc/*/libc/fn.open.html - /// - /// # Examples - /// - /// ```no_run - /// # #![feature(rustc_private)] - /// #![feature(open_options_ext_as_flags)] - /// extern crate libc; - /// use std::ffi::CString; - /// use std::fs::OpenOptions; - /// use std::os::unix::fs::OpenOptionsExt; - /// - /// let mut options = OpenOptions::new(); - /// options.write(true).read(true); - /// let file_name = CString::new("foo.txt").unwrap(); - /// let file = unsafe { libc::open(file_name.as_c_str().as_ptr(), options.as_flags().unwrap()) }; - /// ``` - #[unstable(feature = "open_options_ext_as_flags", issue = "76801")] - fn as_flags(&self) -> io::Result; } #[stable(feature = "fs_ext", since = "1.1.0")] @@ -386,10 +361,6 @@ impl OpenOptionsExt for OpenOptions { self.as_inner_mut().custom_flags(flags); self } - - fn as_flags(&self) -> io::Result { - self.as_inner().as_flags() - } } /// Unix-specific extensions to [`fs::Metadata`]. diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 09954f0c43c56..566ac0920dc8f 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -656,12 +656,6 @@ impl OpenOptions { self.mode = mode as mode_t; } - pub fn as_flags(&self) -> io::Result { - let access_mode = self.get_access_mode()?; - let creation_mode = self.get_creation_mode()?; - Ok(creation_mode | access_mode | self.custom_flags) - } - fn get_access_mode(&self) -> io::Result { match (self.read, self.write, self.append) { (true, false, false) => Ok(libc::O_RDONLY), From 985dff9e7ed1fd7896b071eaf637fd531a690e91 Mon Sep 17 00:00:00 2001 From: blitzerr Date: Tue, 22 Sep 2020 20:16:13 -0700 Subject: [PATCH 0882/1052] fixing the test failure --- src/test/ui/allocator/custom.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/ui/allocator/custom.rs b/src/test/ui/allocator/custom.rs index f54ef1f0bc152..73750bf139a7d 100644 --- a/src/test/ui/allocator/custom.rs +++ b/src/test/ui/allocator/custom.rs @@ -10,6 +10,7 @@ extern crate helper; use std::alloc::{self, AllocRef, Global, Layout, System}; use std::sync::atomic::{AtomicUsize, Ordering}; +use std::ptr::NonNull; static HITS: AtomicUsize = AtomicUsize::new(0); @@ -23,7 +24,7 @@ unsafe impl alloc::GlobalAlloc for A { unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { HITS.fetch_add(1, Ordering::SeqCst); - AllocRef::dealloc(&System, ptr, layout) + AllocRef::dealloc(&System, NonNull::new(ptr).unwrap(), layout) } } From 2b19b14cecbcdd173e29a801baff71e31cae7331 Mon Sep 17 00:00:00 2001 From: blitzerr Date: Tue, 22 Sep 2020 21:04:31 -0700 Subject: [PATCH 0883/1052] a few more &mut self -> self changes --- library/alloc/src/alloc.rs | 8 ++++---- library/core/src/alloc/mod.rs | 16 ++++++++-------- library/std/src/alloc.rs | 16 ++++++++-------- src/test/ui/allocator/custom.rs | 2 +- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 462bcd15fa941..8b8cdbf252555 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -160,7 +160,7 @@ impl Global { // SAFETY: Same as `AllocRef::grow` #[inline] unsafe fn grow_impl( - &mut self, + &self, ptr: NonNull, old_layout: Layout, new_layout: Layout, @@ -228,7 +228,7 @@ unsafe impl AllocRef for Global { #[inline] unsafe fn grow( - &mut self, + &self, ptr: NonNull, old_layout: Layout, new_layout: Layout, @@ -239,7 +239,7 @@ unsafe impl AllocRef for Global { #[inline] unsafe fn grow_zeroed( - &mut self, + &self, ptr: NonNull, old_layout: Layout, new_layout: Layout, @@ -250,7 +250,7 @@ unsafe impl AllocRef for Global { #[inline] unsafe fn shrink( - &mut self, + &self, ptr: NonNull, old_layout: Layout, new_layout: Layout, diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index 5f9092fe7037e..f9eb8981bbfc2 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -183,7 +183,7 @@ pub unsafe trait AllocRef { /// /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html unsafe fn grow( - &mut self, + &self, ptr: NonNull, old_layout: Layout, new_layout: Layout, @@ -244,7 +244,7 @@ pub unsafe trait AllocRef { /// /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html unsafe fn grow_zeroed( - &mut self, + &self, ptr: NonNull, old_layout: Layout, new_layout: Layout, @@ -308,7 +308,7 @@ pub unsafe trait AllocRef { /// /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html unsafe fn shrink( - &mut self, + &self, ptr: NonNull, old_layout: Layout, new_layout: Layout, @@ -337,13 +337,13 @@ pub unsafe trait AllocRef { /// /// The returned adaptor also implements `AllocRef` and will simply borrow this. #[inline(always)] - fn by_ref(&mut self) -> &mut Self { + fn by_ref(&mut self) -> &Self { self } } #[unstable(feature = "allocator_api", issue = "32838")] -unsafe impl AllocRef for &mut A +unsafe impl AllocRef for &A where A: AllocRef + ?Sized, { @@ -365,7 +365,7 @@ where #[inline] unsafe fn grow( - &mut self, + &self, ptr: NonNull, old_layout: Layout, new_layout: Layout, @@ -376,7 +376,7 @@ where #[inline] unsafe fn grow_zeroed( - &mut self, + &self, ptr: NonNull, old_layout: Layout, new_layout: Layout, @@ -387,7 +387,7 @@ where #[inline] unsafe fn shrink( - &mut self, + &self, ptr: NonNull, old_layout: Layout, new_layout: Layout, diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index f41aa28b5ecb5..ba158511f64c0 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -152,7 +152,7 @@ impl System { // SAFETY: Same as `AllocRef::grow` #[inline] unsafe fn grow_impl( - &mut self, + &self, ptr: NonNull, old_layout: Layout, new_layout: Layout, @@ -190,7 +190,7 @@ impl System { old_size => unsafe { let new_ptr = self.alloc_impl(new_layout, zeroed)?; ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_size); - self.dealloc(ptr, old_layout); + AllocRef::dealloc(&self, ptr, old_layout); Ok(new_ptr) }, } @@ -222,7 +222,7 @@ unsafe impl AllocRef for System { #[inline] unsafe fn grow( - &mut self, + &self, ptr: NonNull, old_layout: Layout, new_layout: Layout, @@ -233,7 +233,7 @@ unsafe impl AllocRef for System { #[inline] unsafe fn grow_zeroed( - &mut self, + &self, ptr: NonNull, old_layout: Layout, new_layout: Layout, @@ -244,7 +244,7 @@ unsafe impl AllocRef for System { #[inline] unsafe fn shrink( - &mut self, + &self, ptr: NonNull, old_layout: Layout, new_layout: Layout, @@ -257,7 +257,7 @@ unsafe impl AllocRef for System { match new_layout.size() { // SAFETY: conditions must be upheld by the caller 0 => unsafe { - self.dealloc(ptr, old_layout); + AllocRef::dealloc(&self, ptr, old_layout); Ok(NonNull::slice_from_raw_parts(new_layout.dangling(), 0)) }, @@ -277,9 +277,9 @@ unsafe impl AllocRef for System { // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract // for `dealloc` must be upheld by the caller. new_size => unsafe { - let new_ptr = self.alloc(new_layout)?; + let new_ptr = AllocRef::alloc(&self, new_layout)?; ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_size); - self.dealloc(ptr, old_layout); + AllocRef::dealloc(&self, ptr, old_layout); Ok(new_ptr) }, } diff --git a/src/test/ui/allocator/custom.rs b/src/test/ui/allocator/custom.rs index 73750bf139a7d..dfb5d3e9e38d0 100644 --- a/src/test/ui/allocator/custom.rs +++ b/src/test/ui/allocator/custom.rs @@ -19,7 +19,7 @@ struct A; unsafe impl alloc::GlobalAlloc for A { unsafe fn alloc(&self, layout: Layout) -> *mut u8 { HITS.fetch_add(1, Ordering::SeqCst); - AllocRef::alloc(&System, layout).unwrap().as_mut_ptr() + alloc::GlobalAlloc::alloc(&System, layout) } unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { From 6586c37beca21869f698ef2de10d1df7be7e7879 Mon Sep 17 00:00:00 2001 From: Andreas Jonson Date: Wed, 23 Sep 2020 08:09:16 +0200 Subject: [PATCH 0884/1052] Move MiniSet to data_structures remove the need for T to be copy from MiniSet as was done for MiniMap --- Cargo.lock | 2 - compiler/rustc_data_structures/src/lib.rs | 1 + .../rustc_data_structures/src/mini_set.rs | 41 +++++++++++++++++ compiler/rustc_infer/Cargo.toml | 1 - .../rustc_infer/src/infer/outlives/verify.rs | 2 +- compiler/rustc_middle/Cargo.toml | 1 - compiler/rustc_middle/src/ty/outlives.rs | 2 +- compiler/rustc_middle/src/ty/print/mod.rs | 2 +- compiler/rustc_middle/src/ty/walk.rs | 44 +------------------ 9 files changed, 46 insertions(+), 50 deletions(-) create mode 100644 compiler/rustc_data_structures/src/mini_set.rs diff --git a/Cargo.lock b/Cargo.lock index 68288916e6d12..26a9e64b85af4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3638,7 +3638,6 @@ dependencies = [ name = "rustc_infer" version = "0.0.0" dependencies = [ - "arrayvec", "rustc_ast", "rustc_data_structures", "rustc_errors", @@ -3778,7 +3777,6 @@ dependencies = [ name = "rustc_middle" version = "0.0.0" dependencies = [ - "arrayvec", "bitflags", "chalk-ir", "measureme", diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 1f977805f5e90..5990e94ab7e98 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -102,6 +102,7 @@ pub mod work_queue; pub use atomic_ref::AtomicRef; pub mod frozen; pub mod mini_map; +pub mod mini_set; pub mod tagged_ptr; pub mod temp_dir; pub mod unhash; diff --git a/compiler/rustc_data_structures/src/mini_set.rs b/compiler/rustc_data_structures/src/mini_set.rs new file mode 100644 index 0000000000000..9d45af723deb6 --- /dev/null +++ b/compiler/rustc_data_structures/src/mini_set.rs @@ -0,0 +1,41 @@ +use crate::fx::FxHashSet; +use arrayvec::ArrayVec; +use std::hash::Hash; +/// Small-storage-optimized implementation of a set. +/// +/// Stores elements in a small array up to a certain length +/// and switches to `HashSet` when that length is exceeded. +pub enum MiniSet { + Array(ArrayVec<[T; 8]>), + Set(FxHashSet), +} + +impl MiniSet { + /// Creates an empty `MiniSet`. + pub fn new() -> Self { + MiniSet::Array(ArrayVec::new()) + } + + /// Adds a value to the set. + /// + /// If the set did not have this value present, true is returned. + /// + /// If the set did have this value present, false is returned. + pub fn insert(&mut self, elem: T) -> bool { + match self { + MiniSet::Array(array) => { + if array.iter().any(|e| *e == elem) { + false + } else { + if let Err(error) = array.try_push(elem) { + let mut set: FxHashSet = array.drain(..).collect(); + set.insert(error.element()); + *self = MiniSet::Set(set); + } + true + } + } + MiniSet::Set(set) => set.insert(elem), + } + } +} diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml index a8c1a370cef82..5dba4106c9423 100644 --- a/compiler/rustc_infer/Cargo.toml +++ b/compiler/rustc_infer/Cargo.toml @@ -21,5 +21,4 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } -arrayvec = { version = "0.5.1", default-features = false } rustc_ast = { path = "../rustc_ast" } diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index e06bfb5958086..21b0836563f6c 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -1,9 +1,9 @@ use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::{GenericKind, VerifyBound}; use rustc_data_structures::captures::Captures; +use rustc_data_structures::mini_set::MiniSet; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; -use rustc_middle::ty::walk::MiniSet; use rustc_middle::ty::{self, Ty, TyCtxt}; /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a` diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 1d84ddad7f52d..a5a860a38b3e8 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -28,6 +28,5 @@ rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } chalk-ir = "0.21.0" smallvec = { version = "1.0", features = ["union", "may_dangle"] } -arrayvec = { version = "0.5.1", default-features = false } measureme = "0.7.1" rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_middle/src/ty/outlives.rs b/compiler/rustc_middle/src/ty/outlives.rs index 01649f44c8861..ca992d36e9545 100644 --- a/compiler/rustc_middle/src/ty/outlives.rs +++ b/compiler/rustc_middle/src/ty/outlives.rs @@ -3,8 +3,8 @@ // RFC for reference. use crate::ty::subst::{GenericArg, GenericArgKind}; -use crate::ty::walk::MiniSet; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc_data_structures::mini_set::MiniSet; use smallvec::SmallVec; #[derive(Debug)] diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index f315292dab546..225ea2399fbfd 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -2,9 +2,9 @@ use crate::ty::subst::{GenericArg, Subst}; use crate::ty::{self, DefIdTree, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::mini_set::MiniSet; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; -use rustc_middle::ty::walk::MiniSet; // `pretty` is a separate module only for organization. mod pretty; diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 7afa6e6cc056d..80ade7dda4ca1 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -3,50 +3,8 @@ use crate::ty; use crate::ty::subst::{GenericArg, GenericArgKind}; -use arrayvec::ArrayVec; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::mini_set::MiniSet; use smallvec::{self, SmallVec}; -use std::hash::Hash; - -/// Small-storage-optimized implementation of a set -/// made specifically for walking type tree. -/// -/// Stores elements in a small array up to a certain length -/// and switches to `HashSet` when that length is exceeded. -pub enum MiniSet { - Array(ArrayVec<[T; 8]>), - Set(FxHashSet), -} - -impl MiniSet { - /// Creates an empty `MiniSet`. - pub fn new() -> Self { - MiniSet::Array(ArrayVec::new()) - } - - /// Adds a value to the set. - /// - /// If the set did not have this value present, true is returned. - /// - /// If the set did have this value present, false is returned. - pub fn insert(&mut self, elem: T) -> bool { - match self { - MiniSet::Array(array) => { - if array.iter().any(|e| *e == elem) { - false - } else { - if array.try_push(elem).is_err() { - let mut set: FxHashSet = array.iter().copied().collect(); - set.insert(elem); - *self = MiniSet::Set(set); - } - true - } - } - MiniSet::Set(set) => set.insert(elem), - } - } -} // The TypeWalker's stack is hot enough that it's worth going to some effort to // avoid heap allocations. From 98eab09cf4ee1a35290a2061ee0e7a19703923a8 Mon Sep 17 00:00:00 2001 From: Jacob Hughes Date: Wed, 23 Sep 2020 02:14:42 -0400 Subject: [PATCH 0885/1052] Add enum and type alias tests for generic default stability --- .../auxiliary/unstable_generic_param.rs | 106 +++++++ .../generics-default-stability.rs | 144 +++++++++ .../generics-default-stability.stderr | 292 +++++++++++++++++- 3 files changed, 540 insertions(+), 2 deletions(-) diff --git a/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs b/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs index b5490381a46b6..231ab966558f9 100644 --- a/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs +++ b/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs @@ -75,6 +75,112 @@ pub const STRUCT4: Struct4 = Struct4 { field: 1 }; #[stable(feature = "stable_test_feature", since = "1.0.0")] pub const STRUCT5: Struct5 = Struct5 { field: 1 }; +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub enum Enum1<#[unstable(feature = "unstable_default", issue = "none")] T = usize> { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Some(#[stable(feature = "stable_test_feature", since = "1.0.0")] T), + #[stable(feature = "stable_test_feature", since = "1.0.0")] + None, +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub enum Enum2 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Some(#[stable(feature = "stable_test_feature", since = "1.0.0")] T), + #[stable(feature = "stable_test_feature", since = "1.0.0")] + None, +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub enum Enum3 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Ok(#[stable(feature = "stable_test_feature", since = "1.0.0")] T), + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Err(#[stable(feature = "stable_test_feature", since = "1.0.0")] E), +} + +#[rustc_deprecated(since = "1.1.0", reason = "test")] +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub enum Enum4 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Some(#[stable(feature = "stable_test_feature", since = "1.0.0")] T), + #[stable(feature = "stable_test_feature", since = "1.0.0")] + None, +} + +#[rustc_deprecated(since = "1.1.0", reason = "test")] +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub enum Enum5<#[unstable(feature = "unstable_default", issue = "none")] T = usize> { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Some(#[stable(feature = "stable_test_feature", since = "1.0.0")] T), + #[stable(feature = "stable_test_feature", since = "1.0.0")] + None, +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub enum Enum6<#[unstable(feature = "unstable_default6", issue = "none")] T = usize> { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Some(#[stable(feature = "stable_test_feature", since = "1.0.0")] T), + #[stable(feature = "stable_test_feature", since = "1.0.0")] + None, +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ENUM1: Enum1 = Enum1::Some(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ENUM2: Enum2 = Enum2::Some(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ENUM3: Enum3 = Enum3::Ok(1); +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ENUM3B: Enum3 = Enum3::Err(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ENUM4: Enum4 = Enum4::Some(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ENUM5: Enum5 = Enum5::Some(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub type Alias1<#[unstable(feature = "unstable_default", issue = "none")] T = usize> = Option; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub type Alias2 = Option; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub type Alias3 = + Result; + +#[rustc_deprecated(since = "1.1.0", reason = "test")] +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub type Alias4 = Option; + +#[rustc_deprecated(since = "1.1.0", reason = "test")] +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub type Alias5<#[unstable(feature = "unstable_default", issue = "none")] T = usize> = Option; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub type Alias6<#[unstable(feature = "unstable_default6", issue = "none")] T = usize> = Option; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ALIAS1: Alias1 = Alias1::Some(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ALIAS2: Alias2 = Alias2::Some(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ALIAS3: Alias3 = Alias3::Ok(1); +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ALIAS3B: Alias3 = Alias3::Err(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ALIAS4: Alias4 = Alias4::Some(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ALIAS5: Alias5 = Alias5::Some(1); + + #[stable(feature = "stable_test_feature", since = "1.0.0")] pub trait Alloc {} diff --git a/src/test/ui/stability-attribute/generics-default-stability.rs b/src/test/ui/stability-attribute/generics-default-stability.rs index 461b1d405cb10..d6f28e3e447e2 100644 --- a/src/test/ui/stability-attribute/generics-default-stability.rs +++ b/src/test/ui/stability-attribute/generics-default-stability.rs @@ -110,6 +110,150 @@ fn main() { let _: Struct6 = Struct6 { field: 1 }; // ok let _: Struct6 = Struct6 { field: 0 }; // ok + let _: Alias1 = Alias1::Some(1); //~ ERROR use of unstable library feature 'unstable_default' + + let _ = ALIAS1; // ok + let _: Alias1 = ALIAS1; // ok + let _: Alias1 = ALIAS1; //~ ERROR use of unstable library feature 'unstable_default' + let _: Alias1 = Alias1::Some(0); //~ ERROR use of unstable library feature 'unstable_default' + + // Instability is not enforced for generic type parameters used in public fields. + // Note how the unstable type default `usize` leaks, + // and can be used without the 'unstable_default' feature. + let _ = Alias1::Some(1); + let _ = Alias1::Some(()); + let _ = Alias1::Some(1isize); + let _: Alias1 = Alias1::Some(1); + let _: usize = ALIAS1.unwrap(); + let _ = ALIAS1.unwrap() + 1; + let _ = ALIAS1.unwrap() + 1usize; + + let _ = Alias2::Some(1); // ok + let _: Alias2 = Alias2::Some(1); // ok + let _: Alias2 = Alias2::Some(1); // ok + + let _ = ALIAS2; + let _: Alias2 = ALIAS2; // ok + let _: Alias2 = ALIAS2; // ok + let _: Alias2 = Alias2::Some(0); // ok + let _ = ALIAS2.unwrap(); // ok + let _: usize = ALIAS2.unwrap(); // ok + let _ = ALIAS2.unwrap() + 1; // ok + let _ = ALIAS2.unwrap() + 1usize; // ok + + let _ = ALIAS3; + let _: Alias3 = ALIAS3; // ok + let _: Alias3 = ALIAS3; //~ ERROR use of unstable library feature 'unstable_default' + let _: Alias3 = ALIAS3; // ok + let _: Alias3 = Alias3::Ok(0); //~ ERROR use of unstable library feature 'unstable_default' + let _: Alias3 = Alias3::Ok(0); //~ ERROR use of unstable library feature 'unstable_default' + let _ = ALIAS3.unwrap(); // ok + let _: isize = ALIAS3.unwrap(); // ok + let _ = ALIAS3.unwrap() + 1; // ok + // Note the aforementioned leak. + let _: usize = ALIAS3B.unwrap_err(); // ok + let _: Alias3 = Alias3::Err(0); // ok + let _ = ALIAS3B.unwrap_err() + 1; // ok + let _ = ALIAS3B.unwrap_err() + 1usize; // ok + + let _ = ALIAS4; + let _: Alias4 = Alias4::Some(1); + //~^ use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] + //~^^ use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] + let _ = ALIAS4; + let _: Alias4 = ALIAS4; //~ use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] + let _: Alias4 = ALIAS4; //~ use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] + let _: Alias4 = Alias4::Some(0); + //~^ use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] + //~^^ use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] + + let _ = ALIAS5; + let _: Alias5 = Alias5::Some(1); //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] + //~^^ use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] + let _ = ALIAS5; + let _: Alias5 = ALIAS5; //~ use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] + let _: Alias5 = ALIAS5; //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] + let _: Alias5 = Alias5::Some(0); //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] + //~^^ use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] + + let _: Alias6 = Alias6::Some(1); // ok + let _: Alias6 = Alias6::Some(0); // ok + + let _: Enum1 = Enum1::Some(1); //~ ERROR use of unstable library feature 'unstable_default' + + let _ = ENUM1; // ok + let _: Enum1 = ENUM1; // ok + let _: Enum1 = ENUM1; //~ ERROR use of unstable library feature 'unstable_default' + let _: Enum1 = Enum1::Some(0); //~ ERROR use of unstable library feature 'unstable_default' + + // Instability is not enforced for generic type parameters used in public fields. + // Note how the unstable type default `usize` leaks, + // and can be used without the 'unstable_default' feature. + let _ = Enum1::Some(1); + let _ = Enum1::Some(()); + let _ = Enum1::Some(1isize); + let _: Enum1 = Enum1::Some(1); + if let Enum1::Some(x) = ENUM1 {let _: usize = x;} + if let Enum1::Some(x) = ENUM1 {let _ = x + 1;} + if let Enum1::Some(x) = ENUM1 {let _ = x + 1usize;} + + let _ = Enum2::Some(1); // ok + let _: Enum2 = Enum2::Some(1); // ok + let _: Enum2 = Enum2::Some(1); // ok + + let _ = ENUM2; + let _: Enum2 = ENUM2; // ok + let _: Enum2 = ENUM2; // ok + let _: Enum2 = Enum2::Some(0); // ok + if let Enum2::Some(x) = ENUM2 {let _ = x;} // ok + if let Enum2::Some(x) = ENUM2 {let _: usize = x;} // ok + if let Enum2::Some(x) = ENUM2 {let _ = x + 1;} // ok + if let Enum2::Some(x) = ENUM2 {let _ = x + 1usize;} // ok + + let _ = ENUM3; + let _: Enum3 = ENUM3; // ok + let _: Enum3 = ENUM3; //~ ERROR use of unstable library feature 'unstable_default' + let _: Enum3 = ENUM3; // ok + let _: Enum3 = Enum3::Ok(0); //~ ERROR use of unstable library feature 'unstable_default' + let _: Enum3 = Enum3::Ok(0); //~ ERROR use of unstable library feature 'unstable_default' + if let Enum3::Ok(x) = ENUM3 {let _ = x;} // ok + if let Enum3::Ok(x) = ENUM3 {let _: isize = x;} // ok + if let Enum3::Ok(x) = ENUM3 {let _ = x + 1;} // ok + // Note the aforementioned leak. + if let Enum3::Err(x) = ENUM3B {let _: usize = x;} // ok + let _: Enum3 = Enum3::Err(0); // ok + if let Enum3::Err(x) = ENUM3B {let _ = x + 1;} // ok + if let Enum3::Err(x) = ENUM3B {let _ = x + 1usize;} // ok + + let _ = ENUM4; + let _: Enum4 = Enum4::Some(1); + //~^ use of deprecated variant `unstable_generic_param::Enum4::Some`: test [deprecated] + //~^^ use of deprecated enum `unstable_generic_param::Enum4`: test [deprecated] + let _ = ENUM4; + let _: Enum4 = ENUM4; //~ use of deprecated enum `unstable_generic_param::Enum4`: test [deprecated] + let _: Enum4 = ENUM4; //~ use of deprecated enum `unstable_generic_param::Enum4`: test [deprecated] + let _: Enum4 = Enum4::Some(0); + //~^ use of deprecated variant `unstable_generic_param::Enum4::Some`: test [deprecated] + //~^^ use of deprecated enum `unstable_generic_param::Enum4`: test [deprecated] + + let _ = ENUM5; + let _: Enum5 = Enum5::Some(1); //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated variant `unstable_generic_param::Enum5::Some`: test [deprecated] + //~^^ use of deprecated enum `unstable_generic_param::Enum5`: test [deprecated] + let _ = ENUM5; + let _: Enum5 = ENUM5; //~ use of deprecated enum `unstable_generic_param::Enum5`: test [deprecated] + let _: Enum5 = ENUM5; //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated enum `unstable_generic_param::Enum5`: test [deprecated] + let _: Enum5 = Enum5::Some(0); //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated variant `unstable_generic_param::Enum5::Some`: test [deprecated] + //~^^ use of deprecated enum `unstable_generic_param::Enum5`: test [deprecated] + + let _: Enum6 = Enum6::Some(1); // ok + let _: Enum6 = Enum6::Some(0); // ok + let _: Box1 = Box1::new(1); //~ ERROR use of unstable library feature 'box_alloc_param' let _: Box1 = Box1::new(1); // ok diff --git a/src/test/ui/stability-attribute/generics-default-stability.stderr b/src/test/ui/stability-attribute/generics-default-stability.stderr index d9b238f8841bd..a5df70bb8b3dd 100644 --- a/src/test/ui/stability-attribute/generics-default-stability.stderr +++ b/src/test/ui/stability-attribute/generics-default-stability.stderr @@ -96,6 +96,150 @@ warning: use of deprecated struct `unstable_generic_param::Struct5`: test LL | let _: Struct5 = Struct5 { field: 0 }; | ^^^^^^^^^^^^^^ +warning: use of deprecated type alias `unstable_generic_param::Alias4`: test + --> $DIR/generics-default-stability.rs:160:28 + | +LL | let _: Alias4 = Alias4::Some(1); + | ^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias4`: test + --> $DIR/generics-default-stability.rs:160:12 + | +LL | let _: Alias4 = Alias4::Some(1); + | ^^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias4`: test + --> $DIR/generics-default-stability.rs:164:12 + | +LL | let _: Alias4 = ALIAS4; + | ^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias4`: test + --> $DIR/generics-default-stability.rs:165:12 + | +LL | let _: Alias4 = ALIAS4; + | ^^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias4`: test + --> $DIR/generics-default-stability.rs:166:28 + | +LL | let _: Alias4 = Alias4::Some(0); + | ^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias4`: test + --> $DIR/generics-default-stability.rs:166:12 + | +LL | let _: Alias4 = Alias4::Some(0); + | ^^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias5`: test + --> $DIR/generics-default-stability.rs:171:28 + | +LL | let _: Alias5 = Alias5::Some(1); + | ^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias5`: test + --> $DIR/generics-default-stability.rs:171:12 + | +LL | let _: Alias5 = Alias5::Some(1); + | ^^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias5`: test + --> $DIR/generics-default-stability.rs:175:12 + | +LL | let _: Alias5 = ALIAS5; + | ^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias5`: test + --> $DIR/generics-default-stability.rs:176:12 + | +LL | let _: Alias5 = ALIAS5; + | ^^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias5`: test + --> $DIR/generics-default-stability.rs:178:28 + | +LL | let _: Alias5 = Alias5::Some(0); + | ^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias5`: test + --> $DIR/generics-default-stability.rs:178:12 + | +LL | let _: Alias5 = Alias5::Some(0); + | ^^^^^^^^^^^^^ + +warning: use of deprecated variant `unstable_generic_param::Enum4::Some`: test + --> $DIR/generics-default-stability.rs:232:27 + | +LL | let _: Enum4 = Enum4::Some(1); + | ^^^^^^^^^^^ + +warning: use of deprecated enum `unstable_generic_param::Enum4`: test + --> $DIR/generics-default-stability.rs:232:12 + | +LL | let _: Enum4 = Enum4::Some(1); + | ^^^^^^^^^^^^ + +warning: use of deprecated enum `unstable_generic_param::Enum4`: test + --> $DIR/generics-default-stability.rs:236:12 + | +LL | let _: Enum4 = ENUM4; + | ^^^^^ + +warning: use of deprecated enum `unstable_generic_param::Enum4`: test + --> $DIR/generics-default-stability.rs:237:12 + | +LL | let _: Enum4 = ENUM4; + | ^^^^^^^^^^^^ + +warning: use of deprecated variant `unstable_generic_param::Enum4::Some`: test + --> $DIR/generics-default-stability.rs:238:27 + | +LL | let _: Enum4 = Enum4::Some(0); + | ^^^^^^^^^^^ + +warning: use of deprecated enum `unstable_generic_param::Enum4`: test + --> $DIR/generics-default-stability.rs:238:12 + | +LL | let _: Enum4 = Enum4::Some(0); + | ^^^^^^^^^^^^ + +warning: use of deprecated variant `unstable_generic_param::Enum5::Some`: test + --> $DIR/generics-default-stability.rs:243:27 + | +LL | let _: Enum5 = Enum5::Some(1); + | ^^^^^^^^^^^ + +warning: use of deprecated enum `unstable_generic_param::Enum5`: test + --> $DIR/generics-default-stability.rs:243:12 + | +LL | let _: Enum5 = Enum5::Some(1); + | ^^^^^^^^^^^^ + +warning: use of deprecated enum `unstable_generic_param::Enum5`: test + --> $DIR/generics-default-stability.rs:247:12 + | +LL | let _: Enum5 = ENUM5; + | ^^^^^ + +warning: use of deprecated enum `unstable_generic_param::Enum5`: test + --> $DIR/generics-default-stability.rs:248:12 + | +LL | let _: Enum5 = ENUM5; + | ^^^^^^^^^^^^ + +warning: use of deprecated variant `unstable_generic_param::Enum5::Some`: test + --> $DIR/generics-default-stability.rs:250:27 + | +LL | let _: Enum5 = Enum5::Some(0); + | ^^^^^^^^^^^ + +warning: use of deprecated enum `unstable_generic_param::Enum5`: test + --> $DIR/generics-default-stability.rs:250:12 + | +LL | let _: Enum5 = Enum5::Some(0); + | ^^^^^^^^^^^^ + error[E0658]: use of unstable library feature 'unstable_default' --> $DIR/generics-default-stability.rs:36:20 | @@ -168,8 +312,152 @@ LL | let _: Struct5 = Struct5 { field: 0 }; | = help: add `#![feature(unstable_default)]` to the crate attributes to enable +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:113:19 + | +LL | let _: Alias1 = Alias1::Some(1); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:117:19 + | +LL | let _: Alias1 = ALIAS1; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:118:19 + | +LL | let _: Alias1 = Alias1::Some(0); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:146:26 + | +LL | let _: Alias3 = ALIAS3; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:148:26 + | +LL | let _: Alias3 = Alias3::Ok(0); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:149:26 + | +LL | let _: Alias3 = Alias3::Ok(0); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:171:19 + | +LL | let _: Alias5 = Alias5::Some(1); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:176:19 + | +LL | let _: Alias5 = ALIAS5; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:178:19 + | +LL | let _: Alias5 = Alias5::Some(0); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:185:18 + | +LL | let _: Enum1 = Enum1::Some(1); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:189:18 + | +LL | let _: Enum1 = ENUM1; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:190:18 + | +LL | let _: Enum1 = Enum1::Some(0); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:218:25 + | +LL | let _: Enum3 = ENUM3; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:220:25 + | +LL | let _: Enum3 = Enum3::Ok(0); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:221:25 + | +LL | let _: Enum3 = Enum3::Ok(0); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:243:18 + | +LL | let _: Enum5 = Enum5::Some(1); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:248:18 + | +LL | let _: Enum5 = ENUM5; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:250:18 + | +LL | let _: Enum5 = Enum5::Some(0); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + error[E0658]: use of unstable library feature 'box_alloc_param' - --> $DIR/generics-default-stability.rs:113:24 + --> $DIR/generics-default-stability.rs:257:24 | LL | let _: Box1 = Box1::new(1); | ^^^^^^ @@ -200,6 +488,6 @@ warning: use of deprecated field `unstable_generic_param::Struct5::field`: test LL | let _: Struct5 = Struct5 { field: 0 }; | ^^^^^^^^ -error: aborting due to 13 previous errors; 16 warnings emitted +error: aborting due to 31 previous errors; 40 warnings emitted For more information about this error, try `rustc --explain E0658`. From 45d92b43e3613ecf26b20215f2db08d7162dbe63 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Wed, 23 Sep 2020 09:24:58 +0200 Subject: [PATCH 0886/1052] merge `need_type_info_err(_const)` --- .../infer/error_reporting/need_type_info.rs | 204 ++++++++++-------- compiler/rustc_infer/src/infer/mod.rs | 5 +- compiler/rustc_middle/src/infer/unify_key.rs | 4 +- .../borrow_check/diagnostics/region_name.rs | 6 +- .../src/traits/error_reporting/mod.rs | 23 +- compiler/rustc_typeck/src/check/fn_ctxt.rs | 2 +- compiler/rustc_typeck/src/check/writeback.rs | 11 +- .../infer/cannot-infer-const-args.full.stderr | 4 +- .../infer/cannot-infer-const-args.min.stderr | 4 +- .../infer/method-chain.full.stderr | 4 +- .../infer/method-chain.min.stderr | 4 +- .../infer/uninferred-consts.full.stderr | 4 +- .../infer/uninferred-consts.min.stderr | 4 +- 13 files changed, 148 insertions(+), 131 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index f87406c2ce469..f17492674ab4c 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -176,7 +176,10 @@ fn closure_return_type_suggestion( suggestion, Applicability::HasPlaceholders, ); - err.span_label(span, InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr)); + err.span_label( + span, + InferCtxt::missing_type_msg("type", &name, &descr, parent_name, parent_descr), + ); } /// Given a closure signature, return a `String` containing a list of all its argument types. @@ -220,60 +223,119 @@ impl Into for TypeAnnotationNeeded { impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn extract_type_name( &self, - ty: Ty<'tcx>, + arg: GenericArg<'tcx>, highlight: Option, ) -> (String, Option, Cow<'static, str>, Option, Option<&'static str>) { - if let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind() { - let mut inner = self.inner.borrow_mut(); - let ty_vars = &inner.type_variables(); - let var_origin = ty_vars.var_origin(ty_vid); - if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = var_origin.kind { - let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id)); - let (parent_name, parent_desc) = if let Some(parent_def_id) = parent_def_id { - let parent_name = self - .tcx - .def_key(parent_def_id) - .disambiguated_data - .data - .get_opt_name() - .map(|parent_symbol| parent_symbol.to_string()); - - (parent_name, Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id))) - } else { - (None, None) - }; + match arg.unpack() { + GenericArgKind::Type(ty) => { + if let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind() { + let mut inner = self.inner.borrow_mut(); + let ty_vars = &inner.type_variables(); + let var_origin = ty_vars.var_origin(ty_vid); + if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = + var_origin.kind + { + let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id)); + let (parent_name, parent_desc) = if let Some(parent_def_id) = parent_def_id + { + let parent_name = self + .tcx + .def_key(parent_def_id) + .disambiguated_data + .data + .get_opt_name() + .map(|parent_symbol| parent_symbol.to_string()); + + ( + parent_name, + Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)), + ) + } else { + (None, None) + }; + + if name != kw::SelfUpper { + return ( + name.to_string(), + Some(var_origin.span), + "type parameter".into(), + parent_name, + parent_desc, + ); + } + } + } - if name != kw::SelfUpper { - return ( - name.to_string(), - Some(var_origin.span), - "type parameter".into(), - parent_name, - parent_desc, - ); + let mut s = String::new(); + let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); + if let Some(highlight) = highlight { + printer.region_highlight_mode = highlight; } + let _ = ty.print(printer); + (s, None, ty.prefix_string(), None, None) } - } + GenericArgKind::Const(ct) => { + if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val { + let origin = + self.inner.borrow_mut().const_unification_table().probe_value(vid).origin; + if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) = + origin.kind + { + let parent_def_id = self.tcx.parent(def_id); + let (parent_name, parent_descr) = if let Some(parent_def_id) = parent_def_id + { + let parent_name = self + .tcx + .def_key(parent_def_id) + .disambiguated_data + .data + .get_opt_name() + .map(|parent_symbol| parent_symbol.to_string()); + + ( + parent_name, + Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)), + ) + } else { + (None, None) + }; + + return ( + name.to_string(), + Some(origin.span), + "const parameter".into(), + parent_name, + parent_descr, + ); + } + } - let mut s = String::new(); - let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); - if let Some(highlight) = highlight { - printer.region_highlight_mode = highlight; + let mut s = String::new(); + let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); + if let Some(highlight) = highlight { + printer.region_highlight_mode = highlight; + } + let _ = ct.print(printer); + (s, None, "".into(), None, None) + } + GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), } - let _ = ty.print(printer); - (s, None, ty.prefix_string(), None, None) } - // FIXME(eddyb) generalize all of this to handle `ty::Const` inference variables as well. pub fn need_type_info_err( &self, body_id: Option, span: Span, - ty: Ty<'tcx>, + ty: GenericArg<'tcx>, error_code: TypeAnnotationNeeded, ) -> DiagnosticBuilder<'tcx> { let ty = self.resolve_vars_if_possible(&ty); - let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None); + let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(ty, None); + let kind_str = match ty.unpack() { + GenericArgKind::Type(_) => "type", + GenericArgKind::Const(_) => "the value", + GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), + }; let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into(), span); let ty_to_string = |ty: Ty<'tcx>| -> String { @@ -545,55 +607,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // Avoid multiple labels pointing at `span`. err.span_label( span, - InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr), + InferCtxt::missing_type_msg(kind_str, &name, &descr, parent_name, parent_descr), ); } err } - // FIXME(const_generics): We should either try and merge this with `need_type_info_err` - // or improve the errors created here. - // - // Unlike for type inference variables, we don't yet store the origin of const inference variables. - // This is needed for to get a more relevant error span. - pub fn need_type_info_err_const( - &self, - body_id: Option, - span: Span, - ct: &'tcx ty::Const<'tcx>, - error_code: TypeAnnotationNeeded, - ) -> DiagnosticBuilder<'tcx> { - let mut local_visitor = FindHirNodeVisitor::new(&self, ct.into(), span); - if let Some(body_id) = body_id { - let expr = self.tcx.hir().expect_expr(body_id.hir_id); - local_visitor.visit_expr(expr); - } - - let mut param_name = None; - let span = if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val { - let origin = self.inner.borrow_mut().const_unification_table().probe_value(vid).origin; - if let ConstVariableOriginKind::ConstParameterDefinition(param) = origin.kind { - param_name = Some(param); - } - origin.span - } else { - local_visitor.target_span - }; - - let error_code = error_code.into(); - let mut err = - self.tcx.sess.struct_span_err_with_code(span, "type annotations needed", error_code); - - if let Some(param_name) = param_name { - err.note(&format!("cannot infer the value of the const parameter `{}`", param_name)); - } else { - err.note("unable to infer the value of a const parameter"); - } - - err - } - /// If the `FnSig` for the method call can be found and type arguments are identified as /// needed, suggest annotating the call, otherwise point out the resulting type of the call. fn annotate_method_call( @@ -647,7 +667,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty: Ty<'tcx>, ) -> DiagnosticBuilder<'tcx> { let ty = self.resolve_vars_if_possible(&ty); - let (name, _, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None); + let (name, _, descr, parent_name, parent_descr) = self.extract_type_name(ty.into(), None); let mut err = struct_span_err!( self.tcx.sess, @@ -656,18 +676,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "type inside {} must be known in this context", kind, ); - err.span_label(span, InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr)); + err.span_label( + span, + InferCtxt::missing_type_msg("type", &name, &descr, parent_name, parent_descr), + ); err } fn missing_type_msg( + kind_str: &str, type_name: &str, descr: &str, parent_name: Option, parent_descr: Option<&str>, - ) -> Cow<'static, str> { + ) -> String { if type_name == "_" { - "cannot infer type".into() + format!("cannot infer {}", kind_str) } else { let parent_desc = if let Some(parent_name) = parent_name { let parent_type_descr = if let Some(parent_descr) = parent_descr { @@ -681,7 +705,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "".to_string() }; - format!("cannot infer type for {} `{}`{}", descr, type_name, parent_desc).into() + let preposition = if "value" == kind_str { "of" } else { "for" }; + // For example: "cannot infer type for type parameter `T`" + format!( + "cannot infer {} {} {} `{}`{}", + kind_str, preposition, descr, type_name, parent_desc + ) + .into() } } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 2cbdc954e2007..d7bfab8a7f85d 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1163,7 +1163,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } GenericParamDefKind::Const { .. } => { let origin = ConstVariableOrigin { - kind: ConstVariableOriginKind::ConstParameterDefinition(param.name), + kind: ConstVariableOriginKind::ConstParameterDefinition( + param.name, + param.def_id, + ), span, }; let const_var_id = diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs index a60a17befeffd..499f92b404116 100644 --- a/compiler/rustc_middle/src/infer/unify_key.rs +++ b/compiler/rustc_middle/src/infer/unify_key.rs @@ -4,6 +4,7 @@ use rustc_data_structures::undo_log::UndoLogs; use rustc_data_structures::unify::{ self, EqUnifyValue, InPlace, NoError, UnificationTable, UnifyKey, UnifyValue, }; +use rustc_span::def_id::DefId; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; @@ -124,8 +125,7 @@ pub struct ConstVariableOrigin { pub enum ConstVariableOriginKind { MiscVariable, ConstInference, - // FIXME(const_generics): Consider storing the `DefId` of the param here. - ConstParameterDefinition(Symbol), + ConstParameterDefinition(Symbol, DefId), SubstitutionPlaceholder, } diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs index da7bc1564c013..d96020fe36106 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs @@ -396,7 +396,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { ) -> Option { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(needle_fr, counter); - let type_name = self.infcx.extract_type_name(&ty, Some(highlight)).0; + let type_name = self.infcx.extract_type_name(ty.into(), Some(highlight)).0; debug!( "highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}", @@ -646,7 +646,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap()); - let type_name = self.infcx.extract_type_name(&return_ty, Some(highlight)).0; + let type_name = self.infcx.extract_type_name(return_ty.into(), Some(highlight)).0; let mir_hir_id = tcx.hir().local_def_id_to_hir_id(self.mir_def_id); @@ -698,7 +698,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap()); - let type_name = self.infcx.extract_type_name(&yield_ty, Some(highlight)).0; + let type_name = self.infcx.extract_type_name(yield_ty.into(), Some(highlight)).0; let mir_hir_id = tcx.hir().local_def_id_to_hir_id(self.mir_def_id); 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 bda4351b2f2d8..4cc9a1ecdc81b 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -20,7 +20,6 @@ use rustc_hir::Node; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::fold::TypeFolder; -use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{ self, fast_reject, AdtKind, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, @@ -1513,10 +1512,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { // check upstream for type errors and don't add the obligations to // begin with in those cases. if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) { - self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0282).emit(); + self.need_type_info_err(body_id, span, self_ty.into(), ErrorCode::E0282).emit(); return; } - let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0283); + let mut err = + self.need_type_info_err(body_id, span, self_ty.into(), ErrorCode::E0283); err.note(&format!("cannot satisfy `{}`", predicate)); if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code { self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id()); @@ -1580,17 +1580,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { return; } - match arg.unpack() { - GenericArgKind::Lifetime(lt) => { - span_bug!(span, "unexpected well formed predicate: {:?}", lt) - } - GenericArgKind::Type(ty) => { - self.need_type_info_err(body_id, span, ty, ErrorCode::E0282) - } - GenericArgKind::Const(ct) => { - self.need_type_info_err_const(body_id, span, ct, ErrorCode::E0282) - } - } + self.need_type_info_err(body_id, span, arg, ErrorCode::E0282) } ty::PredicateAtom::Subtype(data) => { @@ -1601,7 +1591,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { let SubtypePredicate { a_is_expected: _, a, b } = data; // both must be type variables, or the other would've been instantiated assert!(a.is_ty_var() && b.is_ty_var()); - self.need_type_info_err(body_id, span, a, ErrorCode::E0282) + self.need_type_info_err(body_id, span, a.into(), ErrorCode::E0282) } ty::PredicateAtom::Projection(data) => { let trait_ref = ty::Binder::bind(data).to_poly_trait_ref(self.tcx); @@ -1612,7 +1602,8 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { } if self_ty.needs_infer() && ty.needs_infer() { // We do this for the `foo.collect()?` case to produce a suggestion. - let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0284); + let mut err = + self.need_type_info_err(body_id, span, self_ty.into(), ErrorCode::E0284); err.note(&format!("cannot satisfy `{}`", predicate)); err } else { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt.rs b/compiler/rustc_typeck/src/check/fn_ctxt.rs index a03b8064b5909..31010753474be 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt.rs @@ -2991,7 +2991,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } else { if !self.is_tainted_by_errors() { - self.need_type_info_err((**self).body_id, sp, ty, E0282) + self.need_type_info_err((**self).body_id, sp, ty.into(), E0282) .note("type must be known at this point") .emit(); } diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index b55f62ee436e1..ccff9b5cdb4b4 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -653,7 +653,12 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { fn report_type_error(&self, t: Ty<'tcx>) { if !self.tcx.sess.has_errors() { self.infcx - .need_type_info_err(Some(self.body.id()), self.span.to_span(self.tcx), t, E0282) + .need_type_info_err( + Some(self.body.id()), + self.span.to_span(self.tcx), + t.into(), + E0282, + ) .emit(); } } @@ -661,10 +666,10 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { fn report_const_error(&self, c: &'tcx ty::Const<'tcx>) { if !self.tcx.sess.has_errors() { self.infcx - .need_type_info_err_const( + .need_type_info_err( Some(self.body.id()), self.span.to_span(self.tcx), - c, + c.into(), E0282, ) .emit(); diff --git a/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr b/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr index 84e75cc376416..a5f7705804e02 100644 --- a/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr +++ b/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr @@ -2,9 +2,7 @@ error[E0282]: type annotations needed --> $DIR/cannot-infer-const-args.rs:12:5 | LL | foo(); - | ^^^ - | - = note: cannot infer the value of the const parameter `X` + | ^^^ cannot infer the value for const parameter `X` declared on the function `foo` error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr b/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr index 84e75cc376416..a5f7705804e02 100644 --- a/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr +++ b/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr @@ -2,9 +2,7 @@ error[E0282]: type annotations needed --> $DIR/cannot-infer-const-args.rs:12:5 | LL | foo(); - | ^^^ - | - = note: cannot infer the value of the const parameter `X` + | ^^^ cannot infer the value for const parameter `X` declared on the function `foo` error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/method-chain.full.stderr b/src/test/ui/const-generics/infer/method-chain.full.stderr index e65bc3f109681..0344b364166d7 100644 --- a/src/test/ui/const-generics/infer/method-chain.full.stderr +++ b/src/test/ui/const-generics/infer/method-chain.full.stderr @@ -2,9 +2,7 @@ error[E0282]: type annotations needed --> $DIR/method-chain.rs:21:33 | LL | Foo.bar().bar().bar().bar().baz(); - | ^^^ - | - = note: cannot infer the value of the const parameter `N` + | ^^^ cannot infer the value for const parameter `N` declared on the associated function `baz` error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/method-chain.min.stderr b/src/test/ui/const-generics/infer/method-chain.min.stderr index e65bc3f109681..0344b364166d7 100644 --- a/src/test/ui/const-generics/infer/method-chain.min.stderr +++ b/src/test/ui/const-generics/infer/method-chain.min.stderr @@ -2,9 +2,7 @@ error[E0282]: type annotations needed --> $DIR/method-chain.rs:21:33 | LL | Foo.bar().bar().bar().bar().baz(); - | ^^^ - | - = note: cannot infer the value of the const parameter `N` + | ^^^ cannot infer the value for const parameter `N` declared on the associated function `baz` error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/uninferred-consts.full.stderr b/src/test/ui/const-generics/infer/uninferred-consts.full.stderr index e47b6bd5dc691..47ffc7e7157cc 100644 --- a/src/test/ui/const-generics/infer/uninferred-consts.full.stderr +++ b/src/test/ui/const-generics/infer/uninferred-consts.full.stderr @@ -2,9 +2,7 @@ error[E0282]: type annotations needed --> $DIR/uninferred-consts.rs:14:9 | LL | Foo.foo(); - | ^^^ - | - = note: cannot infer the value of the const parameter `N` + | ^^^ cannot infer the value for const parameter `N` declared on the associated function `foo` error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/uninferred-consts.min.stderr b/src/test/ui/const-generics/infer/uninferred-consts.min.stderr index e47b6bd5dc691..47ffc7e7157cc 100644 --- a/src/test/ui/const-generics/infer/uninferred-consts.min.stderr +++ b/src/test/ui/const-generics/infer/uninferred-consts.min.stderr @@ -2,9 +2,7 @@ error[E0282]: type annotations needed --> $DIR/uninferred-consts.rs:14:9 | LL | Foo.foo(); - | ^^^ - | - = note: cannot infer the value of the const parameter `N` + | ^^^ cannot infer the value for const parameter `N` declared on the associated function `foo` error: aborting due to previous error From 0abb1abf04da1dd5a709614f443b57d973d438ba Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Wed, 23 Sep 2020 10:06:32 +0200 Subject: [PATCH 0887/1052] unused path --- .../rustc_infer/src/infer/error_reporting/need_type_info.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index f17492674ab4c..bea1ab519f1d6 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -316,7 +316,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { printer.region_highlight_mode = highlight; } let _ = ct.print(printer); - (s, None, "".into(), None, None) + (s, None, "value".into(), None, None) } GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), } From 3dbfdb0182c7b8bbace4b5d8d4445aac4291351a Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Wed, 23 Sep 2020 10:44:11 +0200 Subject: [PATCH 0888/1052] use the correct span when dealing with inference variables --- .../src/infer/error_reporting/need_type_info.rs | 14 +++++++++----- .../infer/cannot-infer-const-args.full.stderr | 2 +- .../infer/cannot-infer-const-args.min.stderr | 2 +- src/test/ui/const-generics/infer/issue-77092.rs | 16 ++++++++++++++++ .../ui/const-generics/infer/issue-77092.stderr | 9 +++++++++ .../infer/method-chain.full.stderr | 2 +- .../const-generics/infer/method-chain.min.stderr | 2 +- .../infer/uninferred-consts.full.stderr | 2 +- .../infer/uninferred-consts.min.stderr | 2 +- 9 files changed, 40 insertions(+), 11 deletions(-) create mode 100644 src/test/ui/const-generics/infer/issue-77092.rs create mode 100644 src/test/ui/const-generics/infer/issue-77092.stderr diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index bea1ab519f1d6..b7debba68b58e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -275,7 +275,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { (s, None, ty.prefix_string(), None, None) } GenericArgKind::Const(ct) => { - if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val { + let span = if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val { let origin = self.inner.borrow_mut().const_unification_table().probe_value(vid).origin; if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) = @@ -308,15 +308,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { parent_descr, ); } - } + + Some(origin.span).filter(|s| !s.is_dummy()) + } else { + bug!("unexpect const: {:?}", ct); + }; let mut s = String::new(); - let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); + let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::ValueNS); if let Some(highlight) = highlight { printer.region_highlight_mode = highlight; } let _ = ct.print(printer); - (s, None, "value".into(), None, None) + (s, span, "the constant".into(), None, None) } GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), } @@ -705,7 +709,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "".to_string() }; - let preposition = if "value" == kind_str { "of" } else { "for" }; + let preposition = if "the value" == kind_str { "of" } else { "for" }; // For example: "cannot infer type for type parameter `T`" format!( "cannot infer {} {} {} `{}`{}", diff --git a/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr b/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr index a5f7705804e02..b438ed3ad6508 100644 --- a/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr +++ b/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/cannot-infer-const-args.rs:12:5 | LL | foo(); - | ^^^ cannot infer the value for const parameter `X` declared on the function `foo` + | ^^^ cannot infer the value of const parameter `X` declared on the function `foo` error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr b/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr index a5f7705804e02..b438ed3ad6508 100644 --- a/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr +++ b/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/cannot-infer-const-args.rs:12:5 | LL | foo(); - | ^^^ cannot infer the value for const parameter `X` declared on the function `foo` + | ^^^ cannot infer the value of const parameter `X` declared on the function `foo` error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/issue-77092.rs b/src/test/ui/const-generics/infer/issue-77092.rs new file mode 100644 index 0000000000000..9a1dd1a825895 --- /dev/null +++ b/src/test/ui/const-generics/infer/issue-77092.rs @@ -0,0 +1,16 @@ +#![feature(min_const_generics)] + +use std::convert::TryInto; + +fn take_array_from_mut(data: &mut [T], start: usize) -> &mut [T; N] { + (&mut data[start .. start + N]).try_into().unwrap() +} + +fn main() { + let mut arr = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + + for i in 1 .. 4 { + println!("{:?}", take_array_from_mut(&mut arr, i)); + //~^ ERROR type annotations needed + } +} diff --git a/src/test/ui/const-generics/infer/issue-77092.stderr b/src/test/ui/const-generics/infer/issue-77092.stderr new file mode 100644 index 0000000000000..e84ff8baeea53 --- /dev/null +++ b/src/test/ui/const-generics/infer/issue-77092.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/issue-77092.rs:13:26 + | +LL | println!("{:?}", take_array_from_mut(&mut arr, i)); + | ^^^^^^^^^^^^^^^^^^^ cannot infer the value of the constant `{_: usize}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/const-generics/infer/method-chain.full.stderr b/src/test/ui/const-generics/infer/method-chain.full.stderr index 0344b364166d7..1fb0b23cf1157 100644 --- a/src/test/ui/const-generics/infer/method-chain.full.stderr +++ b/src/test/ui/const-generics/infer/method-chain.full.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/method-chain.rs:21:33 | LL | Foo.bar().bar().bar().bar().baz(); - | ^^^ cannot infer the value for const parameter `N` declared on the associated function `baz` + | ^^^ cannot infer the value of const parameter `N` declared on the associated function `baz` error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/method-chain.min.stderr b/src/test/ui/const-generics/infer/method-chain.min.stderr index 0344b364166d7..1fb0b23cf1157 100644 --- a/src/test/ui/const-generics/infer/method-chain.min.stderr +++ b/src/test/ui/const-generics/infer/method-chain.min.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/method-chain.rs:21:33 | LL | Foo.bar().bar().bar().bar().baz(); - | ^^^ cannot infer the value for const parameter `N` declared on the associated function `baz` + | ^^^ cannot infer the value of const parameter `N` declared on the associated function `baz` error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/uninferred-consts.full.stderr b/src/test/ui/const-generics/infer/uninferred-consts.full.stderr index 47ffc7e7157cc..7a451903e9630 100644 --- a/src/test/ui/const-generics/infer/uninferred-consts.full.stderr +++ b/src/test/ui/const-generics/infer/uninferred-consts.full.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/uninferred-consts.rs:14:9 | LL | Foo.foo(); - | ^^^ cannot infer the value for const parameter `N` declared on the associated function `foo` + | ^^^ cannot infer the value of const parameter `N` declared on the associated function `foo` error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/uninferred-consts.min.stderr b/src/test/ui/const-generics/infer/uninferred-consts.min.stderr index 47ffc7e7157cc..7a451903e9630 100644 --- a/src/test/ui/const-generics/infer/uninferred-consts.min.stderr +++ b/src/test/ui/const-generics/infer/uninferred-consts.min.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/uninferred-consts.rs:14:9 | LL | Foo.foo(); - | ^^^ cannot infer the value for const parameter `N` declared on the associated function `foo` + | ^^^ cannot infer the value of const parameter `N` declared on the associated function `foo` error: aborting due to previous error From 0e84b6105376742072e85ae2b85a6a1fd9a9045d Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Wed, 23 Sep 2020 11:00:44 +0200 Subject: [PATCH 0889/1052] use relevant span when unifying `ConstVarValue`s --- .../src/infer/error_reporting/need_type_info.rs | 3 ++- compiler/rustc_middle/src/infer/unify_key.rs | 14 +++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index b7debba68b58e..b00adec822e51 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -309,7 +309,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); } - Some(origin.span).filter(|s| !s.is_dummy()) + debug_assert!(!origin.span.is_dummy()); + Some(origin.span) } else { bug!("unexpect const: {:?}", ct); }; diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs index 499f92b404116..4d884dde39387 100644 --- a/compiler/rustc_middle/src/infer/unify_key.rs +++ b/compiler/rustc_middle/src/infer/unify_key.rs @@ -6,7 +6,7 @@ use rustc_data_structures::unify::{ }; use rustc_span::def_id::DefId; use rustc_span::symbol::Symbol; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; use std::cmp; use std::marker::PhantomData; @@ -176,17 +176,17 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> { type Error = (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>); fn unify_values(value1: &Self, value2: &Self) -> Result { - let val = match (value1.val, value2.val) { + let (val, span) = match (value1.val, value2.val) { (ConstVariableValue::Known { .. }, ConstVariableValue::Known { .. }) => { bug!("equating two const variables, both of which have known values") } // If one side is known, prefer that one. (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => { - Ok(value1.val) + (value1.val, value1.origin.span) } (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => { - Ok(value2.val) + (value2.val, value2.origin.span) } // If both sides are *unknown*, it hardly matters, does it? @@ -200,14 +200,14 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> { // universe is the minimum of the two universes, because that is // the one which contains the fewest names in scope. let universe = cmp::min(universe1, universe2); - Ok(ConstVariableValue::Unknown { universe }) + (ConstVariableValue::Unknown { universe }, value1.origin.span) } - }?; + }; Ok(ConstVarValue { origin: ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, - span: DUMMY_SP, + span: span, }, val, }) From 631c6883502144fdb8ac754c9ef1f74111fd3222 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 23 Sep 2020 11:09:10 +0200 Subject: [PATCH 0890/1052] Make [].as_[mut_]ptr_range() (unstably) const. --- library/core/src/slice/mod.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index ff926c517bc7c..12dcd6c6ba8d0 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -433,8 +433,9 @@ impl [T] { /// assert_eq!(x, &[3, 4, 6]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub fn as_mut_ptr(&mut self) -> *mut T { + pub const fn as_mut_ptr(&mut self) -> *mut T { self as *mut [T] as *mut T } @@ -469,8 +470,9 @@ impl [T] { /// /// [`as_ptr`]: #method.as_ptr #[unstable(feature = "slice_ptr_range", issue = "65807")] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub fn as_ptr_range(&self) -> Range<*const T> { + pub const fn as_ptr_range(&self) -> Range<*const T> { let start = self.as_ptr(); // SAFETY: The `add` here is safe, because: // @@ -510,8 +512,9 @@ impl [T] { /// /// [`as_mut_ptr`]: #method.as_mut_ptr #[unstable(feature = "slice_ptr_range", issue = "65807")] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub fn as_mut_ptr_range(&mut self) -> Range<*mut T> { + pub const fn as_mut_ptr_range(&mut self) -> Range<*mut T> { let start = self.as_mut_ptr(); // SAFETY: See as_ptr_range() above for why `add` here is safe. let end = unsafe { start.add(self.len()) }; From ed97b421059d25a86b2f947734a8ae366b68f473 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Wed, 23 Sep 2020 13:48:21 +0200 Subject: [PATCH 0891/1052] add tracking issue --- library/core/src/array/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 5730074bf2747..966272ca11549 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -20,14 +20,14 @@ mod iter; pub use iter::IntoIter; /// Converts a reference to `T` into a reference to an array of length 1 (without copying). -#[unstable(feature = "array_from_ref", issue = "none")] +#[unstable(feature = "array_from_ref", issue = "77101")] pub fn from_ref(s: &T) -> &[T; 1] { // SAFETY: Converting `&T` to `&[T; 1]` is sound. unsafe { &*(s as *const T).cast::<[T; 1]>() } } /// Converts a mutable reference to `T` into a mutable reference to an array of length 1 (without copying). -#[unstable(feature = "array_from_ref", issue = "none")] +#[unstable(feature = "array_from_ref", issue = "77101")] pub fn from_mut(s: &mut T) -> &mut [T; 1] { // SAFETY: Converting `&mut T` to `&mut [T; 1]` is sound. unsafe { &mut *(s as *mut T).cast::<[T; 1]>() } From b5d47bfa3aafb8fcb8c60d93fea45207c7ea5c7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Wed, 23 Sep 2020 15:45:35 +0200 Subject: [PATCH 0892/1052] clarify that `changelog-seen = 1` goes to the beginning of config.toml Fixes #77105 --- src/bootstrap/bin/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/bin/main.rs b/src/bootstrap/bin/main.rs index f7512aa9fcebd..6af13fc83d0ef 100644 --- a/src/bootstrap/bin/main.rs +++ b/src/bootstrap/bin/main.rs @@ -40,7 +40,7 @@ fn check_version(config: &Config) -> Option { } } else { msg.push_str("warning: x.py has made several changes recently you may want to look at\n"); - format!("add `changelog-seen = {}` to `config.toml`", VERSION) + format!("add `changelog-seen = {}` at the top of `config.toml`", VERSION) }; msg.push_str("help: consider looking at the changes in `src/bootstrap/CHANGELOG.md`\n"); From 1b1b6eabaa9ea0090dd47e642b6bb6606cc52e8c Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 23 Sep 2020 16:28:45 +0200 Subject: [PATCH 0893/1052] Remove the "lift constant to reference" logic --- .../rustc_mir_build/src/build/matches/test.rs | 35 +---------------- .../src/thir/pattern/const_to_pat.rs | 39 +++++++++++++------ 2 files changed, 28 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 796815cf2168c..d81c3b68f4853 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -409,40 +409,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let deref_ty = match *ty.kind() { ty::Ref(_, deref_ty, _) => deref_ty, - _ => { - trace!("non_scalar_compare called on non-reference type: {}", ty); - // Backcompat hack: due to non-structural matches not being a hard error, we can - // reach this for types that have manual `Eq` or `PartialEq` impls. - assert!(!ty.is_structural_eq_shallow(self.hir.tcx())); - let ref_ty = self.hir.tcx().mk_imm_ref(self.hir.tcx().lifetimes.re_erased, ty); - // let y = &place; - let y = self.temp(ref_ty, source_info.span); - self.cfg.push_assign( - block, - source_info, - y, - Rvalue::Ref(self.hir.tcx().lifetimes.re_erased, BorrowKind::Shared, place), - ); - val = Operand::Move(y); - // let temp = expect; - let temp = self.temp(ty, source_info.span); - self.cfg.push_assign( - block, - source_info, - temp, - Rvalue::Use(expect), - ); - // reftemp = &temp; - let reftemp = self.temp(ref_ty, source_info.span); - self.cfg.push_assign( - block, - source_info, - reftemp, - Rvalue::Ref(self.hir.tcx().lifetimes.re_erased, BorrowKind::Shared, temp), - ); - expect = Operand::Move(reftemp); - ty - }, + _ => bug!("non_scalar_compare called on non-reference type: {}", ty), }; let eq_def_id = self.hir.tcx().require_lang_item(LangItem::PartialEq, None); diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index ad0bcfeb367f9..4a50bbca06674 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -58,6 +58,9 @@ struct ConstToPat<'a, 'tcx> { include_lint_checks: bool, } +#[derive(Debug)] +struct FallbackToConstRef; + impl<'a, 'tcx> ConstToPat<'a, 'tcx> { fn new( pat_ctxt: &PatCtxt<'_, 'tcx>, @@ -103,7 +106,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // once indirect_structural_match is a full fledged error, this // level of indirection can be eliminated - let inlined_const_as_pat = self.recur(cv, mir_structural_match_violation); + let inlined_const_as_pat = self.recur(cv, mir_structural_match_violation).unwrap(); if self.include_lint_checks && !self.saw_const_match_error.get() { // If we were able to successfully convert the const to some pat, @@ -216,18 +219,22 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { } // Recursive helper for `to_pat`; invoke that (instead of calling this directly). - fn recur(&self, cv: &'tcx ty::Const<'tcx>, mir_structural_match_violation: bool) -> Pat<'tcx> { + fn recur( + &self, + cv: &'tcx ty::Const<'tcx>, + mir_structural_match_violation: bool, + ) -> Result, FallbackToConstRef> { let id = self.id; let span = self.span; let tcx = self.tcx(); let param_env = self.param_env; - let field_pats = |vals: &[&'tcx ty::Const<'tcx>]| { + let field_pats = |vals: &[&'tcx ty::Const<'tcx>]| -> Result<_, _> { vals.iter() .enumerate() .map(|(idx, val)| { let field = Field::new(idx); - FieldPat { field, pattern: self.recur(val, false) } + Ok(FieldPat { field, pattern: self.recur(val, false)? }) }) .collect() }; @@ -287,7 +294,10 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { |lint| lint.build(&msg).emit(), ); } - PatKind::Constant { value: cv } + // Since we are behind a reference, we can just bubble the error up so we get a + // constant at reference type, making it easy to let the fallback call + // `PartialEq::eq` on it. + return Err(FallbackToConstRef); } ty::Adt(adt_def, _) if !self.type_marked_structural(cv.ty) => { debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, cv.ty); @@ -309,12 +319,12 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { variant_index: destructured .variant .expect("destructed const of adt without variant id"), - subpatterns: field_pats(destructured.fields), + subpatterns: field_pats(destructured.fields)?, } } ty::Tuple(_) | ty::Adt(_, _) => { let destructured = tcx.destructure_const(param_env.and(cv)); - PatKind::Leaf { subpatterns: field_pats(destructured.fields) } + PatKind::Leaf { subpatterns: field_pats(destructured.fields)? } } ty::Array(..) => PatKind::Array { prefix: tcx @@ -322,7 +332,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { .fields .iter() .map(|val| self.recur(val, false)) - .collect(), + .collect::>()?, slice: None, suffix: Vec::new(), }, @@ -355,7 +365,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { .fields .iter() .map(|val| self.recur(val, false)) - .collect(), + .collect::>()?, slice: None, suffix: vec![], }), @@ -379,8 +389,13 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // deref pattern. _ => { let old = self.behind_reference.replace(true); - let val = PatKind::Deref { - subpattern: self.recur(tcx.deref_const(self.param_env.and(cv)), false), + // In case there are structural-match violations somewhere in this subpattern, + // we fall back to a const pattern. If we do not do this, we may end up with + // a !structural-match constant that is not of reference type, which makes it + // very hard to invoke `PartialEq::eq` on it as a fallback. + let val = match self.recur(tcx.deref_const(self.param_env.and(cv)), false) { + Ok(subpattern) => PatKind::Deref { subpattern }, + Err(FallbackToConstRef) => PatKind::Constant { value: cv }, }; self.behind_reference.set(old); val @@ -439,6 +454,6 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { ); } - Pat { span, ty: cv.ty, kind: Box::new(kind) } + Ok(Pat { span, ty: cv.ty, kind: Box::new(kind) }) } } From d486486afdb545e43a27326be07a92d5fc9ad387 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 23 Sep 2020 16:38:30 +0200 Subject: [PATCH 0894/1052] Talk about unpredictable instead of "not deterministic" --- compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs | 4 ++-- src/test/ui/issues/issue-44333.rs | 4 ++-- src/test/ui/issues/issue-44333.stderr | 4 ++-- src/test/ui/rfc1445/issue-63479-match-fnptr.rs | 2 +- src/test/ui/rfc1445/issue-63479-match-fnptr.stderr | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 4a50bbca06674..3c0dec64693fe 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -413,8 +413,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { ty::FnPtr(..) | ty::RawPtr(..) => { if self.include_lint_checks && !self.saw_const_match_error.get() { self.saw_const_match_error.set(true); - let msg = "function pointers and unsized pointers in patterns do not behave \ - deterministically. \ + let msg = "function pointers and unsized pointers in patterns behave \ + unpredictably and should not be relied upon. \ See https://github.com/rust-lang/rust/issues/70861 for details."; tcx.struct_span_lint_hir( lint::builtin::POINTER_STRUCTURAL_MATCH, diff --git a/src/test/ui/issues/issue-44333.rs b/src/test/ui/issues/issue-44333.rs index 85f5ccbdb6561..96e8795e52d56 100644 --- a/src/test/ui/issues/issue-44333.rs +++ b/src/test/ui/issues/issue-44333.rs @@ -16,9 +16,9 @@ const BAR: Func = bar; fn main() { match test(std::env::consts::ARCH.len()) { - FOO => println!("foo"), //~ WARN pointers in patterns do not behave deterministically + FOO => println!("foo"), //~ WARN pointers in patterns behave unpredictably //~^ WARN will become a hard error - BAR => println!("bar"), //~ WARN pointers in patterns do not behave deterministically + BAR => println!("bar"), //~ WARN pointers in patterns behave unpredictably //~^ WARN will become a hard error _ => unreachable!(), } diff --git a/src/test/ui/issues/issue-44333.stderr b/src/test/ui/issues/issue-44333.stderr index a9ee5fc4dd7b1..8302b09e5334d 100644 --- a/src/test/ui/issues/issue-44333.stderr +++ b/src/test/ui/issues/issue-44333.stderr @@ -1,4 +1,4 @@ -warning: function pointers and unsized pointers in patterns do not behave deterministically. See https://github.com/rust-lang/rust/issues/70861 for details. +warning: function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/issue-44333.rs:19:9 | LL | FOO => println!("foo"), @@ -12,7 +12,7 @@ LL | #![warn(pointer_structural_match)] = 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 #62411 -warning: function pointers and unsized pointers in patterns do not behave deterministically. See https://github.com/rust-lang/rust/issues/70861 for details. +warning: function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/issue-44333.rs:21:9 | LL | BAR => println!("bar"), diff --git a/src/test/ui/rfc1445/issue-63479-match-fnptr.rs b/src/test/ui/rfc1445/issue-63479-match-fnptr.rs index 0984b1d480ecb..567685950e9e4 100644 --- a/src/test/ui/rfc1445/issue-63479-match-fnptr.rs +++ b/src/test/ui/rfc1445/issue-63479-match-fnptr.rs @@ -33,7 +33,7 @@ fn main() { let s = B(my_fn); match s { B(TEST) => println!("matched"), - //~^ WARN pointers in patterns do not behave deterministically + //~^ WARN pointers in patterns behave unpredictably //~| WARN this was previously accepted by the compiler but is being phased out _ => panic!("didn't match") }; diff --git a/src/test/ui/rfc1445/issue-63479-match-fnptr.stderr b/src/test/ui/rfc1445/issue-63479-match-fnptr.stderr index 34b9c359ca856..8cf87cc85a1d4 100644 --- a/src/test/ui/rfc1445/issue-63479-match-fnptr.stderr +++ b/src/test/ui/rfc1445/issue-63479-match-fnptr.stderr @@ -1,4 +1,4 @@ -warning: function pointers and unsized pointers in patterns do not behave deterministically. See https://github.com/rust-lang/rust/issues/70861 for details. +warning: function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/issue-63479-match-fnptr.rs:35:7 | LL | B(TEST) => println!("matched"), From 177d0cef48879c7aea8d7dc5064407c454d36124 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 23 Sep 2020 17:03:31 +0200 Subject: [PATCH 0895/1052] Deduplicate errors in const to pat conversion --- .../src/thir/pattern/const_to_pat.rs | 33 ++++++-- .../const_in_pattern/cross-crate-fail.rs | 2 - .../const_in_pattern/cross-crate-fail.stderr | 16 +--- .../const_in_pattern/no-eq-branch-fail.rs | 1 - .../const_in_pattern/no-eq-branch-fail.stderr | 8 +- .../const_in_pattern/reject_non_partial_eq.rs | 1 - .../reject_non_partial_eq.stderr | 8 +- .../const_in_pattern/reject_non_structural.rs | 10 --- .../reject_non_structural.stderr | 82 +++---------------- src/test/ui/match/issue-70972-dyn-trait.rs | 1 - .../ui/match/issue-70972-dyn-trait.stderr | 8 +- ...opaquely-typed-constant-used-in-pattern.rs | 1 - ...uely-typed-constant-used-in-pattern.stderr | 8 +- ...cant-hide-behind-direct-struct-embedded.rs | 1 - ...-hide-behind-direct-struct-embedded.stderr | 8 +- .../cant-hide-behind-direct-struct-param.rs | 1 - ...ant-hide-behind-direct-struct-param.stderr | 8 +- .../ui/rfc1445/match-forbidden-without-eq.rs | 1 - .../rfc1445/match-forbidden-without-eq.stderr | 12 +-- ...tch-nonempty-array-forbidden-without-eq.rs | 1 - ...nonempty-array-forbidden-without-eq.stderr | 8 +- .../match-requires-both-partialeq-and-eq.rs | 1 - ...atch-requires-both-partialeq-and-eq.stderr | 8 +- .../structural-match-no-leak.rs | 1 - .../structural-match-no-leak.stderr | 8 +- .../type-alias-impl-trait/structural-match.rs | 1 - .../structural-match.stderr | 8 +- src/test/ui/union/union-const-pat.rs | 1 - src/test/ui/union/union-const-pat.stderr | 8 +- 29 files changed, 55 insertions(+), 200 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 3c0dec64693fe..9af40acc6d616 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -252,7 +252,12 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { ty::Adt(adt_def, _) if adt_def.is_union() => { // Matching on union fields is unsafe, we can't hide it in constants self.saw_const_match_error.set(true); - tcx.sess.span_err(span, "cannot use unions in constant patterns"); + let msg = "cannot use unions in constant patterns"; + if self.include_lint_checks { + tcx.sess.span_err(span, msg); + } else { + tcx.sess.delay_span_bug(span, msg) + } PatKind::Wild } ty::Adt(..) @@ -267,7 +272,11 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { cv.ty, cv.ty, ); self.saw_const_match_error.set(true); - self.tcx().sess.span_err(self.span, &msg); + if self.include_lint_checks { + tcx.sess.span_err(self.span, &msg); + } else { + tcx.sess.delay_span_bug(self.span, &msg) + } PatKind::Wild } // If the type is not structurally comparable, just emit the constant directly, @@ -308,7 +317,11 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { path, path, ); self.saw_const_match_error.set(true); - tcx.sess.span_err(span, &msg); + if self.include_lint_checks { + tcx.sess.span_err(span, &msg); + } else { + tcx.sess.delay_span_bug(span, &msg) + } PatKind::Wild } ty::Adt(adt_def, substs) if adt_def.is_enum() => { @@ -340,7 +353,12 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // These are not allowed and will error elsewhere anyway. ty::Dynamic(..) => { self.saw_const_match_error.set(true); - tcx.sess.span_err(span, &format!("`{}` cannot be used in patterns", cv.ty)); + let msg = format!("`{}` cannot be used in patterns", cv.ty); + if self.include_lint_checks { + tcx.sess.span_err(span, &msg); + } else { + tcx.sess.delay_span_bug(span, &msg) + } PatKind::Wild } // `&str` and `&[u8]` are represented as `ConstValue::Slice`, let's keep using this @@ -427,7 +445,12 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { } _ => { self.saw_const_match_error.set(true); - tcx.sess.span_err(span, &format!("`{}` cannot be used in patterns", cv.ty)); + let msg = format!("`{}` cannot be used in patterns", cv.ty); + if self.include_lint_checks { + tcx.sess.span_err(span, &msg); + } else { + tcx.sess.delay_span_bug(span, &msg) + } PatKind::Wild } }; diff --git a/src/test/ui/consts/const_in_pattern/cross-crate-fail.rs b/src/test/ui/consts/const_in_pattern/cross-crate-fail.rs index 05c53e5edccc5..ab297f54dff3e 100644 --- a/src/test/ui/consts/const_in_pattern/cross-crate-fail.rs +++ b/src/test/ui/consts/const_in_pattern/cross-crate-fail.rs @@ -12,7 +12,6 @@ fn main() { match None { consts::SOME => panic!(), //~^ must be annotated with `#[derive(PartialEq, Eq)]` - //~| must be annotated with `#[derive(PartialEq, Eq)]` _ => {} } @@ -20,7 +19,6 @@ fn main() { match None { ::SOME => panic!(), //~^ must be annotated with `#[derive(PartialEq, Eq)]` - //~| must be annotated with `#[derive(PartialEq, Eq)]` _ => {} } diff --git a/src/test/ui/consts/const_in_pattern/cross-crate-fail.stderr b/src/test/ui/consts/const_in_pattern/cross-crate-fail.stderr index 95db19e342a95..a8066a88c35a6 100644 --- a/src/test/ui/consts/const_in_pattern/cross-crate-fail.stderr +++ b/src/test/ui/consts/const_in_pattern/cross-crate-fail.stderr @@ -5,22 +5,10 @@ LL | consts::SOME => panic!(), | ^^^^^^^^^^^^ error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/cross-crate-fail.rs:21:9 + --> $DIR/cross-crate-fail.rs:20:9 | LL | ::SOME => panic!(), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/cross-crate-fail.rs:13:9 - | -LL | consts::SOME => panic!(), - | ^^^^^^^^^^^^ - -error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/cross-crate-fail.rs:21:9 - | -LL | ::SOME => panic!(), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.rs b/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.rs index c7f02c615a02a..fc80d51c72daa 100644 --- a/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.rs +++ b/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.rs @@ -20,7 +20,6 @@ fn main() { match Foo::Qux(NoEq) { BAR_BAZ => panic!(), //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => {} } } diff --git a/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.stderr b/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.stderr index ee78c6f5c3e9f..e505dad69be07 100644 --- a/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.stderr +++ b/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.stderr @@ -4,11 +4,5 @@ error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated wit LL | BAR_BAZ => panic!(), | ^^^^^^^ -error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/no-eq-branch-fail.rs:21:9 - | -LL | BAR_BAZ => panic!(), - | ^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/consts/const_in_pattern/reject_non_partial_eq.rs b/src/test/ui/consts/const_in_pattern/reject_non_partial_eq.rs index b2b2daa830f89..a8216901c027f 100644 --- a/src/test/ui/consts/const_in_pattern/reject_non_partial_eq.rs +++ b/src/test/ui/consts/const_in_pattern/reject_non_partial_eq.rs @@ -27,7 +27,6 @@ fn main() { match None { NO_PARTIAL_EQ_NONE => println!("NO_PARTIAL_EQ_NONE"), //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => panic!("whoops"), } } diff --git a/src/test/ui/consts/const_in_pattern/reject_non_partial_eq.stderr b/src/test/ui/consts/const_in_pattern/reject_non_partial_eq.stderr index dc830d360031a..8462c32ea809b 100644 --- a/src/test/ui/consts/const_in_pattern/reject_non_partial_eq.stderr +++ b/src/test/ui/consts/const_in_pattern/reject_non_partial_eq.stderr @@ -4,11 +4,5 @@ error: to use a constant of type `Option` in a pattern, `Option println!("NO_PARTIAL_EQ_NONE"), | ^^^^^^^^^^^^^^^^^^ -error: to use a constant of type `Option` in a pattern, `Option` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_partial_eq.rs:28:9 - | -LL | NO_PARTIAL_EQ_NONE => println!("NO_PARTIAL_EQ_NONE"), - | ^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/consts/const_in_pattern/reject_non_structural.rs b/src/test/ui/consts/const_in_pattern/reject_non_structural.rs index bbeaeea1f87d8..7a8169bec45be 100644 --- a/src/test/ui/consts/const_in_pattern/reject_non_structural.rs +++ b/src/test/ui/consts/const_in_pattern/reject_non_structural.rs @@ -39,51 +39,41 @@ fn main() { const ENUM: Derive = Derive::Some(NoDerive); match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const FIELD: OND = TrivialEq(Some(NoDerive)).0; match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const NO_DERIVE_SOME: OND = Some(NoDerive); const INDIRECT: OND = NO_DERIVE_SOME; match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const TUPLE: (OND, OND) = (None, Some(NoDerive)); match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const TYPE_ASCRIPTION: OND = Some(NoDerive): OND; match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const ARRAY: [OND; 2] = [None, Some(NoDerive)]; match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const REPEAT: [OND; 2] = [Some(NoDerive); 2]; match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` trait Trait: Sized { const ASSOC: Option; } impl Trait for NoDerive { const ASSOC: Option = Some(NoDerive); } match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const BLOCK: OND = { NoDerive; Some(NoDerive) }; match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const ADDR_OF: &OND = &Some(NoDerive); match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), }; diff --git a/src/test/ui/consts/const_in_pattern/reject_non_structural.stderr b/src/test/ui/consts/const_in_pattern/reject_non_structural.stderr index b1310cf101eaa..56405a55d699d 100644 --- a/src/test/ui/consts/const_in_pattern/reject_non_structural.stderr +++ b/src/test/ui/consts/const_in_pattern/reject_non_structural.stderr @@ -5,61 +5,61 @@ LL | match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops" | ^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:45:28 + --> $DIR/reject_non_structural.rs:44:28 | LL | match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), }; | ^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:51:27 + --> $DIR/reject_non_structural.rs:49:27 | LL | match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), }; | ^^^^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:56:36 + --> $DIR/reject_non_structural.rs:53:36 | LL | match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), }; | ^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:61:28 + --> $DIR/reject_non_structural.rs:57:28 | LL | match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), }; | ^^^^^^^^^^^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:66:36 + --> $DIR/reject_non_structural.rs:61:36 | LL | match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), }; | ^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:71:33 + --> $DIR/reject_non_structural.rs:65:33 | LL | match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; | ^^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:71:33 + --> $DIR/reject_non_structural.rs:65:33 | LL | match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; | ^^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:79:28 + --> $DIR/reject_non_structural.rs:71:28 | LL | match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; | ^^^^^^^^^^^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:84:28 + --> $DIR/reject_non_structural.rs:75:28 | LL | match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), }; | ^^^^^ warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:89:29 + --> $DIR/reject_non_structural.rs:79:29 | LL | match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), }; | ^^^^^^^ @@ -72,65 +72,5 @@ LL | #![warn(indirect_structural_match)] = 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 #62411 -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:40:36 - | -LL | match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops"), }; - | ^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:45:28 - | -LL | match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), }; - | ^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:51:27 - | -LL | match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), }; - | ^^^^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:56:36 - | -LL | match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), }; - | ^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:61:28 - | -LL | match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), }; - | ^^^^^^^^^^^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:66:36 - | -LL | match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), }; - | ^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:71:33 - | -LL | match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; - | ^^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:71:33 - | -LL | match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; - | ^^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:79:28 - | -LL | match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; - | ^^^^^^^^^^^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:84:28 - | -LL | match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), }; - | ^^^^^ - -error: aborting due to 20 previous errors; 1 warning emitted +error: aborting due to 10 previous errors; 1 warning emitted diff --git a/src/test/ui/match/issue-70972-dyn-trait.rs b/src/test/ui/match/issue-70972-dyn-trait.rs index b69e2dab2650b..97d161c59ec2a 100644 --- a/src/test/ui/match/issue-70972-dyn-trait.rs +++ b/src/test/ui/match/issue-70972-dyn-trait.rs @@ -5,7 +5,6 @@ fn main() { match a { F => panic!(), //~^ ERROR `&dyn Send` cannot be used in patterns - //~| ERROR `&dyn Send` cannot be used in patterns _ => {} } } diff --git a/src/test/ui/match/issue-70972-dyn-trait.stderr b/src/test/ui/match/issue-70972-dyn-trait.stderr index 985799b3c8357..7581070ebc172 100644 --- a/src/test/ui/match/issue-70972-dyn-trait.stderr +++ b/src/test/ui/match/issue-70972-dyn-trait.stderr @@ -4,11 +4,5 @@ error: `&dyn Send` cannot be used in patterns LL | F => panic!(), | ^ -error: `&dyn Send` cannot be used in patterns - --> $DIR/issue-70972-dyn-trait.rs:6:9 - | -LL | F => panic!(), - | ^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs index 0c38b533a16e6..427f4cd8c780c 100644 --- a/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs +++ b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs @@ -5,7 +5,6 @@ fn main() { const C: impl Copy = 0; match C { C => {} //~ ERROR: `impl Copy` cannot be used in patterns - //~^ ERROR: `impl Copy` cannot be used in patterns _ => {} } } diff --git a/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr index ad6cc0aa3e3e9..c22e6eb944394 100644 --- a/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr +++ b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr @@ -4,11 +4,5 @@ error: `impl Copy` cannot be used in patterns LL | C => {} | ^ -error: `impl Copy` cannot be used in patterns - --> $DIR/issue-71042-opaquely-typed-constant-used-in-pattern.rs:7:9 - | -LL | C => {} - | ^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.rs b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.rs index c663535e533bd..4a8a09493798e 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.rs +++ b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.rs @@ -21,7 +21,6 @@ fn main() { match WRAP_DIRECT_INLINE { WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); } //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => { println!("WRAP_DIRECT_INLINE did not match itself"); } } } diff --git a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.stderr b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.stderr index 9c7d1f3a18fec..c73a6cf1326b3 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.stderr +++ b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.stderr @@ -4,11 +4,5 @@ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be ann LL | WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); } | ^^^^^^^^^^^^^^^^^^ -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/cant-hide-behind-direct-struct-embedded.rs:22:9 - | -LL | WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); } - | ^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.rs b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.rs index 872bf5a63fffd..93022a23dbfb8 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.rs +++ b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.rs @@ -21,7 +21,6 @@ fn main() { match WRAP_DIRECT_PARAM { WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); } //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => { println!("WRAP_DIRECT_PARAM did not match itself"); } } } diff --git a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.stderr b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.stderr index 6f49a8a0c9d21..6fdf9db89b8dc 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.stderr +++ b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.stderr @@ -4,11 +4,5 @@ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be ann LL | WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); } | ^^^^^^^^^^^^^^^^^ -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/cant-hide-behind-direct-struct-param.rs:22:9 - | -LL | WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); } - | ^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/rfc1445/match-forbidden-without-eq.rs b/src/test/ui/rfc1445/match-forbidden-without-eq.rs index 59141eac3e896..1cca27520618d 100644 --- a/src/test/ui/rfc1445/match-forbidden-without-eq.rs +++ b/src/test/ui/rfc1445/match-forbidden-without-eq.rs @@ -12,7 +12,6 @@ fn main() { match y { FOO => { } //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => { } } diff --git a/src/test/ui/rfc1445/match-forbidden-without-eq.stderr b/src/test/ui/rfc1445/match-forbidden-without-eq.stderr index 1f26f0f11dc14..02fa23981894a 100644 --- a/src/test/ui/rfc1445/match-forbidden-without-eq.stderr +++ b/src/test/ui/rfc1445/match-forbidden-without-eq.stderr @@ -5,7 +5,7 @@ LL | FOO => { } | ^^^ warning: floating-point types cannot be used in patterns - --> $DIR/match-forbidden-without-eq.rs:21:9 + --> $DIR/match-forbidden-without-eq.rs:20:9 | LL | f32::INFINITY => { } | ^^^^^^^^^^^^^ @@ -14,14 +14,8 @@ LL | f32::INFINITY => { } = 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 -error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/match-forbidden-without-eq.rs:13:9 - | -LL | FOO => { } - | ^^^ - warning: floating-point types cannot be used in patterns - --> $DIR/match-forbidden-without-eq.rs:21:9 + --> $DIR/match-forbidden-without-eq.rs:20:9 | LL | f32::INFINITY => { } | ^^^^^^^^^^^^^ @@ -29,5 +23,5 @@ LL | f32::INFINITY => { } = 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 -error: aborting due to 2 previous errors; 2 warnings emitted +error: aborting due to previous error; 2 warnings emitted diff --git a/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.rs b/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.rs index 4112e8f45179c..151a475c91906 100644 --- a/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.rs +++ b/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.rs @@ -15,6 +15,5 @@ fn main() { match [B(1)] { FOO => { } //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` } } diff --git a/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.stderr b/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.stderr index 7e354bf9ade5a..371f8a0aa1d77 100644 --- a/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.stderr +++ b/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.stderr @@ -4,11 +4,5 @@ error: to use a constant of type `B` in a pattern, `B` must be annotated with `# LL | FOO => { } | ^^^ -error: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/match-nonempty-array-forbidden-without-eq.rs:16:9 - | -LL | FOO => { } - | ^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.rs b/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.rs index 9530a1ffec453..6b7d94603b567 100644 --- a/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.rs +++ b/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.rs @@ -16,7 +16,6 @@ fn main() { match y { FOO => { } //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => { } } } diff --git a/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.stderr b/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.stderr index 7ef082852ba8d..4157cf65283e3 100644 --- a/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.stderr +++ b/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.stderr @@ -4,11 +4,5 @@ error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated wit LL | FOO => { } | ^^^ -error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/match-requires-both-partialeq-and-eq.rs:17:9 - | -LL | FOO => { } - | ^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs index 54fc4956b9b28..d50835608fad1 100644 --- a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs +++ b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs @@ -13,7 +13,6 @@ fn leak_free_test() { match todo!() { LEAK_FREE => (), //~^ `impl Send` cannot be used in patterns - //~| `impl Send` cannot be used in patterns _ => (), } } diff --git a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr index 90b44f6598df6..889c4fd4b0405 100644 --- a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr +++ b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr @@ -4,11 +4,5 @@ error: `impl Send` cannot be used in patterns LL | LEAK_FREE => (), | ^^^^^^^^^ -error: `impl Send` cannot be used in patterns - --> $DIR/structural-match-no-leak.rs:14:9 - | -LL | LEAK_FREE => (), - | ^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/structural-match.rs b/src/test/ui/type-alias-impl-trait/structural-match.rs index 5fe5bb4bdeaa8..a3ff4ad1d4705 100644 --- a/src/test/ui/type-alias-impl-trait/structural-match.rs +++ b/src/test/ui/type-alias-impl-trait/structural-match.rs @@ -14,7 +14,6 @@ fn test() { match todo!() { VALUE => (), //~^ `impl Send` cannot be used in patterns - //~| `impl Send` cannot be used in patterns _ => (), } } diff --git a/src/test/ui/type-alias-impl-trait/structural-match.stderr b/src/test/ui/type-alias-impl-trait/structural-match.stderr index 7aca3ba8640f1..262fd0726137e 100644 --- a/src/test/ui/type-alias-impl-trait/structural-match.stderr +++ b/src/test/ui/type-alias-impl-trait/structural-match.stderr @@ -4,11 +4,5 @@ error: `impl Send` cannot be used in patterns LL | VALUE => (), | ^^^^^ -error: `impl Send` cannot be used in patterns - --> $DIR/structural-match.rs:15:9 - | -LL | VALUE => (), - | ^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/union/union-const-pat.rs b/src/test/ui/union/union-const-pat.rs index cb2248cc6d189..e7cb248a201ac 100644 --- a/src/test/ui/union/union-const-pat.rs +++ b/src/test/ui/union/union-const-pat.rs @@ -8,7 +8,6 @@ const C: U = U { a: 10 }; fn main() { match C { C => {} //~ ERROR cannot use unions in constant patterns - //~| ERROR cannot use unions in constant patterns _ => {} } } diff --git a/src/test/ui/union/union-const-pat.stderr b/src/test/ui/union/union-const-pat.stderr index bec720401b9e1..dc87f4de5219f 100644 --- a/src/test/ui/union/union-const-pat.stderr +++ b/src/test/ui/union/union-const-pat.stderr @@ -4,11 +4,5 @@ error: cannot use unions in constant patterns LL | C => {} | ^ -error: cannot use unions in constant patterns - --> $DIR/union-const-pat.rs:10:9 - | -LL | C => {} - | ^ - -error: aborting due to 2 previous errors +error: aborting due to previous error From 9a7e66aeafe8debdee9b3b5e128c47034864f2b1 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 23 Sep 2020 17:52:37 +0200 Subject: [PATCH 0896/1052] Make sure we don't hide errors just because a lint has been emitted --- .../src/thir/pattern/const_to_pat.rs | 27 ++++++++++++++----- src/test/ui/consts/match_ice.rs | 6 ++--- src/test/ui/consts/match_ice.stderr | 17 ++++-------- ...nt-hide-behind-doubly-indirect-embedded.rs | 2 +- .../cant-hide-behind-doubly-indirect-param.rs | 2 +- ...nt-hide-behind-indirect-struct-embedded.rs | 2 +- .../cant-hide-behind-indirect-struct-param.rs | 2 +- ...2307-match-ref-ref-forbidden-without-eq.rs | 4 +-- 8 files changed, 34 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 9af40acc6d616..f80c60b181ebc 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -43,11 +43,16 @@ struct ConstToPat<'a, 'tcx> { span: Span, param_env: ty::ParamEnv<'tcx>, - // This tracks if we saw some error or lint for a given const value, so that + // This tracks if we emitted some hard error for a given const value, so that // we will not subsequently issue an irrelevant lint for the same const // value. saw_const_match_error: Cell, + // This tracks if we emitted some diagnostic for a given const value, so that + // we will not subsequently issue an irrelevant lint for the same const + // value. + saw_const_match_lint: Cell, + // For backcompat we need to keep allowing non-structurally-eq types behind references. // See also all the `cant-hide-behind` tests. behind_reference: Cell, @@ -75,6 +80,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { param_env: pat_ctxt.param_env, include_lint_checks: pat_ctxt.include_lint_checks, saw_const_match_error: Cell::new(false), + saw_const_match_lint: Cell::new(false), behind_reference: Cell::new(false), } } @@ -165,7 +171,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { if !self.type_has_partial_eq_impl(cv.ty) { // span_fatal avoids ICE from resolution of non-existent method (rare case). self.tcx().sess.span_fatal(self.span, &msg); - } else if mir_structural_match_violation { + } else if mir_structural_match_violation && !self.saw_const_match_lint.get() { self.tcx().struct_span_lint_hir( lint::builtin::INDIRECT_STRUCTURAL_MATCH, self.id, @@ -289,8 +295,11 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // Backwards compatibility hack because we can't cause hard errors on these // types, so we compare them via `PartialEq::eq` at runtime. ty::Adt(..) if !self.type_marked_structural(cv.ty) && self.behind_reference.get() => { - if self.include_lint_checks && !self.saw_const_match_error.get() { - self.saw_const_match_error.set(true); + if self.include_lint_checks + && !self.saw_const_match_error.get() + && !self.saw_const_match_lint.get() + { + self.saw_const_match_lint.set(true); let msg = format!( "to use a constant of type `{}` in a pattern, \ `{}` must be annotated with `#[derive(PartialEq, Eq)]`", @@ -429,8 +438,11 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // compilation choices change the runtime behaviour of the match. // See https://github.com/rust-lang/rust/issues/70861 for examples. ty::FnPtr(..) | ty::RawPtr(..) => { - if self.include_lint_checks && !self.saw_const_match_error.get() { - self.saw_const_match_error.set(true); + if self.include_lint_checks + && !self.saw_const_match_error.get() + && !self.saw_const_match_lint.get() + { + self.saw_const_match_lint.set(true); let msg = "function pointers and unsized pointers in patterns behave \ unpredictably and should not be relied upon. \ See https://github.com/rust-lang/rust/issues/70861 for details."; @@ -457,12 +469,13 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { if self.include_lint_checks && !self.saw_const_match_error.get() + && !self.saw_const_match_lint.get() && mir_structural_match_violation // FIXME(#73448): Find a way to bring const qualification into parity with // `search_for_structural_match_violation` and then remove this condition. && self.search_for_structural_match_violation(cv.ty).is_some() { - self.saw_const_match_error.set(true); + self.saw_const_match_lint.set(true); let msg = format!( "to use a constant of type `{}` in a pattern, \ the constant's initializer must be trivial or all types \ diff --git a/src/test/ui/consts/match_ice.rs b/src/test/ui/consts/match_ice.rs index db76e23007089..73ff15f212234 100644 --- a/src/test/ui/consts/match_ice.rs +++ b/src/test/ui/consts/match_ice.rs @@ -8,10 +8,10 @@ struct T; fn main() { const C: &S = &S; match C { - //~^ non-exhaustive patterns: `&S` not covered C => {} - //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN was previously accepted by the compiler + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + //~| WARN must be annotated + //~| WARN previously accepted } const K: &T = &T; match K { diff --git a/src/test/ui/consts/match_ice.stderr b/src/test/ui/consts/match_ice.stderr index 6cc79dbca7cc2..915111b3ce4b4 100644 --- a/src/test/ui/consts/match_ice.stderr +++ b/src/test/ui/consts/match_ice.stderr @@ -1,5 +1,5 @@ warning: to use a constant of type `&S` in a pattern, the constant's initializer must be trivial or all types in the constant must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/match_ice.rs:12:9 + --> $DIR/match_ice.rs:11:9 | LL | C => {} | ^ @@ -8,18 +8,11 @@ LL | C => {} = 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 #73448 -error[E0004]: non-exhaustive patterns: `&S` not covered - --> $DIR/match_ice.rs:10:11 +error: to use a constant of type `S` in a pattern, `S` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/match_ice.rs:11:9 | -LL | struct S; - | --------- `S` defined here -... -LL | match C { - | ^ pattern `&S` 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 `&S` +LL | C => {} + | ^ error: aborting due to previous error; 1 warning emitted -For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.rs b/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.rs index f6947819695a6..fe62774d220d4 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.rs +++ b/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.rs @@ -23,7 +23,7 @@ fn main() { match WRAP_DOUBLY_INDIRECT_INLINE { WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLINE matched itself"); } //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN will become a hard error in a future release + //~| WARN this was previously accepted _ => { println!("WRAP_DOUBLY_INDIRECT_INLINE correctly did not match itself"); } } } diff --git a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.rs b/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.rs index 1c29d67b65529..c3a30674ea387 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.rs +++ b/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.rs @@ -23,7 +23,7 @@ fn main() { match WRAP_DOUBLY_INDIRECT_PARAM { WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM matched itself"); } //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN will become a hard error in a future release + //~| WARN this was previously accepted _ => { println!("WRAP_DOUBLY_INDIRECT_PARAM correctly did not match itself"); } } } diff --git a/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-embedded.rs b/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-embedded.rs index 1a41dbb55c2e9..4d0e80d5af312 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-embedded.rs +++ b/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-embedded.rs @@ -23,7 +23,7 @@ fn main() { match WRAP_INDIRECT_INLINE { WRAP_INDIRECT_INLINE => { panic!("WRAP_INDIRECT_INLINE matched itself"); } //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN will become a hard error in a future release + //~| WARN this was previously accepted _ => { println!("WRAP_INDIRECT_INLINE did not match itself"); } } } diff --git a/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-param.rs b/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-param.rs index 46032c4b0ebd4..432f196ec8127 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-param.rs +++ b/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-param.rs @@ -23,7 +23,7 @@ fn main() { match WRAP_INDIRECT_PARAM { WRAP_INDIRECT_PARAM => { panic!("WRAP_INDIRECT_PARAM matched itself"); } //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN will become a hard error in a future release + //~| WARN this was previously accepted _ => { println!("WRAP_INDIRECT_PARAM correctly did not match itself"); } } } diff --git a/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.rs b/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.rs index b5e19611da83a..46d8ee3b6be9c 100644 --- a/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.rs +++ b/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.rs @@ -30,14 +30,14 @@ fn main() { match RR_B0 { RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); } //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN will become a hard error in a future release + //~| WARN this was previously accepted _ => { } } match RR_B1 { RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1); } //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN will become a hard error in a future release + //~| WARN this was previously accepted _ => { } } } From 6a33de017007233346c26a6f7b20c3e35e6b9e90 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 23 Sep 2020 17:55:14 +0200 Subject: [PATCH 0897/1052] Name function correctly --- compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index f80c60b181ebc..78b0a5a82eb55 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -168,7 +168,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { } }); - if !self.type_has_partial_eq_impl(cv.ty) { + if !self.type_may_have_partial_eq_impl(cv.ty) { // span_fatal avoids ICE from resolution of non-existent method (rare case). self.tcx().sess.span_fatal(self.span, &msg); } else if mir_structural_match_violation && !self.saw_const_match_lint.get() { @@ -190,7 +190,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { inlined_const_as_pat } - fn type_has_partial_eq_impl(&self, ty: Ty<'tcx>) -> bool { + fn type_may_have_partial_eq_impl(&self, ty: Ty<'tcx>) -> bool { // double-check there even *is* a semantic `PartialEq` to dispatch to. // // (If there isn't, then we can safely issue a hard @@ -267,7 +267,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { PatKind::Wild } ty::Adt(..) - if !self.type_has_partial_eq_impl(cv.ty) + if !self.type_may_have_partial_eq_impl(cv.ty) // FIXME(#73448): Find a way to bring const qualification into parity with // `search_for_structural_match_violation` and then remove this condition. && self.search_for_structural_match_violation(cv.ty).is_some() => From 017423179a9ea3267d0fab7bd20fd73b0cd8a528 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 23 Sep 2020 18:04:44 +0200 Subject: [PATCH 0898/1052] Make sure we report a future incompat error in all cases --- .../src/thir/pattern/const_to_pat.rs | 20 ++++++++++++++++++- src/test/ui/consts/match_ice.stderr | 6 +++--- ...ide-behind-doubly-indirect-embedded.stderr | 10 +++++++--- ...t-hide-behind-doubly-indirect-param.stderr | 10 +++++++--- ...-match-ref-ref-forbidden-without-eq.stderr | 12 +++++------ 5 files changed, 42 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 78b0a5a82eb55..cf731a076ff0a 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -408,7 +408,25 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // this pattern to a `PartialEq::eq` comparison and `PartialEq::eq` takes a // reference. This makes the rest of the matching logic simpler as it doesn't have // to figure out how to get a reference again. - ty::Adt(..) if !self.type_marked_structural(pointee_ty) => { + ty::Adt(adt_def, _) if !self.type_marked_structural(pointee_ty) => { + if self.include_lint_checks + && !self.saw_const_match_error.get() + && !self.saw_const_match_lint.get() + { + self.saw_const_match_lint.set(true); + let path = self.tcx().def_path_str(adt_def.did); + let msg = format!( + "to use a constant of type `{}` in a pattern, \ + `{}` must be annotated with `#[derive(PartialEq, Eq)]`", + path, path, + ); + self.tcx().struct_span_lint_hir( + lint::builtin::INDIRECT_STRUCTURAL_MATCH, + self.id, + self.span, + |lint| lint.build(&msg).emit(), + ); + } PatKind::Constant { value: cv } } // All other references are converted into deref patterns and then recursively diff --git a/src/test/ui/consts/match_ice.stderr b/src/test/ui/consts/match_ice.stderr index 915111b3ce4b4..c46f2c2e97236 100644 --- a/src/test/ui/consts/match_ice.stderr +++ b/src/test/ui/consts/match_ice.stderr @@ -1,12 +1,12 @@ -warning: to use a constant of type `&S` in a pattern, the constant's initializer must be trivial or all types in the constant must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `S` in a pattern, `S` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/match_ice.rs:11:9 | LL | C => {} | ^ | - = note: `#[warn(nontrivial_structural_match)]` on by default + = note: `#[warn(indirect_structural_match)]` 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 #73448 + = note: for more information, see issue #62411 error: to use a constant of type `S` in a pattern, `S` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/match_ice.rs:11:9 diff --git a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.stderr b/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.stderr index eb13eed6ec11b..659a981267233 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.stderr +++ b/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.stderr @@ -1,12 +1,16 @@ -warning: to use a constant of type `&&WrapInline` in a pattern, the constant's initializer must be trivial or all types in the constant must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/cant-hide-behind-doubly-indirect-embedded.rs:24:9 | LL | WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLINE matched itself"); } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `#[warn(nontrivial_structural_match)]` on by default +note: the lint level is defined here + --> $DIR/cant-hide-behind-doubly-indirect-embedded.rs:7:9 + | +LL | #![warn(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ = 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 #73448 + = note: for more information, see issue #62411 warning: 1 warning emitted diff --git a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.stderr b/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.stderr index ddee99e76bbb9..c8c36510542a2 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.stderr +++ b/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.stderr @@ -1,12 +1,16 @@ -warning: to use a constant of type `&&WrapParam` in a pattern, the constant's initializer must be trivial or all types in the constant must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/cant-hide-behind-doubly-indirect-param.rs:24:9 | LL | WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM matched itself"); } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `#[warn(nontrivial_structural_match)]` on by default +note: the lint level is defined here + --> $DIR/cant-hide-behind-doubly-indirect-param.rs:7:9 + | +LL | #![warn(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ = 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 #73448 + = note: for more information, see issue #62411 warning: 1 warning emitted diff --git a/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.stderr b/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.stderr index 7f4b4923332a4..a50093a5b1128 100644 --- a/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.stderr +++ b/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.stderr @@ -1,25 +1,25 @@ -warning: to use a constant of type `&&B` in a pattern, the constant's initializer must be trivial or all types in the constant must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:31:9 | LL | RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); } | ^^^^^ | note: the lint level is defined here - --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:13:36 + --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:13:9 | LL | #![warn(indirect_structural_match, nontrivial_structural_match)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ = 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 #73448 + = note: for more information, see issue #62411 -warning: to use a constant of type `&&B` in a pattern, the constant's initializer must be trivial or all types in the constant must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:38:9 | LL | RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1); } | ^^^^^ | = 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 #73448 + = note: for more information, see issue #62411 warning: 2 warnings emitted From 05f84c67a4f38136b1a7be9065781611061a23d3 Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Wed, 23 Sep 2020 18:25:55 +0200 Subject: [PATCH 0899/1052] Ignore test on wasm as it does not unwind --- ...annot_opt_generic.RemoveUnneededDrops.diff | 24 +++++++++---------- ...ed_drops.dont_opt.RemoveUnneededDrops.diff | 24 +++++++++---------- ...nneeded_drops.opt.RemoveUnneededDrops.diff | 22 ++++++++--------- ....opt_generic_copy.RemoveUnneededDrops.diff | 22 ++++++++--------- src/test/mir-opt/remove_unneeded_drops.rs | 1 + 5 files changed, 47 insertions(+), 46 deletions(-) diff --git a/src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff index 545ad2794ee17..787cf6f97c1f2 100644 --- a/src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff +++ b/src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff @@ -2,31 +2,31 @@ + // MIR for `cannot_opt_generic` after RemoveUnneededDrops fn cannot_opt_generic(_1: T) -> () { - debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:19:26: 19:27 - let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:19:32: 19:32 - let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:20:5: 20:12 - let mut _3: T; // in scope 0 at $DIR/remove_unneeded_drops.rs:20:10: 20:11 + debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:20:26: 20:27 + let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:20:32: 20:32 + let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:21:5: 21:12 + let mut _3: T; // in scope 0 at $DIR/remove_unneeded_drops.rs:21:10: 21:11 scope 1 { debug _x => _3; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL } bb0: { - StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:20:5: 20:12 - StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:20:10: 20:11 - _3 = move _1; // scope 0 at $DIR/remove_unneeded_drops.rs:20:10: 20:11 + StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:21:5: 21:12 + StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:21:10: 21:11 + _3 = move _1; // scope 0 at $DIR/remove_unneeded_drops.rs:21:10: 21:11 _2 = const (); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL drop(_3) -> [return: bb2, unwind: bb1]; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL } bb1 (cleanup): { - resume; // scope 0 at $DIR/remove_unneeded_drops.rs:19:1: 21:2 + resume; // scope 0 at $DIR/remove_unneeded_drops.rs:20:1: 22:2 } bb2: { - StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:20:11: 20:12 - StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:20:12: 20:13 - _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:19:32: 21:2 - return; // scope 0 at $DIR/remove_unneeded_drops.rs:21:2: 21:2 + StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:21:11: 21:12 + StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:21:12: 21:13 + _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:20:32: 22:2 + return; // scope 0 at $DIR/remove_unneeded_drops.rs:22:2: 22:2 } } diff --git a/src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff index 78d65d13bd1bf..52e182eeb4a8a 100644 --- a/src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff +++ b/src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff @@ -2,31 +2,31 @@ + // MIR for `dont_opt` after RemoveUnneededDrops fn dont_opt(_1: Vec) -> () { - debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:7:13: 7:14 - let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:7:27: 7:27 - let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:8:5: 8:12 - let mut _3: std::vec::Vec; // in scope 0 at $DIR/remove_unneeded_drops.rs:8:10: 8:11 + debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:8:13: 8:14 + let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:8:27: 8:27 + let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:9:5: 9:12 + let mut _3: std::vec::Vec; // in scope 0 at $DIR/remove_unneeded_drops.rs:9:10: 9:11 scope 1 { debug _x => _3; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL } bb0: { - StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:8:5: 8:12 - StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:8:10: 8:11 - _3 = move _1; // scope 0 at $DIR/remove_unneeded_drops.rs:8:10: 8:11 + StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:9:5: 9:12 + StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:9:10: 9:11 + _3 = move _1; // scope 0 at $DIR/remove_unneeded_drops.rs:9:10: 9:11 _2 = const (); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL drop(_3) -> [return: bb2, unwind: bb1]; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL } bb1 (cleanup): { - resume; // scope 0 at $DIR/remove_unneeded_drops.rs:7:1: 9:2 + resume; // scope 0 at $DIR/remove_unneeded_drops.rs:8:1: 10:2 } bb2: { - StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:8:11: 8:12 - StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:8:12: 8:13 - _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:7:27: 9:2 - return; // scope 0 at $DIR/remove_unneeded_drops.rs:9:2: 9:2 + StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:9:11: 9:12 + StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:9:12: 9:13 + _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:8:27: 10:2 + return; // scope 0 at $DIR/remove_unneeded_drops.rs:10:2: 10:2 } } diff --git a/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff index eba839cf0a48b..bc9e1344f3176 100644 --- a/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff +++ b/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff @@ -2,27 +2,27 @@ + // MIR for `opt` after RemoveUnneededDrops fn opt(_1: bool) -> () { - debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:2:8: 2:9 - let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:2:17: 2:17 - let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:3:5: 3:12 - let mut _3: bool; // in scope 0 at $DIR/remove_unneeded_drops.rs:3:10: 3:11 + debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:3:8: 3:9 + let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:3:17: 3:17 + let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:4:5: 4:12 + let mut _3: bool; // in scope 0 at $DIR/remove_unneeded_drops.rs:4:10: 4:11 scope 1 { debug _x => _3; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL } bb0: { - StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:3:5: 3:12 - StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:3:10: 3:11 - _3 = _1; // scope 0 at $DIR/remove_unneeded_drops.rs:3:10: 3:11 + StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:4:5: 4:12 + StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:4:10: 4:11 + _3 = _1; // scope 0 at $DIR/remove_unneeded_drops.rs:4:10: 4:11 _2 = const (); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - drop(_3) -> bb1; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - } - - bb1: { - StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:3:11: 3:12 - StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:3:12: 3:13 - _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:2:17: 4:2 - return; // scope 0 at $DIR/remove_unneeded_drops.rs:4:2: 4:2 + StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:4:11: 4:12 + StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:4:12: 4:13 + _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:3:17: 5:2 + return; // scope 0 at $DIR/remove_unneeded_drops.rs:5:2: 5:2 } } diff --git a/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff index 840b1ba30fb9b..5c8b1d1372115 100644 --- a/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff +++ b/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff @@ -2,27 +2,27 @@ + // MIR for `opt_generic_copy` after RemoveUnneededDrops fn opt_generic_copy(_1: T) -> () { - debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:12:30: 12:31 - let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:12:36: 12:36 - let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:13:5: 13:12 - let mut _3: T; // in scope 0 at $DIR/remove_unneeded_drops.rs:13:10: 13:11 + debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:13:30: 13:31 + let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:13:36: 13:36 + let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:14:5: 14:12 + let mut _3: T; // in scope 0 at $DIR/remove_unneeded_drops.rs:14:10: 14:11 scope 1 { debug _x => _3; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL } bb0: { - StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:13:5: 13:12 - StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:13:10: 13:11 - _3 = _1; // scope 0 at $DIR/remove_unneeded_drops.rs:13:10: 13:11 + StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:14:5: 14:12 + StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:14:10: 14:11 + _3 = _1; // scope 0 at $DIR/remove_unneeded_drops.rs:14:10: 14:11 _2 = const (); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - drop(_3) -> bb1; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - } - - bb1: { - StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:13:11: 13:12 - StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:13:12: 13:13 - _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:12:36: 14:2 - return; // scope 0 at $DIR/remove_unneeded_drops.rs:14:2: 14:2 + StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:14:11: 14:12 + StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:14:12: 14:13 + _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:13:36: 15:2 + return; // scope 0 at $DIR/remove_unneeded_drops.rs:15:2: 15:2 } } diff --git a/src/test/mir-opt/remove_unneeded_drops.rs b/src/test/mir-opt/remove_unneeded_drops.rs index 17d7e79a1eb0a..1052f2886770d 100644 --- a/src/test/mir-opt/remove_unneeded_drops.rs +++ b/src/test/mir-opt/remove_unneeded_drops.rs @@ -1,3 +1,4 @@ +// ignore-wasm32-bare compiled with panic=abort by default // EMIT_MIR remove_unneeded_drops.opt.RemoveUnneededDrops.diff fn opt(x: bool) { drop(x); From da217644a1e6fdf97ea745d5f3bc527477e4a3f6 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 23 Sep 2020 18:36:53 +0200 Subject: [PATCH 0900/1052] Make sure we keep emitting a hard error --- .../src/thir/pattern/const_to_pat.rs | 54 ++++++++++++------- src/test/ui/consts/match_ice.rs | 2 - src/test/ui/consts/match_ice.stderr | 12 +---- 3 files changed, 37 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index cf731a076ff0a..5025bacafa1db 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -409,25 +409,43 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // reference. This makes the rest of the matching logic simpler as it doesn't have // to figure out how to get a reference again. ty::Adt(adt_def, _) if !self.type_marked_structural(pointee_ty) => { - if self.include_lint_checks - && !self.saw_const_match_error.get() - && !self.saw_const_match_lint.get() - { - self.saw_const_match_lint.set(true); - let path = self.tcx().def_path_str(adt_def.did); - let msg = format!( - "to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - path, path, - ); - self.tcx().struct_span_lint_hir( - lint::builtin::INDIRECT_STRUCTURAL_MATCH, - self.id, - self.span, - |lint| lint.build(&msg).emit(), - ); + if self.behind_reference.get() { + if self.include_lint_checks + && !self.saw_const_match_error.get() + && !self.saw_const_match_lint.get() + { + self.saw_const_match_lint.set(true); + let path = self.tcx().def_path_str(adt_def.did); + let msg = format!( + "to use a constant of type `{}` in a pattern, \ + `{}` must be annotated with `#[derive(PartialEq, Eq)]`", + path, path, + ); + self.tcx().struct_span_lint_hir( + lint::builtin::INDIRECT_STRUCTURAL_MATCH, + self.id, + self.span, + |lint| lint.build(&msg).emit(), + ); + } + PatKind::Constant { value: cv } + } else { + if !self.saw_const_match_error.get() { + self.saw_const_match_error.set(true); + let path = self.tcx().def_path_str(adt_def.did); + let msg = format!( + "to use a constant of type `{}` in a pattern, \ + `{}` must be annotated with `#[derive(PartialEq, Eq)]`", + path, path, + ); + if self.include_lint_checks { + tcx.sess.span_err(span, &msg); + } else { + tcx.sess.delay_span_bug(span, &msg) + } + } + PatKind::Wild } - PatKind::Constant { value: cv } } // All other references are converted into deref patterns and then recursively // convert the dereferenced constant to a pattern that is the sub-pattern of the diff --git a/src/test/ui/consts/match_ice.rs b/src/test/ui/consts/match_ice.rs index 73ff15f212234..632335c841e3a 100644 --- a/src/test/ui/consts/match_ice.rs +++ b/src/test/ui/consts/match_ice.rs @@ -10,8 +10,6 @@ fn main() { match C { C => {} //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN must be annotated - //~| WARN previously accepted } const K: &T = &T; match K { diff --git a/src/test/ui/consts/match_ice.stderr b/src/test/ui/consts/match_ice.stderr index c46f2c2e97236..699b4a5e200e4 100644 --- a/src/test/ui/consts/match_ice.stderr +++ b/src/test/ui/consts/match_ice.stderr @@ -1,18 +1,8 @@ -warning: to use a constant of type `S` in a pattern, `S` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/match_ice.rs:11:9 - | -LL | C => {} - | ^ - | - = note: `#[warn(indirect_structural_match)]` 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 #62411 - error: to use a constant of type `S` in a pattern, `S` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/match_ice.rs:11:9 | LL | C => {} | ^ -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error From 9aa1c0934cffb5a6f83cdd3943873e6b973382f9 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 23 Sep 2020 18:55:27 +0200 Subject: [PATCH 0901/1052] Update documentation tests --- compiler/rustc_session/src/lint/builtin.rs | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_session/src/lint/builtin.rs b/compiler/rustc_session/src/lint/builtin.rs index b39e01a009eb2..8e1c843ae6134 100644 --- a/compiler/rustc_session/src/lint/builtin.rs +++ b/compiler/rustc_session/src/lint/builtin.rs @@ -2239,23 +2239,13 @@ declare_lint! { /// ```rust,compile_fail /// #![deny(nontrivial_structural_match)] /// - /// struct Plus(i32, i32); - /// const ONE_PLUS_TWO: &&Plus = &&Plus(1, 2); - /// - /// impl PartialEq for Plus { - /// fn eq(&self, other: &Self) -> bool { - /// self.0 + self.1 == other.0 + other.1 - /// } - /// } - /// - /// impl Eq for Plus {} - /// + /// #[derive(Copy, Clone, Debug)] + /// struct NoDerive(u32); + /// impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + /// impl Eq for NoDerive { } /// fn main() { - /// if let ONE_PLUS_TWO = &&Plus(3, 0) { - /// println!("semantic!"); - /// } else { - /// println!("structural!"); - /// } + /// const INDEX: Option = [None, Some(NoDerive(10))][0]; + /// match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), }; /// } /// ``` /// From 90c7731f6cca6e4c741c5f465b307b4ac4a7f31f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 23 Sep 2020 15:54:21 +0200 Subject: [PATCH 0902/1052] Enable const prop into operands at mir_opt_level=2 --- compiler/rustc_mir/src/transform/const_prop.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs index aa88719c26a49..0f04ead94dd33 100644 --- a/compiler/rustc_mir/src/transform/const_prop.rs +++ b/compiler/rustc_mir/src/transform/const_prop.rs @@ -1046,9 +1046,9 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) { self.super_operand(operand, location); - // Only const prop copies and moves on `mir_opt_level=3` as doing so - // currently increases compile time. - if self.tcx.sess.opts.debugging_opts.mir_opt_level >= 3 { + // Only const prop copies and moves on `mir_opt_level=2` as doing so + // currently slightly increases compile time in some cases. + if self.tcx.sess.opts.debugging_opts.mir_opt_level >= 2 { self.propagate_operand(operand) } } @@ -1246,8 +1246,8 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { | TerminatorKind::InlineAsm { .. } => {} // Every argument in our function calls have already been propagated in `visit_operand`. // - // NOTE: because LLVM codegen gives performance regressions with it, so this is gated - // on `mir_opt_level=3`. + // NOTE: because LLVM codegen gives slight performance regressions with it, so this is + // gated on `mir_opt_level=2`. TerminatorKind::Call { .. } => {} } From dd66ea2d3d78727eb3d3574f4f6fbe82085d9ee2 Mon Sep 17 00:00:00 2001 From: Erik Hofmayer Date: Wed, 23 Sep 2020 21:14:43 +0200 Subject: [PATCH 0903/1052] Updated html_root_url for compiler crates --- compiler/rustc_apfloat/src/lib.rs | 2 +- compiler/rustc_arena/src/lib.rs | 2 +- compiler/rustc_ast/src/lib.rs | 2 +- compiler/rustc_builtin_macros/src/lib.rs | 2 +- compiler/rustc_codegen_llvm/src/lib.rs | 2 +- compiler/rustc_codegen_ssa/src/lib.rs | 2 +- compiler/rustc_data_structures/src/lib.rs | 2 +- compiler/rustc_driver/src/lib.rs | 2 +- compiler/rustc_errors/src/lib.rs | 2 +- compiler/rustc_graphviz/src/lib.rs | 2 +- compiler/rustc_incremental/src/lib.rs | 2 +- compiler/rustc_infer/src/lib.rs | 2 +- compiler/rustc_lint/src/lib.rs | 2 +- compiler/rustc_llvm/src/lib.rs | 2 +- compiler/rustc_metadata/src/lib.rs | 2 +- compiler/rustc_middle/src/lib.rs | 2 +- compiler/rustc_parse_format/src/lib.rs | 2 +- compiler/rustc_passes/src/lib.rs | 2 +- compiler/rustc_plugin_impl/src/lib.rs | 2 +- compiler/rustc_privacy/src/lib.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 2 +- compiler/rustc_save_analysis/src/lib.rs | 2 +- compiler/rustc_serialize/src/lib.rs | 2 +- compiler/rustc_span/src/lib.rs | 2 +- compiler/rustc_symbol_mangling/src/lib.rs | 2 +- compiler/rustc_target/src/lib.rs | 2 +- compiler/rustc_trait_selection/src/lib.rs | 2 +- compiler/rustc_ty/src/lib.rs | 2 +- compiler/rustc_typeck/src/lib.rs | 2 +- 29 files changed, 29 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_apfloat/src/lib.rs b/compiler/rustc_apfloat/src/lib.rs index ba3adc4a135cb..7c96be4f479a1 100644 --- a/compiler/rustc_apfloat/src/lib.rs +++ b/compiler/rustc_apfloat/src/lib.rs @@ -30,7 +30,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![no_std] #![forbid(unsafe_code)] #![feature(nll)] diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 6f9cccf58dd01..86a0fb64f2c73 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -8,7 +8,7 @@ //! This crate implements several kinds of arena. #![doc( - html_root_url = "https://doc.rust-lang.org/nightly/", + html_root_url = "https://doc.rust-lang.org/nightly-rustc/", test(no_crate_inject, attr(deny(warnings))) )] #![feature(dropck_eyepatch)] diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 480a5d2f18eca..2072462baa025 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -4,7 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/", test(attr(deny(warnings))))] #![feature(box_syntax)] #![feature(const_fn)] // For the `transmute` in `P::new` #![feature(const_fn_transmute)] diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 87be6d1743a2a..6bffad3661567 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -1,7 +1,7 @@ //! This crate contains implementations of built-in macros and other code generating facilities //! injecting code into the crate before it is lowered to HIR. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 2e2abe9fb30f8..64c58775f49c3 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -4,7 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(bool_to_option)] #![feature(const_cstr_unchecked)] #![feature(crate_visibility_modifier)] diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index a87ce1446ba14..16babec6255e7 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(bool_to_option)] #![feature(option_expect_none)] #![feature(box_patterns)] diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 1f977805f5e90..e037169b252dd 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -6,7 +6,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![allow(incomplete_features)] #![feature(array_windows)] #![feature(control_flow_enum)] diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 972e04fd101f0..5316fedee10ab 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -4,7 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(nll)] #![feature(once_cell)] #![recursion_limit = "256"] diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index b16fe5603c100..b221219bedd07 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -2,7 +2,7 @@ //! //! This module contains the code for creating and emitting diagnostics. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(crate_visibility_modifier)] #![feature(backtrace)] #![feature(nll)] diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs index 58db81bc1dc61..4bd334e15e118 100644 --- a/compiler/rustc_graphviz/src/lib.rs +++ b/compiler/rustc_graphviz/src/lib.rs @@ -272,7 +272,7 @@ //! * [DOT language](http://www.graphviz.org/doc/info/lang.html) #![doc( - html_root_url = "https://doc.rust-lang.org/nightly/", + html_root_url = "https://doc.rust-lang.org/nightly-rustc/", test(attr(allow(unused_variables), deny(warnings))) )] #![feature(nll)] diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs index ad18913805467..bcd700e5ac1e6 100644 --- a/compiler/rustc_incremental/src/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -1,6 +1,6 @@ //! Support for serializing the dep-graph and reloading it. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(in_band_lifetimes)] #![feature(nll)] #![recursion_limit = "256"] diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 504b66bae7329..99bec24b86844 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -12,7 +12,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index b48592c103ca2..c4832aa85e46a 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -25,7 +25,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![cfg_attr(test, feature(test))] #![feature(array_windows)] #![feature(bool_to_option)] diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index 9d23397ade08e..dfcb6d04b6fab 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -1,6 +1,6 @@ #![feature(nll)] #![feature(static_nobundle)] -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] // NOTE: This crate only exists to allow linking on mingw targets. diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 85490f5f6e91a..4011521d23739 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(bool_to_option)] #![feature(core_intrinsics)] #![feature(crate_visibility_modifier)] diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 74cb3c130b7f0..86ceaca9b044b 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -22,7 +22,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(array_windows)] #![feature(backtrace)] #![feature(bool_to_option)] diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index cef632b1d8f03..a0d64107c9185 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -5,7 +5,7 @@ //! generated instead. #![doc( - html_root_url = "https://doc.rust-lang.org/nightly/", + html_root_url = "https://doc.rust-lang.org/nightly-rustc/", html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))) )] diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index be4c542ec3a1d..08e152cf5ee39 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -4,7 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(or_patterns)] diff --git a/compiler/rustc_plugin_impl/src/lib.rs b/compiler/rustc_plugin_impl/src/lib.rs index 1eb65dd96ba57..efa2f6e96f948 100644 --- a/compiler/rustc_plugin_impl/src/lib.rs +++ b/compiler/rustc_plugin_impl/src/lib.rs @@ -6,7 +6,7 @@ //! feature](https://doc.rust-lang.org/nightly/unstable-book/language-features/plugin.html) //! of the Unstable Book for some examples. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(nll)] #![recursion_limit = "256"] diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index c2de4cdbf0dd5..0b45d7792604c 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(in_band_lifetimes)] #![feature(nll)] #![recursion_limit = "256"] diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 677cf27cde71c..a34572e7f36fa 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -8,7 +8,7 @@ //! //! Type-relative name resolution (methods, fields, associated items) happens in `librustc_typeck`. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(nll)] diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index 032d7cb3ed6b7..af001594b20d2 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(nll)] #![feature(or_patterns)] #![recursion_limit = "256"] diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index 265b3b95e956a..fa6f5ab3db62a 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -5,7 +5,7 @@ Core encoding and decoding interfaces. */ #![doc( - html_root_url = "https://doc.rust-lang.org/nightly/", + html_root_url = "https://doc.rust-lang.org/nightly-rustc/", html_playground_url = "https://play.rust-lang.org/", test(attr(allow(unused_variables), deny(warnings))) )] diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 4b02a2d4076d7..20b2eff8555db 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -4,7 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(array_windows)] #![feature(crate_visibility_modifier)] #![feature(const_fn)] diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 296b40c4e395d..c15cb4bf6c5ed 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -87,7 +87,7 @@ //! virtually impossible. Thus, symbol hash generation exclusively relies on //! DefPaths which are much more robust in the face of changes to the code base. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(never_type)] #![feature(nll)] #![feature(or_patterns)] diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index 5788e1e838598..eacc1d0c23d17 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -7,7 +7,7 @@ //! more 'stuff' here in the future. It does not have a dependency on //! LLVM. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(bool_to_option)] #![feature(const_fn)] #![feature(const_panic)] diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index da1996b92a60b..b9e300a3ec1a1 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -10,7 +10,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(drain_filter)] diff --git a/compiler/rustc_ty/src/lib.rs b/compiler/rustc_ty/src/lib.rs index 8dd6aa3c7fcc1..9f6a310033b7b 100644 --- a/compiler/rustc_ty/src/lib.rs +++ b/compiler/rustc_ty/src/lib.rs @@ -4,7 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(nll)] #![recursion_limit = "256"] diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 0e9f4476c2075..7ee62c77dbfb8 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -55,7 +55,7 @@ This API is completely unstable and subject to change. */ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![allow(non_camel_case_types)] #![feature(bool_to_option)] #![feature(box_syntax)] From 947536fca06e6dc6c3a3dd4ff1f66fc5080e9cbb Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Mon, 7 Sep 2020 17:43:48 +0200 Subject: [PATCH 0904/1052] Make delegation methods of `std::net::IpAddr` unstable const Make the following methods of `std::net::IpAddr` unstable const under the `const_ip` feature: - `is_unspecified` - `is_loopback` - `is_global` - `is_multicast` Also adds a test for these methods in a const context. Possible because these methods delegate to the inner `Ipv4Addr` or `Ipv6Addr`, which were made const, and the recent stabilization of const control flow. Part of #76205 --- library/std/src/lib.rs | 1 + library/std/src/net/ip.rs | 15 ++++++++++----- library/std/src/net/ip/tests.rs | 19 +++++++++++++++++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 309657e70424b..ac0075ad129c5 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -238,6 +238,7 @@ #![feature(const_cstr_unchecked)] #![feature(const_fn_transmute)] #![feature(const_fn)] +#![feature(const_ip)] #![feature(const_ipv6)] #![feature(const_raw_ptr_deref)] #![feature(const_ipv4)] diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index e2fc7edb87e2c..f01a7b72a6559 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -148,8 +148,9 @@ impl IpAddr { /// assert_eq!(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)).is_unspecified(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)).is_unspecified(), true); /// ``` + #[rustc_const_unstable(feature = "const_ip", issue = "76205")] #[stable(feature = "ip_shared", since = "1.12.0")] - pub fn is_unspecified(&self) -> bool { + pub const fn is_unspecified(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_unspecified(), IpAddr::V6(ip) => ip.is_unspecified(), @@ -169,8 +170,9 @@ impl IpAddr { /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).is_loopback(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1)).is_loopback(), true); /// ``` + #[rustc_const_unstable(feature = "const_ip", issue = "76205")] #[stable(feature = "ip_shared", since = "1.12.0")] - pub fn is_loopback(&self) -> bool { + pub const fn is_loopback(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_loopback(), IpAddr::V6(ip) => ip.is_loopback(), @@ -192,7 +194,8 @@ impl IpAddr { /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), true); /// ``` - pub fn is_global(&self) -> bool { + #[rustc_const_unstable(feature = "const_ip", issue = "76205")] + pub const fn is_global(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_global(), IpAddr::V6(ip) => ip.is_global(), @@ -212,8 +215,9 @@ impl IpAddr { /// assert_eq!(IpAddr::V4(Ipv4Addr::new(224, 254, 0, 0)).is_multicast(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0)).is_multicast(), true); /// ``` + #[rustc_const_unstable(feature = "const_ip", issue = "76205")] #[stable(feature = "ip_shared", since = "1.12.0")] - pub fn is_multicast(&self) -> bool { + pub const fn is_multicast(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_multicast(), IpAddr::V6(ip) => ip.is_multicast(), @@ -238,7 +242,8 @@ impl IpAddr { /// true /// ); /// ``` - pub fn is_documentation(&self) -> bool { + #[rustc_const_unstable(feature = "const_ip", issue = "76205")] + pub const fn is_documentation(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_documentation(), IpAddr::V6(ip) => ip.is_documentation(), diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs index 76a0ae8b9454d..d9fbdd1b5e794 100644 --- a/library/std/src/net/ip/tests.rs +++ b/library/std/src/net/ip/tests.rs @@ -918,3 +918,22 @@ fn ipv6_const() { const IP_V4: Option = IP_ADDRESS.to_ipv4(); assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1)); } + +#[test] +fn ip_const() { + // test that the methods of `IpAddr` are usable in a const context + + const IP_ADDRESS: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST); + + const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified(); + assert!(!IS_UNSPECIFIED); + + const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback(); + assert!(IS_LOOPBACK); + + const IS_GLOBAL: bool = IP_ADDRESS.is_global(); + assert!(!IS_GLOBAL); + + const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); + assert!(!IS_MULTICAST); +} From 138a2e5eaaafeee8b981045857f9df18ef4689d5 Mon Sep 17 00:00:00 2001 From: Erik Hofmayer Date: Wed, 23 Sep 2020 21:51:56 +0200 Subject: [PATCH 0905/1052] /nightly/nightly-rustc --- compiler/rustc_apfloat/src/lib.rs | 2 +- compiler/rustc_arena/src/lib.rs | 2 +- compiler/rustc_ast/src/lib.rs | 2 +- compiler/rustc_builtin_macros/src/lib.rs | 2 +- compiler/rustc_codegen_llvm/src/lib.rs | 2 +- compiler/rustc_codegen_ssa/src/lib.rs | 2 +- compiler/rustc_data_structures/src/lib.rs | 2 +- compiler/rustc_driver/src/lib.rs | 2 +- compiler/rustc_errors/src/lib.rs | 2 +- compiler/rustc_graphviz/src/lib.rs | 2 +- compiler/rustc_incremental/src/lib.rs | 2 +- compiler/rustc_infer/src/lib.rs | 2 +- compiler/rustc_lint/src/lib.rs | 2 +- compiler/rustc_llvm/src/lib.rs | 2 +- compiler/rustc_metadata/src/lib.rs | 2 +- compiler/rustc_middle/src/lib.rs | 2 +- compiler/rustc_parse_format/src/lib.rs | 2 +- compiler/rustc_passes/src/lib.rs | 2 +- compiler/rustc_plugin_impl/src/lib.rs | 2 +- compiler/rustc_privacy/src/lib.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 2 +- compiler/rustc_save_analysis/src/lib.rs | 2 +- compiler/rustc_serialize/src/lib.rs | 2 +- compiler/rustc_span/src/lib.rs | 2 +- compiler/rustc_symbol_mangling/src/lib.rs | 2 +- compiler/rustc_target/src/lib.rs | 2 +- compiler/rustc_trait_selection/src/lib.rs | 2 +- compiler/rustc_ty/src/lib.rs | 2 +- compiler/rustc_typeck/src/lib.rs | 2 +- 29 files changed, 29 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_apfloat/src/lib.rs b/compiler/rustc_apfloat/src/lib.rs index 7c96be4f479a1..4a845fcb6917b 100644 --- a/compiler/rustc_apfloat/src/lib.rs +++ b/compiler/rustc_apfloat/src/lib.rs @@ -30,7 +30,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![no_std] #![forbid(unsafe_code)] #![feature(nll)] diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 86a0fb64f2c73..152f0f1ab2a6f 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -8,7 +8,7 @@ //! This crate implements several kinds of arena. #![doc( - html_root_url = "https://doc.rust-lang.org/nightly-rustc/", + html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(no_crate_inject, attr(deny(warnings))) )] #![feature(dropck_eyepatch)] diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 2072462baa025..765a21fd93e1b 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -4,7 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/", test(attr(deny(warnings))))] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(attr(deny(warnings))))] #![feature(box_syntax)] #![feature(const_fn)] // For the `transmute` in `P::new` #![feature(const_fn_transmute)] diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 6bffad3661567..97cadb913cacf 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -1,7 +1,7 @@ //! This crate contains implementations of built-in macros and other code generating facilities //! injecting code into the crate before it is lowered to HIR. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 64c58775f49c3..456e9c7ce75fa 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -4,7 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(const_cstr_unchecked)] #![feature(crate_visibility_modifier)] diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 16babec6255e7..8568bd64f4c4f 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(option_expect_none)] #![feature(box_patterns)] diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index e037169b252dd..b0b7f9058f973 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -6,7 +6,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![allow(incomplete_features)] #![feature(array_windows)] #![feature(control_flow_enum)] diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 5316fedee10ab..7118437c0c850 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -4,7 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(nll)] #![feature(once_cell)] #![recursion_limit = "256"] diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index b221219bedd07..2e8a4ef327ac4 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -2,7 +2,7 @@ //! //! This module contains the code for creating and emitting diagnostics. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(crate_visibility_modifier)] #![feature(backtrace)] #![feature(nll)] diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs index 4bd334e15e118..76e33bed97f27 100644 --- a/compiler/rustc_graphviz/src/lib.rs +++ b/compiler/rustc_graphviz/src/lib.rs @@ -272,7 +272,7 @@ //! * [DOT language](http://www.graphviz.org/doc/info/lang.html) #![doc( - html_root_url = "https://doc.rust-lang.org/nightly-rustc/", + html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(attr(allow(unused_variables), deny(warnings))) )] #![feature(nll)] diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs index bcd700e5ac1e6..a80c4be3e9335 100644 --- a/compiler/rustc_incremental/src/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -1,6 +1,6 @@ //! Support for serializing the dep-graph and reloading it. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(in_band_lifetimes)] #![feature(nll)] #![recursion_limit = "256"] diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 99bec24b86844..ea9a46613484a 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -12,7 +12,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index c4832aa85e46a..7f7472d9283b8 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -25,7 +25,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![cfg_attr(test, feature(test))] #![feature(array_windows)] #![feature(bool_to_option)] diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index dfcb6d04b6fab..a7a10b91b4eca 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -1,6 +1,6 @@ #![feature(nll)] #![feature(static_nobundle)] -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] // NOTE: This crate only exists to allow linking on mingw targets. diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 4011521d23739..77766be7397c7 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(core_intrinsics)] #![feature(crate_visibility_modifier)] diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 86ceaca9b044b..fa885ce2e7cdf 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -22,7 +22,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(array_windows)] #![feature(backtrace)] #![feature(bool_to_option)] diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index a0d64107c9185..25e3e67e28e6c 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -5,7 +5,7 @@ //! generated instead. #![doc( - html_root_url = "https://doc.rust-lang.org/nightly-rustc/", + html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))) )] diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 08e152cf5ee39..c14d6aace87e0 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -4,7 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(or_patterns)] diff --git a/compiler/rustc_plugin_impl/src/lib.rs b/compiler/rustc_plugin_impl/src/lib.rs index efa2f6e96f948..5bf4d300e9e54 100644 --- a/compiler/rustc_plugin_impl/src/lib.rs +++ b/compiler/rustc_plugin_impl/src/lib.rs @@ -6,7 +6,7 @@ //! feature](https://doc.rust-lang.org/nightly/unstable-book/language-features/plugin.html) //! of the Unstable Book for some examples. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(nll)] #![recursion_limit = "256"] diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 0b45d7792604c..8d1b826ea3595 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(in_band_lifetimes)] #![feature(nll)] #![recursion_limit = "256"] diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index a34572e7f36fa..283db1404d0a4 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -8,7 +8,7 @@ //! //! Type-relative name resolution (methods, fields, associated items) happens in `librustc_typeck`. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(nll)] diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index af001594b20d2..f6434689fec01 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(nll)] #![feature(or_patterns)] #![recursion_limit = "256"] diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index fa6f5ab3db62a..ed48fbf40ac1f 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -5,7 +5,7 @@ Core encoding and decoding interfaces. */ #![doc( - html_root_url = "https://doc.rust-lang.org/nightly-rustc/", + html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", html_playground_url = "https://play.rust-lang.org/", test(attr(allow(unused_variables), deny(warnings))) )] diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 20b2eff8555db..96a6956a40c54 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -4,7 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(array_windows)] #![feature(crate_visibility_modifier)] #![feature(const_fn)] diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index c15cb4bf6c5ed..75150a56c43be 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -87,7 +87,7 @@ //! virtually impossible. Thus, symbol hash generation exclusively relies on //! DefPaths which are much more robust in the face of changes to the code base. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(never_type)] #![feature(nll)] #![feature(or_patterns)] diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index eacc1d0c23d17..fb747dfcbd337 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -7,7 +7,7 @@ //! more 'stuff' here in the future. It does not have a dependency on //! LLVM. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(const_fn)] #![feature(const_panic)] diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index b9e300a3ec1a1..caf0325084c09 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -10,7 +10,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(drain_filter)] diff --git a/compiler/rustc_ty/src/lib.rs b/compiler/rustc_ty/src/lib.rs index 9f6a310033b7b..904c0062a926f 100644 --- a/compiler/rustc_ty/src/lib.rs +++ b/compiler/rustc_ty/src/lib.rs @@ -4,7 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(nll)] #![recursion_limit = "256"] diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 7ee62c77dbfb8..84efb92582ed2 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -55,7 +55,7 @@ This API is completely unstable and subject to change. */ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![allow(non_camel_case_types)] #![feature(bool_to_option)] #![feature(box_syntax)] From 5b3016134fef93d9bed343bb15da837acf50b635 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Wed, 23 Sep 2020 21:33:45 +0200 Subject: [PATCH 0906/1052] use array::from_ref for slices --- library/core/src/slice/raw.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs index a5811c5e47289..09209306c9d0f 100644 --- a/library/core/src/slice/raw.rs +++ b/library/core/src/slice/raw.rs @@ -1,5 +1,6 @@ //! Free functions to create `&[T]` and `&mut [T]`. +use crate::array; use crate::intrinsics::is_aligned_and_not_null; use crate::mem; use crate::ptr; @@ -140,19 +141,11 @@ pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] /// Converts a reference to T into a slice of length 1 (without copying). #[stable(feature = "from_ref", since = "1.28.0")] pub fn from_ref(s: &T) -> &[T] { - // SAFETY: a reference is guaranteed to be valid for reads. The returned - // reference cannot be mutated as it is an immutable reference. - // `mem::size_of::()` cannot be larger than `isize::MAX`. - // Thus the call to `from_raw_parts` is safe. - unsafe { from_raw_parts(s, 1) } + array::from_ref(s) } /// Converts a reference to T into a slice of length 1 (without copying). #[stable(feature = "from_ref", since = "1.28.0")] pub fn from_mut(s: &mut T) -> &mut [T] { - // SAFETY: a mutable reference is guaranteed to be valid for writes. - // The reference cannot be accessed by another pointer as it is an mutable reference. - // `mem::size_of::()` cannot be larger than `isize::MAX`. - // Thus the call to `from_raw_parts_mut` is safe. - unsafe { from_raw_parts_mut(s, 1) } + array::from_mut(s) } From 764967a7e5cd260db94395614399e2638bee1eda Mon Sep 17 00:00:00 2001 From: Erik Hofmayer Date: Wed, 23 Sep 2020 22:08:30 +0200 Subject: [PATCH 0907/1052] tidy --- compiler/rustc_ast/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 765a21fd93e1b..6e47ff7d74081 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -4,7 +4,10 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(attr(deny(warnings))))] +#![doc( + html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", + test(attr(deny(warnings))) +)] #![feature(box_syntax)] #![feature(const_fn)] // For the `transmute` in `P::new` #![feature(const_fn_transmute)] From bcbd2ccc8d4591705fd5b63a5d5f5fc320cd89be Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 23 Sep 2020 14:25:23 -0700 Subject: [PATCH 0908/1052] Add `keep-stage-std` to `x.py` This keeps only the `std` artifacts compiled by the given stage, not the compiler. This is useful when working on the latter stages of the compiler in tandem with the standard library, since you don't have to rebuild the *entire* compiler when the standard library changes. --- src/bootstrap/compile.rs | 9 ++++++++- src/bootstrap/config.rs | 2 ++ src/bootstrap/flags.rs | 17 ++++++++++++++++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 08907edef1d1e..02095c27335e4 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -59,7 +59,9 @@ impl Step for Std { let target = self.target; let compiler = self.compiler; - if builder.config.keep_stage.contains(&compiler.stage) { + if builder.config.keep_stage.contains(&compiler.stage) + || builder.config.keep_stage_std.contains(&compiler.stage) + { builder.info("Warning: Using a potentially old libstd. This may not behave well."); builder.ensure(StdLink { compiler, target_compiler: compiler, target }); return; @@ -472,6 +474,11 @@ impl Step for Rustc { if builder.config.keep_stage.contains(&compiler.stage) { builder.info("Warning: Using a potentially old librustc. This may not behave well."); + builder.info("Warning: Use `--keep-stage-std` if you want to rebuild the compiler when it changes"); + builder.info( + "Warning: Please file a GitHub issue if `--keep-stage-std` doesn't work for you.", + ); + builder.info("Warning: It may replace `--keep-stage` in the future"); builder.ensure(RustcLink { compiler, target_compiler: compiler, target }); return; } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index c74501979f0ec..53fef7a838df6 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -71,6 +71,7 @@ pub struct Config { pub on_fail: Option, pub stage: u32, pub keep_stage: Vec, + pub keep_stage_std: Vec, pub src: PathBuf, pub jobs: Option, pub cmd: Subcommand, @@ -539,6 +540,7 @@ impl Config { config.incremental = flags.incremental; config.dry_run = flags.dry_run; config.keep_stage = flags.keep_stage; + config.keep_stage_std = flags.keep_stage_std; config.bindir = "bin".into(); // default if let Some(value) = flags.deny_warnings { config.deny_warnings = value; diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 842c84a3e5cd6..dad31fc77be17 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -19,6 +19,7 @@ pub struct Flags { pub on_fail: Option, pub stage: Option, pub keep_stage: Vec, + pub keep_stage_std: Vec, pub host: Option>, pub target: Option>, @@ -144,6 +145,13 @@ To learn more about a subcommand, run `./x.py -h`", (pass multiple times to keep e.g., both stages 0 and 1)", "N", ); + opts.optmulti( + "", + "keep-stage-std", + "stage(s) of the standard library to keep without recompiling \ + (pass multiple times to keep e.g., both stages 0 and 1)", + "N", + ); opts.optopt("", "src", "path to the root of the rust checkout", "DIR"); let j_msg = format!( "number of jobs to run in parallel; \ @@ -510,7 +518,9 @@ Arguments: println!("--stage not supported for x.py check, always treated as stage 0"); process::exit(1); } - if matches.opt_str("keep-stage").is_some() { + if matches.opt_str("keep-stage").is_some() + || matches.opt_str("keep-stage-std").is_some() + { println!("--keep-stage not supported for x.py check, only one stage available"); process::exit(1); } @@ -528,6 +538,11 @@ Arguments: .into_iter() .map(|j| j.parse().expect("`keep-stage` should be a number")) .collect(), + keep_stage_std: matches + .opt_strs("keep-stage-std") + .into_iter() + .map(|j| j.parse().expect("`keep-stage-std` should be a number")) + .collect(), host: if matches.opt_present("host") { Some( split(&matches.opt_strs("host")) From 0e2db577546ee52901c9d350aaa96f6ba700d9ff Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Thu, 24 Sep 2020 09:00:04 +1000 Subject: [PATCH 0909/1052] update tracking issue for const_type_id --- library/core/src/any.rs | 2 +- library/core/src/intrinsics.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 88ff2a632fd49..d1951fbbf103a 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -435,7 +435,7 @@ impl TypeId { /// assert_eq!(is_string(&"cookie monster".to_string()), true); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_type_id", issue = "63084")] + #[rustc_const_unstable(feature = "const_type_id", issue = "77125")] pub const fn of() -> TypeId { TypeId { t: intrinsics::type_id::() } } diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index b8c0519f659c1..bcbb760021ee4 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -807,7 +807,7 @@ extern "rust-intrinsic" { /// crate it is invoked in. /// /// The stabilized version of this intrinsic is [`crate::any::TypeId::of`]. - #[rustc_const_unstable(feature = "const_type_id", issue = "63084")] + #[rustc_const_unstable(feature = "const_type_id", issue = "77125")] pub fn type_id() -> u64; /// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited: From df004df3a79b70b4af2b8c267457a5be76bb0d85 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Wed, 23 Sep 2020 19:03:52 -0400 Subject: [PATCH 0910/1052] Re-download LLVM on submodule updates only --- src/bootstrap/bootstrap.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 1f0b55a78698d..5c9184f450687 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -424,8 +424,19 @@ def download_stage0(self): rustfmt_stamp.write(self.date + self.rustfmt_channel) if self.downloading_llvm(): - llvm_sha = subprocess.check_output(["git", "log", "--author=bors", - "--format=%H", "-n1"]).decode(sys.getdefaultencoding()).strip() + # We want the most recent LLVM submodule update to avoid downloading + # LLVM more often than necessary. + # + # This git command finds that commit SHA, looking for bors-authored + # merges that modified src/llvm-project. + # + # This works even in a repository that has not yet initialized + # submodules. + llvm_sha = subprocess.check_output([ + "git", "log", "--author=bors", "--format=%H", "-n1", + "-m", "--first-parent", + "--", "src/llvm-project" + ]).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)): self._download_ci_llvm(llvm_sha, llvm_assertions) From ef95430b9bb42fefa0a5e885525525bb52d9cb00 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Wed, 23 Sep 2020 19:05:11 -0400 Subject: [PATCH 0911/1052] Adjust support expectations for downloaded LLVMs --- config.toml.example | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config.toml.example b/config.toml.example index fb62e1b4726bc..c5efb8ed5e51c 100644 --- a/config.toml.example +++ b/config.toml.example @@ -36,8 +36,8 @@ changelog-seen = 1 # toolchain or changing LLVM locally, you probably want to set this to true. # # It's currently false by default due to being newly added; please file bugs if -# enabling this did not work for you on Linux (macOS and Windows support is -# coming soon). +# enabling this did not work for you on x86_64-unknown-linux-gnu. +# Other target triples are currently not supported; see #77084. # # We also currently only support this when building LLVM for the build triple. # @@ -380,7 +380,7 @@ changelog-seen = 1 # Whether or not to leave debug! and trace! calls in the rust binary. # Overrides the `debug-assertions` option, if defined. -# +# # Defaults to rust.debug-assertions value #debug-logging = debug-assertions From c0ddaed2bfa95d488db7576055ee7472968babfd Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 23 Sep 2020 16:17:11 -0700 Subject: [PATCH 0912/1052] Remove warning about possible future deprecation --- src/bootstrap/compile.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 02095c27335e4..40bf6c48296b2 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -475,10 +475,6 @@ impl Step for Rustc { if builder.config.keep_stage.contains(&compiler.stage) { builder.info("Warning: Using a potentially old librustc. This may not behave well."); builder.info("Warning: Use `--keep-stage-std` if you want to rebuild the compiler when it changes"); - builder.info( - "Warning: Please file a GitHub issue if `--keep-stage-std` doesn't work for you.", - ); - builder.info("Warning: It may replace `--keep-stage` in the future"); builder.ensure(RustcLink { compiler, target_compiler: compiler, target }); return; } From 945a732dd6c3928e0219a862066c92bde45d26bf Mon Sep 17 00:00:00 2001 From: Camelid Date: Wed, 23 Sep 2020 16:18:59 -0700 Subject: [PATCH 0913/1052] Update mdBook 0.4.2 -> 0.4.3 --- Cargo.lock | 4 ++-- src/tools/rustbook/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 68288916e6d12..3727e3d20f86b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1848,9 +1848,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75e31ae4eaa0e45e17ee2b6b9e3ed969c3c6ff12bb4c2e352c42493f4ebb706" +checksum = "29be448fcafb00c5a8966c4020c2a5ffbbc333e5b96d0bb5ef54b5bd0524d9ff" dependencies = [ "ammonia", "anyhow", diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index f0a6ce2fa06c2..f5e5c0867b48a 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -9,6 +9,6 @@ edition = "2018" clap = "2.25.0" [dependencies.mdbook] -version = "0.4.0" +version = "0.4.3" default-features = false features = ["search"] From 16769eb19e8051a32a93c1b3fd7847aff5c9eded Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 23 Sep 2020 16:22:53 -0700 Subject: [PATCH 0914/1052] Add entry to CHANGELOG for `--keep-stage-std` --- src/bootstrap/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bootstrap/CHANGELOG.md b/src/bootstrap/CHANGELOG.md index 5fcaafab959e9..1510f4d59fa34 100644 --- a/src/bootstrap/CHANGELOG.md +++ b/src/bootstrap/CHANGELOG.md @@ -15,6 +15,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Make the default stage for x.py configurable [#76625](https://github.com/rust-lang/rust/pull/76625) - Add a dedicated debug-logging option [#76588](https://github.com/rust-lang/rust/pull/76588) - Add sample defaults for x.py [#76628](https://github.com/rust-lang/rust/pull/76628) +- Add `--keep-stage-std`, which behaves like `keep-stage` but allows the stage + 0 compiler artifacts (i.e., stage1/bin/rustc) to be rebuilt if changed + [#77120](https://github.com/rust-lang/rust/pull/77120). + ## [Version 0] - 2020-09-11 From a09d6078443aac66f48ef64b13914506d50e38ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Thu, 24 Sep 2020 00:00:00 +0000 Subject: [PATCH 0915/1052] Remove duplicated SimplifyCfg pass --- compiler/rustc_mir/src/transform/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index f48ad039b4ff9..a622de9a8af3e 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -476,7 +476,6 @@ fn run_optimization_passes<'tcx>( ©_prop::CopyPropagation, &simplify_branches::SimplifyBranches::new("after-copy-prop"), &remove_noop_landing_pads::RemoveNoopLandingPads, - &simplify::SimplifyCfg::new("after-remove-noop-landing-pads"), &simplify::SimplifyCfg::new("final"), &nrvo::RenameReturnPlace, &simplify::SimplifyLocals, From 50d96635872b0625da84b7f2e2556b1804cc9de7 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 23 Sep 2020 17:06:56 -0700 Subject: [PATCH 0916/1052] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 8777a6b1e8834..05c611ae3c425 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 8777a6b1e8834899f51b7e09cc9b8d85b2417110 +Subproject commit 05c611ae3c4255b7a2bcf4fcfa65b20286a07839 From dd7b8c85a6a2bffb2cce1c40ba72680a1d7be93b Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 20 Sep 2020 00:32:00 -0400 Subject: [PATCH 0917/1052] Perform most diagnostic lookups in `resolution_failure` Previously, these were spread throughout the codebase. This had two drawbacks: 1. It caused the fast path to be slower: even if a link resolved, rustdoc would still perform various lookups for the error diagnostic. 2. It was inconsistent and didn't always give all diagnostics (https://github.com/rust-lang/rust/issues/76925) Now, diagnostics only perform expensive lookups in the error case. Additionally, the error handling is much more consistent, both in wording and behavior. - Remove `CannotHaveAssociatedItems`, `NotInScope`, `NoAssocItem`, and `NotAVariant` in favor of the more general `NotResolved` `resolution_failure` will now look up which of the four above categories is relevant, instead of requiring the rest of the code to be consistent and accurate in which it picked. - Remove unnecessary lookups throughout the intra-doc link pass. These are now done by `resolution_failure`. + Remove unnecessary `extra_fragment` argument to `variant_field()`; it was only used to do lookups on failure. + Remove various lookups related to associated items + Remove distinction between 'not in scope' and 'no associated item' - Don't perform unnecessary copies - Remove unused variables and code - Update tests - Note why looking at other namespaces is still necessary - 'has no inner item' -> 'contains no item' bless tests --- .../passes/collect_intra_doc_links.rs | 397 +++++++++--------- .../deny-intra-link-resolution-failure.stderr | 2 +- src/test/rustdoc-ui/intra-link-errors.rs | 16 +- src/test/rustdoc-ui/intra-link-errors.stderr | 51 ++- .../intra-link-span-ice-55723.stderr | 2 +- .../intra-links-warning-crlf.stderr | 8 +- .../rustdoc-ui/intra-links-warning.stderr | 36 +- src/test/rustdoc-ui/lint-group.stderr | 2 +- .../rustdoc/intra-link-associated-items.rs | 2 + 9 files changed, 263 insertions(+), 253 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 5a9eeec4dfec3..71fd5deca54b7 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -60,14 +60,6 @@ impl<'a> From> for ErrorKind<'a> { #[derive(Debug)] enum ResolutionFailure<'a> { - /// This resolved, but with the wrong namespace. - /// `Namespace` is the expected namespace (as opposed to the actual). - WrongNamespace(Res, Namespace), - /// This has a partial resolution, but is not in the TypeNS and so cannot - /// have associated items or fields. - CannotHaveAssociatedItems(Res, Namespace), - /// `name` is the base name of the path (not necessarily the whole link) - NotInScope { module_id: DefId, name: Cow<'a, str> }, /// this is a primitive type without an impls (no associated methods) /// when will this actually happen? /// the `Res` is the primitive it resolved to @@ -75,33 +67,19 @@ enum ResolutionFailure<'a> { /// `[u8::not_found]` /// the `Res` is the primitive it resolved to NoPrimitiveAssocItem { res: Res, prim_name: &'a str, assoc_item: Symbol }, - /// `[S::not_found]` - /// the `String` is the associated item that wasn't found - NoAssocItem(Res, Symbol), + /// This resolved, but with the wrong namespace. + /// `Namespace` is the expected namespace (as opposed to the actual). + WrongNamespace(Res, Namespace), + /// The link failed to resolve. `resolution_failure` should look to see if there's + /// a more helpful error that can be given. + NotResolved { module_id: DefId, partial_res: Option, unresolved: Cow<'a, str> }, /// should not ever happen NoParentItem, - /// this could be an enum variant, but the last path fragment wasn't resolved. - /// the `String` is the variant that didn't exist - NotAVariant(Res, Symbol), /// used to communicate that this should be ignored, but shouldn't be reported to the user Dummy, } impl ResolutionFailure<'a> { - // A partial or full resolution - fn res(&self) -> Option { - use ResolutionFailure::*; - match self { - NoPrimitiveAssocItem { res, .. } - | NoAssocItem(res, _) - | NoPrimitiveImpl(res, _) - | NotAVariant(res, _) - | WrongNamespace(res, _) - | CannotHaveAssociatedItems(res, _) => Some(*res), - NotInScope { .. } | NoParentItem | Dummy => None, - } - } - // This resolved fully (not just partially) but is erroneous for some other reason fn full_res(&self) -> Option { match self { @@ -136,22 +114,25 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { path_str: &'path str, current_item: &Option, module_id: DefId, - extra_fragment: &Option, ) -> Result<(Res, Option), ErrorKind<'path>> { let cx = self.cx; + let no_res = || ResolutionFailure::NotResolved { + module_id, + partial_res: None, + unresolved: path_str.into(), + }; debug!("looking for enum variant {}", path_str); let mut split = path_str.rsplitn(3, "::"); - let variant_field_name = split + let (variant_field_str, variant_field_name) = split .next() - .map(|f| Symbol::intern(f)) + .map(|f| (f, Symbol::intern(f))) .expect("fold_item should ensure link is non-empty"); - let variant_name = + let (variant_str, variant_name) = // we're not sure this is a variant at all, so use the full string - split.next().map(|f| Symbol::intern(f)).ok_or_else(|| ResolutionFailure::NotInScope { - module_id, - name: path_str.into(), - })?; + // If there's no second component, the link looks like `[path]`. + // So there's no partial res and we should say the whole link failed to resolve. + split.next().map(|f| (f, Symbol::intern(f))).ok_or_else(no_res)?; let path = split .next() .map(|f| { @@ -162,10 +143,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } f.to_owned() }) - .ok_or_else(|| ResolutionFailure::NotInScope { - module_id, - name: variant_name.to_string().into(), - })?; + // If there's no third component, we saw `[a::b]` before and it failed to resolve. + // So there's no partial res. + .ok_or_else(no_res)?; let ty_res = cx .enter_resolver(|resolver| { resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) @@ -173,7 +153,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .map(|(_, res)| res) .unwrap_or(Res::Err); if let Res::Err = ty_res { - return Err(ResolutionFailure::NotInScope { module_id, name: path.into() }.into()); + return Err(no_res().into()); } let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); match ty_res { @@ -196,38 +176,27 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { ty_res, Some(format!( "variant.{}.field.{}", - variant_name, variant_field_name + variant_str, variant_field_name )), )) } else { - Err(ResolutionFailure::NotAVariant(ty_res, variant_field_name).into()) + Err(ResolutionFailure::NotResolved { + module_id, + partial_res: Some(Res::Def(DefKind::Enum, def.did)), + unresolved: variant_field_str.into(), + } + .into()) } } _ => unreachable!(), } } - // `variant_field` looks at 3 different path segments in a row. - // But `NoAssocItem` assumes there are only 2. Check to see if there's - // an intermediate segment that resolves. - _ => { - let intermediate_path = format!("{}::{}", path, variant_name); - // NOTE: we have to be careful here, because we're already in `resolve`. - // We know this doesn't recurse forever because we use a shorter path each time. - // NOTE: this uses `TypeNS` because nothing else has a valid path segment after - let kind = if let Some(intermediate) = self.check_full_res( - TypeNS, - &intermediate_path, - module_id, - current_item, - extra_fragment, - ) { - ResolutionFailure::NoAssocItem(intermediate, variant_field_name) - } else { - // Even with the shorter path, it didn't resolve, so say that. - ResolutionFailure::NoAssocItem(ty_res, variant_name) - }; - Err(kind.into()) + _ => Err(ResolutionFailure::NotResolved { + module_id, + partial_res: Some(ty_res), + unresolved: variant_str.into(), } + .into()), } } @@ -248,11 +217,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { false, ) { if let SyntaxExtensionKind::LegacyBang { .. } = ext.kind { - return Some(Ok(res.map_id(|_| panic!("unexpected id")))); + return Ok(res.map_id(|_| panic!("unexpected id"))); } } if let Some(res) = resolver.all_macros().get(&Symbol::intern(path_str)) { - return Some(Ok(res.map_id(|_| panic!("unexpected id")))); + return Ok(res.map_id(|_| panic!("unexpected id"))); } debug!("resolving {} as a macro in the module {:?}", path_str, module_id); if let Ok((_, res)) = @@ -261,28 +230,14 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // don't resolve builtins like `#[derive]` if let Res::Def(..) = res { let res = res.map_id(|_| panic!("unexpected node_id")); - return Some(Ok(res)); - } - } - None - }) - // This weird control flow is so we don't borrow the resolver more than once at a time - .unwrap_or_else(|| { - let mut split = path_str.rsplitn(2, "::"); - if let Some((parent, base)) = split.next().and_then(|x| Some((split.next()?, x))) { - if let Some(res) = self.check_full_res(TypeNS, parent, module_id, &None, &None) { - return Err(if matches!(res, Res::PrimTy(_)) { - ResolutionFailure::NoPrimitiveAssocItem { - res, - prim_name: parent, - assoc_item: Symbol::intern(base), - } - } else { - ResolutionFailure::NoAssocItem(res, Symbol::intern(base)) - }); + return Ok(res); } } - Err(ResolutionFailure::NotInScope { module_id, name: path_str.into() }) + Err(ResolutionFailure::NotResolved { + module_id, + partial_res: None, + unresolved: path_str.into(), + }) }) } @@ -347,7 +302,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // Try looking for methods and associated items. let mut split = path_str.rsplitn(2, "::"); // this can be an `unwrap()` because we ensure the link is never empty - let item_name = Symbol::intern(split.next().unwrap()); + let (item_str, item_name) = split.next().map(|i| (i, Symbol::intern(i))).unwrap(); let path_root = split .next() .map(|f| { @@ -362,7 +317,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved. .ok_or_else(|| { debug!("found no `::`, assumming {} was correctly not in scope", item_name); - ResolutionFailure::NotInScope { module_id, name: item_name.to_string().into() } + ResolutionFailure::NotResolved { + module_id, + partial_res: None, + unresolved: item_str.into(), + } })?; if let Some((path, prim)) = is_primitive(&path_root, TypeNS) { @@ -383,7 +342,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { ty::AssocKind::Const => "associatedconstant", ty::AssocKind::Type => "associatedtype", }) - .map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_name)))); + .map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_str)))); if let Some(link) = link { return Ok(link); } @@ -411,25 +370,14 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { let ty_res = match ty_res { Err(()) | Ok(Res::Err) => { return if ns == Namespace::ValueNS { - self.variant_field(path_str, current_item, module_id, extra_fragment) + self.variant_field(path_str, current_item, module_id) } else { - // See if it only broke because of the namespace. - let kind = cx.enter_resolver(|resolver| { - // NOTE: this doesn't use `check_full_res` because we explicitly want to ignore `TypeNS` (we already checked it) - for &ns in &[MacroNS, ValueNS] { - match resolver - .resolve_str_path_error(DUMMY_SP, &path_root, ns, module_id) - { - Ok((_, Res::Err)) | Err(()) => {} - Ok((_, res)) => { - let res = res.map_id(|_| panic!("unexpected node_id")); - return ResolutionFailure::CannotHaveAssociatedItems(res, ns); - } - } - } - ResolutionFailure::NotInScope { module_id, name: path_root.into() } - }); - Err(kind.into()) + Err(ResolutionFailure::NotResolved { + module_id, + partial_res: None, + unresolved: path_root.into(), + } + .into()) }; } Ok(res) => res, @@ -479,7 +427,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // but the disambiguator logic expects the associated item. // Store the kind in a side channel so that only the disambiguator logic looks at it. self.kind_side_channel.set(Some((kind.as_def_kind(), id))); - Ok((ty_res, Some(format!("{}.{}", out, item_name)))) + Ok((ty_res, Some(format!("{}.{}", out, item_str)))) }) } else if ns == Namespace::ValueNS { debug!("looking for variants or fields named {} for {:?}", item_name, did); @@ -522,7 +470,12 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } } else { // We already know this isn't in ValueNS, so no need to check variant_field - return Err(ResolutionFailure::NoAssocItem(ty_res, item_name).into()); + return Err(ResolutionFailure::NotResolved { + module_id, + partial_res: Some(ty_res), + unresolved: item_str.into(), + } + .into()); } } Res::Def(DefKind::Trait, did) => cx @@ -546,16 +499,21 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(ty_res))) } else { let res = Res::Def(item.kind.as_def_kind(), item.def_id); - Ok((res, Some(format!("{}.{}", kind, item_name)))) + Ok((res, Some(format!("{}.{}", kind, item_str)))) } }), _ => None, }; res.unwrap_or_else(|| { if ns == Namespace::ValueNS { - self.variant_field(path_str, current_item, module_id, extra_fragment) + self.variant_field(path_str, current_item, module_id) } else { - Err(ResolutionFailure::NoAssocItem(ty_res, item_name).into()) + Err(ResolutionFailure::NotResolved { + module_id, + partial_res: Some(ty_res), + unresolved: item_str.into(), + } + .into()) } }) } @@ -1133,6 +1091,8 @@ impl LinkCollector<'_, '_> { // We only looked in one namespace. Try to give a better error if possible. if kind.full_res().is_none() { let other_ns = if ns == ValueNS { TypeNS } else { ValueNS }; + // FIXME: really it should be `resolution_failure` that does this, not `resolve_with_disambiguator` + // See https://github.com/rust-lang/rust/pull/76955#discussion_r493953382 for a good approach for &new_ns in &[other_ns, MacroNS] { if let Some(res) = self.check_full_res( new_ns, @@ -1535,7 +1495,6 @@ fn resolution_failure( dox, &link_range, |diag, sp| { - let in_scope = kinds.iter().any(|kind| kind.res().is_some()); let item = |res: Res| { format!( "the {} `{}`", @@ -1556,53 +1515,142 @@ fn resolution_failure( // ignore duplicates let mut variants_seen = SmallVec::<[_; 3]>::new(); for mut failure in kinds { - // Check if _any_ parent of the path gets resolved. - // If so, report it and say the first which failed; if not, say the first path segment didn't resolve. - if let ResolutionFailure::NotInScope { module_id, name } = &mut failure { - let mut current = name.as_ref(); - loop { - current = match current.rsplitn(2, "::").nth(1) { - Some(p) => p, - None => { - *name = current.to_owned().into(); - break; - } - }; - if let Some(res) = - collector.check_full_res(TypeNS, ¤t, *module_id, &None, &None) - { - failure = ResolutionFailure::NoAssocItem(res, Symbol::intern(current)); - break; - } - } - } let variant = std::mem::discriminant(&failure); if variants_seen.contains(&variant) { continue; } variants_seen.push(variant); - let note = match failure { - ResolutionFailure::NotInScope { module_id, name, .. } => { - if in_scope { - continue; + + if let ResolutionFailure::NotResolved { module_id, partial_res, unresolved } = + &mut failure + { + use DefKind::*; + + let module_id = *module_id; + // FIXME(jynelson): this might conflict with my `Self` fix in #76467 + fn split(path: &str) -> Option<(&str, &str)> { + let mut splitter = path.rsplitn(2, "::"); + splitter.next().and_then(|right| splitter.next().map(|left| (left, right))) + } + + // Check if _any_ parent of the path gets resolved. + // If so, report it and say the first which failed; if not, say the first path segment didn't resolve. + let mut name = path_str; + 'outer: loop { + let (start, end) = if let Some(x) = split(name) { + x + } else { + // avoid bug that marked [Quux::Z] as missing Z, not Quux + if partial_res.is_none() { + *unresolved = name.into(); + } + break; + }; + name = start; + for &ns in &[TypeNS, ValueNS, MacroNS] { + if let Some(res) = + collector.check_full_res(ns, &start, module_id, &None, &None) + { + debug!("found partial_res={:?}", res); + *partial_res = Some(res); + *unresolved = end.into(); + break 'outer; + } } + *unresolved = end.into(); + } + + let last_found_module = match *partial_res { + Some(Res::Def(DefKind::Mod, id)) => Some(id), + None => Some(module_id), + _ => None, + }; + // See if this was a module: `[path]` or `[std::io::nope]` + if let Some(module) = last_found_module { // NOTE: uses an explicit `continue` so the `note:` will come before the `help:` - let module_name = collector.cx.tcx.item_name(module_id); - let note = format!("no item named `{}` in `{}`", name, module_name); + let module_name = collector.cx.tcx.item_name(module); + let note = format!( + "the module `{}` contains no item named `{}`", + module_name, unresolved + ); if let Some(span) = sp { diag.span_label(span, ¬e); } else { diag.note(¬e); } - // If the link has `::` in the path, assume it's meant to be an intra-doc link + // If the link has `::` in it, assume it was meant to be an intra-doc link. + // Otherwise, the `[]` might be unrelated. + // FIXME: don't show this for autolinks (`<>`), `()` style links, or reference links if !path_str.contains("::") { - // Otherwise, the `[]` might be unrelated. - // FIXME(https://github.com/raphlinus/pulldown-cmark/issues/373): - // don't show this for autolinks (`<>`), `()` style links, or reference links diag.help(r#"to escape `[` and `]` characters, add '\' before them like `\[` or `\]`"#); } continue; } + + // Otherwise, it must be an associated item or variant + let res = partial_res.expect("None case was handled by `last_found_module`"); + let diagnostic_name; + let (kind, name) = match res { + Res::Def(kind, def_id) => { + diagnostic_name = collector.cx.tcx.item_name(def_id).as_str(); + (Some(kind), &*diagnostic_name) + } + Res::PrimTy(_) => (None, name), + _ => unreachable!("only ADTs and primitives are in scope at module level"), + }; + let path_description = if let Some(kind) = kind { + match kind { + Mod | ForeignMod => "inner item", + Struct => "field or associated item", + Enum | Union => "variant or associated item", + Variant + | Field + | Closure + | Generator + | AssocTy + | AssocConst + | AssocFn + | Fn + | Macro(_) + | Const + | ConstParam + | ExternCrate + | Use + | LifetimeParam + | Ctor(_, _) + | AnonConst => { + let note = assoc_item_not_allowed(res); + if let Some(span) = sp { + diag.span_label(span, ¬e); + } else { + diag.note(¬e); + } + return; + } + Trait | TyAlias | ForeignTy | OpaqueTy | TraitAlias | TyParam + | Static => "associated item", + Impl | GlobalAsm => unreachable!("not a path"), + } + } else { + res.descr() + }; + let note = format!( + "the {} `{}` has no {} named `{}`", + res.descr(), + name, + disambiguator.map_or(path_description, |d| d.descr()), + unresolved, + ); + if let Some(span) = sp { + diag.span_label(span, ¬e); + } else { + diag.note(¬e); + } + + continue; + } + let note = match failure { + ResolutionFailure::NotResolved { .. } => unreachable!("handled above"), ResolutionFailure::Dummy => continue, ResolutionFailure::WrongNamespace(res, expected_ns) => { if let Res::Def(kind, _) = res { @@ -1637,69 +1685,6 @@ fn resolution_failure( prim_name, assoc_item ) } - ResolutionFailure::NoAssocItem(res, assoc_item) => { - use DefKind::*; - - let (kind, def_id) = match res { - Res::Def(kind, def_id) => (kind, def_id), - x => unreachable!( - "primitives are covered above and other `Res` variants aren't possible at module scope: {:?}", - x, - ), - }; - let name = collector.cx.tcx.item_name(def_id); - let path_description = if let Some(disambiguator) = disambiguator { - disambiguator.descr() - } else { - match kind { - Mod | ForeignMod => "inner item", - Struct => "field or associated item", - Enum | Union => "variant or associated item", - Variant - | Field - | Closure - | Generator - | AssocTy - | AssocConst - | AssocFn - | Fn - | Macro(_) - | Const - | ConstParam - | ExternCrate - | Use - | LifetimeParam - | Ctor(_, _) - | AnonConst => { - let note = assoc_item_not_allowed(res); - if let Some(span) = sp { - diag.span_label(span, ¬e); - } else { - diag.note(¬e); - } - return; - } - Trait | TyAlias | ForeignTy | OpaqueTy | TraitAlias | TyParam - | Static => "associated item", - Impl | GlobalAsm => unreachable!("not a path"), - } - }; - format!( - "the {} `{}` has no {} named `{}`", - res.descr(), - name, - path_description, - assoc_item - ) - } - ResolutionFailure::CannotHaveAssociatedItems(res, _) => { - assoc_item_not_allowed(res) - } - ResolutionFailure::NotAVariant(res, variant) => format!( - "this link partially resolves to {}, but there is no variant named {}", - item(res), - variant - ), }; if let Some(span) = sp { diag.span_label(span, ¬e); diff --git a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr index 5020b97b2f201..33260fa0e1e66 100644 --- a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr +++ b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr @@ -2,7 +2,7 @@ error: unresolved link to `v2` --> $DIR/deny-intra-link-resolution-failure.rs:3:6 | LL | /// [v2] - | ^^ no item named `v2` in `deny_intra_link_resolution_failure` + | ^^ the module `deny_intra_link_resolution_failure` contains no item named `v2` | note: the lint level is defined here --> $DIR/deny-intra-link-resolution-failure.rs:1:9 diff --git a/src/test/rustdoc-ui/intra-link-errors.rs b/src/test/rustdoc-ui/intra-link-errors.rs index 26b629b1313da..8c250fbc58b27 100644 --- a/src/test/rustdoc-ui/intra-link-errors.rs +++ b/src/test/rustdoc-ui/intra-link-errors.rs @@ -6,19 +6,23 @@ /// [path::to::nonexistent::module] //~^ ERROR unresolved link -//~| NOTE no item named `path` in `intra_link_errors` +//~| NOTE `intra_link_errors` contains no item named `path` /// [path::to::nonexistent::macro!] //~^ ERROR unresolved link -//~| NOTE no item named `path` in `intra_link_errors` +//~| NOTE `intra_link_errors` contains no item named `path` /// [type@path::to::nonexistent::type] //~^ ERROR unresolved link -//~| NOTE no item named `path` in `intra_link_errors` +//~| NOTE `intra_link_errors` contains no item named `path` /// [std::io::not::here] //~^ ERROR unresolved link -//~| NOTE the module `io` has no inner item +//~| NOTE `io` contains no item named `not` + +/// [type@std::io::not::here] +//~^ ERROR unresolved link +//~| NOTE `io` contains no item named `not` /// [std::io::Error::x] //~^ ERROR unresolved link @@ -32,6 +36,10 @@ //~^ ERROR unresolved link //~| NOTE `f` is a function, not a module +/// [f::A!] +//~^ ERROR unresolved link +//~| NOTE `f` is a function, not a module + /// [S::A] //~^ ERROR unresolved link //~| NOTE struct `S` has no field or associated item diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr index fbf3dcbbec29a..cd06ee6f798dc 100644 --- a/src/test/rustdoc-ui/intra-link-errors.stderr +++ b/src/test/rustdoc-ui/intra-link-errors.stderr @@ -2,7 +2,7 @@ error: unresolved link to `path::to::nonexistent::module` --> $DIR/intra-link-errors.rs:7:6 | LL | /// [path::to::nonexistent::module] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in `intra_link_errors` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the module `intra_link_errors` contains no item named `path` | note: the lint level is defined here --> $DIR/intra-link-errors.rs:1:9 @@ -14,64 +14,79 @@ error: unresolved link to `path::to::nonexistent::macro` --> $DIR/intra-link-errors.rs:11:6 | LL | /// [path::to::nonexistent::macro!] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in `intra_link_errors` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the module `intra_link_errors` contains no item named `path` error: unresolved link to `path::to::nonexistent::type` --> $DIR/intra-link-errors.rs:15:6 | LL | /// [type@path::to::nonexistent::type] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in `intra_link_errors` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the module `intra_link_errors` contains no item named `path` error: unresolved link to `std::io::not::here` --> $DIR/intra-link-errors.rs:19:6 | LL | /// [std::io::not::here] - | ^^^^^^^^^^^^^^^^^^ the module `io` has no inner item named `not` + | ^^^^^^^^^^^^^^^^^^ the module `io` contains no item named `not` -error: unresolved link to `std::io::Error::x` +error: unresolved link to `std::io::not::here` --> $DIR/intra-link-errors.rs:23:6 | +LL | /// [type@std::io::not::here] + | ^^^^^^^^^^^^^^^^^^^^^^^ the module `io` contains no item named `not` + +error: unresolved link to `std::io::Error::x` + --> $DIR/intra-link-errors.rs:27:6 + | LL | /// [std::io::Error::x] | ^^^^^^^^^^^^^^^^^ the struct `Error` has no field or associated item named `x` error: unresolved link to `std::io::ErrorKind::x` - --> $DIR/intra-link-errors.rs:27:6 + --> $DIR/intra-link-errors.rs:31:6 | LL | /// [std::io::ErrorKind::x] | ^^^^^^^^^^^^^^^^^^^^^ the enum `ErrorKind` has no variant or associated item named `x` error: unresolved link to `f::A` - --> $DIR/intra-link-errors.rs:31:6 + --> $DIR/intra-link-errors.rs:35:6 | LL | /// [f::A] | ^^^^ `f` is a function, not a module or type, and cannot have associated items +error: unresolved link to `f::A` + --> $DIR/intra-link-errors.rs:39:6 + | +LL | /// [f::A!] + | ^^^^^ `f` is a function, not a module or type, and cannot have associated items + error: unresolved link to `S::A` - --> $DIR/intra-link-errors.rs:35:6 + --> $DIR/intra-link-errors.rs:43:6 | LL | /// [S::A] | ^^^^ the struct `S` has no field or associated item named `A` error: unresolved link to `S::fmt` - --> $DIR/intra-link-errors.rs:39:6 + --> $DIR/intra-link-errors.rs:47:6 | LL | /// [S::fmt] | ^^^^^^ the struct `S` has no field or associated item named `fmt` error: unresolved link to `E::D` - --> $DIR/intra-link-errors.rs:43:6 + --> $DIR/intra-link-errors.rs:51:6 | LL | /// [E::D] | ^^^^ the enum `E` has no variant or associated item named `D` error: unresolved link to `u8::not_found` - --> $DIR/intra-link-errors.rs:47:6 + --> $DIR/intra-link-errors.rs:55:6 | LL | /// [u8::not_found] - | ^^^^^^^^^^^^^ the builtin type `u8` does not have an associated item named `not_found` + | ^^^^^^^^^^^^^ + | | + | the builtin type `u8` does not have an associated item named `not_found` + | the builtin type `u8` has no builtin type named `not_found` error: unresolved link to `S` - --> $DIR/intra-link-errors.rs:51:6 + --> $DIR/intra-link-errors.rs:59:6 | LL | /// [S!] | ^^ @@ -80,7 +95,7 @@ LL | /// [S!] | help: to link to the struct, prefix with `struct@`: `struct@S` error: unresolved link to `T::g` - --> $DIR/intra-link-errors.rs:69:6 + --> $DIR/intra-link-errors.rs:77:6 | LL | /// [type@T::g] | ^^^^^^^^^ @@ -89,13 +104,13 @@ LL | /// [type@T::g] | help: to link to the associated function, add parentheses: `T::g()` error: unresolved link to `T::h` - --> $DIR/intra-link-errors.rs:74:6 + --> $DIR/intra-link-errors.rs:82:6 | LL | /// [T::h!] | ^^^^^ the trait `T` has no macro named `h` error: unresolved link to `S::h` - --> $DIR/intra-link-errors.rs:61:6 + --> $DIR/intra-link-errors.rs:69:6 | LL | /// [type@S::h] | ^^^^^^^^^ @@ -104,7 +119,7 @@ LL | /// [type@S::h] | help: to link to the associated function, add parentheses: `S::h()` error: unresolved link to `m` - --> $DIR/intra-link-errors.rs:81:6 + --> $DIR/intra-link-errors.rs:89:6 | LL | /// [m()] | ^^^ @@ -112,5 +127,5 @@ LL | /// [m()] | this link resolves to the macro `m`, which is not in the value namespace | help: to link to the macro, add an exclamation mark: `m!` -error: aborting due to 16 previous errors +error: aborting due to 18 previous errors diff --git a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr index 3c13df20588d8..d946aa939800c 100644 --- a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr +++ b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr @@ -2,7 +2,7 @@ error: unresolved link to `i` --> $DIR/intra-link-span-ice-55723.rs:9:10 | LL | /// (arr[i]) - | ^ no item named `i` in `intra_link_span_ice_55723` + | ^ the module `intra_link_span_ice_55723` contains no item named `i` | note: the lint level is defined here --> $DIR/intra-link-span-ice-55723.rs:1:9 diff --git a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr b/src/test/rustdoc-ui/intra-links-warning-crlf.stderr index 351f8fafa64d8..76a2ac0c8cf02 100644 --- a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr +++ b/src/test/rustdoc-ui/intra-links-warning-crlf.stderr @@ -2,7 +2,7 @@ warning: unresolved link to `error` --> $DIR/intra-links-warning-crlf.rs:7:6 | LL | /// [error] - | ^^^^^ no item named `error` in `intra_links_warning_crlf` + | ^^^^^ the module `intra_links_warning_crlf` contains no item named `error` | = note: `#[warn(broken_intra_doc_links)]` on by default = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -11,7 +11,7 @@ warning: unresolved link to `error1` --> $DIR/intra-links-warning-crlf.rs:12:11 | LL | /// docs [error1] - | ^^^^^^ no item named `error1` in `intra_links_warning_crlf` + | ^^^^^^ the module `intra_links_warning_crlf` contains no item named `error1` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -19,7 +19,7 @@ warning: unresolved link to `error2` --> $DIR/intra-links-warning-crlf.rs:15:11 | LL | /// docs [error2] - | ^^^^^^ no item named `error2` in `intra_links_warning_crlf` + | ^^^^^^ the module `intra_links_warning_crlf` contains no item named `error2` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -27,7 +27,7 @@ warning: unresolved link to `error` --> $DIR/intra-links-warning-crlf.rs:23:20 | LL | * It also has an [error]. - | ^^^^^ no item named `error` in `intra_links_warning_crlf` + | ^^^^^ the module `intra_links_warning_crlf` contains no item named `error` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` diff --git a/src/test/rustdoc-ui/intra-links-warning.stderr b/src/test/rustdoc-ui/intra-links-warning.stderr index 0832e00d35a00..09db465df59fb 100644 --- a/src/test/rustdoc-ui/intra-links-warning.stderr +++ b/src/test/rustdoc-ui/intra-links-warning.stderr @@ -10,37 +10,37 @@ warning: unresolved link to `Bar::foo` --> $DIR/intra-links-warning.rs:3:35 | LL | //! Test with [Foo::baz], [Bar::foo], ... - | ^^^^^^^^ no item named `Bar` in `intra_links_warning` + | ^^^^^^^^ the module `intra_links_warning` contains no item named `Bar` warning: unresolved link to `Uniooon::X` --> $DIR/intra-links-warning.rs:6:13 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^^^^^ no item named `Uniooon` in `intra_links_warning` + | ^^^^^^^^^^ the module `intra_links_warning` contains no item named `Uniooon` warning: unresolved link to `Qux::Z` --> $DIR/intra-links-warning.rs:6:30 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^ no item named `Qux` in `intra_links_warning` + | ^^^^^^ the module `intra_links_warning` contains no item named `Qux` warning: unresolved link to `Uniooon::X` --> $DIR/intra-links-warning.rs:10:14 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^^^^^ no item named `Uniooon` in `intra_links_warning` + | ^^^^^^^^^^ the module `intra_links_warning` contains no item named `Uniooon` warning: unresolved link to `Qux::Z` --> $DIR/intra-links-warning.rs:10:31 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^ no item named `Qux` in `intra_links_warning` + | ^^^^^^ the module `intra_links_warning` contains no item named `Qux` warning: unresolved link to `Qux:Y` --> $DIR/intra-links-warning.rs:14:13 | LL | /// [Qux:Y] - | ^^^^^ no item named `Qux:Y` in `intra_links_warning` + | ^^^^^ the module `intra_links_warning` contains no item named `Qux:Y` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -48,7 +48,7 @@ warning: unresolved link to `error` --> $DIR/intra-links-warning.rs:58:30 | LL | * time to introduce a link [error]*/ - | ^^^^^ no item named `error` in `intra_links_warning` + | ^^^^^ the module `intra_links_warning` contains no item named `error` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -56,7 +56,7 @@ warning: unresolved link to `error` --> $DIR/intra-links-warning.rs:64:30 | LL | * time to introduce a link [error] - | ^^^^^ no item named `error` in `intra_links_warning` + | ^^^^^ the module `intra_links_warning` contains no item named `error` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -70,7 +70,7 @@ LL | #[doc = "single line [error]"] single line [error] ^^^^^ - = note: no item named `error` in `intra_links_warning` + = note: the module `intra_links_warning` contains no item named `error` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` @@ -83,7 +83,7 @@ LL | #[doc = "single line with \"escaping\" [error]"] single line with "escaping" [error] ^^^^^ - = note: no item named `error` in `intra_links_warning` + = note: the module `intra_links_warning` contains no item named `error` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` @@ -98,14 +98,14 @@ LL | | /// [error] [error] ^^^^^ - = note: no item named `error` in `intra_links_warning` + = note: the module `intra_links_warning` contains no item named `error` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error1` --> $DIR/intra-links-warning.rs:80:11 | LL | /// docs [error1] - | ^^^^^^ no item named `error1` in `intra_links_warning` + | ^^^^^^ the module `intra_links_warning` contains no item named `error1` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -113,7 +113,7 @@ warning: unresolved link to `error2` --> $DIR/intra-links-warning.rs:82:11 | LL | /// docs [error2] - | ^^^^^^ no item named `error2` in `intra_links_warning` + | ^^^^^^ the module `intra_links_warning` contains no item named `error2` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -121,7 +121,7 @@ warning: unresolved link to `BarA` --> $DIR/intra-links-warning.rs:21:10 | LL | /// bar [BarA] bar - | ^^^^ no item named `BarA` in `intra_links_warning` + | ^^^^ the module `intra_links_warning` contains no item named `BarA` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -129,7 +129,7 @@ warning: unresolved link to `BarB` --> $DIR/intra-links-warning.rs:27:9 | LL | * bar [BarB] bar - | ^^^^ no item named `BarB` in `intra_links_warning` + | ^^^^ the module `intra_links_warning` contains no item named `BarB` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -137,7 +137,7 @@ warning: unresolved link to `BarC` --> $DIR/intra-links-warning.rs:34:6 | LL | bar [BarC] bar - | ^^^^ no item named `BarC` in `intra_links_warning` + | ^^^^ the module `intra_links_warning` contains no item named `BarC` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -151,7 +151,7 @@ LL | #[doc = "Foo\nbar [BarD] bar\nbaz"] bar [BarD] bar ^^^^ - = note: no item named `BarD` in `intra_links_warning` + = note: the module `intra_links_warning` contains no item named `BarD` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `BarF` @@ -167,7 +167,7 @@ LL | f!("Foo\nbar [BarF] bar\nbaz"); bar [BarF] bar ^^^^ - = note: no item named `BarF` in `intra_links_warning` + = note: the module `intra_links_warning` contains no item named `BarF` = 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) diff --git a/src/test/rustdoc-ui/lint-group.stderr b/src/test/rustdoc-ui/lint-group.stderr index 550b79f6e8928..4e9134ea469bd 100644 --- a/src/test/rustdoc-ui/lint-group.stderr +++ b/src/test/rustdoc-ui/lint-group.stderr @@ -32,7 +32,7 @@ error: unresolved link to `error` --> $DIR/lint-group.rs:9:29 | LL | /// what up, let's make an [error] - | ^^^^^ no item named `error` in `lint_group` + | ^^^^^ the module `lint_group` contains no item named `error` | note: the lint level is defined here --> $DIR/lint-group.rs:7:9 diff --git a/src/test/rustdoc/intra-link-associated-items.rs b/src/test/rustdoc/intra-link-associated-items.rs index 16a21e33748fa..dec0deae5df7c 100644 --- a/src/test/rustdoc/intra-link-associated-items.rs +++ b/src/test/rustdoc/intra-link-associated-items.rs @@ -3,8 +3,10 @@ /// [`std::collections::BTreeMap::into_iter`] /// [`String::from`] is ambiguous as to which `From` impl +/// [type@Vec::into_iter] uses a disambiguator // @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/collections/btree/map/struct.BTreeMap.html#method.into_iter"]' 'std::collections::BTreeMap::into_iter' // @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/string/struct.String.html#method.from"]' 'String::from' +// @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.into_iter"]' 'Vec::into_iter' pub fn foo() {} /// Link to [MyStruct], [link from struct][MyStruct::method], [MyStruct::clone], [MyStruct::Input] From 472e52e5a03790becdbe21be1002a90dd2d7d3d4 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 20 Sep 2020 02:18:09 -0400 Subject: [PATCH 0918/1052] Fix intra-doc links for primitives - Add `PrimTy::name` and `PrimTy::name_str` - Use those new functions to distinguish between the name in scope and the canonical name - Fix diagnostics for primitive types - Add tests for primitives --- compiler/rustc_hir/src/hir.rs | 24 +++++++++++++++++++ .../passes/collect_intra_doc_links.rs | 20 +++++++++++----- src/test/rustdoc-ui/intra-link-errors.stderr | 5 +--- src/test/rustdoc/primitive-link.rs | 7 ++++++ 4 files changed, 46 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index cd4185226dce5..636f67a77c890 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2004,6 +2004,30 @@ pub enum PrimTy { Char, } +impl PrimTy { + pub fn name_str(self) -> &'static str { + match self { + PrimTy::Int(i) => i.name_str(), + PrimTy::Uint(u) => u.name_str(), + PrimTy::Float(f) => f.name_str(), + PrimTy::Str => "str", + PrimTy::Bool => "bool", + PrimTy::Char => "char", + } + } + + pub fn name(self) -> Symbol { + match self { + PrimTy::Int(i) => i.name(), + PrimTy::Uint(u) => u.name(), + PrimTy::Float(f) => f.name(), + PrimTy::Str => sym::str, + PrimTy::Bool => sym::bool, + PrimTy::Char => sym::char, + } + } +} + #[derive(Debug, HashStable_Generic)] pub struct BareFnTy<'hir> { pub unsafety: Unsafety, diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 71fd5deca54b7..af077e0f5eb6b 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -273,13 +273,13 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { return handle_variant(cx, res, extra_fragment); } // Not a trait item; just return what we found. - Res::PrimTy(..) => { + Res::PrimTy(ty) => { if extra_fragment.is_some() { return Err(ErrorKind::AnchorFailure( AnchorFailure::RustdocAnchorConflict(res), )); } - return Ok((res, Some(path_str.to_owned()))); + return Ok((res, Some(ty.name_str().to_owned()))); } Res::Def(DefKind::Mod, _) => { return Ok((res, extra_fragment.clone())); @@ -292,6 +292,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { if value != (ns == ValueNS) { return Err(ResolutionFailure::WrongNamespace(res, ns).into()); } + // FIXME: why is this necessary? } else if let Some((path, prim)) = is_primitive(path_str, ns) { if extra_fragment.is_some() { return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(prim))); @@ -1008,12 +1009,12 @@ impl LinkCollector<'_, '_> { suggest_disambiguator(resolved, diag, path_str, dox, sp, &link_range); }); }; - if let Res::PrimTy(_) = res { + if let Res::PrimTy(ty) = res { match disambiguator { Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => { item.attrs.links.push(ItemLink { link: ori_link, - link_text: path_str.to_owned(), + link_text, did: None, fragment, }); @@ -1488,6 +1489,10 @@ fn resolution_failure( link_range: Option>, kinds: SmallVec<[ResolutionFailure<'_>; 3]>, ) { + let has_primitive = kinds.iter().any(|err| + matches!(err, ResolutionFailure::NoPrimitiveAssocItem{..} | ResolutionFailure::NoPrimitiveImpl(_, _)) + ); + report_diagnostic( collector.cx, &format!("unresolved link to `{}`", path_str), @@ -1528,6 +1533,7 @@ fn resolution_failure( let module_id = *module_id; // FIXME(jynelson): this might conflict with my `Self` fix in #76467 + // FIXME: use itertools `collect_tuple` instead fn split(path: &str) -> Option<(&str, &str)> { let mut splitter = path.rsplitn(2, "::"); splitter.next().and_then(|right| splitter.next().map(|left| (left, right))) @@ -1567,7 +1573,6 @@ fn resolution_failure( }; // See if this was a module: `[path]` or `[std::io::nope]` if let Some(module) = last_found_module { - // NOTE: uses an explicit `continue` so the `note:` will come before the `help:` let module_name = collector.cx.tcx.item_name(module); let note = format!( "the module `{}` contains no item named `{}`", @@ -1595,7 +1600,10 @@ fn resolution_failure( diagnostic_name = collector.cx.tcx.item_name(def_id).as_str(); (Some(kind), &*diagnostic_name) } - Res::PrimTy(_) => (None, name), + Res::PrimTy(_) => { + assert!(has_primitive); + continue; + } _ => unreachable!("only ADTs and primitives are in scope at module level"), }; let path_description = if let Some(kind) = kind { diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr index cd06ee6f798dc..fab8c105a4953 100644 --- a/src/test/rustdoc-ui/intra-link-errors.stderr +++ b/src/test/rustdoc-ui/intra-link-errors.stderr @@ -80,10 +80,7 @@ error: unresolved link to `u8::not_found` --> $DIR/intra-link-errors.rs:55:6 | LL | /// [u8::not_found] - | ^^^^^^^^^^^^^ - | | - | the builtin type `u8` does not have an associated item named `not_found` - | the builtin type `u8` has no builtin type named `not_found` + | ^^^^^^^^^^^^^ the builtin type `u8` does not have an associated item named `not_found` error: unresolved link to `S` --> $DIR/intra-link-errors.rs:59:6 diff --git a/src/test/rustdoc/primitive-link.rs b/src/test/rustdoc/primitive-link.rs index 819ef05174a8a..8f69b894a223d 100644 --- a/src/test/rustdoc/primitive-link.rs +++ b/src/test/rustdoc/primitive-link.rs @@ -4,6 +4,13 @@ // @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.u32.html"]' 'u32' // @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i64.html"]' 'i64' +// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html"]' 'std::primitive::i32' +// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html"]' 'std::primitive::str' + +// FIXME: this doesn't resolve +// @ has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html#associatedconstant.MAX"]' 'std::primitive::i32::MAX' /// It contains [`u32`] and [i64]. +/// It also links to [std::primitive::i32], [std::primitive::str], +/// and [`std::primitive::i32::MAX`]. pub struct Foo; From 049d29bac580b958cdff6e898dad22de09a27958 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 20 Sep 2020 02:39:19 -0400 Subject: [PATCH 0919/1052] Unify primitive errors with other intra-link errors Now that `PrimTy::name()` exists, there's no need to carry around the name of the primitive that failed to resolve. This removes the variants special-casing primitives in favor of `NotResolved`. - Remove `NoPrimitiveImpl` and `NoPrimitiveAssocItem` - Remove hacky `has_primitive` check in `resolution_failure()` - Fixup a couple tests that I forgot to `--bless` before --- .../passes/collect_intra_doc_links.rs | 48 ++++++------------- src/test/rustdoc-ui/intra-link-errors.rs | 11 ++++- src/test/rustdoc-ui/intra-link-errors.stderr | 29 ++++++++--- .../rustdoc/intra-link-associated-items.rs | 2 +- 4 files changed, 47 insertions(+), 43 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index af077e0f5eb6b..cb2de05598f4b 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -60,13 +60,6 @@ impl<'a> From> for ErrorKind<'a> { #[derive(Debug)] enum ResolutionFailure<'a> { - /// this is a primitive type without an impls (no associated methods) - /// when will this actually happen? - /// the `Res` is the primitive it resolved to - NoPrimitiveImpl(Res, String), - /// `[u8::not_found]` - /// the `Res` is the primitive it resolved to - NoPrimitiveAssocItem { res: Res, prim_name: &'a str, assoc_item: Symbol }, /// This resolved, but with the wrong namespace. /// `Namespace` is the expected namespace (as opposed to the actual). WrongNamespace(Res, Namespace), @@ -326,8 +319,12 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { })?; if let Some((path, prim)) = is_primitive(&path_root, TypeNS) { - let impls = primitive_impl(cx, &path) - .ok_or_else(|| ResolutionFailure::NoPrimitiveImpl(prim, path_root.into()))?; + let impls = + primitive_impl(cx, &path).ok_or_else(|| ResolutionFailure::NotResolved { + module_id, + partial_res: Some(prim), + unresolved: item_str.into(), + })?; for &impl_ in impls { let link = cx .tcx @@ -354,10 +351,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { item_name, ns.descr() ); - return Err(ResolutionFailure::NoPrimitiveAssocItem { - res: prim, - prim_name: path, - assoc_item: item_name, + return Err(ResolutionFailure::NotResolved { + module_id, + partial_res: Some(prim), + unresolved: item_str.into(), } .into()); } @@ -1009,7 +1006,7 @@ impl LinkCollector<'_, '_> { suggest_disambiguator(resolved, diag, path_str, dox, sp, &link_range); }); }; - if let Res::PrimTy(ty) = res { + if let Res::PrimTy(..) = res { match disambiguator { Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => { item.attrs.links.push(ItemLink { @@ -1489,10 +1486,6 @@ fn resolution_failure( link_range: Option>, kinds: SmallVec<[ResolutionFailure<'_>; 3]>, ) { - let has_primitive = kinds.iter().any(|err| - matches!(err, ResolutionFailure::NoPrimitiveAssocItem{..} | ResolutionFailure::NoPrimitiveImpl(_, _)) - ); - report_diagnostic( collector.cx, &format!("unresolved link to `{}`", path_str), @@ -1533,7 +1526,7 @@ fn resolution_failure( let module_id = *module_id; // FIXME(jynelson): this might conflict with my `Self` fix in #76467 - // FIXME: use itertools `collect_tuple` instead + // FIXME: maybe use itertools `collect_tuple` instead? fn split(path: &str) -> Option<(&str, &str)> { let mut splitter = path.rsplitn(2, "::"); splitter.next().and_then(|right| splitter.next().map(|left| (left, right))) @@ -1600,10 +1593,7 @@ fn resolution_failure( diagnostic_name = collector.cx.tcx.item_name(def_id).as_str(); (Some(kind), &*diagnostic_name) } - Res::PrimTy(_) => { - assert!(has_primitive); - continue; - } + Res::PrimTy(ty) => (None, ty.name_str()), _ => unreachable!("only ADTs and primitives are in scope at module level"), }; let path_description = if let Some(kind) = kind { @@ -1640,7 +1630,7 @@ fn resolution_failure( Impl | GlobalAsm => unreachable!("not a path"), } } else { - res.descr() + "associated item" }; let note = format!( "the {} `{}` has no {} named `{}`", @@ -1683,16 +1673,6 @@ fn resolution_failure( diag.level = rustc_errors::Level::Bug; "all intra doc links should have a parent item".to_owned() } - ResolutionFailure::NoPrimitiveImpl(res, _) => format!( - "this link partially resolves to {}, which does not have any associated items", - item(res), - ), - ResolutionFailure::NoPrimitiveAssocItem { prim_name, assoc_item, .. } => { - format!( - "the builtin type `{}` does not have an associated item named `{}`", - prim_name, assoc_item - ) - } }; if let Some(span) = sp { diag.span_label(span, ¬e); diff --git a/src/test/rustdoc-ui/intra-link-errors.rs b/src/test/rustdoc-ui/intra-link-errors.rs index 8c250fbc58b27..0278caf308776 100644 --- a/src/test/rustdoc-ui/intra-link-errors.rs +++ b/src/test/rustdoc-ui/intra-link-errors.rs @@ -54,7 +54,16 @@ /// [u8::not_found] //~^ ERROR unresolved link -//~| NOTE the builtin type `u8` does not have an associated item named `not_found` +//~| NOTE the builtin type `u8` has no associated item named `not_found` + +/// [std::primitive::u8::not_found] +//~^ ERROR unresolved link +//~| NOTE the builtin type `u8` has no associated item named `not_found` + +/// [type@Vec::into_iter] +//~^ ERROR unresolved link +//~| HELP to link to the associated function, add parentheses +//~| NOTE this link resolves to the associated function `into_iter` /// [S!] //~^ ERROR unresolved link diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr index fab8c105a4953..b63f799535a1f 100644 --- a/src/test/rustdoc-ui/intra-link-errors.stderr +++ b/src/test/rustdoc-ui/intra-link-errors.stderr @@ -80,11 +80,26 @@ error: unresolved link to `u8::not_found` --> $DIR/intra-link-errors.rs:55:6 | LL | /// [u8::not_found] - | ^^^^^^^^^^^^^ the builtin type `u8` does not have an associated item named `not_found` + | ^^^^^^^^^^^^^ the builtin type `u8` has no associated item named `not_found` -error: unresolved link to `S` +error: unresolved link to `std::primitive::u8::not_found` --> $DIR/intra-link-errors.rs:59:6 | +LL | /// [std::primitive::u8::not_found] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the builtin type `u8` has no associated item named `not_found` + +error: unresolved link to `Vec::into_iter` + --> $DIR/intra-link-errors.rs:63:6 + | +LL | /// [type@Vec::into_iter] + | ^^^^^^^^^^^^^^^^^^^ + | | + | this link resolves to the associated function `into_iter`, which is not in the type namespace + | help: to link to the associated function, add parentheses: `Vec::into_iter()` + +error: unresolved link to `S` + --> $DIR/intra-link-errors.rs:68:6 + | LL | /// [S!] | ^^ | | @@ -92,7 +107,7 @@ LL | /// [S!] | help: to link to the struct, prefix with `struct@`: `struct@S` error: unresolved link to `T::g` - --> $DIR/intra-link-errors.rs:77:6 + --> $DIR/intra-link-errors.rs:86:6 | LL | /// [type@T::g] | ^^^^^^^^^ @@ -101,13 +116,13 @@ LL | /// [type@T::g] | help: to link to the associated function, add parentheses: `T::g()` error: unresolved link to `T::h` - --> $DIR/intra-link-errors.rs:82:6 + --> $DIR/intra-link-errors.rs:91:6 | LL | /// [T::h!] | ^^^^^ the trait `T` has no macro named `h` error: unresolved link to `S::h` - --> $DIR/intra-link-errors.rs:69:6 + --> $DIR/intra-link-errors.rs:78:6 | LL | /// [type@S::h] | ^^^^^^^^^ @@ -116,7 +131,7 @@ LL | /// [type@S::h] | help: to link to the associated function, add parentheses: `S::h()` error: unresolved link to `m` - --> $DIR/intra-link-errors.rs:89:6 + --> $DIR/intra-link-errors.rs:98:6 | LL | /// [m()] | ^^^ @@ -124,5 +139,5 @@ LL | /// [m()] | this link resolves to the macro `m`, which is not in the value namespace | help: to link to the macro, add an exclamation mark: `m!` -error: aborting due to 18 previous errors +error: aborting due to 20 previous errors diff --git a/src/test/rustdoc/intra-link-associated-items.rs b/src/test/rustdoc/intra-link-associated-items.rs index dec0deae5df7c..daf7075a91740 100644 --- a/src/test/rustdoc/intra-link-associated-items.rs +++ b/src/test/rustdoc/intra-link-associated-items.rs @@ -3,7 +3,7 @@ /// [`std::collections::BTreeMap::into_iter`] /// [`String::from`] is ambiguous as to which `From` impl -/// [type@Vec::into_iter] uses a disambiguator +/// [Vec::into_iter()] uses a disambiguator // @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/collections/btree/map/struct.BTreeMap.html#method.into_iter"]' 'std::collections::BTreeMap::into_iter' // @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/string/struct.String.html#method.from"]' 'String::from' // @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.into_iter"]' 'Vec::into_iter' From 085679c8414fbcd0a832d57134eb6832ea7a1020 Mon Sep 17 00:00:00 2001 From: Jarek Samic Date: Wed, 23 Sep 2020 21:31:27 -0400 Subject: [PATCH 0920/1052] Use theme-adaptive SVG favicon from other Rust sites --- src/librustdoc/html/layout.rs | 4 +++- src/librustdoc/html/render/mod.rs | 4 +++- src/librustdoc/html/static/favicon-16x16.png | Bin 0 -> 2214 bytes src/librustdoc/html/static/favicon-32x32.png | Bin 0 -> 2919 bytes src/librustdoc/html/static/favicon.ico | Bin 23229 -> 0 bytes src/librustdoc/html/static/favicon.svg | 24 +++++++++++++++++++ src/librustdoc/html/static_files.rs | 6 +++-- 7 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 src/librustdoc/html/static/favicon-16x16.png create mode 100644 src/librustdoc/html/static/favicon-32x32.png delete mode 100644 src/librustdoc/html/static/favicon.ico create mode 100644 src/librustdoc/html/static/favicon.svg diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 287c85b8c2253..7239b3c5ba2f6 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -158,7 +158,9 @@ pub fn render( keywords = page.keywords, favicon = if layout.favicon.is_empty() { format!( - r#""#, + r##" + +"##, static_root_path = static_root_path, suffix = page.resource_suffix ) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index f095f67b54c63..8b5ba7a239c5f 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -754,7 +754,9 @@ fn write_shared( write(cx.path("rust-logo.png"), static_files::RUST_LOGO)?; } if (*cx.shared).layout.favicon.is_empty() { - write(cx.path("favicon.ico"), static_files::RUST_FAVICON)?; + write(cx.path("favicon.svg"), static_files::RUST_FAVICON_SVG)?; + write(cx.path("favicon-16x16.png"), static_files::RUST_FAVICON_PNG_16)?; + write(cx.path("favicon-32x32.png"), static_files::RUST_FAVICON_PNG_32)?; } write(cx.path("brush.svg"), static_files::BRUSH_SVG)?; write(cx.path("wheel.svg"), static_files::WHEEL_SVG)?; diff --git a/src/librustdoc/html/static/favicon-16x16.png b/src/librustdoc/html/static/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..7cfe6c13550d31bc31355616bbb9cb77fd1b25ef GIT binary patch literal 2214 zcmai0eOwb|96wBnh5{uNA5FX#8j9O(4yl)LyARcIVNxmKrUYOD%pfJyWON=)B<95>De^Rm5G6M}j3YLqKtM+@IBeEw z^+wbz;o5ak@SEL6xUikVXe8WJEFP9pGywO3uTmwxha}|Wr z9u|-rLXDJ)G2t{3kpl`W;YO%bBuJ+P21kd?(GxW6gW)vnCxqExX54RUQWHS;@lhhf zJ|gVd``1Y^@=zFJJK>(g3hajVzz_h_1Q{78U@+bBlQht;p6z!frXHv{LPhwYz<<`72lXv!(d1nyYeRki} zG-TB$r};*eD+wIao;8*Q1z1lX*pMIAo8KMMp3kpQSfT>9<7X{yl)7mmZ&HHTmt$V^;c~|?Lwt01Kia(Ww7QAk1 z37VI_XzHZ4&TD(hrV_xFzrp5h zIDA-gJMuv0N4O`)y}GEDLzI5DRqcQGw4eZ{gx8^nswsmyuR8`H8qrt&We_mQ?E71KoB@x@ws?}G)`?crAQn;UN4 z6pH^kmG!J);&{3;dAl$;_(V^Szpt%NFJJz= zy0-T8z<~J6?w>4P{r&x!3m1l6=;+9(f6gXZaCUdB?(m(=>C3y+SzUDzf4JRP!@oM< Yn%3fx65vtoO=gysTc){dn_8A;mgY3Mwv7J;8=I#3|L3_2=X>9CzO#MjlI-o}Hd}k4HUfc| zO?4;xz;Be|o}mdpp_rIq1VX(S^!1nc(>w`mA>W+E5rzWha=r-05eTA#T*P9B0}@my z5C#fJ=%K5nXcWjHq5Z6AIGV@>;DPQjVt^jw<;#uoG@8VBUyC+h;}WB70)unGigVUEN8lP&?d-=HgyFX$qkP$GnQLeX>ppKUP> zf1wDc@9QdZmgs9_8ts46`TWnqfFzVCI1wL{`k7CEZvgp5ivX+-012gHHb9921d^r7 zOepd~@CM~Tgg+VN0|E%nE(yIF|1U7$8=#9YLMW!gO$Ct97D^pO<_J_iD-7@hITGHq ztxxNofFSJOfWor~siL$D0SL!3wZBrw{}V<++u-4*QWRVX1$-5nt^+~o9ZkrAom;Kc z`UFv3T)f3XE*Jr0kdK=)ib`>@wy?9d#^BAT0)dN0fOSD`G?^uVS$G^Chr!ukEO5RS zHUvvN0cQn^1l*KAN;Z5JI4lY4|M3+ajUvJtG#bGjgd{?7v~p>x&FMholr$wqfXegak(Iz&S(^TbignHAV!(e zSYp&_3zQ<56`$+McmQno+fiaa`iNDWy}z9#V!sH3s3iR3u)=y%Yw!?&rwMj?oWR2L zKmr8t6cWSZCPU1#K_FBTLAXF)6b6AXO_8QFtRka%~Izh4ror z*EZ_|=QE<;c-&c(KbCDA2%Is!@H+g)rZQ&0D#{5Cz@kMoLfJM}sdZNl#oCX>4%v0a znisL7DOS0$j+g^6mUBlNs`}n%hY?$wJRPq86v`{7)93jX?p_lVRnlJ&&afZLZ#&hz zO*L;r_Yz7At=pnIS&x1(ID65shfw2gS^Mv+f$LH_YO+OYq_KaMk=!7=N$s8 zYVb^P@k%r7@*~gE_dVG>kS=f8ngJ&BpPbVtC(o&BusyzO&arf-3>V3FCjyziw}vL} z9Oh8PdKp&CrT}9PWUANt^pi0gLS2UocM;D-O-_!s-5S<7^r8#bN(^WZTqFPeacoP0 zy)NeEyBWEQyN`L_-b6@Dk~P_QYzX;bVSD#L!3h)D<2bbqiwl3s9^aQ+(V3xBlAVY} z((ZcO3=N+xYIsemXzw|b7b4Ro^u(3l)Me_0bv4ljj>4afnIiW92!WV2PjRatG7sv* zpP6bZ*~!;`Yi0U6&-pUA8W*JpZr^s@LEElz(fOFOSxl}IQgcO)DY)q9iK>b%>u&__ zvRF9OMNB(k`N6GOoqZPEZY5um`P|9V%DR}L>-`rGr4p1@kcTSTc%3vbz{xP`*qS+< zRl?zRy}OoBI<{=+M)PZfMxH~$tT?`djmk)EW4fNbO1!E#X-UWeTiuEXf-vFTtUuHS z%c>{aPOG#ca`;4~smG4gTVB7OEBF6ZZRp{SU~?`nB*f81&>>G@IbC>r8?!JFg9}h z32oc#$D||Zkr31zZ$H2E5}cLQ$@}*M)^!a&yv*?R?TI>OXd04|dAgFp%d+PC2!;8l zk|J<;{INS(HnDoo>swFLhh7Tjp3`(h%_%E5>*@Eb%#s#0aLuc*=6Z?Q$bk9d*ai8|Oy~^8zMPyKV`^t-=c~-|`ud_RhdcWd7D=8|%sj<> zA7A=zVZ6Jv>@X*rAYDtLP#zQjJCTOAsM><&`NGa(hEys=@*n4N#$HYUv+miL+Q_QJePvpR)YMcigQ0iSd;4*>-39u=C2}WQ!>F$6s;U`Vok8)> zNF&uFB_#(}ht)T>wN-X>bZBR7R4>U&`(V;9b#d9Esik%3RtbL3Y$H1{`GS946ZEnj z)7IL0;h&yB z^p~mghPtj97>Q&~mJ1n?k&&4}bb4yGLqc9k%6GjzJw+4wiJI<(-Hv-%0sGtYHon}` z(C0xfVU=q#n9SUQ0v{5Iw72I~7NR3A6DYM+KY^*`<- zHk2kfhb5Je4BJD-A+*@(Gwzg%9mTv3ayQk{wy-2a6X6N$1FCQN-$_u`h zo18qe^Qvs!8RogQw9RQ1N3ymRCRN~cdV70oENMpeakk-FFJ8RhWafCb46iJ+^&ad^ zbP5f6i)%}2YFfYXikJcbK!CyS>ZjW3s>QKmc`-3D9aXiWUpTLR8`n#Y>~Ar~&P}d! zh#PM#ivK`>$!Te6A(`0*94>bo)K}kh|2~z)S^~G|Br#^#G~juD(&ERuvQ~k5((c6I z$LnlbhQ{cDfgV)q%*x8jil>pTZf*vKhCL51h1b>9$tRdzq4z!*>5mR~sTq8qYG(R0 z^v`Ab#-mp!`BolVW9>Fmp7j>C(^~?|`pkkF0tfqmbA6Ml6`Ne%l@YX&ivPz{iWfQ0 IIpoLx0#^I3DgXcg literal 0 HcmV?d00001 diff --git a/src/librustdoc/html/static/favicon.ico b/src/librustdoc/html/static/favicon.ico deleted file mode 100644 index b8ad23769ac8d06eb5973bfb3d2acbf385240f98..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23229 zcmeHvc|28H|Nn80c^;Zf$(*SSWu`JD(V;RG>6p@BE^{)JxkzQmP>~SI(4dfxF(slB z5)PR%L}d!)x0ZYM{hrRHTlcx&;g8>bJ@5Nj>$5(?d#%0p+H0?)2Zf?QQKG7KHQB}0m;J^5csADJ;Ux=>OHY2a((G>5y2ee}sw(wi6T`3%ZKV`TrFyPF# zt&A6CYgvuX>mI3Y4iczsT`%x-^H<4K|4iTE5A( zW;pTj)bS=iyy&B$FLZTz6sqXlO(QRPaGH6uCn|hQsGKO}S@_hL9R`fA>g_4(3L74) z=Mhj5{S+k^;9h$yrFNWoZS_9MkBle@w7uv}e0VO(;)O~BN_s=I~%uGO3%LKPp+NC_VOjyiikz7Wk2r6 z?y}oVo2#KHaFYG54CD?V{U0f#D6deJ(I;O>8=(|PlNQygb8S{K1o10}pnz1B`0*i@@Sg+EVqi&Sp>fWfI-G0X^^q3yS z7IcPUOtbmMGonZH6ft-&(L(KE8mn4Qj0<&B11j?I=GmZA?qTQH-`$art_&Zcb9PQo zG0QgY8$X9r!P{{pK4q7mw;k*Tp%SM}MKtFE!;oThbJs zORbMuJC$t^=d_P``$YQNa31F8=u<4JeOjkJXsPq;bqM%)JjBVO(}HWxT)Rh0-c{gn z)s)>SmgjB)Iwm;tBNMrrXVw+p@v^sZ)Ft3>#T*Zt!bf;^-!%`}l4o64g0Xbh#d+fl z2nP4|PddH*ek-}Q0c%SyjhRbgaoiL|-QXf1VQPD@dt&7L({KlR{m6%oT=&oTJT&!_ zqpV87@R;29lTpQt3>x!spW?3)0~*VR#*xSQUCx*uV3n7fe$wEeA0}3G+4S6;(^0D` zr{_vBu6S!+@gUJay@HLKba{5S=}%;PZa=_?b>+@?bQjTpYVa zQxR2AD(!hy-&dB4S(rSj(hw07+1Qn;gE+|6Q9Y^juK`zGqWNJ z&Q^uw#K`wwZkX?3cAhLei_KHfQec)?Md3f{;wR~`UEqSt`N6B!Z$F8RW=ANwbDs~r z9d73)pocEO%%8w_5 zINB&w?%vVRYAXt;d^GeG+pC5*!RrJ@hx!kH$F8pGV2z6vMI}+Zz_j=_-}Y+vtS&s} z5|Sj{l*eyb>EY=7MEUIjOLt4X%i(4Zwzi+15&oh&Zcf-w$S^4hp$&C86_Mf=*|U$( zg6BxUoJ6;lRep1(I5?gif4^i<%cSZI%@n2jY3*T?dR6_aLsP3t;xP9qL_)4Q7NmUT zcfxqwt`PIF=Bo%l$u%>U&`urbD>LB5sS^7%t=R;#T|An@F=Ap88RN*@G=hfA|#>lbNTDBHD3Z^a}2)@(uJa2 z1pM(erS6|p2vxGNB0;N$`3hoF6)o{1iLdGkMO*LEi99`+`Le6t^4^89vUuyuAG2;OiPC>^h?*>zPN>H#OS^pWzyR5Y+sBDTF%C4V`Te#=bIs?Ji;C($TzLB zoV=gS1zsem65Qvnqh35J5}$C!@)TapH(NXLpNt+qG-;`Hktse>dlxMq9cF$-B8Xe& zVGUO0*$ws!w|MAyP`Tlwj`LhewJltkeOhnInQ2D%Y&(7$FWx=6PgzY4c4Hc49@koR zlAxG3%O`waMu66LeJCb#??>w=3qH-y;(~mSFjMrEDcj?8xVi0j1ehM^HTI8CyY`Hy z%)Q=)uJ{GNrTERxgQ#||W*xn3|0?#VASWgZi#;56egl`+`_-=S&~2%OiFZxTehUO(tOY$aNH^|NWHbP;A^jVcUNCvoA-d}y$1dY zzHxp1_nEv51-mYPH7mO(fSI%`xAu1u&u=IbO~;f3O?~}TD9h4*#$welW;aVU6<)@2 zvg?k#QIaO5_M?49caCmK&J65$G=$lFSFOiYfZIyKoi8i(>o(k@T!}O8*ldOLwf5r) z&-LCj3bV;e7iC`2+<9GWx95HR&;;ycXuaC~o105|Jm#45W-0HN9QZ&j@Fr70PPOmG zrqJa@< z2HvsFF=t{30z9;=;SiP3`fQ(GM;He3cdL*W=p06eca&dD5apWqHHu+8Yg}j^}?nbJe$b zK`eWZ=x3#ociv6U$Fm=DSbFG5?lnFh9@3jjJ1^*x$?>ow{A6L+&PPLbX2o4;H`7^+ z`&i@mcBJRVRnbb4(06r}@^2TtBk29}|sh_~cUeIQofh+od5^Y_A?ZI&k_# zZhC5qH%04)W1SE3gJN~vrG+8+uf0m|H`Szq*Ba&0W$ zK63L-sne||uRCfq$WHUC?|jert;(lYWxEd#UHWGR+@_38SHe}9n_|7gxOduJ;P|Rh zQ<#I&TX{sEM)qp((-Bsy3+`5LJ~OG+eXvSPj^Lmugi7S)8^wE!bYXx!-G;a z*63s5t^zq$;azq88_ljh*WVCI`<0zJJ+Z(_bK1qo%*o(c%leIIk1#5H;6696yBAbW zROWQDBws4J5^}|w30EYfK>f5KFZLKSN;J4EAu`SSa>F&HFOAM8mAn0}X3kr9Dp>nT zD+DWQ)#}Y_>*p7xZW+A9!|r9yC*P8w4qgxkCB+pyQVaC4wg!@V*gfA_^tP!m9dC%n zUCb+%quVTGQ;p5;pu_4lRJv)Zh8|JfMH#1iq|(xIvN&DAbnUwVt+iFwi9HX{ijuv0 zhou%yNg9=owzZ`XWIkbHT=BVThvq)}5>PCS;2r!RFF%H|Jg7hv3x%Vv*DHT} zUHu?1Fi^3*aNesqHa~o1Ab+B|KrB$A=h5!fLB$6z$(^jsS^H{;5oI|koHuJMdBd5# zCRE*YO|a4#j>`cb9@I?MYU5i}g2#NCTf#eQ+rY$MpA`Ej($udZ=X<6OPwZj48nODvHWt_U=_#x2<5Vbm+aSf_Jk@ z{`J$9H?7m&GLm zE_%10XB50$&w|SwOPe`~RoPByW!2Nbl~^XxLs+mhE8V-oTr_vfaavD?9BV(1ql1+N zLVlVfs1=)I4p1xdm-{W~577B^?aEa#d=fI~ET|r>x6@zioncM*3N`f1x;LRVxBh98sF}~*6f|XRp|$CVXg5b$ta6odify782stoPy)kjV{wsceTYVk& zr4nAsEbUWTTu~fqgR6iqX243q=z77~cpZ*Mr#hb1Q?5%4%Mr4`aIw zzt`d4VtbP;-Dev^v9=8Qsm_^b2Zug&{p0d+RVvL^G++1k91J(kXKhs$FLrH8)4n%i zgc&xuoLe1Uy4u&w_-2v{%gi-XKjn&y8~Jypbi4K&SmziY+tXm){ld)a$rnQc);-H* z^$0`O#fPmMJdfu_So1Qx#KE(A0uj;zQY#%n}T%5Y*^Z4le<^p;`!}&Xk`0^ zoo9Dv8EO;uqiXNA=*qD?pgDK1N2^9LhR*8C5w46d1;YYPg^Rc@@W?YbMATDRZfwt@ zJw-DTBY)00gHR^@=^^b*=%#aawyRuLiL|ff+}F1AfM$j)N6}gCHC`8ejImcJ?|;s| zIkCUeaL$E5i@PVwc&t(w&%e!P>cFL&b(`oT&E|dfNbGeJo!T_JYkyk>*8r>6c<-brx&Z+8#s2NR7~kKJ{HeuIe8^Fb`$gN^?B$L zpXQRtEJ@WJo;4>D>7VL0RZN!-d8%|625X)bemwG30#Ajv%}Z2?)_Ttx{Ap9Z?>?o+ znqe~q`115EYhFh+zn8sa;<{GAS#|ave!u198G+=~ROz)fFL~m77;$ujM?=k1el6SCab~{;X6L@krdJ2VWrtk4_ z8uTt>v`Fbwbz@;|kI&ipuCvixAAOrE726ae#JqbdyYiWEOV{~xx@LEe#^&yE`&Qtm z6t0;ZmSUZBu|0WellM?@{6^&%O>u|3+=q2Mxhz-Lc-rJ@dNpfXy359S&SuZwm#Wz* z{JPDM$3BGhqxgEw-dS-RCQn%@T*Ip;6FjWQ4`rMnPQhF0~*~*If`S%=C238dNibP{LQBgiHBP%ym?vk zW~WtSDR15K_?)i&SwzHWe50j%!MU;r->=-13k|`#3B=<#@}li-ispMn6?W8k^e$BB zSPeufJkfgW(QwR&LJ~7CNcZNG&3a$|_gKm53e9~I>w8qIDD}6CNEG=rYuM>*zc3WS z(T18)&o_vfJVda{OO&|qI-K!5wp~Fgsrp9mtsYgaO9aO~N7>ScR+bJ4TDl+9e=u6l zwX3Z${A^CaH=*9qNbuh5WV|>m+}tr@Upf?w-?lkPM$GaOdruJKHAQ)Cv-2%^+ty+jx)D8lvH$C53ab(BT(Bok5&{vR#};~-ytXd z>juN8y7%QBc;m2lE(lHIEThn;*k%tOl@-=6zdLjDpygpD7<{Q;^IW^>GZF>o!UF@7@v6jp(-<9 zZmmSR*rooeci9O+ZcWdgquMud4EK69x8&38ssgJ&w=t(Vey&$VhyvCOx{Z&!wmE_KL&i6bd2gJbEt`s<12KxdkG4^=|v8e;P=9 zdjLI?!l6_heuA;)xWF)&xdp97%5BMK1e4NJxs7>*l)b=$nrYP7u%mmMWKC97YX4z< zvynBTZkt`W$K!D?hFWE3Me`@v+EIjlwkM%|y1&ji*OqB;IZ=-OOAguaQ`PFWJ^h zGdG%vhKoQ!*b=CxthDum+YETs*9SVI=S0OD^Ve|lSg#PFdiz4NRU&}Tr+MzeJB!Pj z0Z$L0UkGhz9N+L#nKFRmVPFqO^aT4cpXMs7F5~1-uOwXSbAe%pu)f>HOj$9Pk0kTc z1uJW{mgfqj6?F5`>$*2zKl>tWyd%7VMx}n2W2>o79b2iv&&(#` zxf)~qVR{o~>5#<4bpD5L342#uV1JmUP$h$RqH1nFf2FI%acliZ$YlAuUJqK)LQa?c z6!$mT4k);DH&P|9nzi2WS>%8P^8>~~mDoY2ikt@grtsOzHv;N<1YF+N&V?v4ygKQa zb@k$~{56JFl%kvgmA8?CeEHoVu3}W4kA#a|hsOzU>3a3{j<+wm^eRW?+w%(d{JKSE(kx^NH6M!5)n~ge|);7U{jM^piaeO77TbB zML9p&dHsMn9lbLq;rNKQUp9l9W(+e0K}(+cRK(MXY2^V-i*<_sebf30>fCz%{dDw4 zqYVw;qzW`_@RZP2)_Uh@E>D#qln{KQdjI*Nv_0$@>D4(KTm(#UG+}OXPB_9g-0-^A zX4Y*n4Y48lN+!LZ-bh5cga{d3$W(qVr*4XieILjWK|gqOebji0#nys|k2Jz7x$5+c z!`oS|&Ai@6v%8TyGu05AKBKzon2lf7iR?tpcLqw_-jM;A(xchD`$Y?xrI{00-i;X_ z+*p3U3>^K@SVZ+bl}P+xx!IF1+i%aPmPh#stGXU0oPC~;j@F!n)$A2>t7pyTm|HYE z`>mf+8q^iLHG#(~R;Kz=^Lh%j}}(Fzh^UYmm!OdbCT5DKve=lQr+zjA_tuoJ#q$ck|cOD5-#? zf_XMOw~MCr+3L)%N5H33Wdh})mCvjDwd(q^Y<%;4e78+aP-1&`67FzDFk5$xs^QD< za}jrQFi9aU)A~l)#Z4g`J8wUZU0FN8h)X->r+J>~t%A*`riAP%)2s&0YrX2miQsu^ z&N^&&ZR=;DYh&8?uP4*FT;^e&H4(e?HKg_IXStTu^&wc>>f&=*=L^{hm!4iQ>kf;zMrNgr8hFGc6zg zu^KHZc=a{b7TvF}eIjaa=~1>WZ-F68k6m@*RIg>i)Vh^>j2E=#)GlmJuH8@7+BB-g z#AGns3%-Edx#BLR(?-lRFkElvv9_jgSM4@FxYKLw8{5@s%?QH!&>h7xO83^OELt4n z5vXch9Wz@L)^&4rydVchPf6Ou-3w7o11oGB4q3N$RwI^n_9LZ=)qa51)O53^D$t^6+GDQy+`lMrp$-OknTlY^0Xe-(mz5Kwm zhP$jsD^A3Ge(#C{at>VK%oO9J`4O+<@+bXwhkmZJ+I>eb7VC_^t}$^`6iXFh;Wfw= zIv8QslCL`SLOrW%?cVSdMID?MH%h$SXIhorg^vZ&mXq93e;Kac)z%I zJZmZvUv4=WBH#CzhUZ}Zkvxi=D&5)@+YCm)9F!`M?vYK1ye0A|kSXTnp(Jm%8BUiN zQzExG=UpKuTH10_hE5i821mrs54z!X;u_#DwV@hx+_ny%1WqJWf1+byz24y zl0jR4ZH|!OIV+_qU#sR33Cqd(LhcXroQah4YUOIDTR#r+n&CS=v(yu(1iJ@BvAs@` zyPr-K0CwOIp%}i3zZ75Q-cpiqVUW{zJ{U^-gr@S zgS8=Q8IIBe3A86KdA?ZfT-kGZRh*-R0pn$YV`eJ{_w~-`n^q^1ZIxo|3)Vk(vSEF- z)(_>y79`Nu6m&IF3|nn;=c}2bD0V$EY{p#hl@y(cLe2DjtX}Lh{Nq}>_s`lMqR6!JuS~ymb8Nr(qY+kJG)1OO z_w!-zW)7K@mY0>7?W|iWWv5Rvv}2UkB*a~NS9oK;v4C0$3!6yu3!7t8l@IA=iad5U zVQtx6c0KJsw?e(oc=epQQcQ}B?o*G7N``>u&)GJYwDZClg+xZC)>f)0t1|@ZNz1&$ z7JiV+$#*_8jw@k#G{jdrxh!C`}G(teoo)wb8ITM&z@?Eja?1D zF*anpD&|yHYrJM%4Zrdi)%;M?jx}Z+bywdUv!FP+Zl1a1;{3bv>wTABKib61RzDWF zE2Lp%D9^DilFiv}Gu@3J)bo_7RJN-KZ+m#3V<-muSXnFcP7_1E=0u5a^W%G#NH-F}IW^_V?$=shKfneNqg`gZGSMV)fkvi}md-|&b%!&+(cW=D2 zvYZ^Ca~u&%v}<8jjB#!K+Ihrs^C!dFaEsHt{bN=B=uk#~@Wnr7qm+8lWj}4wVW}+T*IFwToOa((RZ6#ujC{raUjyhW%vozZdX%~68vcU`qq>}lN@ ztvM~7qt?#}jF(V4ZeqOd8pi0=OohMUxZxXTtBS>#(J6WtyHNAnQ`s$|`Br0%{Vp4L zFN`_t(0R|=_LX9+v$U9{y(%dwf4=GNivnp;i%4Nf)JW8ga;}~xoVg}-qLLPKa;vbU$o-m8#NZq%(d6gw_%iS&MCW+adJzOes)PhzV!r#Fx-9pcpyi~ zwpGW|FSPS>am|JwVs2_|)OgRz#3Z$8`C`QaP4%%yslo?z9)Ta`QM%e#t=k&7p!J{( ze(^`)0N~I1%Uuf#3#k8(|NSvo?*9Cao{vw^2|yk30p)yv0+PBqv_b0si6oyh|0EXR zq6Q!UeSus7Fb6ONpaftHut0=paft6K=}Qql9d<}#uogQ{``~i2eHo(Id=h>MJ)fP+@U{= z1!KbUng2%q0mK~t2Iu8s1pJ%)0bhRrI6lV!ZUHQpcOJA=0GtAV^FRuKj|f;c0Pq7S z2Y|NA#mNJ0Fc-|}zg%B_b^Z|JkmpJPdP{(Q0N54{ux7bjFyKT8VhNO}HhCd~U)3rn__`ZVoM*e61qLp42fNp3Bd&o@*+9A9V33Z^&1c03XU-mYC#~+D_ND#9I02$|{WEW_sfEgHRQ`|1(vj7h!vpc z1|Ypxkee}VMtCC<>Oh+^06G5=pgRNb=l99a_#^R_k{|{t7t(SWXrqA~;04OE0OC9PpX>%lnIH3(wF<&!IGk`inph--+vB{bxLgZR?;d2?U7xPN4fspGkCZe+S<| z(8i0H+l8bZa$A9LfH4t39lSvMK@$6EP;Mfr|19@^+6Lzf6_LYJVovh@{<&5myb($C z699hX^X)(7^{f6@AqRK?4yHu@ zUTToDe2Kh}%kO-@|Lpt(p3}g8MEc7Yd0&@ugfRgM0hYUWzjJ;9&qz)K1OO~`u2c;4 zY)kR@Cpr)duA3zQiiJq=>gCpwIwZsHY$MQ0A{3m@-k@G z0U!X7bBA>Ya(kryEB6%If*5}}2O`S_-|=!tT%r#K=x&hM1(CKBZDc_^^j(TKqWd?_ zZ~Z|I*oVJ6KYs>nJOMTXBmqDU@Jtz*7m=W>2mozf03aO6WgcjQxnNFz@_r-rUmbtM zo;YT3E|TY4u3ka(f%l^OH~a!fb1ql@hy2eFd2|8!ck}8!uz_p2Fu)|ha{YvQ7z@UP z<^Rs#j|4${xVBOPz<1owIKejfJInW9uww-_FeZ%s!#eYCjz4)UkgE>>?nw>;knUUI z9vuSdA9>xE=mUNK$9_LufJ)sgue+W!+kMqn*;bi@%!}> z{ej;=|0{n#K>j@c|N4J@8~rzr1q=_r!-(>`{~z^!`$hR3N9_;WzoSr#l7K?dz&awY zv5Zr}I(p0eRwzUKzjp&UkM{q*bqkOv|L-U$Sr!(?q2yawm;rJeg_=Qu9WjvOP|iTf zwB!Z)_@ZU!aNH>70B^<7Q8C7pJxex5l#*A^0xcqC z7yt!80uitbbqc>62pEEqTEyS^fVhkRuK?hlG!p=>zeNDZJMcbH2iu?xv}OFexPO-) z#DM4Z767UM$eRDF68b=2`2W(gA+`qy$#2z_ggfU>OFmfJ0$q((3IPjjreM~<9jywi=9oQTPfct3p z-H7b5VXOplTk`zC2HtNt=A`|G=Tx=;@EyPS8zp%h(mJq#&&L>m0|5LML;3+@!q|V# zhb8jE`GVL(3HPUPEb0Irk>**h4D4XPs{vr&VLr&4G^PdOOPU|pz-J83S<<<7AF=s6 z31cp01L7giCgcEP!yJpxCSnhLfet>iq&$DAjKl!G`~dJ=`d9p3k@6+xhwH|#`2Jvn zeA?w|~x_djzZdPI`8!7|j7UO-0! z@R{5W)J*`^0+6l?NS-i~_!PhfuIEVGCL}(zA<-|k6LoM+fLIN1iQER%`;i!+Y){q> zb5W4wCtYt~4sOJEsr+QI5YFV%6^Q}tc>&DH{1V9WlRkH=5Z`~8AD)+y|LzIDc}Y2v z<|iNjE5KG1a`=b&VIEJU51_09kPm?5Cm(;(`8NRUt^s@_86U)NQ9?cG1#H=u;z{EF z71%@ri~u09Navpd(8Ff}ww(olB>t2F&&6^G9scA-2r{ z*+MMCXKI>Q{(-}<=!l#cfbB_uSgCEq_po(Dkt54n&z@Vk;2j|apfki|T(I4IyhNKB*- z?3UVpbOHTF#O7Be@Yw(WeUbj)LHVcq4c*8VgbOH+8-Av z!}$i!d}aWU+))1Q{);5Wa{JG55a%L*9st}|z_V32Zy}Ez05Jfh&p6Br`wjc^%ll6f z9+AKg##nAnN`N*^q77+ZNqv5M|4ot~&IbzsIA_V@!+JXa=^m5R2KqqXKlhtRTtt%3 zKSWP1K@9k8!f}Rc6!I(=fif~Kuncp;xV}QbGStccU`$d0ZOi~S z07&O5eCI)s>YxoXi7UMK&=>g)AHEw;1Bd{iiGXFOL-wN3_RkogjO2yS4L@mY(lTrV zfHsiN4cG=G>@UI(?zOLxK@`+E0pNUuZKV5gWULVXrQ}xN1J|#m+K_REZN30-eMRgV zKp6+H8sIfi51&g907qiI3rKi>riguk`)0%+t{;%^0}>q`+QAFxrU0NX#8;w@)E|jM zDi1F@|KShc9ncqYfHuMar2fUAz77EX22uh5ZRP=>4%)&x^i3p|n}Mt%mSG$G=4%9i zYYws=LA?|}AOI{wU()*rb<1G}v;_e`KFB;;oX?3rfVPYC zhd6Ge^LGNY1ptVUj1}xJ + + + + diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs index 6bd7e53cdfbe2..213c7f3aab8b6 100644 --- a/src/librustdoc/html/static_files.rs +++ b/src/librustdoc/html/static_files.rs @@ -53,8 +53,10 @@ pub static LICENSE_MIT: &[u8] = include_bytes!("static/LICENSE-MIT.txt"); /// The contents of `rust-logo.png`, the default icon of the documentation. pub static RUST_LOGO: &[u8] = include_bytes!("static/rust-logo.png"); -/// The contents of `favicon.ico`, the default favicon of the documentation. -pub static RUST_FAVICON: &[u8] = include_bytes!("static/favicon.ico"); +/// The default documentation favicons (SVG and PNG fallbacks) +pub static RUST_FAVICON_SVG: &[u8] = include_bytes!("static/favicon.svg"); +pub static RUST_FAVICON_PNG_16: &[u8] = include_bytes!("static/favicon-16x16.png"); +pub static RUST_FAVICON_PNG_32: &[u8] = include_bytes!("static/favicon-32x32.png"); /// The built-in themes given to every documentation site. pub mod themes { From a320ef751bcf3a0c09384cf887ea7eceab2fbee7 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 23 Sep 2020 21:04:07 -0700 Subject: [PATCH 0921/1052] Suggest `const_mut_refs` for mutable references in const fn --- compiler/rustc_mir/src/transform/check_consts/ops.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index e14dcf92b89d2..d978d9279810d 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -535,6 +535,7 @@ impl NonConstOp for UnsizingCast { } } +// Types that cannot appear in the signature or locals of a `const fn`. pub mod ty { use super::*; @@ -548,7 +549,13 @@ pub mod ty { } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - mcf_emit_error(ccx, span, "mutable references in const fn are unstable"); + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_mut_refs, + span, + &format!("mutable references are not allowed in {}s", ccx.const_kind()), + ) + .emit() } } From e5e5e64ff1b91e57fed22e7a52e5de333980fafd Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 23 Sep 2020 21:05:59 -0700 Subject: [PATCH 0922/1052] Bless tests --- .../feature-gate-const_mut_refs.rs | 2 +- .../feature-gate-const_mut_refs.stderr | 8 ++--- src/test/ui/consts/const_let_assign3.stderr | 8 ++--- .../ui/consts/min_const_fn/min_const_fn.rs | 10 +++---- .../consts/min_const_fn/min_const_fn.stderr | 30 +++++++++---------- .../ui/consts/min_const_fn/mutable_borrow.rs | 4 +-- .../consts/min_const_fn/mutable_borrow.stderr | 14 ++++----- src/test/ui/unsafe/ranged_ints2_const.stderr | 14 ++++----- 8 files changed, 45 insertions(+), 45 deletions(-) diff --git a/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs index f31543af590d6..ce9be4ac5c2af 100644 --- a/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs +++ b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs @@ -2,7 +2,7 @@ fn main() { foo(&mut 5); } -const fn foo(x: &mut i32) -> i32 { //~ ERROR mutable references in const fn +const fn foo(x: &mut i32) -> i32 { //~ ERROR mutable references *x + 1 } diff --git a/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr index 83e050c7a5c8a..3f9bd37053a0e 100644 --- a/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr +++ b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr @@ -1,12 +1,12 @@ -error[E0723]: mutable references in const fn are unstable +error[E0658]: mutable references are not allowed in constant functions --> $DIR/feature-gate-const_mut_refs.rs:5:14 | LL | const fn foo(x: &mut i32) -> i32 { | ^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error: aborting due to previous error -For more information about this error, try `rustc --explain E0723`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/const_let_assign3.stderr b/src/test/ui/consts/const_let_assign3.stderr index 785d9c8c2a5fb..15badea003736 100644 --- a/src/test/ui/consts/const_let_assign3.stderr +++ b/src/test/ui/consts/const_let_assign3.stderr @@ -1,11 +1,11 @@ -error[E0723]: mutable references in const fn are unstable +error[E0658]: mutable references are not allowed in constant functions --> $DIR/const_let_assign3.rs:8:18 | LL | const fn foo(&mut self, x: u32) { | ^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0764]: mutable references are not allowed in constants --> $DIR/const_let_assign3.rs:16:5 @@ -29,5 +29,5 @@ LL | *y = 42; error: aborting due to 4 previous errors -Some errors have detailed explanations: E0019, E0723, E0764. +Some errors have detailed explanations: E0019, E0658, E0764. For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs index 5dd70acb6ff1c..336d754b06a73 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs @@ -37,26 +37,26 @@ impl Foo { const fn into_inner(self) -> T { self.0 } //~ destructors cannot be evaluated const fn get(&self) -> &T { &self.0 } const fn get_mut(&mut self) -> &mut T { &mut self.0 } - //~^ mutable references in const fn are unstable + //~^ mutable references } impl<'a, T> Foo { const fn new_lt(t: T) -> Self { Foo(t) } const fn into_inner_lt(self) -> T { self.0 } //~ destructors cannot be evaluated const fn get_lt(&'a self) -> &T { &self.0 } const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 } - //~^ mutable references in const fn are unstable + //~^ mutable references } impl Foo { const fn new_s(t: T) -> Self { Foo(t) } const fn into_inner_s(self) -> T { self.0 } //~ ERROR destructors const fn get_s(&self) -> &T { &self.0 } const fn get_mut_s(&mut self) -> &mut T { &mut self.0 } - //~^ mutable references in const fn are unstable + //~^ mutable references } impl Foo { const fn get_sq(&self) -> &T { &self.0 } const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 } - //~^ mutable references in const fn are unstable + //~^ mutable references } @@ -99,7 +99,7 @@ const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } } //~^ ERROR casting pointers to integers const fn foo30_6() -> bool { let x = true; x } const fn inc(x: &mut i32) { *x += 1 } -//~^ ERROR mutable references in const fn are unstable +//~^ ERROR mutable references // ok const fn foo36(a: bool, b: bool) -> bool { a && b } diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr index d4498f061c64b..c96500e38ec83 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr @@ -6,14 +6,14 @@ LL | const fn into_inner(self) -> T { self.0 } | | | constant functions cannot evaluate destructors -error[E0723]: mutable references in const fn are unstable +error[E0658]: mutable references are not allowed in constant functions --> $DIR/min_const_fn.rs:39:36 | LL | const fn get_mut(&mut self) -> &mut T { &mut self.0 } | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/min_const_fn.rs:44:28 @@ -23,14 +23,14 @@ LL | const fn into_inner_lt(self) -> T { self.0 } | | | constant functions cannot evaluate destructors -error[E0723]: mutable references in const fn are unstable +error[E0658]: mutable references are not allowed in constant functions --> $DIR/min_const_fn.rs:46:42 | LL | const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 } | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/min_const_fn.rs:51:27 @@ -40,23 +40,23 @@ LL | const fn into_inner_s(self) -> T { self.0 } | | | constant functions cannot evaluate destructors -error[E0723]: mutable references in const fn are unstable +error[E0658]: mutable references are not allowed in constant functions --> $DIR/min_const_fn.rs:53:38 | LL | const fn get_mut_s(&mut self) -> &mut T { &mut self.0 } | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0723]: mutable references in const fn are unstable +error[E0658]: mutable references are not allowed in constant functions --> $DIR/min_const_fn.rs:58:39 | LL | const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 } | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn.rs:76:16 @@ -164,14 +164,14 @@ LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } = note: see issue #51910 for more information = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable -error[E0723]: mutable references in const fn are unstable +error[E0658]: mutable references are not allowed in constant functions --> $DIR/min_const_fn.rs:101:14 | LL | const fn inc(x: &mut i32) { *x += 1 } | ^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn.rs:110:6 diff --git a/src/test/ui/consts/min_const_fn/mutable_borrow.rs b/src/test/ui/consts/min_const_fn/mutable_borrow.rs index 89acfea6ed8ff..580b1d50f774e 100644 --- a/src/test/ui/consts/min_const_fn/mutable_borrow.rs +++ b/src/test/ui/consts/min_const_fn/mutable_borrow.rs @@ -1,6 +1,6 @@ const fn mutable_ref_in_const() -> u8 { let mut a = 0; - let b = &mut a; //~ ERROR mutable references in const fn + let b = &mut a; //~ ERROR mutable references *b } @@ -9,7 +9,7 @@ struct X; impl X { const fn inherent_mutable_ref_in_const() -> u8 { let mut a = 0; - let b = &mut a; //~ ERROR mutable references in const fn + let b = &mut a; //~ ERROR mutable references *b } } diff --git a/src/test/ui/consts/min_const_fn/mutable_borrow.stderr b/src/test/ui/consts/min_const_fn/mutable_borrow.stderr index f5a3c168a86d7..4e5cdbb18aae3 100644 --- a/src/test/ui/consts/min_const_fn/mutable_borrow.stderr +++ b/src/test/ui/consts/min_const_fn/mutable_borrow.stderr @@ -1,21 +1,21 @@ -error[E0723]: mutable references in const fn are unstable +error[E0658]: mutable references are not allowed in constant functions --> $DIR/mutable_borrow.rs:3:9 | LL | let b = &mut a; | ^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0723]: mutable references in const fn are unstable +error[E0658]: mutable references are not allowed in constant functions --> $DIR/mutable_borrow.rs:12:13 | LL | let b = &mut a; | ^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0723`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/unsafe/ranged_ints2_const.stderr b/src/test/ui/unsafe/ranged_ints2_const.stderr index d508d07791de9..1a6bcd36ee157 100644 --- a/src/test/ui/unsafe/ranged_ints2_const.stderr +++ b/src/test/ui/unsafe/ranged_ints2_const.stderr @@ -1,20 +1,20 @@ -error[E0723]: mutable references in const fn are unstable +error[E0658]: mutable references are not allowed in constant functions --> $DIR/ranged_ints2_const.rs:11:9 | LL | let y = &mut x.0; | ^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0723]: mutable references in const fn are unstable +error[E0658]: mutable references are not allowed in constant functions --> $DIR/ranged_ints2_const.rs:18:9 | LL | let y = unsafe { &mut x.0 }; | ^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block --> $DIR/ranged_ints2_const.rs:11:13 @@ -26,5 +26,5 @@ LL | let y = &mut x.0; error: aborting due to 3 previous errors -Some errors have detailed explanations: E0133, E0723. +Some errors have detailed explanations: E0133, E0658. For more information about an error, try `rustc --explain E0133`. From e1f408e6c8d440224dfa45f8b1a97ed84c790fcd Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 22 Sep 2020 09:42:29 +0200 Subject: [PATCH 0923/1052] const_evaluatable_checked: collect predicates from fn_sig --- compiler/rustc_typeck/src/collect.rs | 23 +++++++++++++++---- .../cross_crate_predicate.rs | 1 + .../cross_crate_predicate.stderr | 20 +++++++++++++++- .../from-sig-fail.rs | 11 +++++++++ .../from-sig-fail.stderr | 9 ++++++++ .../const_evaluatable_checked/from-sig.rs | 14 +++++++++++ 6 files changed, 72 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/from-sig.rs diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 458622dd65a39..d04b5cf588f72 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1678,8 +1678,10 @@ fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicate if tcx.features().const_evaluatable_checked { let const_evaluatable = const_evaluatable_predicates_of(tcx, def_id, &result); - result.predicates = - tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(const_evaluatable)); + if !const_evaluatable.is_empty() { + result.predicates = + tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(const_evaluatable)); + } } debug!("predicates_defined_on({:?}) = {:?}", def_id, result); @@ -1690,7 +1692,7 @@ pub fn const_evaluatable_predicates_of<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, predicates: &ty::GenericPredicates<'tcx>, -) -> impl Iterator, Span)> { +) -> Vec<(ty::Predicate<'tcx>, Span)> { #[derive(Default)] struct ConstCollector<'tcx> { ct: SmallVec<[(ty::WithOptConstParam, SubstsRef<'tcx>, Span); 4]>, @@ -1711,10 +1713,21 @@ pub fn const_evaluatable_predicates_of<'tcx>( collector.curr_span = span; pred.visit_with(&mut collector); } - warn!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.ct); + + match tcx.def_kind(def_id) { + DefKind::Fn | DefKind::AssocFn => { + tcx.fn_sig(def_id).visit_with(&mut collector); + } + _ => (), + } + debug!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.ct); + + // We only want unique const evaluatable predicates. + collector.ct.sort(); + collector.ct.dedup(); collector.ct.into_iter().map(move |(def_id, subst, span)| { (ty::PredicateAtom::ConstEvaluatable(def_id, subst).to_predicate(tcx), span) - }) + }).collect() } /// Returns a list of all type predicates (explicit and implicit) for the definition with diff --git a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs index 223699233298d..52b89cfa04588 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs +++ b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs @@ -8,6 +8,7 @@ fn user() { //~^ ERROR constant expression depends //~| ERROR constant expression depends //~| ERROR constant expression depends + //~| ERROR constant expression depends } fn main() {} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr index 63abb782b93a3..e8afb495e602b 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr @@ -11,6 +11,19 @@ LL | [u8; std::mem::size_of::() - 1]: Sized, | = note: this may fail depending on what value the parameter takes +error: constant expression depends on a generic parameter + --> $DIR/cross_crate_predicate.rs:7:13 + | +LL | let _ = const_evaluatable_lib::test1::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:41 + | +LL | [u8; std::mem::size_of::() - 1]: Sized, + | ----- required by this bound in `test1` + | + = note: this may fail depending on what value the parameter takes + error: constant expression depends on a generic parameter --> $DIR/cross_crate_predicate.rs:7:13 | @@ -29,8 +42,13 @@ error: constant expression depends on a generic parameter | LL | let _ = const_evaluatable_lib::test1::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:41 + | +LL | [u8; std::mem::size_of::() - 1]: Sized, + | ----- required by this bound in `test1::{{constant}}#1` | = note: this may fail depending on what value the parameter takes -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors diff --git a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs new file mode 100644 index 0000000000000..3da4688702c96 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs @@ -0,0 +1,11 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +fn test() -> [u8; N - 1] { + //~^ ERROR evaluation of constant + todo!() +} + +fn main() { + test::<0>(); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr new file mode 100644 index 0000000000000..a5acfec34aa87 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/from-sig-fail.rs:4:35 + | +LL | fn test() -> [u8; N - 1] { + | ^^^^^ attempt to compute `0_usize - 1_usize` which would overflow + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/const-generics/const_evaluatable_checked/from-sig.rs b/src/test/ui/const-generics/const_evaluatable_checked/from-sig.rs new file mode 100644 index 0000000000000..5c05a5acfe96d --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/from-sig.rs @@ -0,0 +1,14 @@ +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +struct Foo; + +fn test() -> Foo<{ N > 10 }> { + Foo +} + +fn main() { + let _: Foo = test::<12>(); + let _: Foo = test::<9>(); +} From ac1d0d8b28008277a39a3f4d4a6bc34772c06888 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 22 Sep 2020 09:48:20 +0200 Subject: [PATCH 0924/1052] fmt, use IndexSet directly instead of UniquePredicates --- compiler/rustc_typeck/src/collect.rs | 55 ++++++++++------------------ 1 file changed, 20 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index d04b5cf588f72..fd2cd03a9c180 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1679,8 +1679,9 @@ fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicate if tcx.features().const_evaluatable_checked { let const_evaluatable = const_evaluatable_predicates_of(tcx, def_id, &result); if !const_evaluatable.is_empty() { - result.predicates = - tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(const_evaluatable)); + result.predicates = tcx + .arena + .alloc_from_iter(result.predicates.iter().copied().chain(const_evaluatable)); } } @@ -1725,9 +1726,13 @@ pub fn const_evaluatable_predicates_of<'tcx>( // We only want unique const evaluatable predicates. collector.ct.sort(); collector.ct.dedup(); - collector.ct.into_iter().map(move |(def_id, subst, span)| { - (ty::PredicateAtom::ConstEvaluatable(def_id, subst).to_predicate(tcx), span) - }).collect() + collector + .ct + .into_iter() + .map(move |(def_id, subst, span)| { + (ty::PredicateAtom::ConstEvaluatable(def_id, subst).to_predicate(tcx), span) + }) + .collect() } /// Returns a list of all type predicates (explicit and implicit) for the definition with @@ -1767,29 +1772,6 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat debug!("explicit_predicates_of(def_id={:?})", def_id); - /// A data structure with unique elements, which preserves order of insertion. - /// Preserving the order of insertion is important here so as not to break - /// compile-fail UI tests. - struct UniquePredicates<'tcx> { - predicates: FxIndexSet<(ty::Predicate<'tcx>, Span)>, - } - - impl<'tcx> UniquePredicates<'tcx> { - fn new() -> Self { - UniquePredicates { predicates: FxIndexSet::default() } - } - - fn push(&mut self, value: (ty::Predicate<'tcx>, Span)) { - self.predicates.insert(value); - } - - fn extend, Span)>>(&mut self, iter: I) { - for value in iter { - self.push(value); - } - } - } - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); let node = tcx.hir().get(hir_id); @@ -1802,7 +1784,10 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat const NO_GENERICS: &hir::Generics<'_> = &hir::Generics::empty(); - let mut predicates = UniquePredicates::new(); + // We use an `IndexSet` to preserves order of insertion. + // Preserving the order of insertion is important here so as not to break + // compile-fail UI tests. + let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default(); let ast_generics = match node { Node::TraitItem(item) => { @@ -1904,7 +1889,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat // (see below). Recall that a default impl is not itself an impl, but rather a // set of defaults that can be incorporated into another impl. if let Some(trait_ref) = is_default_impl_trait { - predicates.push(( + predicates.insert(( trait_ref.to_poly_trait_ref().without_const().to_predicate(tcx), tcx.def_span(def_id), )); @@ -1928,7 +1913,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat hir::GenericBound::Outlives(lt) => { let bound = AstConv::ast_region_to_region(&icx, <, None); let outlives = ty::Binder::bind(ty::OutlivesPredicate(region, bound)); - predicates.push((outlives.to_predicate(tcx), lt.span)); + predicates.insert((outlives.to_predicate(tcx), lt.span)); } _ => bug!(), }); @@ -1983,7 +1968,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat let span = bound_pred.bounded_ty.span; let re_root_empty = tcx.lifetimes.re_root_empty; let predicate = ty::OutlivesPredicate(ty, re_root_empty); - predicates.push(( + predicates.insert(( ty::PredicateAtom::TypeOutlives(predicate) .potentially_quantified(tcx, ty::PredicateKind::ForAll), span, @@ -2027,11 +2012,11 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat &hir::GenericBound::Outlives(ref lifetime) => { let region = AstConv::ast_region_to_region(&icx, lifetime, None); - predicates.push(( + predicates.insert(( ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty, region)) .potentially_quantified(tcx, ty::PredicateKind::ForAll), lifetime.span, - )) + )); } } } @@ -2076,7 +2061,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat })) } - let mut predicates: Vec<_> = predicates.predicates.into_iter().collect(); + let mut predicates: Vec<_> = predicates.into_iter().collect(); // Subtle: before we store the predicates into the tcx, we // sort them so that predicates like `T: Foo` come From f8d3f401df47cf680180c357fabdc8c76c2a08ab Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 22 Sep 2020 10:54:09 +0200 Subject: [PATCH 0925/1052] walk hir to get const evaluatable predicates --- compiler/rustc_typeck/src/collect.rs | 143 ++++++++++-------- .../cross_crate_predicate.stderr | 20 +-- .../let-bindings.stderr | 6 +- 3 files changed, 96 insertions(+), 73 deletions(-) diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index fd2cd03a9c180..d341e7eec41a3 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -37,12 +37,11 @@ use rustc_middle::hir::map::Map; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::mono::Linkage; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; +use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::util::Discr; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, AdtKind, Const, ToPolyTraitRef, Ty, TyCtxt}; use rustc_middle::ty::{ReprOptions, ToPredicate, WithConstness}; -use rustc_middle::ty::{TypeFoldable, TypeVisitor}; use rustc_session::config::SanitizerSet; use rustc_session::lint; use rustc_session::parse::feature_err; @@ -51,8 +50,6 @@ use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::abi; use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName; -use smallvec::SmallVec; - mod type_of; struct OnlySelfBounds(bool); @@ -1676,65 +1673,10 @@ fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicate } } - if tcx.features().const_evaluatable_checked { - let const_evaluatable = const_evaluatable_predicates_of(tcx, def_id, &result); - if !const_evaluatable.is_empty() { - result.predicates = tcx - .arena - .alloc_from_iter(result.predicates.iter().copied().chain(const_evaluatable)); - } - } - debug!("predicates_defined_on({:?}) = {:?}", def_id, result); result } -pub fn const_evaluatable_predicates_of<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: DefId, - predicates: &ty::GenericPredicates<'tcx>, -) -> Vec<(ty::Predicate<'tcx>, Span)> { - #[derive(Default)] - struct ConstCollector<'tcx> { - ct: SmallVec<[(ty::WithOptConstParam, SubstsRef<'tcx>, Span); 4]>, - curr_span: Span, - } - - impl<'tcx> TypeVisitor<'tcx> for ConstCollector<'tcx> { - fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> bool { - if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val { - self.ct.push((def, substs, self.curr_span)); - } - false - } - } - - let mut collector = ConstCollector::default(); - for &(pred, span) in predicates.predicates.iter() { - collector.curr_span = span; - pred.visit_with(&mut collector); - } - - match tcx.def_kind(def_id) { - DefKind::Fn | DefKind::AssocFn => { - tcx.fn_sig(def_id).visit_with(&mut collector); - } - _ => (), - } - debug!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.ct); - - // We only want unique const evaluatable predicates. - collector.ct.sort(); - collector.ct.dedup(); - collector - .ct - .into_iter() - .map(move |(def_id, subst, span)| { - (ty::PredicateAtom::ConstEvaluatable(def_id, subst).to_predicate(tcx), span) - }) - .collect() -} - /// Returns a list of all type predicates (explicit and implicit) for the definition with /// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus /// `Self: Trait` predicates for traits. @@ -2061,6 +2003,10 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat })) } + if tcx.features().const_evaluatable_checked { + predicates.extend(const_evaluatable_predicates_of(tcx, def_id.expect_local())); + } + let mut predicates: Vec<_> = predicates.into_iter().collect(); // Subtle: before we store the predicates into the tcx, we @@ -2087,6 +2033,85 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat result } +fn const_evaluatable_predicates_of<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> FxIndexSet<(ty::Predicate<'tcx>, Span)> { + struct ConstCollector<'tcx> { + tcx: TyCtxt<'tcx>, + preds: FxIndexSet<(ty::Predicate<'tcx>, Span)>, + } + + impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> { + type Map = Map<'tcx>; + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::None + } + + fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) { + let def_id = self.tcx.hir().local_def_id(c.hir_id); + let ct = ty::Const::from_anon_const(self.tcx, def_id); + if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val { + let span = self.tcx.hir().span(c.hir_id); + self.preds.insert(( + ty::PredicateAtom::ConstEvaluatable(def, substs).to_predicate(self.tcx), + span, + )); + } + } + + // Look into `TyAlias`. + fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { + use ty::fold::{TypeFoldable, TypeVisitor}; + struct TyAliasVisitor<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + preds: &'a mut FxIndexSet<(ty::Predicate<'tcx>, Span)>, + span: Span, + } + + impl<'a, 'tcx> TypeVisitor<'tcx> for TyAliasVisitor<'a, 'tcx> { + fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> bool { + if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val { + self.preds.insert(( + ty::PredicateAtom::ConstEvaluatable(def, substs).to_predicate(self.tcx), + self.span, + )); + } + false + } + } + + if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ty.kind { + if let Res::Def(DefKind::TyAlias, def_id) = path.res { + let mut visitor = + TyAliasVisitor { tcx: self.tcx, preds: &mut self.preds, span: path.span }; + self.tcx.type_of(def_id).visit_with(&mut visitor); + } + } + + intravisit::walk_ty(self, ty) + } + } + + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let node = tcx.hir().get(hir_id); + + let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() }; + if let Some(generics) = node.generics() { + warn!("const_evaluatable_predicates_of({:?}): visit_generics", def_id); + collector.visit_generics(generics); + } + + if let Some(fn_sig) = tcx.hir().fn_sig_by_hir_id(hir_id) { + warn!("const_evaluatable_predicates_of({:?}): visit_fn_decl", def_id); + collector.visit_fn_decl(fn_sig.decl); + } + warn!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.preds); + + collector.preds +} + fn projection_ty_from_predicates( tcx: TyCtxt<'tcx>, key: ( diff --git a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr index e8afb495e602b..e7da191e670ec 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr @@ -4,10 +4,10 @@ error: constant expression depends on a generic parameter LL | let _ = const_evaluatable_lib::test1::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:41 + ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:10 | LL | [u8; std::mem::size_of::() - 1]: Sized, - | ----- required by this bound in `test1` + | ---------------------------- required by this bound in `test1` | = note: this may fail depending on what value the parameter takes @@ -17,10 +17,10 @@ error: constant expression depends on a generic parameter LL | let _ = const_evaluatable_lib::test1::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:41 + ::: $DIR/auxiliary/const_evaluatable_lib.rs:4:27 | -LL | [u8; std::mem::size_of::() - 1]: Sized, - | ----- required by this bound in `test1` +LL | pub fn test1() -> [u8; std::mem::size_of::() - 1] + | ---------------------------- required by this bound in `test1` | = note: this may fail depending on what value the parameter takes @@ -30,10 +30,10 @@ error: constant expression depends on a generic parameter LL | let _ = const_evaluatable_lib::test1::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:41 + ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:10 | LL | [u8; std::mem::size_of::() - 1]: Sized, - | ----- required by this bound in `test1::{{constant}}#1` + | ---------------------------- required by this bound in `test1::{{constant}}#1` | = note: this may fail depending on what value the parameter takes @@ -43,10 +43,10 @@ error: constant expression depends on a generic parameter LL | let _ = const_evaluatable_lib::test1::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:41 + ::: $DIR/auxiliary/const_evaluatable_lib.rs:4:27 | -LL | [u8; std::mem::size_of::() - 1]: Sized, - | ----- required by this bound in `test1::{{constant}}#1` +LL | pub fn test1() -> [u8; std::mem::size_of::() - 1] + | ---------------------------- required by this bound in `test1::{{constant}}#1` | = note: this may fail depending on what value the parameter takes diff --git a/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr index 5749defb3e12c..b76e300663d76 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr @@ -1,10 +1,8 @@ -error: overly complex generic constant +error: constant expression depends on a generic parameter --> $DIR/let-bindings.rs:6:68 | LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - | ^^^^^^-^^^^^^^^^^^^^ - | | - | unsupported statement + | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `test::{{constant}}#0` | = help: consider moving this anonymous constant into a `const` function From b8402d6a6e6cadd3d877c952a2c5bbd694afbc2d Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 22 Sep 2020 11:36:54 +0200 Subject: [PATCH 0926/1052] assign the correct `DefId` in `nominal_obligations` --- .../rustc_trait_selection/src/traits/wf.rs | 20 +++++++++++++++---- .../cross_crate_predicate.stderr | 4 ++-- .../let-bindings.stderr | 2 +- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 998990f374cb9..909cd2aa1551e 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -7,8 +7,9 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_span::Span; -use std::rc::Rc; +use std::iter; +use std::rc::Rc; /// Returns the set of obligations needed to make `arg` well-formed. /// If `arg` contains unresolved inference variables, this may include /// further WF obligations. However, if `arg` IS an unresolved @@ -616,13 +617,24 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { def_id: DefId, substs: SubstsRef<'tcx>, ) -> Vec> { - let predicates = self.infcx.tcx.predicates_of(def_id).instantiate(self.infcx.tcx, substs); + let predicates = self.infcx.tcx.predicates_of(def_id); + let mut origins = vec![def_id; predicates.predicates.len()]; + let mut head = predicates; + while let Some(parent) = head.parent { + head = self.infcx.tcx.predicates_of(parent); + origins.extend(iter::repeat(parent).take(head.predicates.len())); + } + + let predicates = predicates.instantiate(self.infcx.tcx, substs); + debug_assert_eq!(predicates.predicates.len(), origins.len()); + predicates .predicates .into_iter() .zip(predicates.spans.into_iter()) - .map(|(pred, span)| { - let cause = self.cause(traits::BindingObligation(def_id, span)); + .zip(origins.into_iter().rev()) + .map(|((pred, span), origin_def_id)| { + let cause = self.cause(traits::BindingObligation(origin_def_id, span)); traits::Obligation::new(cause, self.param_env, pred) }) .filter(|pred| !pred.has_escaping_bound_vars()) diff --git a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr index e7da191e670ec..4af68118be31f 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr @@ -33,7 +33,7 @@ LL | let _ = const_evaluatable_lib::test1::(); ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:10 | LL | [u8; std::mem::size_of::() - 1]: Sized, - | ---------------------------- required by this bound in `test1::{{constant}}#1` + | ---------------------------- required by this bound in `test1` | = note: this may fail depending on what value the parameter takes @@ -46,7 +46,7 @@ LL | let _ = const_evaluatable_lib::test1::(); ::: $DIR/auxiliary/const_evaluatable_lib.rs:4:27 | LL | pub fn test1() -> [u8; std::mem::size_of::() - 1] - | ---------------------------- required by this bound in `test1::{{constant}}#1` + | ---------------------------- required by this bound in `test1` | = note: this may fail depending on what value the parameter takes diff --git a/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr index b76e300663d76..dd27b81ee0342 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr @@ -2,7 +2,7 @@ error: constant expression depends on a generic parameter --> $DIR/let-bindings.rs:6:68 | LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `test::{{constant}}#0` + | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `test` | = help: consider moving this anonymous constant into a `const` function From 3f9015b22d774dd2af0c3c95dbfb0270d5e0bf7e Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 22 Sep 2020 11:55:03 +0200 Subject: [PATCH 0927/1052] visit impl self ty + trait --- compiler/rustc_typeck/src/collect.rs | 12 +++++++++ .../const_evaluatable_checked/impl-bounds.rs | 25 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/impl-bounds.rs diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index d341e7eec41a3..a571bd58abc34 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2098,6 +2098,18 @@ fn const_evaluatable_predicates_of<'tcx>( let node = tcx.hir().get(hir_id); let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() }; + if let hir::Node::Item(item) = node { + if let hir::ItemKind::Impl { ref of_trait, ref self_ty, .. } = item.kind { + if let Some(of_trait) = of_trait { + warn!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id); + collector.visit_trait_ref(of_trait); + } + + warn!("const_evaluatable_predicates_of({:?}): visit_self_ty", def_id); + collector.visit_ty(self_ty); + } + } + if let Some(generics) = node.generics() { warn!("const_evaluatable_predicates_of({:?}): visit_generics", def_id); collector.visit_generics(generics); diff --git a/src/test/ui/const-generics/const_evaluatable_checked/impl-bounds.rs b/src/test/ui/const-generics/const_evaluatable_checked/impl-bounds.rs new file mode 100644 index 0000000000000..193a365f9b65b --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/impl-bounds.rs @@ -0,0 +1,25 @@ +// check-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +use std::mem::size_of; + +struct Foo(T); + +impl Foo() }> { + fn test() { + let _: [u8; std::mem::size_of::()]; + } +} + +trait Bar { + fn test_me(); +} + +impl Bar<{ size_of::() }> for Foo { + fn test_me() { + let _: [u8; std::mem::size_of::()]; + } +} + +fn main() {} From 21edd10dc5ae8cde041f84a38fd0c4a44a36965d Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 22 Sep 2020 18:00:32 +0200 Subject: [PATCH 0928/1052] update tests --- .../const_evaluatable_checked/let-bindings.stderr | 6 ++++-- src/test/ui/const-generics/issues/issue-76595.stderr | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr index dd27b81ee0342..5749defb3e12c 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr @@ -1,8 +1,10 @@ -error: constant expression depends on a generic parameter +error: overly complex generic constant --> $DIR/let-bindings.rs:6:68 | LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `test` + | ^^^^^^-^^^^^^^^^^^^^ + | | + | unsupported statement | = help: consider moving this anonymous constant into a `const` function diff --git a/src/test/ui/const-generics/issues/issue-76595.stderr b/src/test/ui/const-generics/issues/issue-76595.stderr index 2e457595393ca..bbc81693fc0ef 100644 --- a/src/test/ui/const-generics/issues/issue-76595.stderr +++ b/src/test/ui/const-generics/issues/issue-76595.stderr @@ -8,7 +8,7 @@ error: constant expression depends on a generic parameter --> $DIR/issue-76595.rs:15:5 | LL | fn test() where Bool<{core::mem::size_of::() > 4}>: True { - | ---- required by this bound in `test` + | ------------------------------- required by this bound in `test` ... LL | test::<2>(); | ^^^^^^^^^ From 2bc54d427377d3f5d949434a9eb8a9ba71db69a4 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 24 Sep 2020 09:43:10 +0200 Subject: [PATCH 0929/1052] Don't talk about determinism --- compiler/rustc_session/src/lint/builtin.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_session/src/lint/builtin.rs b/compiler/rustc_session/src/lint/builtin.rs index 8e1c843ae6134..13a4057a35bdf 100644 --- a/compiler/rustc_session/src/lint/builtin.rs +++ b/compiler/rustc_session/src/lint/builtin.rs @@ -2191,8 +2191,8 @@ declare_lint! { } declare_lint! { - /// The `pointer_structural_match` lint detects pointers used in patterns that do not - /// behave deterministically across optimizations. + /// The `pointer_structural_match` lint detects pointers used in patterns whose behaviour + /// cannot be relied upon across compiler versions and optimization levels. /// /// ### Example /// From e4928d77a1eceea9f53e30bd6af9fdf5be205fae Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 24 Sep 2020 10:06:07 +0200 Subject: [PATCH 0930/1052] Use correct type in diagnostics again --- .../src/thir/pattern/const_to_pat.rs | 93 +++++++++---------- .../custom-eq-branch-warn.stderr | 2 +- .../reject_non_partial_eq.stderr | 2 +- .../const_in_pattern/warn_corner_cases.stderr | 6 +- 4 files changed, 50 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 5025bacafa1db..3c8671486bf8f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -89,11 +89,42 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { self.infcx.tcx } - fn search_for_structural_match_violation( - &self, - ty: Ty<'tcx>, - ) -> Option> { - traits::search_for_structural_match_violation(self.id, self.span, self.tcx(), ty) + fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option { + traits::search_for_structural_match_violation(self.id, self.span, self.tcx(), ty).map( + |non_sm_ty| { + with_no_trimmed_paths(|| match non_sm_ty { + traits::NonStructuralMatchTy::Adt(adt_def) => { + let path = self.tcx().def_path_str(adt_def.did); + format!( + "to use a constant of type `{}` in a pattern, \ + `{}` must be annotated with `#[derive(PartialEq, Eq)]`", + path, path, + ) + } + traits::NonStructuralMatchTy::Dynamic => { + "trait objects cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTy::Opaque => { + "opaque types cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTy::Generator => { + "generators cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTy::Closure => { + "closures cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTy::Param => { + bug!("use of a constant whose type is a parameter inside a pattern") + } + traits::NonStructuralMatchTy::Projection => { + bug!("use of a constant whose type is a projection inside a pattern") + } + traits::NonStructuralMatchTy::Foreign => { + bug!("use of a value of a foreign type inside a pattern") + } + }) + }, + ) } fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool { @@ -135,39 +166,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { return inlined_const_as_pat; } - if let Some(non_sm_ty) = structural { - let msg = with_no_trimmed_paths(|| match non_sm_ty { - traits::NonStructuralMatchTy::Adt(adt_def) => { - let path = self.tcx().def_path_str(adt_def.did); - format!( - "to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - path, path, - ) - } - traits::NonStructuralMatchTy::Dynamic => { - "trait objects cannot be used in patterns".to_string() - } - traits::NonStructuralMatchTy::Opaque => { - "opaque types cannot be used in patterns".to_string() - } - traits::NonStructuralMatchTy::Generator => { - "generators cannot be used in patterns".to_string() - } - traits::NonStructuralMatchTy::Closure => { - "closures cannot be used in patterns".to_string() - } - traits::NonStructuralMatchTy::Param => { - bug!("use of a constant whose type is a parameter inside a pattern") - } - traits::NonStructuralMatchTy::Projection => { - bug!("use of a constant whose type is a projection inside a pattern") - } - traits::NonStructuralMatchTy::Foreign => { - bug!("use of a value of a foreign type inside a pattern") - } - }); - + if let Some(msg) = structural { if !self.type_may_have_partial_eq_impl(cv.ty) { // span_fatal avoids ICE from resolution of non-existent method (rare case). self.tcx().sess.span_fatal(self.span, &msg); @@ -272,11 +271,9 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // `search_for_structural_match_violation` and then remove this condition. && self.search_for_structural_match_violation(cv.ty).is_some() => { - let msg = format!( - "to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - cv.ty, cv.ty, - ); + // Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we + // could get `Option`, even though `Option` is annotated with derive. + let msg = self.search_for_structural_match_violation(cv.ty).unwrap(); self.saw_const_match_error.set(true); if self.include_lint_checks { tcx.sess.span_err(self.span, &msg); @@ -512,11 +509,11 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { && self.search_for_structural_match_violation(cv.ty).is_some() { self.saw_const_match_lint.set(true); - let msg = format!( - "to use a constant of type `{}` in a pattern, \ - the constant's initializer must be trivial or all types \ - in the constant must be annotated with `#[derive(PartialEq, Eq)]`", - cv.ty, + // Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we + // could get `Option`, even though `Option` is annotated with derive. + let msg = self.search_for_structural_match_violation(cv.ty).unwrap().replace( + "in a pattern,", + "in a pattern, the constant's initializer must be trivial or", ); tcx.struct_span_lint_hir( lint::builtin::NONTRIVIAL_STRUCTURAL_MATCH, diff --git a/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr b/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr index fd6732195e494..e51d6f916498e 100644 --- a/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr +++ b/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr @@ -1,4 +1,4 @@ -warning: to use a constant of type `Foo` in a pattern, the constant's initializer must be trivial or all types in the constant must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `CustomEq` in a pattern, the constant's initializer must be trivial or `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/custom-eq-branch-warn.rs:29:9 | LL | BAR_BAZ => panic!(), diff --git a/src/test/ui/consts/const_in_pattern/reject_non_partial_eq.stderr b/src/test/ui/consts/const_in_pattern/reject_non_partial_eq.stderr index 8462c32ea809b..95cfa4a9ebe95 100644 --- a/src/test/ui/consts/const_in_pattern/reject_non_partial_eq.stderr +++ b/src/test/ui/consts/const_in_pattern/reject_non_partial_eq.stderr @@ -1,4 +1,4 @@ -error: to use a constant of type `Option` in a pattern, `Option` must be annotated with `#[derive(PartialEq, Eq)]` +error: to use a constant of type `NoPartialEq` in a pattern, `NoPartialEq` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/reject_non_partial_eq.rs:28:9 | LL | NO_PARTIAL_EQ_NONE => println!("NO_PARTIAL_EQ_NONE"), diff --git a/src/test/ui/consts/const_in_pattern/warn_corner_cases.stderr b/src/test/ui/consts/const_in_pattern/warn_corner_cases.stderr index a4feaff55b2e1..a24c8d181843d 100644 --- a/src/test/ui/consts/const_in_pattern/warn_corner_cases.stderr +++ b/src/test/ui/consts/const_in_pattern/warn_corner_cases.stderr @@ -1,4 +1,4 @@ -warning: to use a constant of type `Option` in a pattern, the constant's initializer must be trivial or all types in the constant must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/warn_corner_cases.rs:26:47 | LL | match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), }; @@ -8,7 +8,7 @@ LL | match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), }; = 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 #73448 -warning: to use a constant of type `Option` in a pattern, the constant's initializer must be trivial or all types in the constant must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/warn_corner_cases.rs:32:47 | LL | match None { Some(_) => panic!("whoops"), CALL => dbg!(CALL), }; @@ -17,7 +17,7 @@ LL | match None { Some(_) => panic!("whoops"), CALL => dbg!(CALL), }; = 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 #73448 -warning: to use a constant of type `Option` in a pattern, the constant's initializer must be trivial or all types in the constant must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/warn_corner_cases.rs:38:47 | LL | match None { Some(_) => panic!("whoops"), METHOD_CALL => dbg!(METHOD_CALL), }; From 9550ca624264e3f9b78a95d4454ec30dafd9487b Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 24 Sep 2020 10:18:51 +0200 Subject: [PATCH 0931/1052] Deduplicate the "needs partialeq derive" message creation sites --- .../src/thir/pattern/const_to_pat.rs | 34 +++++++------------ 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 3c8671486bf8f..37f5d5f6cc30f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -3,7 +3,7 @@ use rustc_index::vec::Idx; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_middle::mir::Field; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; use rustc_session::lint; use rustc_span::Span; use rustc_trait_selection::traits::predicate_for_trait_def; @@ -89,18 +89,20 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { self.infcx.tcx } + fn adt_derive_msg(&self, adt_def: &AdtDef) -> String { + let path = self.tcx().def_path_str(adt_def.did); + format!( + "to use a constant of type `{}` in a pattern, \ + `{}` must be annotated with `#[derive(PartialEq, Eq)]`", + path, path, + ) + } + fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option { traits::search_for_structural_match_violation(self.id, self.span, self.tcx(), ty).map( |non_sm_ty| { with_no_trimmed_paths(|| match non_sm_ty { - traits::NonStructuralMatchTy::Adt(adt_def) => { - let path = self.tcx().def_path_str(adt_def.did); - format!( - "to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - path, path, - ) - } + traits::NonStructuralMatchTy::Adt(adt) => self.adt_derive_msg(adt), traits::NonStructuralMatchTy::Dynamic => { "trait objects cannot be used in patterns".to_string() } @@ -412,12 +414,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { && !self.saw_const_match_lint.get() { self.saw_const_match_lint.set(true); - let path = self.tcx().def_path_str(adt_def.did); - let msg = format!( - "to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - path, path, - ); + let msg = self.adt_derive_msg(adt_def); self.tcx().struct_span_lint_hir( lint::builtin::INDIRECT_STRUCTURAL_MATCH, self.id, @@ -429,12 +426,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { } else { if !self.saw_const_match_error.get() { self.saw_const_match_error.set(true); - let path = self.tcx().def_path_str(adt_def.did); - let msg = format!( - "to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - path, path, - ); + let msg = self.adt_derive_msg(adt_def); if self.include_lint_checks { tcx.sess.span_err(span, &msg); } else { From d445493479711389f4dea3a0f433041077ba2088 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 24 Sep 2020 14:51:13 +0200 Subject: [PATCH 0932/1052] Update Cargo.lock --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 26a9e64b85af4..919f2da567483 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -534,7 +534,7 @@ dependencies = [ "if_chain", "itertools 0.9.0", "lazy_static", - "pulldown-cmark 0.7.2", + "pulldown-cmark 0.8.0", "quine-mc_cluskey", "quote", "regex-syntax", From 4de836e2141c418d37e556bc80c4ad0127d74b71 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 24 Sep 2020 09:37:23 -0400 Subject: [PATCH 0933/1052] Install std for non-host targets --- src/bootstrap/install.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index d9ee3bc90fb8c..074f5cd73f32c 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -192,7 +192,7 @@ install!((self, builder, _config), builder.ensure(dist::Docs { host: self.target }); install_docs(builder, self.compiler.stage, self.target); }; - Std, "library/std", true, only_hosts: true, { + Std, "library/std", true, only_hosts: false, { for target in &builder.targets { builder.ensure(dist::Std { compiler: self.compiler, From 9baa601afd50f57655be9eb7e5e2892c2ea9f005 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 12 Sep 2020 02:32:43 -0400 Subject: [PATCH 0934/1052] Add `x.py setup` - Suggest `x.py setup` if config.toml doesn't exist yet (twice, once before and once after the build) - Prompt for a profile if not given on the command line - Print the configuration file that will be used - Print helpful starting commands after setup - Link to the dev-guide after finishing - Note that distro maintainers will see the changelog warning --- src/bootstrap/CHANGELOG.md | 1 + src/bootstrap/bin/main.rs | 19 ++++++-- src/bootstrap/builder.rs | 4 +- src/bootstrap/config.rs | 7 ++- src/bootstrap/flags.rs | 32 +++++++++++++- src/bootstrap/lib.rs | 7 ++- src/bootstrap/run.rs | 2 +- src/bootstrap/setup.rs | 88 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 152 insertions(+), 8 deletions(-) create mode 100644 src/bootstrap/setup.rs diff --git a/src/bootstrap/CHANGELOG.md b/src/bootstrap/CHANGELOG.md index 5fcaafab959e9..aa398f25020f1 100644 --- a/src/bootstrap/CHANGELOG.md +++ b/src/bootstrap/CHANGELOG.md @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Non-breaking changes since the last major version] +- Add `x.py setup` [#76631](https://github.com/rust-lang/rust/pull/76631) - Add a changelog for x.py [#76626](https://github.com/rust-lang/rust/pull/76626) - Optionally, download LLVM from CI on Linux and NixOS + [#76439](https://github.com/rust-lang/rust/pull/76349) diff --git a/src/bootstrap/bin/main.rs b/src/bootstrap/bin/main.rs index f7512aa9fcebd..669dd7a33de18 100644 --- a/src/bootstrap/bin/main.rs +++ b/src/bootstrap/bin/main.rs @@ -7,21 +7,34 @@ use std::env; -use bootstrap::{Build, Config}; +use bootstrap::{Build, Config, Subcommand}; fn main() { let args = env::args().skip(1).collect::>(); let config = Config::parse(&args); let changelog_suggestion = check_version(&config); - if let Some(suggestion) = &changelog_suggestion { + + // NOTE: Since `./configure` generates a `config.toml`, distro maintainers will see the + // changelog warning, not the `x.py setup` message. + let suggest_setup = !config.config.exists() && !matches!(config.cmd, Subcommand::Setup { .. }); + if suggest_setup { + println!("warning: you have not made a `config.toml`"); + println!("help: consider running `x.py setup` or copying `config.toml.example`"); + } else if let Some(suggestion) = &changelog_suggestion { println!("{}", suggestion); } Build::new(config).build(); - if let Some(suggestion) = changelog_suggestion { + if suggest_setup { + println!("warning: you have not made a `config.toml`"); + println!("help: consider running `x.py setup` or copying `config.toml.example`"); + } else if let Some(suggestion) = &changelog_suggestion { println!("{}", suggestion); + } + + if suggest_setup || changelog_suggestion.is_some() { println!("note: this message was printed twice to make it more likely to be seen"); } } diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index d2537d65e67f5..4aaaeb8a93bda 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -549,7 +549,9 @@ impl<'a> Builder<'a> { Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]), Subcommand::Install { ref paths } => (Kind::Install, &paths[..]), Subcommand::Run { ref paths } => (Kind::Run, &paths[..]), - Subcommand::Format { .. } | Subcommand::Clean { .. } => panic!(), + Subcommand::Format { .. } | Subcommand::Clean { .. } | Subcommand::Setup { .. } => { + panic!() + } }; Self::new_internal(build, kind, paths.to_owned()) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index c74501979f0ec..46a9d989652e9 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -72,6 +72,8 @@ pub struct Config { pub stage: u32, pub keep_stage: Vec, pub src: PathBuf, + // defaults to `config.toml` + pub config: PathBuf, pub jobs: Option, pub cmd: Subcommand, pub incremental: bool, @@ -512,6 +514,7 @@ impl Config { config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")]; config.deny_warnings = true; config.missing_tools = false; + config.config = PathBuf::from("config.toml"); // set by bootstrap.py config.build = TargetSelection::from_user(&env!("BUILD_TRIPLE")); @@ -556,7 +559,7 @@ impl Config { let get_toml = |file: PathBuf| { use std::process; - let contents = t!(fs::read_to_string(&file), "configuration file did not exist"); + let contents = t!(fs::read_to_string(&file), "`include` config not found"); match toml::from_str(&contents) { Ok(table) => table, Err(err) => { @@ -642,6 +645,7 @@ impl Config { | Subcommand::Clippy { .. } | Subcommand::Fix { .. } | Subcommand::Run { .. } + | Subcommand::Setup { .. } | Subcommand::Format { .. } => flags.stage.unwrap_or(0), }; @@ -666,6 +670,7 @@ impl Config { | Subcommand::Clippy { .. } | Subcommand::Fix { .. } | Subcommand::Run { .. } + | Subcommand::Setup { .. } | Subcommand::Format { .. } => {} } } diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 842c84a3e5cd6..643edeb8321ba 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -7,6 +7,7 @@ use std::env; use std::path::PathBuf; use std::process; +use build_helper::t; use getopts::Options; use crate::builder::Builder; @@ -88,6 +89,9 @@ pub enum Subcommand { Run { paths: Vec, }, + Setup { + path: String, + }, } impl Default for Subcommand { @@ -191,6 +195,7 @@ To learn more about a subcommand, run `./x.py -h`", || (s == "install") || (s == "run") || (s == "r") + || (s == "setup") }); let subcommand = match subcommand { Some(s) => s, @@ -445,10 +450,21 @@ Arguments: At least a tool needs to be called.", ); } + "setup" => { + subcommand_help.push_str( + "\n +Arguments: + This subcommand accepts a 'profile' to use for builds. For example: + + ./x.py setup library + + The profile is optional and you will be prompted interactively if it is not given.", + ); + } _ => {} }; // Get any optional paths which occur after the subcommand - let paths = matches.free[1..].iter().map(|p| p.into()).collect::>(); + let mut paths = matches.free[1..].iter().map(|p| p.into()).collect::>(); let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from); let verbose = matches.opt_present("verbose"); @@ -500,6 +516,20 @@ Arguments: } Subcommand::Run { paths } } + "setup" => { + let path = if paths.len() > 1 { + println!("\nat most one profile can be passed to setup\n"); + usage(1, &opts, verbose, &subcommand_help) + } else if let Some(path) = paths.pop() { + t!(path.into_os_string().into_string().map_err(|path| format!( + "{} is not a valid UTF8 string", + path.to_string_lossy() + ))) + } else { + t!(crate::setup::interactive_path()) + }; + Subcommand::Setup { path } + } _ => { usage(1, &opts, verbose, &subcommand_help); } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 3f7aeae0ed495..4cc72f5f39c97 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -141,6 +141,7 @@ mod metadata; mod native; mod run; mod sanity; +mod setup; mod test; mod tool; mod toolstate; @@ -165,7 +166,7 @@ mod job { use crate::cache::{Interned, INTERNER}; pub use crate::config::Config; -use crate::flags::Subcommand; +pub use crate::flags::Subcommand; const LLVM_TOOLS: &[&str] = &[ "llvm-nm", // used to inspect binaries; it shows symbol names, their sizes and visibility @@ -470,6 +471,10 @@ impl Build { return clean::clean(self, all); } + if let Subcommand::Setup { path: include_name } = &self.config.cmd { + return setup::setup(&self.config.src, include_name); + } + { let builder = builder::Builder::new(&self); if let Some(path) = builder.paths.get(0) { diff --git a/src/bootstrap/run.rs b/src/bootstrap/run.rs index 900534714277c..ba593cadbad81 100644 --- a/src/bootstrap/run.rs +++ b/src/bootstrap/run.rs @@ -10,7 +10,7 @@ impl Step for ExpandYamlAnchors { /// Runs the `expand-yaml_anchors` tool. /// - /// This tool in `src/tools` read the CI configuration files written in YAML and expands the + /// This tool in `src/tools` reads the CI configuration files written in YAML and expands the /// anchors in them, since GitHub Actions doesn't support them. fn run(self, builder: &Builder<'_>) { builder.info("Expanding YAML anchors in the GitHub Actions configuration"); diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs new file mode 100644 index 0000000000000..9d3a889aa008e --- /dev/null +++ b/src/bootstrap/setup.rs @@ -0,0 +1,88 @@ +use crate::t; +use std::path::{Path, PathBuf}; +use std::{ + env, fs, + io::{self, Write}, +}; + +pub fn setup(src_path: &Path, include_name: &str) { + let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from); + + if cfg_file.as_ref().map_or(false, |f| f.exists()) { + let file = cfg_file.unwrap(); + println!( + "error: you asked `x.py` to setup a new config file, but one already exists at `{}`", + file.display() + ); + println!( + "help: try adding `profile = \"{}\"` at the top of {}", + include_name, + file.display() + ); + println!( + "note: this will use the configuration in {}/src/bootstrap/defaults/config.toml.{}", + src_path.display(), + include_name + ); + std::process::exit(1); + } + + let path = cfg_file.unwrap_or_else(|| src_path.join("config.toml")); + let settings = format!( + "# Includes one of the default files in src/bootstrap/defaults\n\ + profile = \"{}\"\n", + include_name + ); + t!(fs::write(path, settings)); + + let include_path = + format!("{}/src/bootstrap/defaults/config.toml.{}", src_path.display(), include_name); + println!("`x.py` will now use the configuration at {}", include_path); + + let suggestions = match include_name { + "codegen" | "compiler" => &["check", "build", "test"][..], + "library" => &["check", "build", "test library/std", "doc"], + "user" => &["dist", "build"], + _ => return, + }; + + println!("To get started, try one of the following commands:"); + for cmd in suggestions { + println!("- `x.py {}`", cmd); + } + + if include_name != "user" { + println!( + "For more suggestions, see https://rustc-dev-guide.rust-lang.org/building/suggested.html" + ); + } +} + +// Used to get the path for `Subcommand::Setup` +pub fn interactive_path() -> io::Result { + let mut input = String::new(); + println!( + "Welcome to the Rust project! What do you want to do with x.py? +a) Contribute to the standard library +b) Contribute to the compiler +c) Contribute to the compiler, and also modify LLVM or codegen +d) Install Rust from source" + ); + let template = loop { + print!("Please choose one (a/b/c/d): "); + io::stdout().flush()?; + io::stdin().read_line(&mut input)?; + break match input.trim().to_lowercase().as_str() { + "a" | "lib" | "library" => "library", + "b" | "compiler" => "compiler", + "c" | "llvm" => "llvm", + "d" | "user" | "maintainer" => "maintainer", + _ => { + println!("error: unrecognized option '{}'", input.trim()); + println!("note: press Ctrl+C to exit"); + continue; + } + }; + }; + Ok(template.to_owned()) +} From 382d7243a70f7b9fd9330334a12f76985067ef06 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Thu, 24 Sep 2020 14:41:40 +0000 Subject: [PATCH 0935/1052] move test to intergrated test in library/core --- library/core/tests/intrinsics.rs | 15 +++++++++++++++ library/core/tests/lib.rs | 2 ++ src/test/ui/consts/const-eval/const_assume.rs | 17 ----------------- 3 files changed, 17 insertions(+), 17 deletions(-) delete mode 100644 src/test/ui/consts/const-eval/const_assume.rs diff --git a/library/core/tests/intrinsics.rs b/library/core/tests/intrinsics.rs index fed7c4a5bf399..de163a60c98f4 100644 --- a/library/core/tests/intrinsics.rs +++ b/library/core/tests/intrinsics.rs @@ -1,4 +1,5 @@ use core::any::TypeId; +use core::intrinsics::assume; #[test] fn test_typeid_sized_types() { @@ -20,3 +21,17 @@ fn test_typeid_unsized_types() { assert_eq!(TypeId::of::(), TypeId::of::()); assert!(TypeId::of::() != TypeId::of::()); } + +// Check that `const_assume` feature allow `assume` intrinsic +// to be used in const contexts. +#[test] +fn test_assume_can_be_in_const_contexts() { + const unsafe fn foo(x: usize, y: usize) -> usize { + // SAFETY: the entire function is not safe, + // but it is just an example not used elsewhere. + unsafe { assume(y != 0) }; + x / y + } + let rs = unsafe { foo(42, 97) }; + assert_eq!(rs, 0); +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 4db391f3e567e..3a6caaa19fcd9 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -7,6 +7,8 @@ #![feature(bound_cloned)] #![feature(box_syntax)] #![feature(cell_update)] +#![feature(const_assume)] +#![feature(core_intrinsics)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] #![feature(debug_non_exhaustive)] diff --git a/src/test/ui/consts/const-eval/const_assume.rs b/src/test/ui/consts/const-eval/const_assume.rs deleted file mode 100644 index f72f151824bed..0000000000000 --- a/src/test/ui/consts/const-eval/const_assume.rs +++ /dev/null @@ -1,17 +0,0 @@ -// check-pass - -// Check that `const_assume` feature allow `assume` intrinsic -// to be used in const contexts. - -#![feature(core_intrinsics, const_assume)] - -extern crate core; - -use core::intrinsics::assume; - -pub const unsafe fn foo(x: usize, y: usize) -> usize { - assume(y != 0); - x / y -} - -fn main() {} From fc9f2947dab6ad7856986ce98ebd3b75f5293da0 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 24 Sep 2020 17:01:03 +0200 Subject: [PATCH 0936/1052] Document `FallbackToConstRef` and make sure we don't accidentally use it --- .../src/thir/pattern/const_to_pat.rs | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 37f5d5f6cc30f..a203b3a142863 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -63,8 +63,23 @@ struct ConstToPat<'a, 'tcx> { include_lint_checks: bool, } -#[derive(Debug)] -struct FallbackToConstRef; +mod fallback_to_const_ref { + #[derive(Debug)] + /// This error type signals that we encountered a non-struct-eq situation behind a reference. + /// We bubble this up in order to get back to the reference destructuring and make that emit + /// a const pattern instead of a deref pattern. This allows us to simply call `PartialEq::eq` + /// on such patterns (since that function takes a reference) and not have to jump through any + /// hoops to get a reference to the value. + pub(super) struct FallbackToConstRef(()); + + pub(super) fn fallback_to_const_ref<'a, 'tcx>( + c2p: &super::ConstToPat<'a, 'tcx>, + ) -> FallbackToConstRef { + assert!(c2p.behind_reference.get()); + FallbackToConstRef(()) + } +} +use fallback_to_const_ref::{fallback_to_const_ref, FallbackToConstRef}; impl<'a, 'tcx> ConstToPat<'a, 'tcx> { fn new( @@ -314,7 +329,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // Since we are behind a reference, we can just bubble the error up so we get a // constant at reference type, making it easy to let the fallback call // `PartialEq::eq` on it. - return Err(FallbackToConstRef); + return Err(fallback_to_const_ref(self)); } ty::Adt(adt_def, _) if !self.type_marked_structural(cv.ty) => { debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, cv.ty); @@ -447,7 +462,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // very hard to invoke `PartialEq::eq` on it as a fallback. let val = match self.recur(tcx.deref_const(self.param_env.and(cv)), false) { Ok(subpattern) => PatKind::Deref { subpattern }, - Err(FallbackToConstRef) => PatKind::Constant { value: cv }, + Err(_) => PatKind::Constant { value: cv }, }; self.behind_reference.set(old); val From 40629ef827220f4be8f043f6ff28118af22ea3dd Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 24 Sep 2020 17:09:09 +0200 Subject: [PATCH 0937/1052] Always cache const eval queries --- compiler/rustc_middle/src/query/mod.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index b181c3b05af21..325a5937d3df5 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -716,10 +716,7 @@ rustc_queries! { "const-evaluating + checking `{}`", key.value.display(tcx) } - cache_on_disk_if(_, opt_result) { - // Only store results without errors - opt_result.map_or(true, |r| r.is_ok()) - } + cache_on_disk_if { true } } /// Evaluates const items or anonymous constants @@ -734,10 +731,7 @@ rustc_queries! { "simplifying constant for the type system `{}`", key.value.display(tcx) } - cache_on_disk_if(_, opt_result) { - // Only store results without errors - opt_result.map_or(true, |r| r.is_ok()) - } + cache_on_disk_if { true } } /// Destructure a constant ADT or array into its variant index and its From daf976f6129e5fb16effc48bf91853548774e235 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 24 Sep 2020 17:11:47 +0200 Subject: [PATCH 0938/1052] Revert a test change to make sure it's still testing the original issue --- .../issue-71042-opaquely-typed-constant-used-in-pattern.rs | 2 +- .../issue-71042-opaquely-typed-constant-used-in-pattern.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs index 427f4cd8c780c..65f27cf78f120 100644 --- a/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs +++ b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs @@ -4,7 +4,7 @@ fn main() { const C: impl Copy = 0; match C { - C => {} //~ ERROR: `impl Copy` cannot be used in patterns + C | //~ ERROR: `impl Copy` cannot be used in patterns _ => {} } } diff --git a/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr index c22e6eb944394..62dc856be821f 100644 --- a/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr +++ b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr @@ -1,7 +1,7 @@ error: `impl Copy` cannot be used in patterns --> $DIR/issue-71042-opaquely-typed-constant-used-in-pattern.rs:7:9 | -LL | C => {} +LL | C | | ^ error: aborting due to previous error From bab15f773afd5724023d9a065b5af276e2468ff5 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 24 Sep 2020 17:45:50 +0200 Subject: [PATCH 0939/1052] Remove std::io::lazy::Lazy in favour of SyncOnceCell The (internal) std::io::lazy::Lazy was used to lazily initialize the stdout and stdin buffers (and mutexes). It uses atexit() to register a destructor to flush the streams on exit, and mark the streams as 'closed'. Using the stream afterwards would result in a panic. Stdout uses a LineWriter which contains a BufWriter that will flush the buffer on drop. This one is important to be executed during shutdown, to make sure no buffered output is lost. It also forbids access to stdout afterwards, since the buffer is already flushed and gone. Stdin uses a BufReader, which does not implement Drop. It simply forgets any previously read data that was not read from the buffer yet. This means that in the case of stdin, the atexit() function's only effect is making stdin inaccessible to the program, such that later accesses result in a panic. This is uncessary, as it'd have been safe to access stdin during shutdown of the program. --- This change removes the entire io::lazy module in favour of SyncOnceCell. SyncOnceCell's fast path is much faster (a single atomic operation) than locking a sys_common::Mutex on every access like Lazy did. However, SyncOnceCell does not use atexit() to drop the contained object during shutdown. As noted above, this is not a problem for stdin. It simply means stdin is now usable during shutdown. The atexit() call for stdout is moved to the stdio module. Unlike the now-removed Lazy struct, SyncOnceCell does not have a 'gone and unusable' state that panics. Instead of adding this again, this simply replaces the buffer with one with zero capacity. This effectively flushes the old buffer *and* makes any writes afterwards pass through directly without touching a buffer, making print!() available during shutdown without panicking. --- library/std/src/io/lazy.rs | 63 ------------------------------- library/std/src/io/mod.rs | 1 - library/std/src/io/stdio.rs | 74 ++++++++++++++++++++----------------- 3 files changed, 40 insertions(+), 98 deletions(-) delete mode 100644 library/std/src/io/lazy.rs diff --git a/library/std/src/io/lazy.rs b/library/std/src/io/lazy.rs deleted file mode 100644 index 1968d498bbed4..0000000000000 --- a/library/std/src/io/lazy.rs +++ /dev/null @@ -1,63 +0,0 @@ -use crate::cell::Cell; -use crate::ptr; -use crate::sync::Arc; -use crate::sys_common; -use crate::sys_common::mutex::Mutex; - -pub struct Lazy { - // We never call `lock.init()`, so it is UB to attempt to acquire this mutex reentrantly! - lock: Mutex, - ptr: Cell<*mut Arc>, -} - -#[inline] -const fn done() -> *mut Arc { - 1_usize as *mut _ -} - -unsafe impl Sync for Lazy {} - -impl Lazy { - pub const fn new() -> Lazy { - Lazy { lock: Mutex::new(), ptr: Cell::new(ptr::null_mut()) } - } -} - -impl Lazy { - /// Safety: `init` must not call `get` on the variable that is being - /// initialized. - pub unsafe fn get(&'static self, init: fn() -> Arc) -> Option> { - let _guard = self.lock.lock(); - let ptr = self.ptr.get(); - if ptr.is_null() { - Some(self.init(init)) - } else if ptr == done() { - None - } else { - Some((*ptr).clone()) - } - } - - // Must only be called with `lock` held - unsafe fn init(&'static self, init: fn() -> Arc) -> Arc { - // If we successfully register an at exit handler, then we cache the - // `Arc` allocation in our own internal box (it will get deallocated by - // the at exit handler). Otherwise we just return the freshly allocated - // `Arc`. - let registered = sys_common::at_exit(move || { - let ptr = { - let _guard = self.lock.lock(); - self.ptr.replace(done()) - }; - drop(Box::from_raw(ptr)) - }); - // This could reentrantly call `init` again, which is a problem - // because our `lock` allows reentrancy! - // That's why `get` is unsafe and requires the caller to ensure no reentrancy happens. - let ret = init(); - if registered.is_ok() { - self.ptr.set(Box::into_raw(Box::new(ret.clone()))); - } - ret - } -} diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index adea8a804e3ca..d9d0380781925 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -285,7 +285,6 @@ mod buffered; mod cursor; mod error; mod impls; -mod lazy; pub mod prelude; mod stdio; mod util; diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 9974b65f1e164..e0e5ccd062533 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -7,10 +7,11 @@ use crate::io::prelude::*; use crate::cell::RefCell; use crate::fmt; -use crate::io::lazy::Lazy; use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter}; -use crate::sync::{Arc, Mutex, MutexGuard, Once}; +use crate::lazy::SyncOnceCell; +use crate::sync::{Arc, Mutex, MutexGuard}; use crate::sys::stdio; +use crate::sys_common; use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; use crate::thread::LocalKey; @@ -292,15 +293,13 @@ pub struct StdinLock<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stdin() -> Stdin { - static INSTANCE: Lazy>> = Lazy::new(); - return Stdin { - inner: unsafe { INSTANCE.get(stdin_init).expect("cannot access stdin during shutdown") }, - }; - - fn stdin_init() -> Arc>> { - // This must not reentrantly access `INSTANCE` - let stdin = stdin_raw(); - Arc::new(Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin))) + static INSTANCE: SyncOnceCell>>> = SyncOnceCell::new(); + Stdin { + inner: INSTANCE + .get_or_init(|| { + Arc::new(Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin_raw()))) + }) + .clone(), } } @@ -534,19 +533,27 @@ pub struct StdoutLock<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stdout() -> Stdout { - static INSTANCE: Lazy>>> = Lazy::new(); - return Stdout { - inner: unsafe { INSTANCE.get(stdout_init).expect("cannot access stdout during shutdown") }, - }; - - fn stdout_init() -> Arc>>> { - // This must not reentrantly access `INSTANCE` - let stdout = stdout_raw(); - unsafe { - let ret = Arc::new(ReentrantMutex::new(RefCell::new(LineWriter::new(stdout)))); - ret.init(); - ret - } + static INSTANCE: SyncOnceCell>>>> = + SyncOnceCell::new(); + Stdout { + inner: INSTANCE + .get_or_init(|| unsafe { + let _ = sys_common::at_exit(|| { + if let Some(instance) = INSTANCE.get() { + // Flush the data and disable buffering during shutdown + // by replacing the line writer by one with zero + // buffering capacity. + // We use try_lock() instead of lock(), because someone + // might have leaked a StdoutLock, which would + // otherwise cause a deadlock here. + if let Some(lock) = instance.try_lock() { + *lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw()); + } + } + }); + Arc::new(ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw())))) + }) + .clone(), } } @@ -714,16 +721,15 @@ pub fn stderr() -> Stderr { // // This has the added benefit of allowing `stderr` to be usable during // process shutdown as well! - static INSTANCE: ReentrantMutex> = - unsafe { ReentrantMutex::new(RefCell::new(stderr_raw())) }; - - // When accessing stderr we need one-time initialization of the reentrant - // mutex. Afterwards we can just always use the now-filled-in `INSTANCE` value. - static INIT: Once = Once::new(); - INIT.call_once(|| unsafe { - INSTANCE.init(); - }); - Stderr { inner: &INSTANCE } + static INSTANCE: SyncOnceCell>> = SyncOnceCell::new(); + + Stderr { + inner: INSTANCE.get_or_init(|| unsafe { + let r = ReentrantMutex::new(RefCell::new(stderr_raw())); + r.init(); + r + }), + } } impl Stderr { From e9b25f520bd2e3687213aa1162e631b08b9bf7ed Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 24 Sep 2020 18:10:26 +0200 Subject: [PATCH 0940/1052] Add test to check stdout flushing during shutdown. --- src/test/ui/stdout-during-shutdown.rs | 14 ++++++++++++++ src/test/ui/stdout-during-shutdown.run.stdout | 1 + 2 files changed, 15 insertions(+) create mode 100644 src/test/ui/stdout-during-shutdown.rs create mode 100644 src/test/ui/stdout-during-shutdown.run.stdout diff --git a/src/test/ui/stdout-during-shutdown.rs b/src/test/ui/stdout-during-shutdown.rs new file mode 100644 index 0000000000000..c785fc0869610 --- /dev/null +++ b/src/test/ui/stdout-during-shutdown.rs @@ -0,0 +1,14 @@ +// run-pass +// check-run-results + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + extern "C" fn bye() { + print!(", world!"); + } + unsafe { libc::atexit(bye) }; + print!("hello"); +} diff --git a/src/test/ui/stdout-during-shutdown.run.stdout b/src/test/ui/stdout-during-shutdown.run.stdout new file mode 100644 index 0000000000000..30f51a3fba527 --- /dev/null +++ b/src/test/ui/stdout-during-shutdown.run.stdout @@ -0,0 +1 @@ +hello, world! \ No newline at end of file From 45700a9d58679131a628ddc95dd8ce0fcf1f2430 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 24 Sep 2020 19:09:33 +0200 Subject: [PATCH 0941/1052] Drop use of Arc from Stdin and Stdout. --- library/std/src/io/stdio.rs | 50 +++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index e0e5ccd062533..05bdbe0f563c6 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -9,7 +9,7 @@ use crate::cell::RefCell; use crate::fmt; use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter}; use crate::lazy::SyncOnceCell; -use crate::sync::{Arc, Mutex, MutexGuard}; +use crate::sync::{Mutex, MutexGuard}; use crate::sys::stdio; use crate::sys_common; use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; @@ -218,7 +218,7 @@ fn handle_ebadf(r: io::Result, default: T) -> io::Result { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Stdin { - inner: Arc>>, + inner: &'static Mutex>, } /// A locked reference to the `Stdin` handle. @@ -293,13 +293,11 @@ pub struct StdinLock<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stdin() -> Stdin { - static INSTANCE: SyncOnceCell>>> = SyncOnceCell::new(); + static INSTANCE: SyncOnceCell>> = SyncOnceCell::new(); Stdin { - inner: INSTANCE - .get_or_init(|| { - Arc::new(Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin_raw()))) - }) - .clone(), + inner: INSTANCE.get_or_init(|| { + Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin_raw())) + }), } } @@ -475,7 +473,7 @@ pub struct Stdout { // FIXME: this should be LineWriter or BufWriter depending on the state of // stdout (tty or not). Note that if this is not line buffered it // should also flush-on-panic or some form of flush-on-abort. - inner: Arc>>>, + inner: &'static ReentrantMutex>>, } /// A locked reference to the `Stdout` handle. @@ -533,27 +531,25 @@ pub struct StdoutLock<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stdout() -> Stdout { - static INSTANCE: SyncOnceCell>>>> = + static INSTANCE: SyncOnceCell>>> = SyncOnceCell::new(); Stdout { - inner: INSTANCE - .get_or_init(|| unsafe { - let _ = sys_common::at_exit(|| { - if let Some(instance) = INSTANCE.get() { - // Flush the data and disable buffering during shutdown - // by replacing the line writer by one with zero - // buffering capacity. - // We use try_lock() instead of lock(), because someone - // might have leaked a StdoutLock, which would - // otherwise cause a deadlock here. - if let Some(lock) = instance.try_lock() { - *lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw()); - } + inner: INSTANCE.get_or_init(|| unsafe { + let _ = sys_common::at_exit(|| { + if let Some(instance) = INSTANCE.get() { + // Flush the data and disable buffering during shutdown + // by replacing the line writer by one with zero + // buffering capacity. + // We use try_lock() instead of lock(), because someone + // might have leaked a StdoutLock, which would + // otherwise cause a deadlock here. + if let Some(lock) = instance.try_lock() { + *lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw()); } - }); - Arc::new(ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw())))) - }) - .clone(), + } + }); + ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw()))) + }), } } From b832a97a51f510c77f8187c00be3b3544e195e2b Mon Sep 17 00:00:00 2001 From: Bram van den Heuvel Date: Thu, 24 Sep 2020 14:43:41 +0200 Subject: [PATCH 0942/1052] Update chalk to 0.22.0 --- Cargo.lock | 16 ++++++++-------- compiler/rustc_middle/Cargo.toml | 2 +- compiler/rustc_traits/Cargo.toml | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 26a9e64b85af4..84f2c82357b2a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -427,9 +427,9 @@ dependencies = [ [[package]] name = "chalk-derive" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1df0dbb57d74b4acd20f20fa66ab2acd09776b79eaeb9d8f947b2f3e01c40bf" +checksum = "f26289db4cf059de9e0ab868ab9fc0dbc64455c3b09279c62c73ea0b3948b53f" dependencies = [ "proc-macro2", "quote", @@ -439,9 +439,9 @@ dependencies = [ [[package]] name = "chalk-engine" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb7c65a13f32f02aba8f1d9a37f206af615f77ac564624b81a4c593c6c1735b9" +checksum = "45ea68bc2cdd40ea6b48e39580adebfe833dc72a9593426fa73589326a2e1d75" dependencies = [ "chalk-derive", "chalk-ir", @@ -452,9 +452,9 @@ dependencies = [ [[package]] name = "chalk-ir" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44361a25dbdb1dc428f56ad7a3c21ba9ca12f3225c26a47919ff6fcb10a583d4" +checksum = "e155e98d67dbf34f0eaa7b5ef34b629c1d61e949196b3d2bd046e4daed7b506e" dependencies = [ "chalk-derive", "lazy_static", @@ -462,9 +462,9 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a886da37a0dc457057d86f78f026f7a09c6d8088aa13f4f4127fdb8dc80119a3" +checksum = "08cce24bb0f20800287136fec62669bbef50409712162ee51fd1db40926d10f1" dependencies = [ "chalk-derive", "chalk-ir", diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index a5a860a38b3e8..d3aa9742a594f 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -26,7 +26,7 @@ rustc_index = { path = "../rustc_index" } rustc_serialize = { path = "../rustc_serialize" } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } -chalk-ir = "0.21.0" +chalk-ir = "0.22.0" smallvec = { version = "1.0", features = ["union", "may_dangle"] } measureme = "0.7.1" rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml index 3571ff17f31be..399555ddf156c 100644 --- a/compiler/rustc_traits/Cargo.toml +++ b/compiler/rustc_traits/Cargo.toml @@ -12,9 +12,9 @@ rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } -chalk-ir = "0.21.0" -chalk-solve = "0.21.0" -chalk-engine = "0.21.0" +chalk-ir = "0.22.0" +chalk-solve = "0.22.0" +chalk-engine = "0.22.0" smallvec = { version = "1.0", features = ["union", "may_dangle"] } rustc_infer = { path = "../rustc_infer" } rustc_trait_selection = { path = "../rustc_trait_selection" } From 52eeff6fbea7a3252ae292c8c4e23b4c7816e719 Mon Sep 17 00:00:00 2001 From: Bram van den Heuvel Date: Thu, 24 Sep 2020 15:21:46 +0200 Subject: [PATCH 0943/1052] Update chalk to 0.23.0 --- Cargo.lock | 16 ++++++++-------- compiler/rustc_middle/Cargo.toml | 2 +- compiler/rustc_traits/Cargo.toml | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 84f2c82357b2a..a6a2dac02b3e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -427,9 +427,9 @@ dependencies = [ [[package]] name = "chalk-derive" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26289db4cf059de9e0ab868ab9fc0dbc64455c3b09279c62c73ea0b3948b53f" +checksum = "c3cb438e961fd7f1183dc5e0bdcfd09253bf9b90592cf665d1ce6787d8a4908f" dependencies = [ "proc-macro2", "quote", @@ -439,9 +439,9 @@ dependencies = [ [[package]] name = "chalk-engine" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45ea68bc2cdd40ea6b48e39580adebfe833dc72a9593426fa73589326a2e1d75" +checksum = "fd715f39817e75c0f1616e1079880f2a90949af1c607033f922927780017a490" dependencies = [ "chalk-derive", "chalk-ir", @@ -452,9 +452,9 @@ dependencies = [ [[package]] name = "chalk-ir" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e155e98d67dbf34f0eaa7b5ef34b629c1d61e949196b3d2bd046e4daed7b506e" +checksum = "bb332abfcb015b148c6fbab39b1d13282745b0f7f312019dd8e138f5f3f0855d" dependencies = [ "chalk-derive", "lazy_static", @@ -462,9 +462,9 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08cce24bb0f20800287136fec62669bbef50409712162ee51fd1db40926d10f1" +checksum = "802de4eff72e5a5d2828e6c07224c74d66949dc6308aff025d0ae2871a11b4eb" dependencies = [ "chalk-derive", "chalk-ir", diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index d3aa9742a594f..eb495206bbf18 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -26,7 +26,7 @@ rustc_index = { path = "../rustc_index" } rustc_serialize = { path = "../rustc_serialize" } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } -chalk-ir = "0.22.0" +chalk-ir = "0.23.0" smallvec = { version = "1.0", features = ["union", "may_dangle"] } measureme = "0.7.1" rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml index 399555ddf156c..1089e87e0b204 100644 --- a/compiler/rustc_traits/Cargo.toml +++ b/compiler/rustc_traits/Cargo.toml @@ -12,9 +12,9 @@ rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } -chalk-ir = "0.22.0" -chalk-solve = "0.22.0" -chalk-engine = "0.22.0" +chalk-ir = "0.23.0" +chalk-solve = "0.23.0" +chalk-engine = "0.23.0" smallvec = { version = "1.0", features = ["union", "may_dangle"] } rustc_infer = { path = "../rustc_infer" } rustc_trait_selection = { path = "../rustc_trait_selection" } From cb660c6ab5c6c2c3ab7c4bd10535e68a49b940a0 Mon Sep 17 00:00:00 2001 From: Bram van den Heuvel Date: Thu, 24 Sep 2020 16:02:31 +0200 Subject: [PATCH 0944/1052] Update chalk to 0.24.0 --- Cargo.lock | 16 ++++++++-------- compiler/rustc_middle/Cargo.toml | 2 +- compiler/rustc_traits/Cargo.toml | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a6a2dac02b3e2..26c1d26a703d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -427,9 +427,9 @@ dependencies = [ [[package]] name = "chalk-derive" -version = "0.23.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3cb438e961fd7f1183dc5e0bdcfd09253bf9b90592cf665d1ce6787d8a4908f" +checksum = "37f72751ba791492671e4cbc382c9cc0a1051e264e5c4f1cb5bba0ed58f8e65e" dependencies = [ "proc-macro2", "quote", @@ -439,9 +439,9 @@ dependencies = [ [[package]] name = "chalk-engine" -version = "0.23.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd715f39817e75c0f1616e1079880f2a90949af1c607033f922927780017a490" +checksum = "196432c82e77fea69c9ef96070d66f76e91fb067caf7cf21c12878ea334358c7" dependencies = [ "chalk-derive", "chalk-ir", @@ -452,9 +452,9 @@ dependencies = [ [[package]] name = "chalk-ir" -version = "0.23.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb332abfcb015b148c6fbab39b1d13282745b0f7f312019dd8e138f5f3f0855d" +checksum = "45e1d0a1980c632ba01074c44e4299257bb0227d19ac03f7f903127da788ea13" dependencies = [ "chalk-derive", "lazy_static", @@ -462,9 +462,9 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.23.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "802de4eff72e5a5d2828e6c07224c74d66949dc6308aff025d0ae2871a11b4eb" +checksum = "f892ee7c59419a18554fdc006e2fb4237a0af85a6ae59dcc22e0408c3538a093" dependencies = [ "chalk-derive", "chalk-ir", diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index eb495206bbf18..6491d47a911a4 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -26,7 +26,7 @@ rustc_index = { path = "../rustc_index" } rustc_serialize = { path = "../rustc_serialize" } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } -chalk-ir = "0.23.0" +chalk-ir = "0.24.0" smallvec = { version = "1.0", features = ["union", "may_dangle"] } measureme = "0.7.1" rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml index 1089e87e0b204..f170b38a7ecd2 100644 --- a/compiler/rustc_traits/Cargo.toml +++ b/compiler/rustc_traits/Cargo.toml @@ -12,9 +12,9 @@ rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } -chalk-ir = "0.23.0" -chalk-solve = "0.23.0" -chalk-engine = "0.23.0" +chalk-ir = "0.24.0" +chalk-solve = "0.24.0" +chalk-engine = "0.24.0" smallvec = { version = "1.0", features = ["union", "may_dangle"] } rustc_infer = { path = "../rustc_infer" } rustc_trait_selection = { path = "../rustc_trait_selection" } From ed784023e50d47bb8b447ed3a01c254e43c39bb0 Mon Sep 17 00:00:00 2001 From: Bram van den Heuvel Date: Thu, 24 Sep 2020 16:09:39 +0200 Subject: [PATCH 0945/1052] Update chalk to 0.25.0 --- Cargo.lock | 16 ++++++++-------- compiler/rustc_middle/Cargo.toml | 2 +- compiler/rustc_traits/Cargo.toml | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 26c1d26a703d4..f3ed03ae67887 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -427,9 +427,9 @@ dependencies = [ [[package]] name = "chalk-derive" -version = "0.24.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37f72751ba791492671e4cbc382c9cc0a1051e264e5c4f1cb5bba0ed58f8e65e" +checksum = "624e14d3f029186e6ffd97081ffa082f98ddd5df20655b6f0e8efb83dd8ac8b4" dependencies = [ "proc-macro2", "quote", @@ -439,9 +439,9 @@ dependencies = [ [[package]] name = "chalk-engine" -version = "0.24.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196432c82e77fea69c9ef96070d66f76e91fb067caf7cf21c12878ea334358c7" +checksum = "fd172df00ff1de4789ed8971e1623afb10551041a9385d3b4e22fe6b1e8a0d1d" dependencies = [ "chalk-derive", "chalk-ir", @@ -452,9 +452,9 @@ dependencies = [ [[package]] name = "chalk-ir" -version = "0.24.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e1d0a1980c632ba01074c44e4299257bb0227d19ac03f7f903127da788ea13" +checksum = "118c68eccdda5604af50bbef84c94550f3854f76989cb03c36ffd36cc2ffe958" dependencies = [ "chalk-derive", "lazy_static", @@ -462,9 +462,9 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.24.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f892ee7c59419a18554fdc006e2fb4237a0af85a6ae59dcc22e0408c3538a093" +checksum = "45b235a1f568b28707f117b2d30eabbee9cbcfccaa0d6e9697300400c8ca0996" dependencies = [ "chalk-derive", "chalk-ir", diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 6491d47a911a4..3633166df7b3d 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -26,7 +26,7 @@ rustc_index = { path = "../rustc_index" } rustc_serialize = { path = "../rustc_serialize" } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } -chalk-ir = "0.24.0" +chalk-ir = "0.25.0" smallvec = { version = "1.0", features = ["union", "may_dangle"] } measureme = "0.7.1" rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml index f170b38a7ecd2..4377871602fd4 100644 --- a/compiler/rustc_traits/Cargo.toml +++ b/compiler/rustc_traits/Cargo.toml @@ -12,9 +12,9 @@ rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } -chalk-ir = "0.24.0" -chalk-solve = "0.24.0" -chalk-engine = "0.24.0" +chalk-ir = "0.25.0" +chalk-solve = "0.25.0" +chalk-engine = "0.25.0" smallvec = { version = "1.0", features = ["union", "may_dangle"] } rustc_infer = { path = "../rustc_infer" } rustc_trait_selection = { path = "../rustc_trait_selection" } From 61b2a6f5e5ca52328b32cc919d1f2880489a2577 Mon Sep 17 00:00:00 2001 From: Bram van den Heuvel Date: Thu, 24 Sep 2020 16:49:02 +0200 Subject: [PATCH 0946/1052] Update chalk to 0.26.0 --- Cargo.lock | 16 ++++++++-------- compiler/rustc_middle/Cargo.toml | 2 +- compiler/rustc_traits/Cargo.toml | 6 +++--- compiler/rustc_traits/src/chalk/db.rs | 14 ++++++++------ compiler/rustc_traits/src/chalk/lowering.rs | 15 +++++++++------ 5 files changed, 29 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f3ed03ae67887..fc20d70038ade 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -427,9 +427,9 @@ dependencies = [ [[package]] name = "chalk-derive" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624e14d3f029186e6ffd97081ffa082f98ddd5df20655b6f0e8efb83dd8ac8b4" +checksum = "72aade21de1aa12a31fc287ec9891915965b6d7caac1c5de5ea095b6b9bc4cc4" dependencies = [ "proc-macro2", "quote", @@ -439,9 +439,9 @@ dependencies = [ [[package]] name = "chalk-engine" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd172df00ff1de4789ed8971e1623afb10551041a9385d3b4e22fe6b1e8a0d1d" +checksum = "fcffc1240cc5f9c5d1d8028d35a293e193a647a71244d51d3d5b4295cbea0593" dependencies = [ "chalk-derive", "chalk-ir", @@ -452,9 +452,9 @@ dependencies = [ [[package]] name = "chalk-ir" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "118c68eccdda5604af50bbef84c94550f3854f76989cb03c36ffd36cc2ffe958" +checksum = "6b856e69b664ca362a30c21f477fe10f59f74458978bc9bfd667820549bc7758" dependencies = [ "chalk-derive", "lazy_static", @@ -462,9 +462,9 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45b235a1f568b28707f117b2d30eabbee9cbcfccaa0d6e9697300400c8ca0996" +checksum = "abae2ca9cca3b0a2f33fe946a688881a8b17b8edc088fe3820cb770275e965ed" dependencies = [ "chalk-derive", "chalk-ir", diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 3633166df7b3d..026f810fd793a 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -26,7 +26,7 @@ rustc_index = { path = "../rustc_index" } rustc_serialize = { path = "../rustc_serialize" } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } -chalk-ir = "0.25.0" +chalk-ir = "0.26.0" smallvec = { version = "1.0", features = ["union", "may_dangle"] } measureme = "0.7.1" rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml index 4377871602fd4..cd718def79bfb 100644 --- a/compiler/rustc_traits/Cargo.toml +++ b/compiler/rustc_traits/Cargo.toml @@ -12,9 +12,9 @@ rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } -chalk-ir = "0.25.0" -chalk-solve = "0.25.0" -chalk-engine = "0.25.0" +chalk-ir = "0.26.0" +chalk-solve = "0.26.0" +chalk-engine = "0.26.0" smallvec = { version = "1.0", features = ["union", "may_dangle"] } rustc_infer = { path = "../rustc_infer" } rustc_trait_selection = { path = "../rustc_trait_selection" } diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index 2fad54013ad5b..5804296540a7f 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -11,7 +11,6 @@ use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; use rustc_middle::ty::{self, AssocItemContainer, AssocKind, TyCtxt, TypeFoldable}; use rustc_hir::def_id::DefId; -use rustc_hir::Unsafety; use rustc_span::symbol::sym; @@ -19,6 +18,7 @@ use std::fmt; use std::sync::Arc; use crate::chalk::lowering::{self, LowerInto}; +use rustc_hir::Unsafety; pub struct RustIrDatabase<'tcx> { pub(crate) interner: RustInterner<'tcx>, @@ -247,12 +247,14 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t }; Arc::new(chalk_solve::rust_ir::FnDefDatum { id: fn_def_id, - abi: sig.abi(), - safety: match sig.unsafety() { - Unsafety::Normal => chalk_ir::Safety::Safe, - Unsafety::Unsafe => chalk_ir::Safety::Unsafe, + sig: chalk_ir::FnSig { + abi: sig.abi(), + safety: match sig.unsafety() { + Unsafety::Normal => chalk_ir::Safety::Safe, + Unsafety::Unsafe => chalk_ir::Safety::Unsafe, + }, + variadic: sig.c_variadic(), }, - variadic: sig.c_variadic(), binders: chalk_ir::Binders::new(binders, bound), }) } diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 650404e8ca6dd..3a84efb880b4c 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -340,18 +340,20 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { collect_bound_vars(interner, interner.tcx, &sig.inputs_and_output()); TyData::Function(chalk_ir::FnPointer { num_binders: binders.len(interner), + sig: chalk_ir::FnSig { + abi: sig.abi(), + safety: match sig.unsafety() { + rustc_hir::Unsafety::Normal => chalk_ir::Safety::Safe, + rustc_hir::Unsafety::Unsafe => chalk_ir::Safety::Unsafe, + }, + variadic: sig.c_variadic(), + }, substitution: chalk_ir::Substitution::from_iter( interner, inputs_and_outputs.iter().map(|ty| { chalk_ir::GenericArgData::Ty(ty.lower_into(interner)).intern(interner) }), ), - abi: sig.abi(), - safety: match sig.unsafety() { - rustc_hir::Unsafety::Normal => chalk_ir::Safety::Safe, - rustc_hir::Unsafety::Unsafe => chalk_ir::Safety::Unsafe, - }, - variadic: sig.c_variadic(), }) .intern(interner) } @@ -480,6 +482,7 @@ impl<'tcx> LowerInto<'tcx, Ty<'tcx>> for &chalk_ir::Ty> { substs: application_ty.substitution.lower_into(interner), item_def_id: assoc_ty.0, }), + chalk_ir::TypeName::Foreign(def_id) => ty::Foreign(def_id.0), chalk_ir::TypeName::Error => unimplemented!(), }, TyData::Placeholder(placeholder) => ty::Placeholder(ty::Placeholder { From 5f67571e34882ae796d513fcc0f3acb16f44146e Mon Sep 17 00:00:00 2001 From: Bram van den Heuvel Date: Thu, 24 Sep 2020 16:59:21 +0200 Subject: [PATCH 0947/1052] Update chalk to 0.27.0 --- Cargo.lock | 16 ++++++++-------- compiler/rustc_middle/Cargo.toml | 2 +- compiler/rustc_traits/Cargo.toml | 6 +++--- compiler/rustc_traits/src/chalk/db.rs | 1 + 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fc20d70038ade..a9ab90f40093e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -427,9 +427,9 @@ dependencies = [ [[package]] name = "chalk-derive" -version = "0.26.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72aade21de1aa12a31fc287ec9891915965b6d7caac1c5de5ea095b6b9bc4cc4" +checksum = "d5444ff2a211fe2a863e44d16a368c3d8a314d489de21b8eeb6879f14dd5d4a8" dependencies = [ "proc-macro2", "quote", @@ -439,9 +439,9 @@ dependencies = [ [[package]] name = "chalk-engine" -version = "0.26.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcffc1240cc5f9c5d1d8028d35a293e193a647a71244d51d3d5b4295cbea0593" +checksum = "5b8ba5b42db32c9c92deec8baf6821628b1234eaa296c48dff39cecbce3c0271" dependencies = [ "chalk-derive", "chalk-ir", @@ -452,9 +452,9 @@ dependencies = [ [[package]] name = "chalk-ir" -version = "0.26.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b856e69b664ca362a30c21f477fe10f59f74458978bc9bfd667820549bc7758" +checksum = "e39c3db1dd4abfaa7658faaa62e5fe998a982a592b710bd971fad5b6adfcfdef" dependencies = [ "chalk-derive", "lazy_static", @@ -462,9 +462,9 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.26.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abae2ca9cca3b0a2f33fe946a688881a8b17b8edc088fe3820cb770275e965ed" +checksum = "a673abe3077adc25f8ee0894198aed494a5bb0ce50ee993900d0ee1a44e1948a" dependencies = [ "chalk-derive", "chalk-ir", diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 026f810fd793a..b4e1a380ce56d 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -26,7 +26,7 @@ rustc_index = { path = "../rustc_index" } rustc_serialize = { path = "../rustc_serialize" } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } -chalk-ir = "0.26.0" +chalk-ir = "0.27.0" smallvec = { version = "1.0", features = ["union", "may_dangle"] } measureme = "0.7.1" rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml index cd718def79bfb..b9223e4fcef0a 100644 --- a/compiler/rustc_traits/Cargo.toml +++ b/compiler/rustc_traits/Cargo.toml @@ -12,9 +12,9 @@ rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } -chalk-ir = "0.26.0" -chalk-solve = "0.26.0" -chalk-engine = "0.26.0" +chalk-ir = "0.27.0" +chalk-solve = "0.27.0" +chalk-engine = "0.27.0" smallvec = { version = "1.0", features = ["union", "may_dangle"] } rustc_infer = { path = "../rustc_infer" } rustc_trait_selection = { path = "../rustc_trait_selection" } diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index 5804296540a7f..30c33f1e1a631 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -427,6 +427,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t FnMut => self.interner.tcx.lang_items().fn_mut_trait(), FnOnce => self.interner.tcx.lang_items().fn_once_trait(), Unsize => self.interner.tcx.lang_items().unsize_trait(), + Unpin => self.interner.tcx.lang_items().unpin_trait(), }; def_id.map(chalk_ir::TraitId) } From 12ada5cf4bebabd7dc240a3a993eaebbdf2ed3d3 Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 24 Sep 2020 19:10:34 +0200 Subject: [PATCH 0948/1052] Remove TrustedLen requirement from BuilderMethods::switch The main use case of TrustedLen is allowing APIs to specialize on it, but no use of it uses that specialization. Instead, only the .len() function provided by ExactSizeIterator is used, which is already required to be accurate. Thus, the TrustedLen requirement on BuilderMethods::switch is redundant. --- compiler/rustc_codegen_llvm/src/builder.rs | 3 +-- compiler/rustc_codegen_llvm/src/lib.rs | 1 - compiler/rustc_codegen_ssa/src/lib.rs | 1 - compiler/rustc_codegen_ssa/src/traits/builder.rs | 3 +-- 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 23a3be1a2f2e8..27061acd5afd4 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -21,7 +21,6 @@ use rustc_target::abi::{self, Align, Size}; use rustc_target::spec::{HasTargetSpec, Target}; use std::borrow::Cow; use std::ffi::CStr; -use std::iter::TrustedLen; use std::ops::{Deref, Range}; use std::ptr; use tracing::debug; @@ -179,7 +178,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { &mut self, v: &'ll Value, else_llbb: &'ll BasicBlock, - cases: impl ExactSizeIterator + TrustedLen, + cases: impl ExactSizeIterator, ) { let switch = unsafe { llvm::LLVMBuildSwitch(self.llbuilder, v, else_llbb, cases.len() as c_uint) }; diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 2e2abe9fb30f8..2751481535c41 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -12,7 +12,6 @@ #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(or_patterns)] -#![feature(trusted_len)] #![recursion_limit = "256"] use back::write::{create_informational_target_machine, create_target_machine}; diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index a87ce1446ba14..ee0778490eeda 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -6,7 +6,6 @@ #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(or_patterns)] -#![feature(trusted_len)] #![feature(associated_type_bounds)] #![recursion_limit = "256"] diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 5142922260a57..b35b0f24208b2 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -18,7 +18,6 @@ use rustc_middle::ty::Ty; use rustc_target::abi::{Abi, Align, Scalar, Size}; use rustc_target::spec::HasTargetSpec; -use std::iter::TrustedLen; use std::ops::Range; #[derive(Copy, Clone)] @@ -60,7 +59,7 @@ pub trait BuilderMethods<'a, 'tcx>: &mut self, v: Self::Value, else_llbb: Self::BasicBlock, - cases: impl ExactSizeIterator + TrustedLen, + cases: impl ExactSizeIterator, ); fn invoke( &mut self, From 1857184cd1b723a9478a0ed325b4a7f967693f71 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 24 Sep 2020 19:22:36 +0200 Subject: [PATCH 0949/1052] remove enum name from ImplSource variants --- compiler/rustc_middle/src/traits/mod.rs | 89 +++++++++---------- .../src/traits/structural_impls.rs | 22 ++--- compiler/rustc_mir/src/monomorphize/mod.rs | 2 +- .../src/traits/auto_trait.rs | 7 +- .../src/traits/project.rs | 38 ++++---- .../src/traits/select/confirmation.rs | 32 +++---- compiler/rustc_ty/src/instance.rs | 22 ++--- .../rustc_typeck/src/check/method/probe.rs | 2 +- 8 files changed, 104 insertions(+), 110 deletions(-) diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index a554c80cdaa1a..1dd6d590d908f 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -28,7 +28,6 @@ pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, Selecti pub type CanonicalChalkEnvironmentAndGoal<'tcx> = Canonical<'tcx, ChalkEnvironmentAndGoal<'tcx>>; -pub use self::ImplSource::*; pub use self::ObligationCauseCode::*; pub use self::chalk::{ChalkEnvironmentAndGoal, RustInterner as ChalkRustInterner}; @@ -418,10 +417,10 @@ pub type SelectionResult<'tcx, T> = Result, SelectionError<'tcx>>; /// /// // Case B: ImplSource must be provided by caller. This applies when /// // type is a type parameter. -/// param.clone(); // ImplSourceParam +/// param.clone(); // ImplSource::Param /// /// // Case C: A mix of cases A and B. -/// mixed.clone(); // ImplSource(Impl_1, [ImplSourceParam]) +/// mixed.clone(); // ImplSource(Impl_1, [ImplSource::Param]) /// } /// ``` /// @@ -431,72 +430,72 @@ pub type SelectionResult<'tcx, T> = Result, SelectionError<'tcx>>; #[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)] pub enum ImplSource<'tcx, N> { /// ImplSource identifying a particular impl. - ImplSourceUserDefined(ImplSourceUserDefinedData<'tcx, N>), + UserDefined(ImplSourceUserDefinedData<'tcx, N>), /// ImplSource for auto trait implementations. /// This carries the information and nested obligations with regards /// to an auto implementation for a trait `Trait`. The nested obligations /// ensure the trait implementation holds for all the constituent types. - ImplSourceAutoImpl(ImplSourceAutoImplData), + AutoImpl(ImplSourceAutoImplData), /// Successful resolution to an obligation provided by the caller /// for some type parameter. The `Vec` represents the /// obligations incurred from normalizing the where-clause (if /// any). - ImplSourceParam(Vec), + Param(Vec), /// Virtual calls through an object. - ImplSourceObject(ImplSourceObjectData<'tcx, N>), + Object(ImplSourceObjectData<'tcx, N>), /// Successful resolution for a builtin trait. - ImplSourceBuiltin(ImplSourceBuiltinData), + Builtin(ImplSourceBuiltinData), /// ImplSource automatically generated for a closure. The `DefId` is the ID - /// of the closure expression. This is a `ImplSourceUserDefined` in spirit, but the + /// of the closure expression. This is a `ImplSource::UserDefined` in spirit, but the /// impl is generated by the compiler and does not appear in the source. - ImplSourceClosure(ImplSourceClosureData<'tcx, N>), + Closure(ImplSourceClosureData<'tcx, N>), /// Same as above, but for a function pointer type with the given signature. - ImplSourceFnPointer(ImplSourceFnPointerData<'tcx, N>), + FnPointer(ImplSourceFnPointerData<'tcx, N>), /// ImplSource for a builtin `DeterminantKind` trait implementation. - ImplSourceDiscriminantKind(ImplSourceDiscriminantKindData), + DiscriminantKind(ImplSourceDiscriminantKindData), /// ImplSource automatically generated for a generator. - ImplSourceGenerator(ImplSourceGeneratorData<'tcx, N>), + Generator(ImplSourceGeneratorData<'tcx, N>), /// ImplSource for a trait alias. - ImplSourceTraitAlias(ImplSourceTraitAliasData<'tcx, N>), + TraitAlias(ImplSourceTraitAliasData<'tcx, N>), } impl<'tcx, N> ImplSource<'tcx, N> { pub fn nested_obligations(self) -> Vec { match self { - ImplSourceUserDefined(i) => i.nested, - ImplSourceParam(n) => n, - ImplSourceBuiltin(i) => i.nested, - ImplSourceAutoImpl(d) => d.nested, - ImplSourceClosure(c) => c.nested, - ImplSourceGenerator(c) => c.nested, - ImplSourceObject(d) => d.nested, - ImplSourceFnPointer(d) => d.nested, - ImplSourceDiscriminantKind(ImplSourceDiscriminantKindData) => Vec::new(), - ImplSourceTraitAlias(d) => d.nested, + ImplSource::UserDefined(i) => i.nested, + ImplSource::Param(n) => n, + ImplSource::Builtin(i) => i.nested, + ImplSource::AutoImpl(d) => d.nested, + ImplSource::Closure(c) => c.nested, + ImplSource::Generator(c) => c.nested, + ImplSource::Object(d) => d.nested, + ImplSource::FnPointer(d) => d.nested, + ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => Vec::new(), + ImplSource::TraitAlias(d) => d.nested, } } pub fn borrow_nested_obligations(&self) -> &[N] { match &self { - ImplSourceUserDefined(i) => &i.nested[..], - ImplSourceParam(n) => &n[..], - ImplSourceBuiltin(i) => &i.nested[..], - ImplSourceAutoImpl(d) => &d.nested[..], - ImplSourceClosure(c) => &c.nested[..], - ImplSourceGenerator(c) => &c.nested[..], - ImplSourceObject(d) => &d.nested[..], - ImplSourceFnPointer(d) => &d.nested[..], - ImplSourceDiscriminantKind(ImplSourceDiscriminantKindData) => &[], - ImplSourceTraitAlias(d) => &d.nested[..], + ImplSource::UserDefined(i) => &i.nested[..], + ImplSource::Param(n) => &n[..], + ImplSource::Builtin(i) => &i.nested[..], + ImplSource::AutoImpl(d) => &d.nested[..], + ImplSource::Closure(c) => &c.nested[..], + ImplSource::Generator(c) => &c.nested[..], + ImplSource::Object(d) => &d.nested[..], + ImplSource::FnPointer(d) => &d.nested[..], + ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => &[], + ImplSource::TraitAlias(d) => &d.nested[..], } } @@ -505,42 +504,42 @@ impl<'tcx, N> ImplSource<'tcx, N> { F: FnMut(N) -> M, { match self { - ImplSourceUserDefined(i) => ImplSourceUserDefined(ImplSourceUserDefinedData { + ImplSource::UserDefined(i) => ImplSource::UserDefined(ImplSourceUserDefinedData { impl_def_id: i.impl_def_id, substs: i.substs, nested: i.nested.into_iter().map(f).collect(), }), - ImplSourceParam(n) => ImplSourceParam(n.into_iter().map(f).collect()), - ImplSourceBuiltin(i) => ImplSourceBuiltin(ImplSourceBuiltinData { + ImplSource::Param(n) => ImplSource::Param(n.into_iter().map(f).collect()), + ImplSource::Builtin(i) => ImplSource::Builtin(ImplSourceBuiltinData { nested: i.nested.into_iter().map(f).collect(), }), - ImplSourceObject(o) => ImplSourceObject(ImplSourceObjectData { + ImplSource::Object(o) => ImplSource::Object(ImplSourceObjectData { upcast_trait_ref: o.upcast_trait_ref, vtable_base: o.vtable_base, nested: o.nested.into_iter().map(f).collect(), }), - ImplSourceAutoImpl(d) => ImplSourceAutoImpl(ImplSourceAutoImplData { + ImplSource::AutoImpl(d) => ImplSource::AutoImpl(ImplSourceAutoImplData { trait_def_id: d.trait_def_id, nested: d.nested.into_iter().map(f).collect(), }), - ImplSourceClosure(c) => ImplSourceClosure(ImplSourceClosureData { + ImplSource::Closure(c) => ImplSource::Closure(ImplSourceClosureData { closure_def_id: c.closure_def_id, substs: c.substs, nested: c.nested.into_iter().map(f).collect(), }), - ImplSourceGenerator(c) => ImplSourceGenerator(ImplSourceGeneratorData { + ImplSource::Generator(c) => ImplSource::Generator(ImplSourceGeneratorData { generator_def_id: c.generator_def_id, substs: c.substs, nested: c.nested.into_iter().map(f).collect(), }), - ImplSourceFnPointer(p) => ImplSourceFnPointer(ImplSourceFnPointerData { + ImplSource::FnPointer(p) => ImplSource::FnPointer(ImplSourceFnPointerData { fn_ty: p.fn_ty, nested: p.nested.into_iter().map(f).collect(), }), - ImplSourceDiscriminantKind(ImplSourceDiscriminantKindData) => { - ImplSourceDiscriminantKind(ImplSourceDiscriminantKindData) + ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => { + ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) } - ImplSourceTraitAlias(d) => ImplSourceTraitAlias(ImplSourceTraitAliasData { + ImplSource::TraitAlias(d) => ImplSource::TraitAlias(ImplSourceTraitAliasData { alias_def_id: d.alias_def_id, substs: d.substs, nested: d.nested.into_iter().map(f).collect(), diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs index d73fc628ceb70..b8f6675b8e219 100644 --- a/compiler/rustc_middle/src/traits/structural_impls.rs +++ b/compiler/rustc_middle/src/traits/structural_impls.rs @@ -7,25 +7,25 @@ use std::fmt; impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - super::ImplSourceUserDefined(ref v) => write!(f, "{:?}", v), + super::ImplSource::UserDefined(ref v) => write!(f, "{:?}", v), - super::ImplSourceAutoImpl(ref t) => write!(f, "{:?}", t), + super::ImplSource::AutoImpl(ref t) => write!(f, "{:?}", t), - super::ImplSourceClosure(ref d) => write!(f, "{:?}", d), + super::ImplSource::Closure(ref d) => write!(f, "{:?}", d), - super::ImplSourceGenerator(ref d) => write!(f, "{:?}", d), + super::ImplSource::Generator(ref d) => write!(f, "{:?}", d), - super::ImplSourceFnPointer(ref d) => write!(f, "ImplSourceFnPointer({:?})", d), + super::ImplSource::FnPointer(ref d) => write!(f, "({:?})", d), - super::ImplSourceDiscriminantKind(ref d) => write!(f, "{:?}", d), + super::ImplSource::DiscriminantKind(ref d) => write!(f, "{:?}", d), - super::ImplSourceObject(ref d) => write!(f, "{:?}", d), + super::ImplSource::Object(ref d) => write!(f, "{:?}", d), - super::ImplSourceParam(ref n) => write!(f, "ImplSourceParam({:?})", n), + super::ImplSource::Param(ref n) => write!(f, "ImplSourceParamData({:?})", n), - super::ImplSourceBuiltin(ref d) => write!(f, "{:?}", d), + super::ImplSource::Builtin(ref d) => write!(f, "{:?}", d), - super::ImplSourceTraitAlias(ref d) => write!(f, "{:?}", d), + super::ImplSource::TraitAlias(ref d) => write!(f, "{:?}", d), } } } @@ -96,7 +96,7 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitAliasData<'tcx, fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "ImplSourceTraitAlias(alias_def_id={:?}, substs={:?}, nested={:?})", + "ImplSourceTraitAliasData(alias_def_id={:?}, substs={:?}, nested={:?})", self.alias_def_id, self.substs, self.nested ) } diff --git a/compiler/rustc_mir/src/monomorphize/mod.rs b/compiler/rustc_mir/src/monomorphize/mod.rs index edafa00a03ad0..d2586f0f84dff 100644 --- a/compiler/rustc_mir/src/monomorphize/mod.rs +++ b/compiler/rustc_mir/src/monomorphize/mod.rs @@ -21,7 +21,7 @@ pub fn custom_coerce_unsize_info<'tcx>( }); match tcx.codegen_fulfill_obligation((ty::ParamEnv::reveal_all(), trait_ref)) { - Ok(traits::ImplSourceUserDefined(traits::ImplSourceUserDefinedData { + Ok(traits::ImplSource::UserDefined(traits::ImplSourceUserDefinedData { impl_def_id, .. })) => tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap(), diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 6b87bc4f34ad4..35bfeff10b4aa 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -96,7 +96,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { )); match result { - Ok(Some(ImplSource::ImplSourceUserDefined(_))) => { + Ok(Some(ImplSource::UserDefined(_))) => { debug!( "find_auto_trait_generics({:?}): \ manual impl found, bailing out", @@ -315,9 +315,8 @@ impl AutoTraitFinder<'tcx> { // If we see an explicit negative impl (e.g., `impl !Send for MyStruct`), // we immediately bail out, since it's impossible for us to continue. - if let ImplSource::ImplSourceUserDefined(ImplSourceUserDefinedData { - impl_def_id, - .. + if let ImplSource::UserDefined(ImplSourceUserDefinedData { + impl_def_id, .. }) = impl_source { // Blame 'tidy' for the weird bracket placement. diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index d37f819f376d3..ef8f7b69b5d60 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1000,15 +1000,15 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( }; let eligible = match &impl_source { - super::ImplSourceClosure(_) - | super::ImplSourceGenerator(_) - | super::ImplSourceFnPointer(_) - | super::ImplSourceObject(_) - | super::ImplSourceTraitAlias(_) => { + super::ImplSource::Closure(_) + | super::ImplSource::Generator(_) + | super::ImplSource::FnPointer(_) + | super::ImplSource::Object(_) + | super::ImplSource::TraitAlias(_) => { debug!("assemble_candidates_from_impls: impl_source={:?}", impl_source); true } - super::ImplSourceUserDefined(impl_data) => { + super::ImplSource::UserDefined(impl_data) => { // We have to be careful when projecting out of an // impl because of specialization. If we are not in // codegen (i.e., projection mode is not "any"), and the @@ -1060,7 +1060,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( } } } - super::ImplSourceDiscriminantKind(..) => { + super::ImplSource::DiscriminantKind(..) => { // While `DiscriminantKind` is automatically implemented for every type, // the concrete discriminant may not be known yet. // @@ -1100,7 +1100,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Error(_) => false, } } - super::ImplSourceParam(..) => { + super::ImplSource::Param(..) => { // This case tell us nothing about the value of an // associated type. Consider: // @@ -1128,7 +1128,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // in `assemble_candidates_from_param_env`. false } - super::ImplSourceAutoImpl(..) | super::ImplSourceBuiltin(..) => { + super::ImplSource::AutoImpl(..) | super::ImplSource::Builtin(..) => { // These traits have no associated types. selcx.tcx().sess.delay_span_bug( obligation.cause.span, @@ -1186,20 +1186,20 @@ fn confirm_select_candidate<'cx, 'tcx>( impl_source: Selection<'tcx>, ) -> Progress<'tcx> { match impl_source { - super::ImplSourceUserDefined(data) => confirm_impl_candidate(selcx, obligation, data), - super::ImplSourceGenerator(data) => confirm_generator_candidate(selcx, obligation, data), - super::ImplSourceClosure(data) => confirm_closure_candidate(selcx, obligation, data), - super::ImplSourceFnPointer(data) => confirm_fn_pointer_candidate(selcx, obligation, data), - super::ImplSourceDiscriminantKind(data) => { + super::ImplSource::UserDefined(data) => confirm_impl_candidate(selcx, obligation, data), + super::ImplSource::Generator(data) => confirm_generator_candidate(selcx, obligation, data), + super::ImplSource::Closure(data) => confirm_closure_candidate(selcx, obligation, data), + super::ImplSource::FnPointer(data) => confirm_fn_pointer_candidate(selcx, obligation, data), + super::ImplSource::DiscriminantKind(data) => { confirm_discriminant_kind_candidate(selcx, obligation, data) } - super::ImplSourceObject(_) => { + super::ImplSource::Object(_) => { confirm_object_candidate(selcx, obligation, obligation_trait_ref) } - super::ImplSourceAutoImpl(..) - | super::ImplSourceParam(..) - | super::ImplSourceBuiltin(..) - | super::ImplSourceTraitAlias(..) => + super::ImplSource::AutoImpl(..) + | super::ImplSource::Param(..) + | super::ImplSource::Builtin(..) + | super::ImplSource::TraitAlias(..) => // we don't create Select candidates with this kind of resolution { span_bug!( diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 9906c1f325f3d..88b656ce68082 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -19,16 +19,12 @@ use crate::traits::project::{self, normalize_with_depth}; use crate::traits::select::TraitObligationExt; use crate::traits::util; use crate::traits::util::{closure_trait_ref_and_return_type, predicate_for_trait_def}; +use crate::traits::ImplSource; use crate::traits::Normalized; use crate::traits::OutputTypeParameterMismatch; use crate::traits::Selection; use crate::traits::TraitNotObjectSafe; use crate::traits::{BuiltinDerivedObligation, ImplDerivedObligation}; -use crate::traits::{ - ImplSourceAutoImpl, ImplSourceBuiltin, ImplSourceClosure, ImplSourceDiscriminantKind, - ImplSourceFnPointer, ImplSourceGenerator, ImplSourceObject, ImplSourceParam, - ImplSourceTraitAlias, ImplSourceUserDefined, -}; use crate::traits::{ ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData, ImplSourceGeneratorData, @@ -55,67 +51,67 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match candidate { BuiltinCandidate { has_nested } => { let data = self.confirm_builtin_candidate(obligation, has_nested); - Ok(ImplSourceBuiltin(data)) + Ok(ImplSource::Builtin(data)) } ParamCandidate(param) => { let obligations = self.confirm_param_candidate(obligation, param); - Ok(ImplSourceParam(obligations)) + Ok(ImplSource::Param(obligations)) } ImplCandidate(impl_def_id) => { - Ok(ImplSourceUserDefined(self.confirm_impl_candidate(obligation, impl_def_id))) + Ok(ImplSource::UserDefined(self.confirm_impl_candidate(obligation, impl_def_id))) } AutoImplCandidate(trait_def_id) => { let data = self.confirm_auto_impl_candidate(obligation, trait_def_id); - Ok(ImplSourceAutoImpl(data)) + Ok(ImplSource::AutoImpl(data)) } ProjectionCandidate => { self.confirm_projection_candidate(obligation); - Ok(ImplSourceParam(Vec::new())) + Ok(ImplSource::Param(Vec::new())) } ClosureCandidate => { let vtable_closure = self.confirm_closure_candidate(obligation)?; - Ok(ImplSourceClosure(vtable_closure)) + Ok(ImplSource::Closure(vtable_closure)) } GeneratorCandidate => { let vtable_generator = self.confirm_generator_candidate(obligation)?; - Ok(ImplSourceGenerator(vtable_generator)) + Ok(ImplSource::Generator(vtable_generator)) } FnPointerCandidate => { let data = self.confirm_fn_pointer_candidate(obligation)?; - Ok(ImplSourceFnPointer(data)) + Ok(ImplSource::FnPointer(data)) } DiscriminantKindCandidate => { - Ok(ImplSourceDiscriminantKind(ImplSourceDiscriminantKindData)) + Ok(ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)) } TraitAliasCandidate(alias_def_id) => { let data = self.confirm_trait_alias_candidate(obligation, alias_def_id); - Ok(ImplSourceTraitAlias(data)) + Ok(ImplSource::TraitAlias(data)) } ObjectCandidate => { let data = self.confirm_object_candidate(obligation); - Ok(ImplSourceObject(data)) + Ok(ImplSource::Object(data)) } BuiltinObjectCandidate => { // 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(ImplSourceParam(Vec::new())) + Ok(ImplSource::Param(Vec::new())) } BuiltinUnsizeCandidate => { let data = self.confirm_builtin_unsize_candidate(obligation)?; - Ok(ImplSourceBuiltin(data)) + Ok(ImplSource::Builtin(data)) } } } diff --git a/compiler/rustc_ty/src/instance.rs b/compiler/rustc_ty/src/instance.rs index 75bf8ea0bb816..220f4cec742f1 100644 --- a/compiler/rustc_ty/src/instance.rs +++ b/compiler/rustc_ty/src/instance.rs @@ -119,9 +119,9 @@ fn resolve_associated_item<'tcx>( // Now that we know which impl is being used, we can dispatch to // the actual function: Ok(match vtbl { - traits::ImplSourceUserDefined(impl_data) => { + traits::ImplSource::UserDefined(impl_data) => { debug!( - "resolving ImplSourceUserDefined: {:?}, {:?}, {:?}, {:?}", + "resolving ImplSource::UserDefined: {:?}, {:?}, {:?}, {:?}", param_env, trait_item, rcvr_substs, impl_data ); assert!(!rcvr_substs.needs_infer()); @@ -216,13 +216,13 @@ fn resolve_associated_item<'tcx>( Some(ty::Instance::new(leaf_def.item.def_id, substs)) } - traits::ImplSourceGenerator(generator_data) => Some(Instance { + traits::ImplSource::Generator(generator_data) => Some(Instance { def: ty::InstanceDef::Item(ty::WithOptConstParam::unknown( generator_data.generator_def_id, )), substs: generator_data.substs, }), - traits::ImplSourceClosure(closure_data) => { + traits::ImplSource::Closure(closure_data) => { let trait_closure_kind = tcx.fn_trait_kind_from_lang_item(trait_id).unwrap(); Some(Instance::resolve_closure( tcx, @@ -231,18 +231,18 @@ fn resolve_associated_item<'tcx>( trait_closure_kind, )) } - traits::ImplSourceFnPointer(ref data) => match data.fn_ty.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::ImplSourceObject(ref data) => { + 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::ImplSourceBuiltin(..) => { + 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); @@ -271,10 +271,10 @@ fn resolve_associated_item<'tcx>( None } } - traits::ImplSourceAutoImpl(..) - | traits::ImplSourceParam(..) - | traits::ImplSourceTraitAlias(..) - | traits::ImplSourceDiscriminantKind(..) => None, + traits::ImplSource::AutoImpl(..) + | traits::ImplSource::Param(..) + | traits::ImplSource::TraitAlias(..) + | traits::ImplSource::DiscriminantKind(..) => None, }) } diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index 8a62031ec887c..c1ba29284da16 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -1306,7 +1306,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { .at(&ObligationCause::dummy(), self.param_env) .sup(candidate.xform_self_ty, self_ty); match self.select_trait_candidate(trait_ref) { - Ok(Some(traits::ImplSource::ImplSourceUserDefined(ref impl_data))) => { + Ok(Some(traits::ImplSource::UserDefined(ref impl_data))) => { // If only a single impl matches, make the error message point // to that impl. ImplSource(impl_data.impl_def_id) From 6f9c1323a7a0fe162a5642e229d54afec7ccb299 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 24 Sep 2020 19:25:21 +0200 Subject: [PATCH 0950/1052] Call ReentrantMutex::init() in stdout(). --- library/std/src/io/stdio.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 05bdbe0f563c6..b7d3c47e24b09 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -548,7 +548,9 @@ pub fn stdout() -> Stdout { } } }); - ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw()))) + let r = ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw()))); + r.init(); + r }), } } From 13dc237037c8ef66423639c622d6018f1cf9a37e Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 24 Sep 2020 20:50:09 +0200 Subject: [PATCH 0951/1052] Remove workaround for deref issue that no longer exists. The double underscores were used to work around issue #12808, which was solved in 2016. --- library/std/src/sys_common/remutex.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/library/std/src/sys_common/remutex.rs b/library/std/src/sys_common/remutex.rs index 360337c030be4..162eab2388d55 100644 --- a/library/std/src/sys_common/remutex.rs +++ b/library/std/src/sys_common/remutex.rs @@ -37,9 +37,7 @@ impl RefUnwindSafe for ReentrantMutex {} /// guarded data. #[must_use = "if unused the ReentrantMutex will immediately unlock"] pub struct ReentrantMutexGuard<'a, T: 'a> { - // funny underscores due to how Deref currently works (it disregards field - // privacy). - __lock: &'a ReentrantMutex, + lock: &'a ReentrantMutex, } impl !marker::Send for ReentrantMutexGuard<'_, T> {} @@ -129,7 +127,7 @@ impl fmt::Debug for ReentrantMutex { impl<'mutex, T> ReentrantMutexGuard<'mutex, T> { fn new(lock: &'mutex ReentrantMutex) -> ReentrantMutexGuard<'mutex, T> { - ReentrantMutexGuard { __lock: lock } + ReentrantMutexGuard { lock } } } @@ -137,7 +135,7 @@ impl Deref for ReentrantMutexGuard<'_, T> { type Target = T; fn deref(&self) -> &T { - &self.__lock.data + &self.lock.data } } @@ -145,7 +143,7 @@ impl Drop for ReentrantMutexGuard<'_, T> { #[inline] fn drop(&mut self) { unsafe { - self.__lock.inner.unlock(); + self.lock.inner.unlock(); } } } From 51c781f6138ec541c9e3dff30e8d049027075e79 Mon Sep 17 00:00:00 2001 From: Bram van den Heuvel Date: Thu, 24 Sep 2020 17:37:55 +0200 Subject: [PATCH 0952/1052] Upgrade chalk to 0.28.0 --- Cargo.lock | 16 ++-- compiler/rustc_middle/Cargo.toml | 2 +- compiler/rustc_traits/Cargo.toml | 6 +- compiler/rustc_traits/src/chalk/db.rs | 99 +++++++++++++++------ compiler/rustc_traits/src/chalk/lowering.rs | 27 +++--- 5 files changed, 103 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a9ab90f40093e..daaa4ae44bac6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -427,9 +427,9 @@ dependencies = [ [[package]] name = "chalk-derive" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5444ff2a211fe2a863e44d16a368c3d8a314d489de21b8eeb6879f14dd5d4a8" +checksum = "8c85b013e2dc1b46ac4a279f54e62e55556a8c4d859f7b7c4e340a9b1d013640" dependencies = [ "proc-macro2", "quote", @@ -439,9 +439,9 @@ dependencies = [ [[package]] name = "chalk-engine" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8ba5b42db32c9c92deec8baf6821628b1234eaa296c48dff39cecbce3c0271" +checksum = "2a499f81860f6eadfe0c76c5bb606cd2df701939d5a596ed3724c7db04aec14b" dependencies = [ "chalk-derive", "chalk-ir", @@ -452,9 +452,9 @@ dependencies = [ [[package]] name = "chalk-ir" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e39c3db1dd4abfaa7658faaa62e5fe998a982a592b710bd971fad5b6adfcfdef" +checksum = "2135d844688dc920e3ece3012c5d3d4f06e26986fe38bc041bc98f0e7a9f4e2b" dependencies = [ "chalk-derive", "lazy_static", @@ -462,9 +462,9 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a673abe3077adc25f8ee0894198aed494a5bb0ce50ee993900d0ee1a44e1948a" +checksum = "bc69e4e94ffd4b39f1a865824b431bb82a7b4c8f14a0ba3d461cd86e56a590ac" dependencies = [ "chalk-derive", "chalk-ir", diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index b4e1a380ce56d..5136e2743cdb1 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -26,7 +26,7 @@ rustc_index = { path = "../rustc_index" } rustc_serialize = { path = "../rustc_serialize" } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } -chalk-ir = "0.27.0" +chalk-ir = "0.28.0" smallvec = { version = "1.0", features = ["union", "may_dangle"] } measureme = "0.7.1" rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml index b9223e4fcef0a..369d003eb22f7 100644 --- a/compiler/rustc_traits/Cargo.toml +++ b/compiler/rustc_traits/Cargo.toml @@ -12,9 +12,9 @@ rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } -chalk-ir = "0.27.0" -chalk-solve = "0.27.0" -chalk-engine = "0.27.0" +chalk-ir = "0.28.0" +chalk-solve = "0.28.0" +chalk-engine = "0.28.0" smallvec = { version = "1.0", features = ["union", "may_dangle"] } rustc_infer = { path = "../rustc_infer" } rustc_trait_selection = { path = "../rustc_trait_selection" } diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index 30c33f1e1a631..828ee6dea6256 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -18,7 +18,7 @@ use std::fmt; use std::sync::Arc; use crate::chalk::lowering::{self, LowerInto}; -use rustc_hir::Unsafety; +use rustc_ast::ast; pub struct RustIrDatabase<'tcx> { pub(crate) interner: RustInterner<'tcx>, @@ -247,14 +247,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t }; Arc::new(chalk_solve::rust_ir::FnDefDatum { id: fn_def_id, - sig: chalk_ir::FnSig { - abi: sig.abi(), - safety: match sig.unsafety() { - Unsafety::Normal => chalk_ir::Safety::Safe, - Unsafety::Unsafe => chalk_ir::Safety::Unsafe, - }, - variadic: sig.c_variadic(), - }, + sig: sig.lower_into(&self.interner), binders: chalk_ir::Binders::new(binders, bound), }) } @@ -329,21 +322,75 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t fn impl_provided_for( &self, auto_trait_id: chalk_ir::TraitId>, - adt_id: chalk_ir::AdtId>, + app_ty: &chalk_ir::ApplicationTy>, ) -> bool { + use chalk_ir::Scalar::*; + use chalk_ir::TypeName::*; + let trait_def_id = auto_trait_id.0; - let adt_def = adt_id.0; let all_impls = self.interner.tcx.all_impls(trait_def_id); for impl_def_id in all_impls { let trait_ref = self.interner.tcx.impl_trait_ref(impl_def_id).unwrap(); let self_ty = trait_ref.self_ty(); - match *self_ty.kind() { - ty::Adt(impl_adt_def, _) => { - if impl_adt_def == adt_def { - return true; + let provides = match (self_ty.kind(), app_ty.name) { + (&ty::Adt(impl_adt_def, ..), Adt(id)) => impl_adt_def.did == id.0.did, + (_, AssociatedType(_ty_id)) => { + // FIXME(chalk): See https://github.com/rust-lang/rust/pull/77152#discussion_r494484774 + false + } + (ty::Bool, Scalar(Bool)) => true, + (ty::Char, Scalar(Char)) => true, + (ty::Int(ty1), Scalar(Int(ty2))) => match (ty1, ty2) { + (ast::IntTy::Isize, chalk_ir::IntTy::Isize) + | (ast::IntTy::I8, chalk_ir::IntTy::I8) + | (ast::IntTy::I16, chalk_ir::IntTy::I16) + | (ast::IntTy::I32, chalk_ir::IntTy::I32) + | (ast::IntTy::I64, chalk_ir::IntTy::I64) + | (ast::IntTy::I128, chalk_ir::IntTy::I128) => true, + _ => false, + }, + (ty::Uint(ty1), Scalar(Uint(ty2))) => match (ty1, ty2) { + (ast::UintTy::Usize, chalk_ir::UintTy::Usize) + | (ast::UintTy::U8, chalk_ir::UintTy::U8) + | (ast::UintTy::U16, chalk_ir::UintTy::U16) + | (ast::UintTy::U32, chalk_ir::UintTy::U32) + | (ast::UintTy::U64, chalk_ir::UintTy::U64) + | (ast::UintTy::U128, chalk_ir::UintTy::U128) => true, + _ => false, + }, + (ty::Float(ty1), Scalar(Float(ty2))) => match (ty1, ty2) { + (ast::FloatTy::F32, chalk_ir::FloatTy::F32) + | (ast::FloatTy::F64, chalk_ir::FloatTy::F64) => true, + _ => false, + }, + (&ty::Tuple(..), Tuple(..)) => true, + (&ty::Array(..), Array) => true, + (&ty::Slice(..), Slice) => true, + (&ty::RawPtr(type_and_mut), Raw(mutability)) => { + match (type_and_mut.mutbl, mutability) { + (ast::Mutability::Mut, chalk_ir::Mutability::Mut) => true, + (ast::Mutability::Mut, chalk_ir::Mutability::Not) => false, + (ast::Mutability::Not, chalk_ir::Mutability::Mut) => false, + (ast::Mutability::Not, chalk_ir::Mutability::Not) => true, } } - _ => {} + (&ty::Ref(.., mutability1), Ref(mutability2)) => match (mutability1, mutability2) { + (ast::Mutability::Mut, chalk_ir::Mutability::Mut) => true, + (ast::Mutability::Mut, chalk_ir::Mutability::Not) => false, + (ast::Mutability::Not, chalk_ir::Mutability::Mut) => false, + (ast::Mutability::Not, chalk_ir::Mutability::Not) => true, + }, + (&ty::Opaque(def_id, ..), OpaqueType(opaque_ty_id)) => def_id == opaque_ty_id.0, + (&ty::FnDef(def_id, ..), FnDef(fn_def_id)) => def_id == fn_def_id.0, + (&ty::Str, Str) => true, + (&ty::Never, Never) => true, + (&ty::Closure(def_id, ..), Closure(closure_id)) => def_id == closure_id.0, + (&ty::Foreign(def_id), Foreign(foreign_def_id)) => def_id == foreign_def_id.0, + (&ty::Error(..), Error) => false, + _ => false, + }; + if provides { + return true; } } false @@ -418,16 +465,18 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t well_known_trait: chalk_solve::rust_ir::WellKnownTrait, ) -> Option>> { use chalk_solve::rust_ir::WellKnownTrait::*; + let lang_items = self.interner.tcx.lang_items(); let def_id = match well_known_trait { - Sized => self.interner.tcx.lang_items().sized_trait(), - Copy => self.interner.tcx.lang_items().copy_trait(), - Clone => self.interner.tcx.lang_items().clone_trait(), - Drop => self.interner.tcx.lang_items().drop_trait(), - Fn => self.interner.tcx.lang_items().fn_trait(), - FnMut => self.interner.tcx.lang_items().fn_mut_trait(), - FnOnce => self.interner.tcx.lang_items().fn_once_trait(), - Unsize => self.interner.tcx.lang_items().unsize_trait(), - Unpin => self.interner.tcx.lang_items().unpin_trait(), + Sized => lang_items.sized_trait(), + Copy => lang_items.copy_trait(), + Clone => lang_items.clone_trait(), + Drop => lang_items.drop_trait(), + Fn => lang_items.fn_trait(), + FnMut => lang_items.fn_mut_trait(), + FnOnce => lang_items.fn_once_trait(), + Unsize => lang_items.unsize_trait(), + Unpin => lang_items.unpin_trait(), + CoerceUnsized => lang_items.coerce_unsized_trait(), }; def_id.map(chalk_ir::TraitId) } diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 3a84efb880b4c..1e1841a57f818 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -39,6 +39,8 @@ use rustc_middle::ty::{ }; use rustc_span::def_id::DefId; +use chalk_ir::{FnSig, ForeignDefId}; +use rustc_hir::Unsafety; use std::collections::btree_map::{BTreeMap, Entry}; /// Essentially an `Into` with a `&RustInterner` parameter @@ -269,8 +271,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { ast::FloatTy::F64 => float(chalk_ir::FloatTy::F64), }, Adt(def, substs) => apply(struct_ty(def.did), substs.lower_into(interner)), - // FIXME(chalk): lower Foreign - Foreign(def_id) => apply(chalk_ir::TypeName::FnDef(chalk_ir::FnDefId(def_id)), empty()), + Foreign(def_id) => apply(chalk_ir::TypeName::Foreign(ForeignDefId(def_id)), empty()), Str => apply(chalk_ir::TypeName::Str, empty()), Array(ty, len) => { let value = match len.val { @@ -340,14 +341,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { collect_bound_vars(interner, interner.tcx, &sig.inputs_and_output()); TyData::Function(chalk_ir::FnPointer { num_binders: binders.len(interner), - sig: chalk_ir::FnSig { - abi: sig.abi(), - safety: match sig.unsafety() { - rustc_hir::Unsafety::Normal => chalk_ir::Safety::Safe, - rustc_hir::Unsafety::Unsafe => chalk_ir::Safety::Unsafe, - }, - variadic: sig.c_variadic(), - }, + sig: sig.lower_into(interner), substitution: chalk_ir::Substitution::from_iter( interner, inputs_and_outputs.iter().map(|ty| { @@ -721,6 +715,19 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Binders LowerInto<'tcx, chalk_ir::FnSig>> for ty::Binder> { + fn lower_into(self, _interner: &RustInterner<'_>) -> FnSig> { + chalk_ir::FnSig { + abi: self.abi(), + safety: match self.unsafety() { + Unsafety::Normal => chalk_ir::Safety::Safe, + Unsafety::Unsafe => chalk_ir::Safety::Unsafe, + }, + variadic: self.c_variadic(), + } + } +} + /// To collect bound vars, we have to do two passes. In the first pass, we /// collect all `BoundRegion`s and `ty::Bound`s. In the second pass, we then /// replace `BrNamed` into `BrAnon`. The two separate passes are important, From 7dec440340040ae377abcf22968a1d850a908f1b Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Thu, 24 Sep 2020 21:02:53 +0200 Subject: [PATCH 0953/1052] Resolve https://github.com/rust-lang/rust/pull/76673#discussion_r494426303 --- compiler/rustc_middle/src/mir/terminator/mod.rs | 2 ++ compiler/rustc_mir/src/transform/remove_unneeded_drops.rs | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/mir/terminator/mod.rs b/compiler/rustc_middle/src/mir/terminator/mod.rs index fcfd648c2b7aa..8909f02270cb3 100644 --- a/compiler/rustc_middle/src/mir/terminator/mod.rs +++ b/compiler/rustc_middle/src/mir/terminator/mod.rs @@ -96,6 +96,8 @@ pub enum TerminatorKind<'tcx> { /// P <- V /// } /// ``` + /// + /// Note that DropAndReplace is eliminated as part of the `ElaborateDrops` pass. DropAndReplace { place: Place<'tcx>, value: Operand<'tcx>, diff --git a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs index f027f5e33a187..b9f29786c64ea 100644 --- a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs +++ b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs @@ -38,8 +38,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { impl<'a, 'tcx> Visitor<'tcx> for RemoveUnneededDropsOptimizationFinder<'a, 'tcx> { fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { match terminator.kind { - TerminatorKind::Drop { place, target, .. } - | TerminatorKind::DropAndReplace { place, target, .. } => { + TerminatorKind::Drop { place, target, .. } => { let ty = place.ty(self.body, self.tcx); let needs_drop = ty.ty.needs_drop(self.tcx, self.tcx.param_env(self.def_id)); if !needs_drop { From ebf024bba84242e0c4176583b80ddd1cba071c42 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 24 Sep 2020 11:11:53 -0700 Subject: [PATCH 0954/1052] Suggest `const_fn_transmute` instead of `const_fn` --- compiler/rustc_mir/src/transform/check_consts/ops.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index e14dcf92b89d2..9871300027740 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -489,7 +489,14 @@ impl NonConstOp for Transmute { } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - mcf_emit_error(ccx, span, "can only call `transmute` from const items, not `const fn`"); + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_fn_transmute, + span, + &format!("`transmute` is not allowed in {}s", ccx.const_kind()), + ) + .note("`transmute` is only allowed in constants and statics for now") + .emit(); } } From 0f594698aaa2b8330eca219f38105d2f4989c977 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 24 Sep 2020 11:12:28 -0700 Subject: [PATCH 0955/1052] Bless tests --- .../feature-gate-const_fn_transmute.rs | 18 ++--- .../feature-gate-const_fn_transmute.stderr | 65 +++++++++++-------- .../ui/internal/internal-unstable-const.rs | 2 +- .../internal/internal-unstable-const.stderr | 9 +-- 4 files changed, 52 insertions(+), 42 deletions(-) diff --git a/src/test/ui/feature-gates/feature-gate-const_fn_transmute.rs b/src/test/ui/feature-gates/feature-gate-const_fn_transmute.rs index 981680b5d1fad..9007e501bc2bf 100644 --- a/src/test/ui/feature-gates/feature-gate-const_fn_transmute.rs +++ b/src/test/ui/feature-gates/feature-gate-const_fn_transmute.rs @@ -6,33 +6,33 @@ struct Foo(u32); const TRANSMUTED_U32: u32 = unsafe { mem::transmute(Foo(3)) }; const fn transmute_fn() -> u32 { unsafe { mem::transmute(Foo(3)) } } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` const fn transmute_fn_intrinsic() -> u32 { unsafe { std::intrinsics::transmute(Foo(3)) } } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` const fn transmute_fn_core_intrinsic() -> u32 { unsafe { core::intrinsics::transmute(Foo(3)) } } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` const unsafe fn unsafe_transmute_fn() -> u32 { mem::transmute(Foo(3)) } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` const unsafe fn unsafe_transmute_fn_intrinsic() -> u32 { std::intrinsics::transmute(Foo(3)) } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` const unsafe fn unsafe_transmute_fn_core_intrinsic() -> u32 { core::intrinsics::transmute(Foo(3)) } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` const fn safe_transmute_fn() -> u32 { mem::transmute(Foo(3)) } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` //~| ERROR call to unsafe function is unsafe and requires unsafe function or block const fn safe_transmute_fn_intrinsic() -> u32 { std::intrinsics::transmute(Foo(3)) } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` //~| ERROR call to unsafe function is unsafe and requires unsafe function or block const fn safe_transmute_fn_core_intrinsic() -> u32 { core::intrinsics::transmute(Foo(3)) } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` //~| ERROR call to unsafe function is unsafe and requires unsafe function or block fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-const_fn_transmute.stderr b/src/test/ui/feature-gates/feature-gate-const_fn_transmute.stderr index 44430fd577d88..08ba14dc40e86 100644 --- a/src/test/ui/feature-gates/feature-gate-const_fn_transmute.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_fn_transmute.stderr @@ -1,83 +1,92 @@ -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:8:43 | LL | const fn transmute_fn() -> u32 { unsafe { mem::transmute(Foo(3)) } } | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:11:53 | LL | const fn transmute_fn_intrinsic() -> u32 { unsafe { std::intrinsics::transmute(Foo(3)) } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:14:58 | LL | const fn transmute_fn_core_intrinsic() -> u32 { unsafe { core::intrinsics::transmute(Foo(3)) } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:17:48 | LL | const unsafe fn unsafe_transmute_fn() -> u32 { mem::transmute(Foo(3)) } | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:20:58 | LL | const unsafe fn unsafe_transmute_fn_intrinsic() -> u32 { std::intrinsics::transmute(Foo(3)) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:23:63 | LL | const unsafe fn unsafe_transmute_fn_core_intrinsic() -> u32 { core::intrinsics::transmute(Foo(3)) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:26:39 | LL | const fn safe_transmute_fn() -> u32 { mem::transmute(Foo(3)) } | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:30:49 | LL | const fn safe_transmute_fn_intrinsic() -> u32 { std::intrinsics::transmute(Foo(3)) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:34:54 | LL | const fn safe_transmute_fn_core_intrinsic() -> u32 { core::intrinsics::transmute(Foo(3)) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now error[E0133]: call to unsafe function is unsafe and requires unsafe function or block --> $DIR/feature-gate-const_fn_transmute.rs:26:39 @@ -105,5 +114,5 @@ LL | const fn safe_transmute_fn_core_intrinsic() -> u32 { core::intrinsics::tran error: aborting due to 12 previous errors -Some errors have detailed explanations: E0133, E0723. +Some errors have detailed explanations: E0133, E0658. For more information about an error, try `rustc --explain E0133`. diff --git a/src/test/ui/internal/internal-unstable-const.rs b/src/test/ui/internal/internal-unstable-const.rs index b923bc22f6e5f..554c67be4e0b0 100644 --- a/src/test/ui/internal/internal-unstable-const.rs +++ b/src/test/ui/internal/internal-unstable-const.rs @@ -8,7 +8,7 @@ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn foo() -> i32 { - unsafe { std::mem::transmute(4u32) } //~ ERROR can only call `transmute` from const items + unsafe { std::mem::transmute(4u32) } //~ ERROR `transmute` } fn main() {} diff --git a/src/test/ui/internal/internal-unstable-const.stderr b/src/test/ui/internal/internal-unstable-const.stderr index 9626df23ec3c2..adfb8dc36918d 100644 --- a/src/test/ui/internal/internal-unstable-const.stderr +++ b/src/test/ui/internal/internal-unstable-const.stderr @@ -1,12 +1,13 @@ -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/internal-unstable-const.rs:11:14 | LL | unsafe { std::mem::transmute(4u32) } | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now error: aborting due to previous error -For more information about this error, try `rustc --explain E0723`. +For more information about this error, try `rustc --explain E0658`. From 47843f52d3f3a99f8f6fb64c434341838670f371 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 24 Sep 2020 21:53:07 +0200 Subject: [PATCH 0956/1052] update Miri --- src/tools/miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri b/src/tools/miri index 02a33d411d8e3..2f84bfc57dd0e 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit 02a33d411d8e385942776760a99535d69826349b +Subproject commit 2f84bfc57dd0ef22269bb84dae10f71e5e23e85d From e5430e5306a2f3706797d5e453860875abe463ed Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 24 Sep 2020 22:01:46 +0200 Subject: [PATCH 0957/1052] the two hardest things in programming, names and... --- .../infer/error_reporting/need_type_info.rs | 194 +++++++++++------- .../borrow_check/diagnostics/region_name.rs | 6 +- 2 files changed, 118 insertions(+), 82 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index b00adec822e51..ce249404e8ead 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -178,7 +178,7 @@ fn closure_return_type_suggestion( ); err.span_label( span, - InferCtxt::missing_type_msg("type", &name, &descr, parent_name, parent_descr), + InferCtxt::cannot_infer_msg("type", &name, &descr, parent_name, parent_descr), ); } @@ -220,12 +220,23 @@ impl Into for TypeAnnotationNeeded { } } +/// Information about a constant or a type containing inference variables. +pub struct InferDiagnosticsData { + pub name: String, + pub span: Option, + pub description: Cow<'static, str>, + pub parent_name: Option, + pub parent_description: Option<&'static str>, +} + impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - pub fn extract_type_name( + /// Extracts data used by diagnostic for either types or constants + /// which were stuck during inference. + pub fn extract_infer_data( &self, arg: GenericArg<'tcx>, highlight: Option, - ) -> (String, Option, Cow<'static, str>, Option, Option<&'static str>) { + ) -> InferDiagnosticsData { match arg.unpack() { GenericArgKind::Type(ty) => { if let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind() { @@ -236,32 +247,32 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { var_origin.kind { let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id)); - let (parent_name, parent_desc) = if let Some(parent_def_id) = parent_def_id - { - let parent_name = self - .tcx - .def_key(parent_def_id) - .disambiguated_data - .data - .get_opt_name() - .map(|parent_symbol| parent_symbol.to_string()); - - ( - parent_name, - Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)), - ) - } else { - (None, None) - }; + let (parent_name, parent_description) = + if let Some(parent_def_id) = parent_def_id { + let parent_name = self + .tcx + .def_key(parent_def_id) + .disambiguated_data + .data + .get_opt_name() + .map(|parent_symbol| parent_symbol.to_string()); + + ( + parent_name, + Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)), + ) + } else { + (None, None) + }; if name != kw::SelfUpper { - return ( - name.to_string(), - Some(var_origin.span), - "type parameter".into(), + return InferDiagnosticsData { + name: name.to_string(), + span: Some(var_origin.span), + description: "type parameter".into(), parent_name, - parent_desc, - ); + parent_description, + }; } } } @@ -272,56 +283,67 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { printer.region_highlight_mode = highlight; } let _ = ty.print(printer); - (s, None, ty.prefix_string(), None, None) + InferDiagnosticsData { + name: s, + span: None, + description: ty.prefix_string(), + parent_name: None, + parent_description: None, + } } GenericArgKind::Const(ct) => { - let span = if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val { + if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val { let origin = self.inner.borrow_mut().const_unification_table().probe_value(vid).origin; if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) = origin.kind { let parent_def_id = self.tcx.parent(def_id); - let (parent_name, parent_descr) = if let Some(parent_def_id) = parent_def_id - { - let parent_name = self - .tcx - .def_key(parent_def_id) - .disambiguated_data - .data - .get_opt_name() - .map(|parent_symbol| parent_symbol.to_string()); - - ( - parent_name, - Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)), - ) - } else { - (None, None) - }; - - return ( - name.to_string(), - Some(origin.span), - "const parameter".into(), + let (parent_name, parent_description) = + if let Some(parent_def_id) = parent_def_id { + let parent_name = self + .tcx + .def_key(parent_def_id) + .disambiguated_data + .data + .get_opt_name() + .map(|parent_symbol| parent_symbol.to_string()); + + ( + parent_name, + Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)), + ) + } else { + (None, None) + }; + + return InferDiagnosticsData { + name: name.to_string(), + span: Some(origin.span), + description: "const parameter".into(), parent_name, - parent_descr, - ); + parent_description, + }; } debug_assert!(!origin.span.is_dummy()); - Some(origin.span) + let mut s = String::new(); + let mut printer = + ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::ValueNS); + if let Some(highlight) = highlight { + printer.region_highlight_mode = highlight; + } + let _ = ct.print(printer); + InferDiagnosticsData { + name: s, + span: Some(origin.span), + description: "the constant".into(), + parent_name: None, + parent_description: None, + } } else { bug!("unexpect const: {:?}", ct); - }; - - let mut s = String::new(); - let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::ValueNS); - if let Some(highlight) = highlight { - printer.region_highlight_mode = highlight; } - let _ = ct.print(printer); - (s, span, "the constant".into(), None, None) } GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), } @@ -331,18 +353,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, body_id: Option, span: Span, - ty: GenericArg<'tcx>, + arg: GenericArg<'tcx>, error_code: TypeAnnotationNeeded, ) -> DiagnosticBuilder<'tcx> { - let ty = self.resolve_vars_if_possible(&ty); - let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(ty, None); + let ty = self.resolve_vars_if_possible(&arg); + let arg_data = self.extract_infer_data(arg, None); let kind_str = match ty.unpack() { GenericArgKind::Type(_) => "type", GenericArgKind::Const(_) => "the value", GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), }; - let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into(), span); + let mut local_visitor = FindHirNodeVisitor::new(&self, arg.into(), span); let ty_to_string = |ty: Ty<'tcx>| -> String { let mut s = String::new(); let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); @@ -372,7 +394,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } let err_span = if let Some(pattern) = local_visitor.found_arg_pattern { pattern.span - } else if let Some(span) = name_sp { + } else if let Some(span) = arg_data.span { // `span` here lets us point at `sum` instead of the entire right hand side expr: // error[E0282]: type annotations needed // --> file2.rs:3:15 @@ -419,7 +441,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => String::new(), }; - // When `name` corresponds to a type argument, show the path of the full type we're + // When `arg_data.name` corresponds to a type argument, show the path of the full type we're // trying to infer. In the following example, `ty_msg` contains // " in `std::result::Result`": // ``` @@ -458,11 +480,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &mut err, &decl.output, self.tcx.hir().body(body_id), - &descr, - &name, + &arg_data.description, + &arg_data.name, &ret, - parent_name, - parent_descr, + arg_data.parent_name, + arg_data.parent_description, ); // We don't want to give the other suggestions when the problem is the // closure return type. @@ -476,15 +498,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // nudge them in the right direction. format!("a boxed closure type like `Box {}>`", args, ret) } - Some(ty) if is_named_and_not_impl_trait(ty) && name == "_" => { + Some(ty) if is_named_and_not_impl_trait(ty) && arg_data.name == "_" => { let ty = ty_to_string(ty); format!("the explicit type `{}`, with the type parameters specified", ty) } - Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != name => { + Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != arg_data.name => { let ty = ty_to_string(ty); format!( "the explicit type `{}`, where the type parameter `{}` is specified", - ty, name, + ty, arg_data.name, ) } _ => "a type".to_string(), @@ -601,7 +623,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // | ^^^ cannot infer type for `S` // | // = note: type must be known at this point - let span = name_sp.unwrap_or(err_span); + let span = arg_data.span.unwrap_or(err_span); if !err .span .span_labels() @@ -612,7 +634,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // Avoid multiple labels pointing at `span`. err.span_label( span, - InferCtxt::missing_type_msg(kind_str, &name, &descr, parent_name, parent_descr), + InferCtxt::cannot_infer_msg( + kind_str, + &arg_data.name, + &arg_data.description, + arg_data.parent_name, + arg_data.parent_description, + ), ); } @@ -672,7 +700,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty: Ty<'tcx>, ) -> DiagnosticBuilder<'tcx> { let ty = self.resolve_vars_if_possible(&ty); - let (name, _, descr, parent_name, parent_descr) = self.extract_type_name(ty.into(), None); + let data = self.extract_infer_data(ty.into(), None); let mut err = struct_span_err!( self.tcx.sess, @@ -683,12 +711,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); err.span_label( span, - InferCtxt::missing_type_msg("type", &name, &descr, parent_name, parent_descr), + InferCtxt::cannot_infer_msg( + "type", + &data.name, + &data.description, + data.parent_name, + data.parent_description, + ), ); err } - fn missing_type_msg( + fn cannot_infer_msg( kind_str: &str, type_name: &str, descr: &str, @@ -710,6 +744,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "".to_string() }; + // FIXME: We really shouldn't be dealing with strings here + // but instead use a sensible enum for cases like this. let preposition = if "the value" == kind_str { "of" } else { "for" }; // For example: "cannot infer type for type parameter `T`" format!( diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs index d96020fe36106..e7ab97515b668 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs @@ -396,7 +396,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { ) -> Option { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(needle_fr, counter); - let type_name = self.infcx.extract_type_name(ty.into(), Some(highlight)).0; + let type_name = self.infcx.extract_infer_data(ty.into(), Some(highlight)).name; debug!( "highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}", @@ -646,7 +646,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap()); - let type_name = self.infcx.extract_type_name(return_ty.into(), Some(highlight)).0; + let type_name = self.infcx.extract_infer_data(return_ty.into(), Some(highlight)).name; let mir_hir_id = tcx.hir().local_def_id_to_hir_id(self.mir_def_id); @@ -698,7 +698,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap()); - let type_name = self.infcx.extract_type_name(yield_ty.into(), Some(highlight)).0; + let type_name = self.infcx.extract_infer_data(yield_ty.into(), Some(highlight)).name; let mir_hir_id = tcx.hir().local_def_id_to_hir_id(self.mir_def_id); From ff7009a4d279c1e5ce1248ca373b91678ad6709c Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 24 Sep 2020 22:03:39 +0200 Subject: [PATCH 0958/1052] nit --- compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs index e7ab97515b668..86e8675afb2fb 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs @@ -404,7 +404,6 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { ); if type_name.find(&format!("'{}", counter)).is_some() { // Only add a label if we can confirm that a region was labelled. - Some(RegionNameHighlight::CannotMatchHirTy(span, type_name)) } else { None From 06d2325a50d55ab11e5f540d9b45d7bb0dcd8504 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 24 Sep 2020 19:52:49 +0200 Subject: [PATCH 0959/1052] perf: split progress_obligations with inline(never) --- .../src/traits/fulfill.rs | 45 +++++++++++-------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 77073f51eb7af..7e5be8276f7ff 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -305,8 +305,34 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { return ProcessResult::Unchanged; } - // This part of the code is much colder. + self.progress_changed_obligations(pending_obligation) + } + fn process_backedge<'c, I>( + &mut self, + cycle: I, + _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>, + ) where + I: Clone + Iterator>, + { + if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) { + debug!("process_child_obligations: coinductive match"); + } else { + let cycle: Vec<_> = cycle.map(|c| c.obligation.clone()).collect(); + self.selcx.infcx().report_overflow_error_cycle(&cycle); + } + } +} + +impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { + // The code calling this method is extremely hot and only rarely + // actually uses this, so move this part of the code + // out of that loop. + #[inline(never)] + fn progress_changed_obligations( + &mut self, + pending_obligation: &mut PendingPredicateObligation<'tcx>, + ) -> ProcessResult, FulfillmentErrorCode<'tcx>> { pending_obligation.stalled_on.truncate(0); let obligation = &mut pending_obligation.obligation; @@ -565,23 +591,6 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } - fn process_backedge<'c, I>( - &mut self, - cycle: I, - _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>, - ) where - I: Clone + Iterator>, - { - if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) { - debug!("process_child_obligations: coinductive match"); - } else { - let cycle: Vec<_> = cycle.map(|c| c.obligation.clone()).collect(); - self.selcx.infcx().report_overflow_error_cycle(&cycle); - } - } -} - -impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { fn process_trait_obligation( &mut self, obligation: &PredicateObligation<'tcx>, From 74952b9f2140d2006d615c3665db4f8daa741738 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 24 Sep 2020 22:29:32 +0200 Subject: [PATCH 0960/1052] Fix FIXME in core::num test: Check sign of zero in min/max tests. --- library/core/tests/num/mod.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs index 939f1325c8499..378c8af344b59 100644 --- a/library/core/tests/num/mod.rs +++ b/library/core/tests/num/mod.rs @@ -634,14 +634,18 @@ assume_usize_width! { macro_rules! test_float { ($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr) => { mod $modname { - // FIXME(nagisa): these tests should test for sign of -0.0 #[test] fn min() { assert_eq!((0.0 as $fty).min(0.0), 0.0); + assert!((0.0 as $fty).min(0.0).is_sign_positive()); assert_eq!((-0.0 as $fty).min(-0.0), -0.0); + assert!((-0.0 as $fty).min(-0.0).is_sign_negative()); assert_eq!((9.0 as $fty).min(9.0), 9.0); assert_eq!((-9.0 as $fty).min(0.0), -9.0); assert_eq!((0.0 as $fty).min(9.0), 0.0); + assert!((0.0 as $fty).min(9.0).is_sign_positive()); + assert_eq!((-0.0 as $fty).min(9.0), -0.0); + assert!((-0.0 as $fty).min(9.0).is_sign_negative()); assert_eq!((-0.0 as $fty).min(-9.0), -9.0); assert_eq!(($inf as $fty).min(9.0), 9.0); assert_eq!((9.0 as $fty).min($inf), 9.0); @@ -660,11 +664,19 @@ macro_rules! test_float { #[test] fn max() { assert_eq!((0.0 as $fty).max(0.0), 0.0); + assert!((0.0 as $fty).max(0.0).is_sign_positive()); assert_eq!((-0.0 as $fty).max(-0.0), -0.0); + assert!((-0.0 as $fty).max(-0.0).is_sign_negative()); assert_eq!((9.0 as $fty).max(9.0), 9.0); assert_eq!((-9.0 as $fty).max(0.0), 0.0); + assert!((-9.0 as $fty).max(0.0).is_sign_positive()); + assert_eq!((-9.0 as $fty).max(-0.0), -0.0); + assert!((-9.0 as $fty).max(-0.0).is_sign_negative()); assert_eq!((0.0 as $fty).max(9.0), 9.0); + assert_eq!((0.0 as $fty).max(-9.0), 0.0); + assert!((0.0 as $fty).max(-9.0).is_sign_positive()); assert_eq!((-0.0 as $fty).max(-9.0), -0.0); + assert!((-0.0 as $fty).max(-9.0).is_sign_negative()); assert_eq!(($inf as $fty).max(9.0), $inf); assert_eq!((9.0 as $fty).max($inf), $inf); assert_eq!(($inf as $fty).max(-9.0), $inf); From 1d3717d17c8891db85a8316ea869a3ceca60b53d Mon Sep 17 00:00:00 2001 From: Austin Keeley Date: Fri, 25 Sep 2020 00:03:59 -0400 Subject: [PATCH 0961/1052] Removing erroneous semicolon --- library/core/src/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index bcbb760021ee4..581b6af70da61 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -904,7 +904,7 @@ extern "rust-intrinsic" { /// let raw_bytes = [0x78, 0x56, 0x34, 0x12]; /// /// let num = unsafe { - /// std::mem::transmute::<[u8; 4], u32>(raw_bytes); + /// std::mem::transmute::<[u8; 4], u32>(raw_bytes) /// }; /// /// // use `u32::from_ne_bytes` instead From 1e64d98761c4713f739656bcff218dbdb1b08ad9 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Sun, 9 Aug 2020 12:25:20 +0200 Subject: [PATCH 0962/1052] BTreeMap: refactor correct_childrens_parent_links --- library/alloc/src/collections/btree/node.rs | 42 ++++++++------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index f1d66e973cb52..a141c1d08e29b 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -597,18 +597,17 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Leaf> { impl<'a, K, V> NodeRef, K, V, marker::Internal> { /// # Safety - /// 'first' and 'after_last' must be in range. - unsafe fn correct_childrens_parent_links(&mut self, first: usize, after_last: usize) { - debug_assert!(first <= self.len()); - debug_assert!(after_last <= self.len() + 1); - for i in first..after_last { + /// Every item returned by `range` is a valid edge index for the node. + unsafe fn correct_childrens_parent_links>(&mut self, range: R) { + for i in range { + debug_assert!(i <= self.len()); unsafe { Handle::new_edge(self.reborrow_mut(), i) }.correct_parent_link(); } } fn correct_all_childrens_parent_links(&mut self) { let len = self.len(); - unsafe { self.correct_childrens_parent_links(0, len + 1) }; + unsafe { self.correct_childrens_parent_links(0..=len) }; } } @@ -708,9 +707,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { let mut new_root = Root { node: edge, height: internal.height - 1 }; new_root.node_as_mut().as_leaf_mut().parent = None; - for i in 0..old_len { - Handle::new_edge(internal.reborrow_mut(), i).correct_parent_link(); - } + internal.correct_childrens_parent_links(0..old_len); Some(new_root) } @@ -986,9 +983,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, edge.node, ); - for i in (self.idx + 1)..(self.node.len() + 1) { - Handle::new_edge(self.node.reborrow_mut(), i).correct_parent_link(); - } + self.node.correct_childrens_parent_links((self.idx + 1)..=self.node.len()); } } @@ -1215,9 +1210,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, let mut new_root = Root { node: BoxedNode::from_internal(new_node), height }; - for i in 0..(new_len + 1) { - Handle::new_edge(new_root.node_as_mut().cast_unchecked(), i).correct_parent_link(); - } + new_root.node_as_mut().cast_unchecked().correct_childrens_parent_links(0..=new_len); (self.node, k, v, new_root) } @@ -1261,9 +1254,8 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, ); slice_remove(&mut self.node.as_internal_mut().edges, self.idx + 1); - for i in self.idx + 1..self.node.len() { - Handle::new_edge(self.node.reborrow_mut(), i).correct_parent_link(); - } + let self_len = self.node.len(); + self.node.correct_childrens_parent_links(self.idx + 1..self_len); self.node.as_leaf_mut().len -= 1; left_node.as_leaf_mut().len += right_len as u16 + 1; @@ -1271,17 +1263,15 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, if self.node.height > 1 { // SAFETY: the height of the nodes being merged is one below the height // of the node of this edge, thus above zero, so they are internal. - let mut left_node = left_node.cast_unchecked(); - let mut right_node = right_node.cast_unchecked(); + let mut left_node = left_node.cast_unchecked::(); + let mut right_node = right_node.cast_unchecked::(); ptr::copy_nonoverlapping( right_node.as_internal().edges.as_ptr(), left_node.as_internal_mut().edges.as_mut_ptr().add(left_len + 1), right_len + 1, ); - for i in left_len + 1..left_len + right_len + 2 { - Handle::new_edge(left_node.reborrow_mut(), i).correct_parent_link(); - } + left_node.correct_childrens_parent_links(left_len + 1..=left_len + 1 + right_len); Global.dealloc(right_node.node.cast(), Layout::new::>()); } else { @@ -1371,7 +1361,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, // Make room for stolen edges. let right_edges = right.reborrow_mut().as_internal_mut().edges.as_mut_ptr(); ptr::copy(right_edges, right_edges.add(count), right_len + 1); - right.correct_childrens_parent_links(count, count + right_len + 1); + right.correct_childrens_parent_links(count..count + right_len + 1); move_edges(left, new_left_len + 1, right, 0, count); } @@ -1430,7 +1420,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, // Fix right indexing. let right_edges = right.reborrow_mut().as_internal_mut().edges.as_mut_ptr(); ptr::copy(right_edges.add(count), right_edges, new_right_len + 1); - right.correct_childrens_parent_links(0, new_right_len + 1); + right.correct_childrens_parent_links(0..=new_right_len); } (ForceResult::Leaf(_), ForceResult::Leaf(_)) => {} _ => { @@ -1466,7 +1456,7 @@ unsafe fn move_edges( let dest_ptr = dest.as_internal_mut().edges.as_mut_ptr(); unsafe { ptr::copy_nonoverlapping(source_ptr.add(source_offset), dest_ptr.add(dest_offset), count); - dest.correct_childrens_parent_links(dest_offset, dest_offset + count); + dest.correct_childrens_parent_links(dest_offset..dest_offset + count); } } From 396552457033925010df3eccbee21bdff2aa1122 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Sun, 9 Aug 2020 12:25:20 +0200 Subject: [PATCH 0963/1052] BTreeMap: introduce edge methods similar to those of keys and values --- library/alloc/src/collections/btree/node.rs | 58 ++++++++++++--------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index a141c1d08e29b..3ce5dfbc4dc2a 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -351,7 +351,22 @@ impl NodeRef { unsafe fn val_at(&self, idx: usize) -> &V { unsafe { self.reborrow().into_val_at(idx) } } +} +impl NodeRef { + /// Borrows a reference to the contents of one of the edges that delimit + /// the elements of the node, without invalidating other references. + /// + /// # Safety + /// The node has more than `idx` initialized elements. + unsafe fn edge_at(&self, idx: usize) -> &BoxedNode { + debug_assert!(idx <= self.len()); + let node = self.as_internal_ptr(); + unsafe { (*node).edges.get_unchecked(idx).assume_init_ref() } + } +} + +impl NodeRef { /// Finds the parent of the current node. Returns `Ok(handle)` if the current /// node actually has a parent, where `handle` points to the edge of the parent /// that points to the current node. Returns `Err(self)` if the current node has @@ -498,6 +513,17 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { } } +impl<'a, K, V> NodeRef, K, V, marker::Internal> { + fn edges_mut(&mut self) -> &mut [BoxedNode] { + unsafe { + slice::from_raw_parts_mut( + MaybeUninit::slice_as_mut_ptr(&mut self.as_internal_mut().edges), + self.len() + 1, + ) + } + } +} + impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { /// # Safety /// The node has more than `idx` initialized elements. @@ -669,9 +695,8 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { let val = ptr::read(self.val_at(idx)); let edge = match self.reborrow_mut().force() { ForceResult::Leaf(_) => None, - ForceResult::Internal(mut internal) => { - let edge = - ptr::read(internal.as_internal().edges.get_unchecked(idx + 1).as_ptr()); + ForceResult::Internal(internal) => { + let edge = ptr::read(internal.edge_at(idx + 1)); let mut new_root = Root { node: edge, height: internal.height - 1 }; new_root.node_as_mut().as_leaf_mut().parent = None; Some(new_root) @@ -696,14 +721,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { let edge = match self.reborrow_mut().force() { ForceResult::Leaf(_) => None, ForceResult::Internal(mut internal) => { - let edge = slice_remove( - slice::from_raw_parts_mut( - MaybeUninit::slice_as_mut_ptr(&mut internal.as_internal_mut().edges), - old_len + 1, - ), - 0, - ); - + let edge = slice_remove(internal.edges_mut(), 0); let mut new_root = Root { node: edge, height: internal.height - 1 }; new_root.node_as_mut().as_leaf_mut().parent = None; @@ -972,17 +990,9 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, debug_assert!(edge.height == self.node.height - 1); unsafe { + slice_insert(self.node.edges_mut(), self.idx + 1, edge.node); self.leafy_insert_fit(key, val); - slice_insert( - slice::from_raw_parts_mut( - MaybeUninit::slice_as_mut_ptr(&mut self.node.as_internal_mut().edges), - self.node.len(), - ), - self.idx + 1, - edge.node, - ); - self.node.correct_childrens_parent_links((self.idx + 1)..=self.node.len()); } } @@ -1253,7 +1263,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, right_len, ); - slice_remove(&mut self.node.as_internal_mut().edges, self.idx + 1); + slice_remove(&mut self.node.edges_mut(), self.idx + 1); let self_len = self.node.len(); self.node.correct_childrens_parent_links(self.idx + 1..self_len); self.node.as_leaf_mut().len -= 1; @@ -1264,10 +1274,10 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, // SAFETY: the height of the nodes being merged is one below the height // of the node of this edge, thus above zero, so they are internal. let mut left_node = left_node.cast_unchecked::(); - let mut right_node = right_node.cast_unchecked::(); + let right_node = right_node.cast_unchecked::(); ptr::copy_nonoverlapping( - right_node.as_internal().edges.as_ptr(), - left_node.as_internal_mut().edges.as_mut_ptr().add(left_len + 1), + right_node.edge_at(0), + left_node.edges_mut().as_mut_ptr().add(left_len + 1), right_len + 1, ); From 55fa8afe94019cb1da29d5fab7fd7ad5795b2c39 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Sun, 9 Aug 2020 12:25:20 +0200 Subject: [PATCH 0964/1052] BTreeMap: various tweaks --- library/alloc/src/collections/btree/node.rs | 111 +++++++++----------- 1 file changed, 50 insertions(+), 61 deletions(-) diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 3ce5dfbc4dc2a..c3f27c105994f 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -47,8 +47,7 @@ const KV_IDX_CENTER: usize = B - 1; const EDGE_IDX_LEFT_OF_CENTER: usize = B - 1; const EDGE_IDX_RIGHT_OF_CENTER: usize = B; -/// The underlying representation of leaf nodes. -#[repr(C)] +/// The underlying representation of leaf nodes and part of the representation of internal nodes. struct LeafNode { /// We want to be covariant in `K` and `V`. parent: Option>>, @@ -59,9 +58,6 @@ struct LeafNode { parent_idx: MaybeUninit, /// The number of keys and values this node stores. - /// - /// This next to `parent_idx` to encourage the compiler to join `len` and - /// `parent_idx` into the same 32-bit word, reducing space overhead. len: u16, /// The arrays storing the actual data of the node. Only the first `len` elements of each @@ -92,7 +88,9 @@ impl LeafNode { /// node, allowing code to act on leaf and internal nodes generically without having to even check /// which of the two a pointer is pointing at. This property is enabled by the use of `repr(C)`. #[repr(C)] +// gdb_providers.py uses this type name for introspection. struct InternalNode { + // gdb_providers.py uses this field name for introspection. data: LeafNode, /// The pointers to the children of this node. `len + 1` of these are considered @@ -183,9 +181,9 @@ impl Root { NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } } - /// Adds a new internal node with a single edge, pointing to the previous root, and make that - /// new node the root. This increases the height by 1 and is the opposite of - /// `pop_internal_level`. + /// 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, K, V, marker::Internal> { let mut new_node = Box::new(unsafe { InternalNode::new() }); new_node.edges[0].write(unsafe { BoxedNode::from_ptr(self.node.as_ptr()) }); @@ -322,7 +320,7 @@ impl NodeRef { NodeRef { height: self.height, node: self.node, _marker: PhantomData } } - /// Exposes the leaf "portion" of any leaf or internal node. + /// Exposes the leaf portion of any leaf or internal node. /// If the node is a leaf, this function simply opens up its data. /// If the node is an internal node, so not a leaf, it does have all the data a leaf has /// (header, keys and values), and this function exposes that. @@ -472,7 +470,7 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { NodeRef { height: self.height, node: self.node, _marker: PhantomData } } - /// Exposes the leaf "portion" of any leaf or internal node for writing. + /// Exposes the leaf portion of any leaf or internal node for writing. /// If the node is a leaf, this function simply opens up its data. /// If the node is an internal node, so not a leaf, it does have all the data a leaf has /// (header, keys and values), and this function exposes that. @@ -498,18 +496,38 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { unsafe { self.reborrow_mut().into_val_mut_at(idx) } } - fn keys_mut(&mut self) -> &mut [K] { + fn keys_mut(&mut self) -> &mut [K] + where + K: 'a, + V: 'a, + { // SAFETY: the caller will not be able to call further methods on self // until the key slice reference is dropped, as we have unique access // for the lifetime of the borrow. - unsafe { self.reborrow_mut().into_key_slice_mut() } + // SAFETY: The keys of a node must always be initialized up to length. + unsafe { + slice::from_raw_parts_mut( + MaybeUninit::slice_as_mut_ptr(&mut self.as_leaf_mut().keys), + self.len(), + ) + } } - fn vals_mut(&mut self) -> &mut [V] { + fn vals_mut(&mut self) -> &mut [V] + where + K: 'a, + V: 'a, + { // SAFETY: the caller will not be able to call further methods on self // until the value slice reference is dropped, as we have unique access // for the lifetime of the borrow. - unsafe { self.reborrow_mut().into_val_slice_mut() } + // SAFETY: The values of a node must always be initialized up to length. + unsafe { + slice::from_raw_parts_mut( + MaybeUninit::slice_as_mut_ptr(&mut self.as_leaf_mut().vals), + self.len(), + ) + } } } @@ -539,26 +557,6 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { } impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { - fn into_key_slice_mut(mut self) -> &'a mut [K] { - // SAFETY: The keys of a node must always be initialized up to length. - unsafe { - slice::from_raw_parts_mut( - MaybeUninit::slice_as_mut_ptr(&mut self.as_leaf_mut().keys), - self.len(), - ) - } - } - - fn into_val_slice_mut(mut self) -> &'a mut [V] { - // SAFETY: The values of a node must always be initialized up to length. - unsafe { - slice::from_raw_parts_mut( - MaybeUninit::slice_as_mut_ptr(&mut self.as_leaf_mut().vals), - self.len(), - ) - } - } - /// # Safety /// The node has more than `idx` initialized elements. unsafe fn into_key_mut_at(mut self, idx: usize) -> &'a mut K { @@ -610,8 +608,8 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Leaf> { } /// Adds a key/value pair to the beginning of the node. - pub fn push_front(&mut self, key: K, val: V) { - assert!(self.len() < CAPACITY); + fn push_front(&mut self, key: K, val: V) { + debug_assert!(self.len() < CAPACITY); unsafe { slice_insert(self.keys_mut(), 0, key); @@ -683,10 +681,9 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { /// Removes a key/value pair from the end of this node and returns the pair. /// If this is an internal node, also removes the edge that was to the right - /// of that pair and returns the orphaned node that this edge owned with its - /// parent erased. - pub fn pop(&mut self) -> (K, V, Option>) { - assert!(self.len() > 0); + /// of that pair and returns the orphaned node that this edge owned. + fn pop(&mut self) -> (K, V, Option>) { + debug_assert!(self.len() > 0); let idx = self.len() - 1; @@ -708,10 +705,11 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { } } - /// Removes a key/value pair from the beginning of this node. If this is an internal node, - /// also removes the edge that was to the left of that pair. - pub fn pop_front(&mut self) -> (K, V, Option>) { - assert!(self.len() > 0); + /// Removes a key/value pair from the beginning of this node and returns the pair. + /// If this is an internal node, also removes the edge that was to the left + /// of that pair and returns the orphaned node that this edge owned. + fn pop_front(&mut self) -> (K, V, Option>) { + debug_assert!(self.len() > 0); let old_len = self.len(); @@ -913,7 +911,6 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType> /// this edge. This method assumes that there is enough space in the node for the new /// pair to fit. fn leafy_insert_fit(&mut self, key: K, val: V) { - // Necessary for correctness, but in a private module debug_assert!(self.node.len() < CAPACITY); unsafe { @@ -951,18 +948,18 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, mark 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 val_ptr = match insertion { + let mut insertion_edge = match insertion { InsertionPlace::Left(insert_idx) => unsafe { - Handle::new_edge(left.reborrow_mut(), insert_idx).insert_fit(key, val) + Handle::new_edge(left.reborrow_mut(), insert_idx) }, InsertionPlace::Right(insert_idx) => unsafe { Handle::new_edge( right.node_as_mut().cast_unchecked::(), insert_idx, ) - .insert_fit(key, val) }, }; + let val_ptr = insertion_edge.insert_fit(key, val); (InsertResult::Split(SplitResult { left: left.forget_type(), k, v, right }), val_ptr) } } @@ -985,8 +982,6 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, /// between this edge and the key/value pair to the right of this edge. This method assumes /// that there is enough space in the node for the new pair to fit. fn insert_fit(&mut self, key: K, val: V, edge: Root) { - // Necessary for correctness, but in an internal module - debug_assert!(self.node.len() < CAPACITY); debug_assert!(edge.height == self.node.height - 1); unsafe { @@ -1136,12 +1131,12 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType> ptr::copy_nonoverlapping( self.node.key_at(self.idx + 1), - new_node.keys.as_mut_ptr() as *mut K, + MaybeUninit::slice_as_mut_ptr(&mut new_node.keys), new_len, ); ptr::copy_nonoverlapping( self.node.val_at(self.idx + 1), - new_node.vals.as_mut_ptr() as *mut V, + MaybeUninit::slice_as_mut_ptr(&mut new_node.vals), new_len, ); @@ -1376,9 +1371,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, move_edges(left, new_left_len + 1, right, 0, count); } (ForceResult::Leaf(_), ForceResult::Leaf(_)) => {} - _ => { - unreachable!(); - } + _ => unreachable!(), } } } @@ -1433,9 +1426,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, right.correct_childrens_parent_links(0..=new_right_len); } (ForceResult::Leaf(_), ForceResult::Leaf(_)) => {} - _ => { - unreachable!(); - } + _ => unreachable!(), } } } @@ -1568,9 +1559,7 @@ impl<'a, K, V> Handle, K, V, marker::LeafOrInternal>, ma move_edges(left, left_new_len + 1, right, 1, right_new_len); } (ForceResult::Leaf(_), ForceResult::Leaf(_)) => {} - _ => { - unreachable!(); - } + _ => unreachable!(), } } } From bfdb7903c924127e90afe8838410feb660ec4811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Fri, 25 Sep 2020 13:33:25 +0200 Subject: [PATCH 0965/1052] Link dynamic and static late_link_args before generic ones --- compiler/rustc_codegen_ssa/src/back/link.rs | 6 +++--- compiler/rustc_target/src/spec/windows_gnu_base.rs | 7 +------ 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index faeb727202cd6..87d539f748c6b 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1333,9 +1333,6 @@ fn add_late_link_args( crate_type: CrateType, codegen_results: &CodegenResults, ) { - if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) { - cmd.args(args); - } let any_dynamic_crate = crate_type == CrateType::Dylib || codegen_results.crate_info.dependency_formats.iter().any(|(ty, list)| { *ty == crate_type && list.iter().any(|&linkage| linkage == Linkage::Dynamic) @@ -1349,6 +1346,9 @@ fn add_late_link_args( cmd.args(args); } } + if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) { + cmd.args(args); + } } /// Add arbitrary "post-link" args defined by the target spec. diff --git a/compiler/rustc_target/src/spec/windows_gnu_base.rs b/compiler/rustc_target/src/spec/windows_gnu_base.rs index a864918655fb8..0234ff55f0118 100644 --- a/compiler/rustc_target/src/spec/windows_gnu_base.rs +++ b/compiler/rustc_target/src/spec/windows_gnu_base.rs @@ -23,6 +23,7 @@ pub fn opts() -> TargetOptions { "-lmsvcrt".to_string(), "-lmingwex".to_string(), "-lmingw32".to_string(), + "-lgcc".to_string(), // alas, mingw* libraries above depend on libgcc // mingw's msvcrt is a weird hybrid import library and static library. // And it seems that the linker fails to use import symbols from msvcrt // that are required from functions in msvcrt in certain cases. For example @@ -41,8 +42,6 @@ pub fn opts() -> TargetOptions { // the shared libgcc_s-dw2-1.dll. This is required to support // unwinding across DLL boundaries. "-lgcc_s".to_string(), - "-lgcc".to_string(), - "-lkernel32".to_string(), ]; late_link_args_dynamic.insert(LinkerFlavor::Gcc, dynamic_unwind_libs.clone()); late_link_args_dynamic.insert(LinkerFlavor::Lld(LldFlavor::Ld), dynamic_unwind_libs); @@ -54,10 +53,6 @@ pub fn opts() -> TargetOptions { // boundaries when unwinding across FFI boundaries. "-lgcc_eh".to_string(), "-l:libpthread.a".to_string(), - "-lgcc".to_string(), - // libpthread depends on libmsvcrt, so we need to link it *again*. - "-lmsvcrt".to_string(), - "-lkernel32".to_string(), ]; late_link_args_static.insert(LinkerFlavor::Gcc, static_unwind_libs.clone()); late_link_args_static.insert(LinkerFlavor::Lld(LldFlavor::Ld), static_unwind_libs); From bca8e07ef4048a7ca912d157156268f958369ef2 Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Thu, 19 Mar 2020 16:40:33 +0100 Subject: [PATCH 0966/1052] rust inline assembly lvi hardening test --- ...ortanix-unknown-sgx-lvi-inline-assembly.rs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs diff --git a/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs new file mode 100644 index 0000000000000..7e440169edbb1 --- /dev/null +++ b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs @@ -0,0 +1,41 @@ +// Test LVI load hardening on SGX inline assembly code + +// assembly-output: emit-asm +// compile-flags: --crate-type staticlib +// only-x86_64-fortanix-unknown-sgx + +#![feature(asm)] + +#[no_mangle] +pub extern fn get(ptr: *const u64) -> u64 { + let value : u64; + unsafe { + asm!(".start_inline_asm:", + "mov {}, [{}]", + ".end_inline_asm:", + out(reg) value, + in(reg) ptr); + } + value +} + +// CHECK: get +// CHECK: .start_inline_asm +// CHECK-NEXT: movq +// CHECK-NEXT: lfence +// CHECK-NEXT: .end_inline_asm + +#[no_mangle] +pub extern fn myret() { + unsafe { + asm!(".start_myret_inline_asm: + ret + .end_myret_inline_asm:"); + } +} + +// CHECK: myret +// CHECK: .start_myret_inline_asm +// CHECK-NEXT: shlq $0, (%rsp) +// CHECK-NEXT: lfence +// CHECK-NEXT: retq From 4d1d0c6bd7e9b5dda47691729fe15a49091d2e4d Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Fri, 20 Mar 2020 10:51:18 +0100 Subject: [PATCH 0967/1052] skeleton check module level assembly --- ...anix-unknown-sgx-lvi-module-level-assembly.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-module-level-assembly.rs diff --git a/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-module-level-assembly.rs b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-module-level-assembly.rs new file mode 100644 index 0000000000000..6b7e7b7767c60 --- /dev/null +++ b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-module-level-assembly.rs @@ -0,0 +1,16 @@ +// Test LVI load hardening on SGX module level assembly code + +// assembly-output: emit-asm +// compile-flags: --crate-type staticlib +// only-x86_64-fortanix-unknown-sgx + +#![feature(global_asm)] + +global_asm!(".start_module_asm: + movq (%rdi), %rax + retq + .end_module_asm:" ); + +// CHECK: .start_module_asm +// TODO add check, when module-level pass is corrected +// CHECK: .end_module_asm From 947d7238e0db03146d33d6b3354231d7e3384735 Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Wed, 25 Mar 2020 15:28:34 +0100 Subject: [PATCH 0968/1052] Adding checks for assembly files in libunwind --- .../x86_64-fortanix-unknown-sgx-lvi/Makefile | 17 +++++++++++++++++ .../x86_64-fortanix-unknown-sgx-lvi/enclave.rs | 5 +++++ .../jumpto.checks | 8 ++++++++ .../unw_getcontext.checks | 7 +++++++ 4 files changed, 37 insertions(+) create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave.rs create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/unw_getcontext.checks diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile new file mode 100644 index 0000000000000..b17f9a12a2938 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile @@ -0,0 +1,17 @@ +-include ../../run-make-fulldeps/tools.mk + +#only-x86_64-fortanix-unknown-sgx + +OBJDUMP="${S}/build/x86_64-unknown-linux-gnu/llvm/build/bin/llvm-objdump" +FILECHECK="${S}/build/x86_64-unknown-linux-gnu/llvm/build/bin/FileCheck" + +all: + $(RUSTC) --target ${TARGET} enclave.rs + + #TODO: re-enable check when newly compiled libunwind is used + #${OBJDUMP} --disassemble-symbols=unw_getcontext --demangle $(TMPDIR)/enclave > $(TMPDIR)/unw_getcontext.asm + #${FILECHECK} --input-file $(TMPDIR)/unw_getcontext.asm unw_getcontext.checks + + #TODO: re-enable check when newly compiled libunwind is used + ${OBJDUMP} --disassemble-symbols="libunwind::Registers_x86_64::jumpto()" --demangle $(TMPDIR)/enclave > $(TMPDIR)/jumpto.asm + ${FILECHECK} --input-file $(TMPDIR)/jumpto.asm jumpto.checks diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave.rs b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave.rs new file mode 100644 index 0000000000000..66c8ead3e0ff4 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave.rs @@ -0,0 +1,5 @@ + +pub fn main() { + println!("Hello, World!"); +} + diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks new file mode 100644 index 0000000000000..15211e3ade795 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks @@ -0,0 +1,8 @@ +CHECK: libunwind::Registers_x86_64::jumpto +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: shlq $0, (%rsp) +CHECK-NEXT: lfence +CHECK-NEXT: retq diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/unw_getcontext.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/unw_getcontext.checks new file mode 100644 index 0000000000000..50b828662e350 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/unw_getcontext.checks @@ -0,0 +1,7 @@ +CHECK: unw_getcontext +CHECK: lfence +CHECK: lfence +CHECK: notq (%rsp) +CHECK-NEXT: notq (%rsp) +CHECK-NEXT: lfence +CHECK-NEXT: retq From 6db05904f6e64714537b37a6ca82010aa6cb46d0 Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Thu, 26 Mar 2020 10:51:14 +0100 Subject: [PATCH 0969/1052] LVI test std lib --- .../x86_64-fortanix-unknown-sgx-lvi/Makefile | 28 ++++++++----- .../enclave.rs | 5 --- .../enclave/Cargo.toml | 9 ++++ .../enclave/src/main.rs | 3 ++ .../print.checks | 7 ++++ .../x86_64-fortanix-unknown-sgx-lvi/script.sh | 42 +++++++++++++++++++ 6 files changed, 78 insertions(+), 16 deletions(-) delete mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave.rs create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/Cargo.toml create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/print.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile index b17f9a12a2938..6a04d34391035 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile @@ -2,16 +2,22 @@ #only-x86_64-fortanix-unknown-sgx -OBJDUMP="${S}/build/x86_64-unknown-linux-gnu/llvm/build/bin/llvm-objdump" -FILECHECK="${S}/build/x86_64-unknown-linux-gnu/llvm/build/bin/FileCheck" +# For cargo setting +export RUSTC := $(RUSTC_ORIGINAL) +export LD_LIBRARY_PATH := $(HOST_RPATH_DIR) +# We need to be outside of 'src' dir in order to run cargo +export WORK_DIR := $(TMPDIR) +export TEST_DIR := $(shell pwd) -all: - $(RUSTC) --target ${TARGET} enclave.rs - - #TODO: re-enable check when newly compiled libunwind is used - #${OBJDUMP} --disassemble-symbols=unw_getcontext --demangle $(TMPDIR)/enclave > $(TMPDIR)/unw_getcontext.asm - #${FILECHECK} --input-file $(TMPDIR)/unw_getcontext.asm unw_getcontext.checks +## clean up unused env variables which might cause harm. +unexport RUSTC_LINKER +unexport RUSTC_BOOTSTRAP +unexport RUST_BUILD_STAGE +unexport RUST_TEST_THREADS +unexport RUST_TEST_TMPDIR +unexport AR +unexport CC +unexport CXX - #TODO: re-enable check when newly compiled libunwind is used - ${OBJDUMP} --disassemble-symbols="libunwind::Registers_x86_64::jumpto()" --demangle $(TMPDIR)/enclave > $(TMPDIR)/jumpto.asm - ${FILECHECK} --input-file $(TMPDIR)/jumpto.asm jumpto.checks +all: + bash script.sh diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave.rs b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave.rs deleted file mode 100644 index 66c8ead3e0ff4..0000000000000 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave.rs +++ /dev/null @@ -1,5 +0,0 @@ - -pub fn main() { - println!("Hello, World!"); -} - diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/Cargo.toml b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/Cargo.toml new file mode 100644 index 0000000000000..723cd7c3cc232 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "enclave" +version = "0.1.0" +authors = ["Raoul Strackx "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs new file mode 100644 index 0000000000000..e7a11a969c037 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/print.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/print.checks new file mode 100644 index 0000000000000..0fe88141b2473 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/print.checks @@ -0,0 +1,7 @@ +CHECK: print +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: popq +CHECK: callq 0x{{[[:xdigit:]]*}} <_Unwind_Resume> +CHECK-NEXT: ud2 diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh new file mode 100644 index 0000000000000..98e5284aadcbe --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh @@ -0,0 +1,42 @@ +set -exuo pipefail + +function build { + CRATE=enclave + + mkdir -p $WORK_DIR + pushd $WORK_DIR + rm -rf $CRATE + cp -a $TEST_DIR/enclave . + pushd $CRATE + echo ${WORK_DIR} + # HACK(eddyb) sets `RUSTC_BOOTSTRAP=1` so Cargo can accept nightly features. + # These come from the top-level Rust workspace, that this crate is not a + # member of, but Cargo tries to load the workspace `Cargo.toml` anyway. + env RUSTC_BOOTSTRAP=1 \ + cargo -v run --target $TARGET + env RUSTC_BOOTSTRAP=1 \ + cargo -v run --target $TARGET --release + popd + popd +} + +function check { + local func=$1 + local checks="${TEST_DIR}/$2" + local asm=$(mktemp) + local objdump="${BUILD_DIR}/x86_64-unknown-linux-gnu/llvm/build/bin/llvm-objdump" + local filecheck="${BUILD_DIR}/x86_64-unknown-linux-gnu/llvm/build/bin/FileCheck" + + ${objdump} --disassemble-symbols=${func} --demangle ${WORK_DIR}/enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave > ${asm} + ${filecheck} --input-file ${asm} ${checks} +} + +build + +#TODO: re-enable check when newly compiled libunwind is used +#check unw_getcontext unw_getcontext.checks + +#TODO: re-enable check when newly compiled libunwind is used +#check "libunwind::Registers_x86_64::jumpto()" jumpto.checks + +check "std::io::stdio::_print::h87f0c238421c45bc" print.checks From 0526e750cd4e88fbb24ea92e809dfb6eefbf8fa0 Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Thu, 26 Mar 2020 13:57:37 +0100 Subject: [PATCH 0970/1052] started using cc crate --- .../cc_plus_one_c.checks | 6 ++++++ .../x86_64-fortanix-unknown-sgx-lvi/enclave/Cargo.toml | 3 +++ .../x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs | 5 +++++ .../x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c | 4 ++++ .../enclave/src/main.rs | 10 +++++++++- .../run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh | 5 ++--- 6 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c.checks new file mode 100644 index 0000000000000..b93b33afb3fc4 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c.checks @@ -0,0 +1,6 @@ +CHECK: cc_plus_one_c +CHECK: lfence +CHECK: popq +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] +CHECK-NEXT: lfence +CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/Cargo.toml b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/Cargo.toml index 723cd7c3cc232..da1b1e7f06c58 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/Cargo.toml +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/Cargo.toml @@ -7,3 +7,6 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] + +[build-dependencies] +cc = "1.0" diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs new file mode 100644 index 0000000000000..3ccb4100ceb98 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs @@ -0,0 +1,5 @@ +fn main() { + cc::Build::new() + .file("foo.c") + .compile("foo"); +} diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c new file mode 100644 index 0000000000000..bfe7757e4c1fe --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c @@ -0,0 +1,4 @@ + +int cc_plus_one_c(int *arg) { + return *arg + 1; +} diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs index e7a11a969c037..25adef5f91714 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs @@ -1,3 +1,11 @@ +extern { + fn cc_plus_one_c(arg : &u32) -> u32; +} + fn main() { - println!("Hello, world!"); + let value : u32 = 41; + + unsafe{ + println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cc_plus_one_c(&value)); + } } diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh index 98e5284aadcbe..ae95dd9dac0ee 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh @@ -12,10 +12,8 @@ function build { # HACK(eddyb) sets `RUSTC_BOOTSTRAP=1` so Cargo can accept nightly features. # These come from the top-level Rust workspace, that this crate is not a # member of, but Cargo tries to load the workspace `Cargo.toml` anyway. - env RUSTC_BOOTSTRAP=1 \ + env RUSTC_BOOTSTRAP=1 cargo -v run --target $TARGET - env RUSTC_BOOTSTRAP=1 \ - cargo -v run --target $TARGET --release popd popd } @@ -40,3 +38,4 @@ build #check "libunwind::Registers_x86_64::jumpto()" jumpto.checks check "std::io::stdio::_print::h87f0c238421c45bc" print.checks +check cc_plus_one_c cc_plus_one_c.checks From bdf81f508d0b79751063b93f4d151ec6a90d2a09 Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Thu, 26 Mar 2020 15:05:43 +0100 Subject: [PATCH 0971/1052] test hardening C inline assembly code (cc crate) --- .../cc_plus_one_c_asm.checks | 15 +++++++++++++++ .../enclave/build.rs | 2 +- .../x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c | 14 ++++++++++++++ .../enclave/src/main.rs | 2 ++ .../x86_64-fortanix-unknown-sgx-lvi/script.sh | 1 + 5 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c_asm.checks diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c_asm.checks new file mode 100644 index 0000000000000..d1fae3d495fb1 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c_asm.checks @@ -0,0 +1,15 @@ +CHECK: cc_plus_one_c_asm +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK-NEXT: incl +CHECK-NEXT: jmp +CHECK-NEXT: shlq $0, (%rsp) +CHECK-NEXT: lfence +CHECK-NEXT: retq +CHECK: popq +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] +CHECK-NEXT: lfence +CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs index 3ccb4100ceb98..b0d0b42a30d15 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs @@ -1,5 +1,5 @@ fn main() { cc::Build::new() .file("foo.c") - .compile("foo"); + .compile("foo_c"); } diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c index bfe7757e4c1fe..971dfa9d171dd 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c @@ -2,3 +2,17 @@ int cc_plus_one_c(int *arg) { return *arg + 1; } + +int cc_plus_one_c_asm(int *arg) { + int value = 0; + + asm volatile ( " movl (%1), %0\n" + " inc %0\n" + " jmp 1f\n" + " retq\n" // never executed, but a shortcut to determine how the assembler deals with `ret` instructions + "1:\n" + : "=r"(value) + : "r"(arg) ); + + return value; +} diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs index 25adef5f91714..f8a27255ed081 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs @@ -1,5 +1,6 @@ extern { fn cc_plus_one_c(arg : &u32) -> u32; + fn cc_plus_one_c_asm(arg : &u32) -> u32; } fn main() { @@ -7,5 +8,6 @@ fn main() { unsafe{ println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cc_plus_one_c(&value)); + println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cc_plus_one_c_asm(&value)); } } diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh index ae95dd9dac0ee..91f7ee45b5492 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh @@ -39,3 +39,4 @@ build check "std::io::stdio::_print::h87f0c238421c45bc" print.checks check cc_plus_one_c cc_plus_one_c.checks +check cc_plus_one_c_asm cc_plus_one_c_asm.checks From 64811ed5a590ef4c89c09f4d04d3cea11251da52 Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Fri, 27 Mar 2020 11:24:17 +0100 Subject: [PATCH 0972/1052] testing c++ code (cc crate) --- .../cc_plus_one_cxx.checks | 6 ++++++ .../cc_plus_one_cxx_asm.checks | 16 +++++++++++++++ .../enclave/build.rs | 6 ++++++ .../enclave/foo_cxx.cpp | 20 +++++++++++++++++++ .../enclave/src/main.rs | 4 ++++ .../x86_64-fortanix-unknown-sgx-lvi/script.sh | 3 +++ 6 files changed, 55 insertions(+) create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx_asm.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_cxx.cpp diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx.checks new file mode 100644 index 0000000000000..f96f152c02fcc --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx.checks @@ -0,0 +1,6 @@ +CHECK: cc_plus_one_cxx +CHECK: lfence +CHECK: popq +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] +CHECK-NEXT: lfence +CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx_asm.checks new file mode 100644 index 0000000000000..e704bf4172434 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx_asm.checks @@ -0,0 +1,16 @@ +CHECK: cc_plus_one_cxx_asm +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: movl +CHECK: lfence +CHECK: lfence +CHECK-NEXT: incl +CHECK-NEXT: jmp 0x{{[[:xdigit:]]+}} +CHECK-NEXT: shlq $0, (%rsp) +CHECK-NEXT: lfence +CHECK-NEXT: retq +CHECK: popq +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] +CHECK-NEXT: lfence +CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs index b0d0b42a30d15..66ddea3793aa8 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs @@ -2,4 +2,10 @@ fn main() { cc::Build::new() .file("foo.c") .compile("foo_c"); + + cc::Build::new() + .cpp(true) + .cpp_set_stdlib(None) + .file("foo_cxx.cpp") + .compile("foo_cxx"); } diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_cxx.cpp b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_cxx.cpp new file mode 100644 index 0000000000000..1f22c85c4cdb5 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_cxx.cpp @@ -0,0 +1,20 @@ +extern "C" int cc_plus_one_cxx(int *arg); +extern "C" int cc_plus_one_cxx_asm(int *arg); + +int cc_plus_one_cxx(int *arg) { + return *arg + 1; +} + +int cc_plus_one_cxx_asm(int *arg) { + int value = 0; + + asm volatile ( " movl (%1), %0\n" + " inc %0\n" + " jmp 1f\n" + " retq\n" // never executed, but a shortcut to determine how the assembler deals with `ret` instructions + "1:\n" + : "=r"(value) + : "r"(arg) ); + + return value; +} diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs index f8a27255ed081..afbee78e3450d 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs @@ -1,6 +1,8 @@ extern { fn cc_plus_one_c(arg : &u32) -> u32; fn cc_plus_one_c_asm(arg : &u32) -> u32; + fn cc_plus_one_cxx(arg : &u32) -> u32; + fn cc_plus_one_cxx_asm(arg : &u32) -> u32; } fn main() { @@ -9,5 +11,7 @@ fn main() { unsafe{ println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cc_plus_one_c(&value)); println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cc_plus_one_c_asm(&value)); + println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cc_plus_one_cxx(&value)); + println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cc_plus_one_cxx_asm(&value)); } } diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh index 91f7ee45b5492..be2d247de0bd5 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh @@ -9,6 +9,7 @@ function build { cp -a $TEST_DIR/enclave . pushd $CRATE echo ${WORK_DIR} + hardening_flags="-mlvi-hardening -mllvm -x86-lvi-load-inline-asm" # HACK(eddyb) sets `RUSTC_BOOTSTRAP=1` so Cargo can accept nightly features. # These come from the top-level Rust workspace, that this crate is not a # member of, but Cargo tries to load the workspace `Cargo.toml` anyway. @@ -40,3 +41,5 @@ build check "std::io::stdio::_print::h87f0c238421c45bc" print.checks check cc_plus_one_c cc_plus_one_c.checks check cc_plus_one_c_asm cc_plus_one_c_asm.checks +check cc_plus_one_cxx cc_plus_one_cxx.checks +check cc_plus_one_cxx_asm cc_plus_one_cxx_asm.checks From d8a7904e06e77baf137b6713f9bf79f74ae6edfe Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Fri, 27 Mar 2020 14:19:07 +0100 Subject: [PATCH 0973/1052] LVI hardening tests for cmake --- .../cmake_plus_one_c.checks | 6 ++++++ .../cmake_plus_one_c_asm.checks | 16 +++++++++++++++ .../cmake_plus_one_cxx.checks | 6 ++++++ .../cmake_plus_one_cxx_asm.checks | 16 +++++++++++++++ .../enclave/Cargo.toml | 1 + .../enclave/build.rs | 15 ++++++++++++++ .../enclave/libcmake_foo/CMakeLists.txt | 4 ++++ .../enclave/libcmake_foo/src/foo.c | 17 ++++++++++++++++ .../enclave/libcmake_foo/src/foo_cxx.cpp | 20 +++++++++++++++++++ .../enclave/src/main.rs | 9 +++++++++ .../x86_64-fortanix-unknown-sgx-lvi/script.sh | 10 ++++++++++ 11 files changed, 120 insertions(+) create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_asm.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_asm.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/CMakeLists.txt create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo.c create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_cxx.cpp diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c.checks new file mode 100644 index 0000000000000..f551356b2ff81 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c.checks @@ -0,0 +1,6 @@ +CHECK: cmake_plus_one_c +CHECK: lfence +CHECK: popq +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] +CHECK-NEXT: lfence +CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_asm.checks new file mode 100644 index 0000000000000..87c806f137a94 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_asm.checks @@ -0,0 +1,16 @@ +CHECK: cmake_plus_one_c_asm +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: movl +CHECK: lfence +CHECK-NEXT: incl +CHECK-NEXT: jmp 0x{{[[:xdigit:]]+}} +CHECK-NEXT: shlq $0, (%rsp) +CHECK-NEXT: lfence +CHECK-NEXT: retq +CHECK: popq +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] +CHECK-NEXT: lfence +CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx.checks new file mode 100644 index 0000000000000..0f403e0203c12 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx.checks @@ -0,0 +1,6 @@ +CHECK: cmake_plus_one_cxx +CHECK: lfence +CHECK: popq +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] +CHECK-NEXT: lfence +CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_asm.checks new file mode 100644 index 0000000000000..9cac8711ea84b --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_asm.checks @@ -0,0 +1,16 @@ +CHECK: cmake_plus_one_cxx_asm +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: movl +CHECK: lfence +CHECK-NEXT: incl +CHECK-NEXT: jmp 0x{{[[:xdigit:]]+}} +CHECK-NEXT: shlq $0, (%rsp) +CHECK-NEXT: lfence +CHECK-NEXT: retq +CHECK: popq +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] +CHECK-NEXT: lfence +CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/Cargo.toml b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/Cargo.toml index da1b1e7f06c58..89490686584d5 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/Cargo.toml +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/Cargo.toml @@ -10,3 +10,4 @@ edition = "2018" [build-dependencies] cc = "1.0" +cmake = "0.1" diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs index 66ddea3793aa8..eff25e8641b79 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs @@ -8,4 +8,19 @@ fn main() { .cpp_set_stdlib(None) .file("foo_cxx.cpp") .compile("foo_cxx"); + + // When the cmake crate detects the clang compiler, it passes the + // "--target" argument to the linker which subsequently fails. The + // `CMAKE_C_COMPILER_FORCED` option makes sure that `cmake` does not + // tries to test the compiler. From version 3.6 the option + // `CMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY` can be used + // https://cmake.org/cmake/help/v3.5/module/CMakeForceCompiler.html + let dst = cmake::Config::new("libcmake_foo") + .build_target("cmake_foo") + .define("CMAKE_C_COMPILER_FORCED", "1") + .define("CMAKE_CXX_COMPILER_FORCED", "1") + .define("CMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY", "1") + .build(); + println!("cargo:rustc-link-search=native={}/build/", dst.display()); + println!("cargo:rustc-link-lib=static=cmake_foo"); } diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/CMakeLists.txt b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/CMakeLists.txt new file mode 100644 index 0000000000000..f501fe6f7dde4 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/CMakeLists.txt @@ -0,0 +1,4 @@ +add_library(cmake_foo STATIC + src/foo.c + src/foo_cxx.cpp +) diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo.c b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo.c new file mode 100644 index 0000000000000..cbfde6ce92994 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo.c @@ -0,0 +1,17 @@ +int cmake_plus_one_c(int *arg) { + return *arg + 1; +} + +int cmake_plus_one_c_asm(int *arg) { + int value = 0; + + asm volatile ( " movl (%1), %0\n" + " inc %0\n" + " jmp 1f\n" + " retq\n" // never executed, but a shortcut to determine how the assembler deals with `ret` instructions + "1:\n" + : "=r"(value) + : "r"(arg) ); + + return value; +} diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_cxx.cpp b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_cxx.cpp new file mode 100644 index 0000000000000..63a89111c119a --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_cxx.cpp @@ -0,0 +1,20 @@ +extern "C" int cmake_plus_one_cxx(int *arg); +extern "C" int cmake_plus_one_cxx_asm(int *arg); + +int cmake_plus_one_cxx(int *arg) { + return *arg + 1; +} + +int cmake_plus_one_cxx_asm(int *arg) { + int value = 0; + + asm volatile ( " movl (%1), %0\n" + " inc %0\n" + " jmp 1f\n" + " retq\n" // never executed, but a shortcut to determine how the assembler deals with `ret` instructions + "1:\n" + : "=r"(value) + : "r"(arg) ); + + return value; +} diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs index afbee78e3450d..358547c13621d 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs @@ -3,6 +3,10 @@ extern { fn cc_plus_one_c_asm(arg : &u32) -> u32; fn cc_plus_one_cxx(arg : &u32) -> u32; fn cc_plus_one_cxx_asm(arg : &u32) -> u32; + fn cmake_plus_one_c(arg : &u32) -> u32; + fn cmake_plus_one_c_asm(arg : &u32) -> u32; + fn cmake_plus_one_cxx(arg : &u32) -> u32; + fn cmake_plus_one_cxx_asm(arg : &u32) -> u32; } fn main() { @@ -13,5 +17,10 @@ fn main() { println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cc_plus_one_c_asm(&value)); println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cc_plus_one_cxx(&value)); println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cc_plus_one_cxx_asm(&value)); + + println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cmake_plus_one_c(&value)); + println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cmake_plus_one_c_asm(&value)); + println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cmake_plus_one_cxx(&value)); + println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cmake_plus_one_cxx_asm(&value)); } } diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh index be2d247de0bd5..1595dbbbb9f2b 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh @@ -39,7 +39,17 @@ build #check "libunwind::Registers_x86_64::jumpto()" jumpto.checks check "std::io::stdio::_print::h87f0c238421c45bc" print.checks +#TODO: the current passes cannot handle module level assembly! +# No checks are implemented check cc_plus_one_c cc_plus_one_c.checks check cc_plus_one_c_asm cc_plus_one_c_asm.checks check cc_plus_one_cxx cc_plus_one_cxx.checks check cc_plus_one_cxx_asm cc_plus_one_cxx_asm.checks + +check cmake_plus_one_c cmake_plus_one_c.checks +check cmake_plus_one_c_asm cmake_plus_one_c_asm.checks +check cmake_plus_one_cxx cmake_plus_one_cxx.checks +check cmake_plus_one_cxx_asm cmake_plus_one_cxx_asm.checks + +#WARNING clang/clang++ use an integrated assembler when given an assembly file. +# LVI patches are *not* applied From 72a8e6b1931cac7e1c716688501c324cb77c9d09 Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Fri, 27 Mar 2020 15:48:10 +0100 Subject: [PATCH 0974/1052] Adding checks for module level assembly --- .../cc_plus_one_asm.checks | 8 +++++ .../cmake_plus_one_asm.checks | 7 ++++ .../cmake_plus_one_c_global_asm.checks | 2 ++ .../cmake_plus_one_cxx_global_asm.checks | 2 ++ .../enclave/build.rs | 4 +++ .../enclave/foo_asm.s | 7 ++++ .../enclave/libcmake_foo/CMakeLists.txt | 33 +++++++++++++++++-- .../enclave/libcmake_foo/src/foo.c | 8 +++++ .../enclave/libcmake_foo/src/foo_asm.s | 7 ++++ .../enclave/libcmake_foo/src/foo_cxx.cpp | 8 +++++ .../enclave/src/main.rs | 23 ++++++++++++- .../rust_plus_one_global_asm.checks | 2 ++ .../x86_64-fortanix-unknown-sgx-lvi/script.sh | 13 ++++---- 13 files changed, 115 insertions(+), 9 deletions(-) create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_asm.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_global_asm.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_global_asm.checks create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_asm.s create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_asm.s create mode 100644 src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/rust_plus_one_global_asm.checks diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks new file mode 100644 index 0000000000000..e839c200bbb96 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks @@ -0,0 +1,8 @@ +CHECK: cc_plus_one_asm +CHECK-NEXT: movl +CHECK-NEXT: lfence +CHECK-NEXT: inc +CHECK-NEXT: notq (%rsp) +CHECK-NEXT: notq (%rsp) +CHECK-NEXT: lfence +CHECK-NEXT: retq diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_asm.checks new file mode 100644 index 0000000000000..78b18ccbfcb31 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_asm.checks @@ -0,0 +1,7 @@ +CHECK: cmake_plus_one_asm +CHECK-NEXT: movl +CHECK-NEXT: lfence +CHECK-NEXT: incl +CHECK-NEXT: shlq $0, (%rsp) +CHECK-NEXT: lfence +CHECK-NEXT: retq diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_global_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_global_asm.checks new file mode 100644 index 0000000000000..4b66cc5bc83b5 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_global_asm.checks @@ -0,0 +1,2 @@ +CHECK: cmake_plus_one_c_global_asm +CHECK: lfence diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_global_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_global_asm.checks new file mode 100644 index 0000000000000..d4a3d4479014c --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_global_asm.checks @@ -0,0 +1,2 @@ +CHECK: cmake_plus_one_cxx_global_asm +CHECK: lfence diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs index eff25e8641b79..3a7aa1be868c9 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs @@ -3,6 +3,10 @@ fn main() { .file("foo.c") .compile("foo_c"); + cc::Build::new() + .file("foo_asm.s") + .compile("foo_asm"); + cc::Build::new() .cpp(true) .cpp_set_stdlib(None) diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_asm.s b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_asm.s new file mode 100644 index 0000000000000..6d56214e87ed9 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_asm.s @@ -0,0 +1,7 @@ + .text + .global cc_plus_one_asm + .type cc_plus_one_asm, @function +cc_plus_one_asm: + movl (%rdi), %eax + inc %eax + retq diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/CMakeLists.txt b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/CMakeLists.txt index f501fe6f7dde4..27cdf2ecf826d 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/CMakeLists.txt +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/CMakeLists.txt @@ -1,4 +1,33 @@ -add_library(cmake_foo STATIC +enable_language(C CXX ASM) + +set(C_SOURCES src/foo.c + ) + +set_source_files_properties(${C_SOURCES} + PROPERTIES + LANGUAGE C) + +set(CXX_SOURCES src/foo_cxx.cpp -) + ) + +set_source_files_properties(${CXX_SOURCES} + PROPERTIES + LANGUAGE CXX) + +set(ASM_SOURCES + src/foo_asm.s + ) + +set_source_files_properties(${ASM_SOURCES} + PROPERTIES + LANGUAGE ASM) + +set(SOURCES + ${C_SOURCES} + ${CXX_SOURCES} + ${ASM_SOURCES}) + +add_library(cmake_foo STATIC + ${SOURCES}) diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo.c b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo.c index cbfde6ce92994..e3a8fcdf414ac 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo.c +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo.c @@ -15,3 +15,11 @@ int cmake_plus_one_c_asm(int *arg) { return value; } + +asm(".text\n" +" .global cmake_plus_one_c_global_asm\n" +" .type cmake_plus_one_c_global_asm, @function\n" +"cmake_plus_one_c_global_asm:\n" +" movl (%rdi), %eax\n" +" inc %eax\n" +" retq\n" ); diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_asm.s b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_asm.s new file mode 100644 index 0000000000000..64b6b430eeaa1 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_asm.s @@ -0,0 +1,7 @@ + .text + .global cmake_plus_one_asm + .type cmake_plus_one_asm, @function +cmake_plus_one_asm: + movl (%rdi), %eax + inc %eax + retq diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_cxx.cpp b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_cxx.cpp index 63a89111c119a..a1a7b29d8c17b 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_cxx.cpp +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_cxx.cpp @@ -18,3 +18,11 @@ int cmake_plus_one_cxx_asm(int *arg) { return value; } + +asm(".text\n" +" .global cmake_plus_one_cxx_global_asm\n" +" .type cmake_plus_one_cxx_global_asm, @function\n" +"cmake_plus_one_cxx_global_asm:\n" +" movl (%rdi), %eax\n" +" inc %eax\n" +" retq\n" ); diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs index 358547c13621d..697ab29a59c9a 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs @@ -1,26 +1,47 @@ +#![feature(global_asm)] + +global_asm!( r#" + .text + .global rust_plus_one_global_asm + .type rust_plus_one_global_asm, @function +rust_plus_one_global_asm: + movl (%rdi), %eax + inc %eax + retq +"# ); + extern { fn cc_plus_one_c(arg : &u32) -> u32; fn cc_plus_one_c_asm(arg : &u32) -> u32; fn cc_plus_one_cxx(arg : &u32) -> u32; fn cc_plus_one_cxx_asm(arg : &u32) -> u32; + fn cc_plus_one_asm(arg : &u32) -> u32; fn cmake_plus_one_c(arg : &u32) -> u32; fn cmake_plus_one_c_asm(arg : &u32) -> u32; fn cmake_plus_one_cxx(arg : &u32) -> u32; fn cmake_plus_one_cxx_asm(arg : &u32) -> u32; + fn cmake_plus_one_c_global_asm(arg : &u32) -> u32; + fn cmake_plus_one_cxx_global_asm(arg : &u32) -> u32; + fn cmake_plus_one_asm(arg : &u32) -> u32; + fn rust_plus_one_global_asm(arg : &u32) -> u32; } fn main() { let value : u32 = 41; unsafe{ + println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", rust_plus_one_global_asm(&value)); println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cc_plus_one_c(&value)); println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cc_plus_one_c_asm(&value)); println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cc_plus_one_cxx(&value)); println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cc_plus_one_cxx_asm(&value)); - + println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cc_plus_one_asm(&value)); println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cmake_plus_one_c(&value)); println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cmake_plus_one_c_asm(&value)); println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cmake_plus_one_cxx(&value)); println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cmake_plus_one_cxx_asm(&value)); + println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cmake_plus_one_c_global_asm(&value)); + println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cmake_plus_one_cxx_global_asm(&value)); + println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cmake_plus_one_asm(&value)); } } diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/rust_plus_one_global_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/rust_plus_one_global_asm.checks new file mode 100644 index 0000000000000..fe6777537fb80 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/rust_plus_one_global_asm.checks @@ -0,0 +1,2 @@ +CHECK: rust_plus_one_global_asm +CHECK: lfence diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh index 1595dbbbb9f2b..9f151b34c9178 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh @@ -9,7 +9,6 @@ function build { cp -a $TEST_DIR/enclave . pushd $CRATE echo ${WORK_DIR} - hardening_flags="-mlvi-hardening -mllvm -x86-lvi-load-inline-asm" # HACK(eddyb) sets `RUSTC_BOOTSTRAP=1` so Cargo can accept nightly features. # These come from the top-level Rust workspace, that this crate is not a # member of, but Cargo tries to load the workspace `Cargo.toml` anyway. @@ -39,17 +38,19 @@ build #check "libunwind::Registers_x86_64::jumpto()" jumpto.checks check "std::io::stdio::_print::h87f0c238421c45bc" print.checks -#TODO: the current passes cannot handle module level assembly! -# No checks are implemented +check rust_plus_one_global_asm rust_plus_one_global_asm.checks || echo "warning: module level assembly currently not hardened" + check cc_plus_one_c cc_plus_one_c.checks check cc_plus_one_c_asm cc_plus_one_c_asm.checks check cc_plus_one_cxx cc_plus_one_cxx.checks check cc_plus_one_cxx_asm cc_plus_one_cxx_asm.checks +check cc_plus_one_asm cc_plus_one_asm.checks || echo "warning: the cc crate forwards assembly files to the CC compiler.\ + Clang uses its own intergrated assembler, which does not include the LVI passes." check cmake_plus_one_c cmake_plus_one_c.checks check cmake_plus_one_c_asm cmake_plus_one_c_asm.checks +check cmake_plus_one_c_global_asm cmake_plus_one_c_global_asm.checks || echo "warning: module level assembly currently not hardened" check cmake_plus_one_cxx cmake_plus_one_cxx.checks check cmake_plus_one_cxx_asm cmake_plus_one_cxx_asm.checks - -#WARNING clang/clang++ use an integrated assembler when given an assembly file. -# LVI patches are *not* applied +check cmake_plus_one_cxx_global_asm cmake_plus_one_cxx_global_asm.checks || echo "warning: module level assembly currently not hardened" +check cmake_plus_one_asm cmake_plus_one_asm.checks From 8ca26cca2919977cba79e7436c4f72fb6661ea9b Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Fri, 27 Mar 2020 16:46:52 +0100 Subject: [PATCH 0975/1052] Building libunwind with new CMakeLists. The old CMakeLists file of libunwind used the C compiler to compile assembly files. This caused such code not to be hardened. --- ...6_64-fortanix-unknown-sgx-lvi-module-level-assembly.rs | 4 ---- .../run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh | 8 ++------ .../x86_64-fortanix-unknown-sgx-lvi/unw_getcontext.checks | 3 +-- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-module-level-assembly.rs b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-module-level-assembly.rs index 6b7e7b7767c60..b8dc747d3b4cb 100644 --- a/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-module-level-assembly.rs +++ b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-module-level-assembly.rs @@ -10,7 +10,3 @@ global_asm!(".start_module_asm: movq (%rdi), %rax retq .end_module_asm:" ); - -// CHECK: .start_module_asm -// TODO add check, when module-level pass is corrected -// CHECK: .end_module_asm diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh index 9f151b34c9178..ee6dc33feae6f 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh @@ -31,12 +31,8 @@ function check { build -#TODO: re-enable check when newly compiled libunwind is used -#check unw_getcontext unw_getcontext.checks - -#TODO: re-enable check when newly compiled libunwind is used -#check "libunwind::Registers_x86_64::jumpto()" jumpto.checks - +check unw_getcontext unw_getcontext.checks +check "libunwind::Registers_x86_64::jumpto()" jumpto.checks check "std::io::stdio::_print::h87f0c238421c45bc" print.checks check rust_plus_one_global_asm rust_plus_one_global_asm.checks || echo "warning: module level assembly currently not hardened" diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/unw_getcontext.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/unw_getcontext.checks index 50b828662e350..4b7615b115dc4 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/unw_getcontext.checks +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/unw_getcontext.checks @@ -1,7 +1,6 @@ CHECK: unw_getcontext CHECK: lfence CHECK: lfence -CHECK: notq (%rsp) -CHECK-NEXT: notq (%rsp) +CHECK: shlq $0, (%rsp) CHECK-NEXT: lfence CHECK-NEXT: retq From 7d3c3fdc1d57d555c726f1caa444e9dd5a02e142 Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Fri, 25 Sep 2020 15:13:55 +0200 Subject: [PATCH 0976/1052] cleaning up code --- ...4-fortanix-unknown-sgx-lvi-generic-load.rs | 1 - ...64-fortanix-unknown-sgx-lvi-generic-ret.rs | 1 - ...x-unknown-sgx-lvi-module-level-assembly.rs | 12 -------- .../enclave/foo.c | 4 +-- .../enclave/foo_cxx.cpp | 3 +- .../enclave/libcmake_foo/src/foo.c | 3 +- .../enclave/libcmake_foo/src/foo_cxx.cpp | 3 +- .../enclave/src/main.rs | 29 ++++++++++--------- .../x86_64-fortanix-unknown-sgx-lvi/script.sh | 19 +++++++----- 9 files changed, 35 insertions(+), 40 deletions(-) delete mode 100644 src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-module-level-assembly.rs diff --git a/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs index 87ebb71dce9a3..79d82cf70d381 100644 --- a/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs +++ b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs @@ -15,4 +15,3 @@ pub extern fn plus_one(r: &mut u64) { // CHECK: popq [[REGISTER:%[a-z]+]] // CHECK-NEXT: lfence // CHECK-NEXT: jmpq *[[REGISTER]] - diff --git a/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs index 5ca5dd6f27282..a21ef6b75894e 100644 --- a/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs +++ b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs @@ -10,4 +10,3 @@ pub extern fn myret() {} // CHECK: popq [[REGISTER:%[a-z]+]] // CHECK-NEXT: lfence // CHECK-NEXT: jmpq *[[REGISTER]] - diff --git a/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-module-level-assembly.rs b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-module-level-assembly.rs deleted file mode 100644 index b8dc747d3b4cb..0000000000000 --- a/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-module-level-assembly.rs +++ /dev/null @@ -1,12 +0,0 @@ -// Test LVI load hardening on SGX module level assembly code - -// assembly-output: emit-asm -// compile-flags: --crate-type staticlib -// only-x86_64-fortanix-unknown-sgx - -#![feature(global_asm)] - -global_asm!(".start_module_asm: - movq (%rdi), %rax - retq - .end_module_asm:" ); diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c index 971dfa9d171dd..dd76d4f303a95 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c @@ -1,4 +1,3 @@ - int cc_plus_one_c(int *arg) { return *arg + 1; } @@ -9,7 +8,8 @@ int cc_plus_one_c_asm(int *arg) { asm volatile ( " movl (%1), %0\n" " inc %0\n" " jmp 1f\n" - " retq\n" // never executed, but a shortcut to determine how the assembler deals with `ret` instructions + " retq\n" // never executed, but a shortcut to determine how + // the assembler deals with `ret` instructions "1:\n" : "=r"(value) : "r"(arg) ); diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_cxx.cpp b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_cxx.cpp index 1f22c85c4cdb5..ac6f64ac413d0 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_cxx.cpp +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_cxx.cpp @@ -11,7 +11,8 @@ int cc_plus_one_cxx_asm(int *arg) { asm volatile ( " movl (%1), %0\n" " inc %0\n" " jmp 1f\n" - " retq\n" // never executed, but a shortcut to determine how the assembler deals with `ret` instructions + " retq\n" // never executed, but a shortcut to determine how + // the assembler deals with `ret` instructions "1:\n" : "=r"(value) : "r"(arg) ); diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo.c b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo.c index e3a8fcdf414ac..c3b731a2d5096 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo.c +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo.c @@ -8,7 +8,8 @@ int cmake_plus_one_c_asm(int *arg) { asm volatile ( " movl (%1), %0\n" " inc %0\n" " jmp 1f\n" - " retq\n" // never executed, but a shortcut to determine how the assembler deals with `ret` instructions + " retq\n" // never executed, but a shortcut to determine how + // the assembler deals with `ret` instructions "1:\n" : "=r"(value) : "r"(arg) ); diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_cxx.cpp b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_cxx.cpp index a1a7b29d8c17b..824e2afebcc78 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_cxx.cpp +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_cxx.cpp @@ -11,7 +11,8 @@ int cmake_plus_one_cxx_asm(int *arg) { asm volatile ( " movl (%1), %0\n" " inc %0\n" " jmp 1f\n" - " retq\n" // never executed, but a shortcut to determine how the assembler deals with `ret` instructions + " retq\n" // never executed, but a shortcut to determine how + // the assembler deals with `ret` instructions "1:\n" : "=r"(value) : "r"(arg) ); diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs index 697ab29a59c9a..8e91a8d842c62 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs @@ -28,20 +28,21 @@ extern { fn main() { let value : u32 = 41; - + let question = "Answer to the Ultimate Question of Life, the Universe, and Everything:"; + unsafe{ - println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", rust_plus_one_global_asm(&value)); - println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cc_plus_one_c(&value)); - println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cc_plus_one_c_asm(&value)); - println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cc_plus_one_cxx(&value)); - println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cc_plus_one_cxx_asm(&value)); - println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cc_plus_one_asm(&value)); - println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cmake_plus_one_c(&value)); - println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cmake_plus_one_c_asm(&value)); - println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cmake_plus_one_cxx(&value)); - println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cmake_plus_one_cxx_asm(&value)); - println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cmake_plus_one_c_global_asm(&value)); - println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cmake_plus_one_cxx_global_asm(&value)); - println!("Answer to the Ultimate Question of Life, the Universe, and Everything: {}!", cmake_plus_one_asm(&value)); + println!("{}: {}!", question,rust_plus_one_global_asm(&value)); + println!("{}: {}!", question,cc_plus_one_c(&value)); + println!("{}: {}!", question,cc_plus_one_c_asm(&value)); + println!("{}: {}!", question,cc_plus_one_cxx(&value)); + println!("{}: {}!", question,cc_plus_one_cxx_asm(&value)); + println!("{}: {}!", question,cc_plus_one_asm(&value)); + println!("{}: {}!", question,cmake_plus_one_c(&value)); + println!("{}: {}!", question,cmake_plus_one_c_asm(&value)); + println!("{}: {}!", question,cmake_plus_one_cxx(&value)); + println!("{}: {}!", question,cmake_plus_one_cxx_asm(&value)); + println!("{}: {}!", question,cmake_plus_one_c_global_asm(&value)); + println!("{}: {}!", question,cmake_plus_one_cxx_global_asm(&value)); + println!("{}: {}!", question,cmake_plus_one_asm(&value)); } } diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh index ee6dc33feae6f..ec93c98016078 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh @@ -24,8 +24,9 @@ function check { local asm=$(mktemp) local objdump="${BUILD_DIR}/x86_64-unknown-linux-gnu/llvm/build/bin/llvm-objdump" local filecheck="${BUILD_DIR}/x86_64-unknown-linux-gnu/llvm/build/bin/FileCheck" - - ${objdump} --disassemble-symbols=${func} --demangle ${WORK_DIR}/enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave > ${asm} + + ${objdump} --disassemble-symbols=${func} --demangle \ + ${WORK_DIR}/enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave > ${asm} ${filecheck} --input-file ${asm} ${checks} } @@ -34,19 +35,23 @@ build check unw_getcontext unw_getcontext.checks check "libunwind::Registers_x86_64::jumpto()" jumpto.checks check "std::io::stdio::_print::h87f0c238421c45bc" print.checks -check rust_plus_one_global_asm rust_plus_one_global_asm.checks || echo "warning: module level assembly currently not hardened" +check rust_plus_one_global_asm rust_plus_one_global_asm.checks \ + || echo "warning: module level assembly currently not hardened" check cc_plus_one_c cc_plus_one_c.checks check cc_plus_one_c_asm cc_plus_one_c_asm.checks check cc_plus_one_cxx cc_plus_one_cxx.checks check cc_plus_one_cxx_asm cc_plus_one_cxx_asm.checks -check cc_plus_one_asm cc_plus_one_asm.checks || echo "warning: the cc crate forwards assembly files to the CC compiler.\ - Clang uses its own intergrated assembler, which does not include the LVI passes." +check cc_plus_one_asm cc_plus_one_asm.checks \ + || echo "warning: the cc crate forwards assembly files to the CC compiler." \ + "Clang uses its own intergrated assembler, which does not include the LVI passes." check cmake_plus_one_c cmake_plus_one_c.checks check cmake_plus_one_c_asm cmake_plus_one_c_asm.checks -check cmake_plus_one_c_global_asm cmake_plus_one_c_global_asm.checks || echo "warning: module level assembly currently not hardened" +check cmake_plus_one_c_global_asm cmake_plus_one_c_global_asm.checks \ + || echo "warning: module level assembly currently not hardened" check cmake_plus_one_cxx cmake_plus_one_cxx.checks check cmake_plus_one_cxx_asm cmake_plus_one_cxx_asm.checks -check cmake_plus_one_cxx_global_asm cmake_plus_one_cxx_global_asm.checks || echo "warning: module level assembly currently not hardened" +check cmake_plus_one_cxx_global_asm cmake_plus_one_cxx_global_asm.checks \ + || echo "warning: module level assembly currently not hardened" check cmake_plus_one_asm cmake_plus_one_asm.checks From 159d11fb069fca88056bc1b8194d520489e3e921 Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Tue, 31 Mar 2020 11:28:01 +0200 Subject: [PATCH 0977/1052] Patch compilation test helpers for sgx platform --- src/bootstrap/native.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 9e4d6d0023dc9..1e233cb389187 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -625,7 +625,14 @@ impl Step for TestHelpers { if builder.config.dry_run { return; } - let target = self.target; + // The x86_64-fortanix-unknown-sgx target doesn't have a working C + // toolchain. However, some x86_64 ELF objects can be linked + // without issues. Use this hack to compile the test helpers. + let target = if self.target == "x86_64-fortanix-unknown-sgx" { + TargetSelection::from_user("x86_64-unknown-linux-gnu") + } else { + self.target + }; let dst = builder.test_helpers_out(target); let src = builder.src.join("src/test/auxiliary/rust_test_helpers.c"); if up_to_date(&src, &dst.join("librust_test_helpers.a")) { @@ -649,7 +656,6 @@ impl Step for TestHelpers { } cfg.compiler(builder.cc(target)); } - cfg.cargo_metadata(false) .out_dir(&dst) .target(&target.triple) From 54c9c949a171b9c55d265ab4831d310e5865b4ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Fri, 25 Sep 2020 14:40:16 +0200 Subject: [PATCH 0978/1052] Allow multiple allow_internal_unstable attributes Co-authored-by: varkor --- compiler/rustc_attr/src/builtin.rs | 21 ++++++++++++------- .../internal/auxiliary/internal_unstable.rs | 9 ++++++++ src/test/ui/internal/internal-unstable.rs | 1 + src/test/ui/internal/internal-unstable.stderr | 8 +++---- 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 1808eb270baa9..03dbcc450246f 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -1022,14 +1022,21 @@ pub fn find_transparency( pub fn allow_internal_unstable<'a>( sess: &'a Session, - attrs: &[Attribute], + attrs: &'a [Attribute], ) -> Option + 'a> { - let attr = sess.find_by_name(attrs, sym::allow_internal_unstable)?; - let list = attr.meta_item_list().or_else(|| { - sess.diagnostic() - .span_err(attr.span, "allow_internal_unstable expects list of feature names"); - None - })?; + let attrs = sess.filter_by_name(attrs, sym::allow_internal_unstable); + let list = attrs + .filter_map(move |attr| { + attr.meta_item_list().or_else(|| { + sess.diagnostic().span_err( + attr.span, + "`allow_internal_unstable` expects a list of feature names", + ); + None + }) + }) + .flatten(); + Some(list.into_iter().filter_map(move |it| { let name = it.ident().map(|ident| ident.name); if name.is_none() { diff --git a/src/test/ui/internal/auxiliary/internal_unstable.rs b/src/test/ui/internal/auxiliary/internal_unstable.rs index 148cbd1899eba..eb4d6cb380efe 100644 --- a/src/test/ui/internal/auxiliary/internal_unstable.rs +++ b/src/test/ui/internal/auxiliary/internal_unstable.rs @@ -52,6 +52,15 @@ macro_rules! access_field_allow { ($e: expr) => { $e.x } } +// regression test for #77088 +#[stable(feature = "stable", since = "1.0.0")] +#[allow_internal_unstable(struct_field)] +#[allow_internal_unstable(struct2_field)] +#[macro_export] +macro_rules! access_field_allow2 { + ($e: expr) => { $e.x } +} + #[stable(feature = "stable", since = "1.0.0")] #[allow_internal_unstable()] #[macro_export] diff --git a/src/test/ui/internal/internal-unstable.rs b/src/test/ui/internal/internal-unstable.rs index e09a5d89172e8..94bd6aab23bff 100644 --- a/src/test/ui/internal/internal-unstable.rs +++ b/src/test/ui/internal/internal-unstable.rs @@ -28,6 +28,7 @@ fn main() { construct_unstable_allow!(0); |x: internal_unstable::Foo| { call_method_allow!(x) }; |x: internal_unstable::Bar| { access_field_allow!(x) }; + |x: internal_unstable::Bar| { access_field_allow2!(x) }; // regression test for #77088 // bad. pass_through_allow!(internal_unstable::unstable()); //~ ERROR use of unstable diff --git a/src/test/ui/internal/internal-unstable.stderr b/src/test/ui/internal/internal-unstable.stderr index 2c6bf42ae86f0..2e6360c75c42a 100644 --- a/src/test/ui/internal/internal-unstable.stderr +++ b/src/test/ui/internal/internal-unstable.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:33:25 + --> $DIR/internal-unstable.rs:34:25 | LL | pass_through_allow!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | pass_through_allow!(internal_unstable::unstable()); = help: add `#![feature(function)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:35:27 + --> $DIR/internal-unstable.rs:36:27 | LL | pass_through_noallow!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | pass_through_noallow!(internal_unstable::unstable()); = help: add `#![feature(function)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:39:22 + --> $DIR/internal-unstable.rs:40:22 | LL | println!("{:?}", internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | println!("{:?}", internal_unstable::unstable()); = help: add `#![feature(function)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:41:10 + --> $DIR/internal-unstable.rs:42:10 | LL | bar!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 939fd37643e8cfee43672bd3120df1bfae513f9d Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Fri, 25 Sep 2020 22:19:28 +0800 Subject: [PATCH 0979/1052] Rust vec bench import specific rand::RngCore --- library/alloc/benches/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/benches/vec.rs b/library/alloc/benches/vec.rs index 687efa8e9e777..789ae3a20eabf 100644 --- a/library/alloc/benches/vec.rs +++ b/library/alloc/benches/vec.rs @@ -1,4 +1,4 @@ -use rand::prelude::*; +use rand::RngCore; use std::iter::{repeat, FromIterator}; use test::{black_box, Bencher}; From 606ed2a07632af470f53a5d8cfaa0a4f453b50c0 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Fri, 25 Sep 2020 23:20:22 +0800 Subject: [PATCH 0980/1052] Remove extra space from vec drawing --- library/alloc/src/vec.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index c54b3aef95ed4..cfa899377942d 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -2099,7 +2099,6 @@ impl Extend for Vec { /// | slice::Iter | | | /// | Iterator | +---------------------+ /// +---------------------------------+ -/// /// ``` trait SpecFromIter { fn from_iter(iter: I) -> Self; From 0d2521aaf7548f0de6c227ef68eae76df4420c03 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 23 Sep 2020 11:53:58 -0700 Subject: [PATCH 0981/1052] Add `const_fn_floating_point_arithmetic` --- compiler/rustc_feature/src/active.rs | 3 +++ .../src/transform/check_consts/ops.rs | 24 +++++++++++++++++++ compiler/rustc_span/src/symbol.rs | 1 + 3 files changed, 28 insertions(+) diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 6452bda293ef5..720fa9939f399 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -584,6 +584,9 @@ declare_features! ( /// Allows non trivial generic constants which have to be manually propageted upwards. (active, const_evaluatable_checked, "1.48.0", Some(76560), None), + /// Allows basic arithmetic on floating point types in a `const fn`. + (active, const_fn_floating_point_arithmetic, "1.48.0", Some(57563), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index 496e620dd9df6..1d74108585360 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -112,6 +112,30 @@ impl NonConstOp for Abort { } } +#[derive(Debug)] +pub struct FloatingPointOp; +impl NonConstOp for FloatingPointOp { + const STOPS_CONST_CHECKING: bool = true; + + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + if ccx.const_kind() == hir::ConstContext::ConstFn { + Status::Unstable(sym::const_fn_floating_point_arithmetic) + } else { + Status::Allowed + } + } + + fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_fn_floating_point_arithmetic, + span, + &format!("floating point arithmetic is not allowed in {}s", ccx.const_kind()), + ) + .emit(); + } +} + #[derive(Debug)] pub struct NonPrimitiveOp; impl NonConstOp for NonPrimitiveOp { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 2d5c6451d1a52..4447564c8b4c5 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -351,6 +351,7 @@ symbols! { const_evaluatable_checked, const_extern_fn, const_fn, + const_fn_floating_point_arithmetic, const_fn_transmute, const_fn_union, const_generics, From 2049052cb9880c97bb289a086815576f5aabc6c9 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 23 Sep 2020 11:54:11 -0700 Subject: [PATCH 0982/1052] Put floating point arithmetic behind its own feature gate This refactors handling of `Rvalue::{Unary,Binary}Op` in the const-checker. Now we `span_bug` if there's an unexpected type in a primitive operation. This also allows unary negation on `char` values through the const-checker because it makes the code a bit cleaner. `char` does not actually support these operations, and if it did, we could evaluate them at compile-time. --- .../src/transform/check_consts/validation.rs | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index dc28ba46d7cbb..73725c7b98eee 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -540,8 +540,12 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { Rvalue::UnaryOp(_, ref operand) => { let ty = operand.ty(self.body, self.tcx); - if !(ty.is_integral() || ty.is_bool()) { - self.check_op(ops::NonPrimitiveOp) + if is_int_bool_or_char(ty) { + // Int, bool, and char operations are fine. + } else if ty.is_floating_point() { + self.check_op(ops::FloatingPointOp); + } else { + span_bug!(self.span, "non-primitive type in `Rvalue::UnaryOp`: {:?}", ty); } } @@ -550,7 +554,9 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { let lhs_ty = lhs.ty(self.body, self.tcx); let rhs_ty = rhs.ty(self.body, self.tcx); - if let ty::RawPtr(_) | ty::FnPtr(..) = lhs_ty.kind() { + if is_int_bool_or_char(lhs_ty) && is_int_bool_or_char(rhs_ty) { + // Int, bool, and char operations are fine. + } else if lhs_ty.is_fn_ptr() || lhs_ty.is_unsafe_ptr() { assert_eq!(lhs_ty, rhs_ty); assert!( op == BinOp::Eq @@ -563,12 +569,15 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { ); self.check_op(ops::RawPtrComparison); - } - - if !(lhs_ty.is_integral() || lhs_ty.is_bool() || lhs_ty.is_char()) - || !(rhs_ty.is_integral() || rhs_ty.is_bool() || rhs_ty.is_char()) - { - self.check_op(ops::NonPrimitiveOp) + } else if lhs_ty.is_floating_point() || rhs_ty.is_floating_point() { + self.check_op(ops::FloatingPointOp); + } else { + span_bug!( + self.span, + "non-primitive type in `Rvalue::BinaryOp`: {:?} ⚬ {:?}", + lhs_ty, + rhs_ty + ); } } } @@ -867,3 +876,7 @@ fn place_as_reborrow( } }) } + +fn is_int_bool_or_char(ty: Ty<'_>) -> bool { + ty.is_bool() || ty.is_integral() || ty.is_char() +} From 6a52c094408370a3bd60ed0976211995ef52fc23 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 23 Sep 2020 11:58:22 -0700 Subject: [PATCH 0983/1052] Add new feature gate to standard library --- library/core/src/lib.rs | 1 + library/std/src/lib.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 63ca6e517d214..30fb87b022645 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -82,6 +82,7 @@ #![feature(const_pin)] #![feature(const_fn_union)] #![feature(const_fn)] +#![cfg_attr(not(bootstrap), feature(const_fn_floating_point_arithmetic))] #![feature(const_generics)] #![feature(const_option)] #![feature(const_precise_live_drops)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index ac0075ad129c5..d03428dd08282 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -236,6 +236,7 @@ #![feature(clamp)] #![feature(concat_idents)] #![feature(const_cstr_unchecked)] +#![cfg_attr(not(bootstrap), feature(const_fn_floating_point_arithmetic))] #![feature(const_fn_transmute)] #![feature(const_fn)] #![feature(const_ip)] From b428f287c3ddb951450bc5f94cf3a5e38a59e3d6 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 23 Sep 2020 11:58:41 -0700 Subject: [PATCH 0984/1052] Bless tests --- .../const-extern-fn-min-const-fn.rs | 2 +- .../const-extern-fn-min-const-fn.stderr | 4 ++-- src/test/ui/consts/const_let_eq_float.rs | 4 ++-- src/test/ui/consts/min_const_fn/min_const_fn.rs | 8 ++++---- .../ui/consts/min_const_fn/min_const_fn.stderr | 16 ++++++++-------- .../min_const_fn_libstd_stability.rs | 6 +++--- .../min_const_fn_libstd_stability.stderr | 2 +- .../min_const_unsafe_fn_libstd_stability.rs | 4 ++-- .../min_const_unsafe_fn_libstd_stability.stderr | 2 +- 9 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs index e0b9e5f33759e..094ae7378bce8 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs @@ -4,7 +4,7 @@ const extern fn unsize(x: &[u8; 3]) -> &[u8] { x } const unsafe extern "C" fn closure() -> fn() { || {} } //~^ ERROR function pointers in const fn are unstable const unsafe extern fn use_float() { 1.0 + 1.0; } -//~^ ERROR only int, `bool` and `char` operations are stable in const fn +//~^ ERROR floating point arithmetic const extern "C" fn ptr_cast(val: *const u8) { val as usize; } //~^ ERROR casting pointers to integers diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr index 5ca44b3fa7e65..49caac00ca884 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr @@ -7,14 +7,14 @@ LL | const unsafe extern "C" fn closure() -> fn() { || {} } = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: only int, `bool` and `char` operations are stable in const fn +error[E0658]: floating point arithmetic is not allowed in constant functions --> $DIR/const-extern-fn-min-const-fn.rs:6:38 | LL | const unsafe extern fn use_float() { 1.0 + 1.0; } | ^^^^^^^^^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable error[E0658]: casting pointers to integers in constant functions is unstable --> $DIR/const-extern-fn-min-const-fn.rs:8:48 diff --git a/src/test/ui/consts/const_let_eq_float.rs b/src/test/ui/consts/const_let_eq_float.rs index bc0ef26eb2fe5..e15f4b804f716 100644 --- a/src/test/ui/consts/const_let_eq_float.rs +++ b/src/test/ui/consts/const_let_eq_float.rs @@ -1,6 +1,6 @@ -// build-pass (FIXME(62277): could be check-pass?) +// run-pass -#![feature(const_fn)] +#![feature(const_fn_floating_point_arithmetic)] struct Foo(T); struct Bar { x: T } diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs index 336d754b06a73..86b26a53371d8 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs @@ -78,13 +78,13 @@ const fn foo11(t: T) -> T { t } const fn foo11_2(t: T) -> T { t } //~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable const fn foo19(f: f32) -> f32 { f * 2.0 } -//~^ ERROR int, `bool` and `char` operations +//~^ ERROR floating point arithmetic const fn foo19_2(f: f32) -> f32 { 2.0 - f } -//~^ ERROR int, `bool` and `char` operations +//~^ ERROR floating point arithmetic const fn foo19_3(f: f32) -> f32 { -f } -//~^ ERROR int, `bool` and `char` operations +//~^ ERROR floating point arithmetic const fn foo19_4(f: f32, g: f32) -> f32 { f / g } -//~^ ERROR int, `bool` and `char` operations +//~^ ERROR floating point arithmetic static BAR: u32 = 42; const fn foo25() -> u32 { BAR } //~ ERROR cannot refer to statics diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr index c96500e38ec83..60c4eef795359 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr @@ -76,41 +76,41 @@ LL | const fn foo11_2(t: T) -> T { t } = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: only int, `bool` and `char` operations are stable in const fn +error[E0658]: floating point arithmetic is not allowed in constant functions --> $DIR/min_const_fn.rs:80:33 | LL | const fn foo19(f: f32) -> f32 { f * 2.0 } | ^^^^^^^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable -error[E0723]: only int, `bool` and `char` operations are stable in const fn +error[E0658]: floating point arithmetic is not allowed in constant functions --> $DIR/min_const_fn.rs:82:35 | LL | const fn foo19_2(f: f32) -> f32 { 2.0 - f } | ^^^^^^^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable -error[E0723]: only int, `bool` and `char` operations are stable in const fn +error[E0658]: floating point arithmetic is not allowed in constant functions --> $DIR/min_const_fn.rs:84:35 | LL | const fn foo19_3(f: f32) -> f32 { -f } | ^^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable -error[E0723]: only int, `bool` and `char` operations are stable in const fn +error[E0658]: floating point arithmetic is not allowed in constant functions --> $DIR/min_const_fn.rs:86:43 | LL | const fn foo19_4(f: f32, g: f32) -> f32 { f / g } | ^^^^^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable error[E0013]: constant functions cannot refer to statics --> $DIR/min_const_fn.rs:90:27 diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs index b83fdf7c656cd..292e2dd167c91 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs @@ -3,7 +3,7 @@ we're apparently really bad at it", issue = "none")] -#![feature(const_fn, foo, foo2)] +#![feature(const_fn, const_fn_floating_point_arithmetic, foo, foo2)] #![feature(staged_api)] #[stable(feature = "rust1", since = "1.0.0")] @@ -25,9 +25,9 @@ const fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] -// conformity is required, even with `const_fn` feature gate +// Const-stable functions cannot rely on unstable const-eval features. const fn bar3() -> u32 { (5f32 + 6f32) as u32 } -//~^ ERROR const-stable function cannot use `#[feature(const_fn)]` +//~^ ERROR const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` // check whether this function cannot be called even with the feature gate active #[unstable(feature = "foo2", issue = "none")] diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr index a1f1f6f52ab2a..fa2260b40d19f 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr @@ -14,7 +14,7 @@ LL | const fn bar2() -> u32 { foo2() } | = help: Const-stable functions can only call other const-stable functions -error: const-stable function cannot use `#[feature(const_fn)]` +error: const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` --> $DIR/min_const_fn_libstd_stability.rs:29:26 | LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 } diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs index 902ed435e31bc..0f48341ddf3ec 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs @@ -3,7 +3,7 @@ we're apparently really bad at it", issue = "none")] -#![feature(const_fn, foo, foo2)] +#![feature(const_fn, const_fn_floating_point_arithmetic, foo, foo2)] #![feature(staged_api)] #[stable(feature = "rust1", since = "1.0.0")] @@ -27,7 +27,7 @@ const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR not yet stable as #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // conformity is required, even with `const_fn` feature gate const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } -//~^ ERROR const-stable function cannot use `#[feature(const_fn)]` +//~^ ERROR const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` // check whether this function cannot be called even with the feature gate active #[unstable(feature = "foo2", issue = "none")] diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr index 2741a86440487..1ca5964ce0fc4 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr @@ -14,7 +14,7 @@ LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } | = help: Const-stable functions can only call other const-stable functions -error: const-stable function cannot use `#[feature(const_fn)]` +error: const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` --> $DIR/min_const_unsafe_fn_libstd_stability.rs:29:33 | LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } From 4cac90c968774b799697d5ce18da75483dc2f15b Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 23 Sep 2020 12:38:21 -0700 Subject: [PATCH 0985/1052] Move const fn floating point test out of `min_const_fn` --- ..._fn_floating_point_arithmetic.gated.stderr | 8 +++ .../const_fn_floating_point_arithmetic.rs | 20 ++++++ ..._fn_floating_point_arithmetic.stock.stderr | 48 +++++++++++++ .../ui/consts/min_const_fn/min_const_fn.rs | 8 --- .../consts/min_const_fn/min_const_fn.stderr | 72 +++++-------------- 5 files changed, 94 insertions(+), 62 deletions(-) create mode 100644 src/test/ui/consts/const_fn_floating_point_arithmetic.gated.stderr create mode 100644 src/test/ui/consts/const_fn_floating_point_arithmetic.rs create mode 100644 src/test/ui/consts/const_fn_floating_point_arithmetic.stock.stderr diff --git a/src/test/ui/consts/const_fn_floating_point_arithmetic.gated.stderr b/src/test/ui/consts/const_fn_floating_point_arithmetic.gated.stderr new file mode 100644 index 0000000000000..ae24f8f65009a --- /dev/null +++ b/src/test/ui/consts/const_fn_floating_point_arithmetic.gated.stderr @@ -0,0 +1,8 @@ +error: fatal error triggered by #[rustc_error] + --> $DIR/const_fn_floating_point_arithmetic.rs:20:1 + | +LL | fn main() {} + | ^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const_fn_floating_point_arithmetic.rs b/src/test/ui/consts/const_fn_floating_point_arithmetic.rs new file mode 100644 index 0000000000000..5e32482b21a52 --- /dev/null +++ b/src/test/ui/consts/const_fn_floating_point_arithmetic.rs @@ -0,0 +1,20 @@ +// gate-test-const_fn_floating_point_arithmetic + +// revisions: stock gated + +#![feature(rustc_attrs)] +#![cfg_attr(gated, feature(const_fn_floating_point_arithmetic))] + +const fn add(f: f32) -> f32 { f + 2.0 } +//[stock]~^ floating point arithmetic +const fn sub(f: f32) -> f32 { 2.0 - f } +//[stock]~^ floating point arithmetic +const fn mul(f: f32, g: f32) -> f32 { f * g } +//[stock]~^ floating point arithmetic +const fn div(f: f32, g: f32) -> f32 { f / g } +//[stock]~^ floating point arithmetic +const fn neg(f: f32) -> f32 { -f } +//[stock]~^ floating point arithmetic + +#[rustc_error] +fn main() {} //[gated]~ fatal error triggered by #[rustc_error] diff --git a/src/test/ui/consts/const_fn_floating_point_arithmetic.stock.stderr b/src/test/ui/consts/const_fn_floating_point_arithmetic.stock.stderr new file mode 100644 index 0000000000000..7461007fc2aa5 --- /dev/null +++ b/src/test/ui/consts/const_fn_floating_point_arithmetic.stock.stderr @@ -0,0 +1,48 @@ +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const_fn_floating_point_arithmetic.rs:8:31 + | +LL | const fn add(f: f32) -> f32 { f + 2.0 } + | ^^^^^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable + +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const_fn_floating_point_arithmetic.rs:10:31 + | +LL | const fn sub(f: f32) -> f32 { 2.0 - f } + | ^^^^^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable + +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const_fn_floating_point_arithmetic.rs:12:39 + | +LL | const fn mul(f: f32, g: f32) -> f32 { f * g } + | ^^^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable + +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const_fn_floating_point_arithmetic.rs:14:39 + | +LL | const fn div(f: f32, g: f32) -> f32 { f / g } + | ^^^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable + +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const_fn_floating_point_arithmetic.rs:16:31 + | +LL | const fn neg(f: f32) -> f32 { -f } + | ^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs index 86b26a53371d8..55a999d5cdc04 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs @@ -77,14 +77,6 @@ const fn foo11(t: T) -> T { t } //~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable const fn foo11_2(t: T) -> T { t } //~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable -const fn foo19(f: f32) -> f32 { f * 2.0 } -//~^ ERROR floating point arithmetic -const fn foo19_2(f: f32) -> f32 { 2.0 - f } -//~^ ERROR floating point arithmetic -const fn foo19_3(f: f32) -> f32 { -f } -//~^ ERROR floating point arithmetic -const fn foo19_4(f: f32, g: f32) -> f32 { f / g } -//~^ ERROR floating point arithmetic static BAR: u32 = 42; const fn foo25() -> u32 { BAR } //~ ERROR cannot refer to statics diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr index 60c4eef795359..a37e5203eeef4 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr @@ -76,44 +76,8 @@ LL | const fn foo11_2(t: T) -> T { t } = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0658]: floating point arithmetic is not allowed in constant functions - --> $DIR/min_const_fn.rs:80:33 - | -LL | const fn foo19(f: f32) -> f32 { f * 2.0 } - | ^^^^^^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable - -error[E0658]: floating point arithmetic is not allowed in constant functions - --> $DIR/min_const_fn.rs:82:35 - | -LL | const fn foo19_2(f: f32) -> f32 { 2.0 - f } - | ^^^^^^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable - -error[E0658]: floating point arithmetic is not allowed in constant functions - --> $DIR/min_const_fn.rs:84:35 - | -LL | const fn foo19_3(f: f32) -> f32 { -f } - | ^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable - -error[E0658]: floating point arithmetic is not allowed in constant functions - --> $DIR/min_const_fn.rs:86:43 - | -LL | const fn foo19_4(f: f32, g: f32) -> f32 { f / g } - | ^^^^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable - error[E0013]: constant functions cannot refer to statics - --> $DIR/min_const_fn.rs:90:27 + --> $DIR/min_const_fn.rs:82:27 | LL | const fn foo25() -> u32 { BAR } | ^^^ @@ -121,7 +85,7 @@ LL | const fn foo25() -> u32 { BAR } = help: consider extracting the value of the `static` to a `const`, and referring to that error[E0013]: constant functions cannot refer to statics - --> $DIR/min_const_fn.rs:91:37 + --> $DIR/min_const_fn.rs:83:37 | LL | const fn foo26() -> &'static u32 { &BAR } | ^^^ @@ -129,7 +93,7 @@ LL | const fn foo26() -> &'static u32 { &BAR } = help: consider extracting the value of the `static` to a `const`, and referring to that error[E0658]: casting pointers to integers in constant functions is unstable - --> $DIR/min_const_fn.rs:92:42 + --> $DIR/min_const_fn.rs:84:42 | LL | const fn foo30(x: *const u32) -> usize { x as usize } | ^^^^^^^^^^ @@ -138,7 +102,7 @@ LL | const fn foo30(x: *const u32) -> usize { x as usize } = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable error[E0658]: casting pointers to integers in constant functions is unstable - --> $DIR/min_const_fn.rs:94:63 + --> $DIR/min_const_fn.rs:86:63 | LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } } | ^^^^^^^^^^ @@ -147,7 +111,7 @@ LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable error[E0658]: casting pointers to integers in constant functions is unstable - --> $DIR/min_const_fn.rs:96:42 + --> $DIR/min_const_fn.rs:88:42 | LL | const fn foo30_2(x: *mut u32) -> usize { x as usize } | ^^^^^^^^^^ @@ -156,7 +120,7 @@ LL | const fn foo30_2(x: *mut u32) -> usize { x as usize } = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable error[E0658]: casting pointers to integers in constant functions is unstable - --> $DIR/min_const_fn.rs:98:63 + --> $DIR/min_const_fn.rs:90:63 | LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } } | ^^^^^^^^^^ @@ -165,7 +129,7 @@ LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable error[E0658]: mutable references are not allowed in constant functions - --> $DIR/min_const_fn.rs:101:14 + --> $DIR/min_const_fn.rs:93:14 | LL | const fn inc(x: &mut i32) { *x += 1 } | ^ @@ -174,7 +138,7 @@ LL | const fn inc(x: &mut i32) { *x += 1 } = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:110:6 + --> $DIR/min_const_fn.rs:102:6 | LL | impl Foo { | ^ @@ -183,7 +147,7 @@ LL | impl Foo { = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:115:6 + --> $DIR/min_const_fn.rs:107:6 | LL | impl Foo { | ^ @@ -192,7 +156,7 @@ LL | impl Foo { = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:120:6 + --> $DIR/min_const_fn.rs:112:6 | LL | impl Foo { | ^ @@ -201,7 +165,7 @@ LL | impl Foo { = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:126:34 + --> $DIR/min_const_fn.rs:118:34 | LL | const fn no_apit2(_x: AlanTuring) {} | ^^^^^^^^^^^^^^^^^^^^ @@ -210,7 +174,7 @@ LL | const fn no_apit2(_x: AlanTuring) {} = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:128:22 + --> $DIR/min_const_fn.rs:120:22 | LL | const fn no_apit(_x: impl std::fmt::Debug) {} | ^^^^^^^^^^^^^^^^^^^^ @@ -219,7 +183,7 @@ LL | const fn no_apit(_x: impl std::fmt::Debug) {} = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:129:23 + --> $DIR/min_const_fn.rs:121:23 | LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} | ^^ @@ -228,7 +192,7 @@ LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:130:32 + --> $DIR/min_const_fn.rs:122:32 | LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -237,7 +201,7 @@ LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:135:41 + --> $DIR/min_const_fn.rs:127:41 | LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -246,7 +210,7 @@ LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: function pointers in const fn are unstable - --> $DIR/min_const_fn.rs:138:21 + --> $DIR/min_const_fn.rs:130:21 | LL | const fn no_fn_ptrs(_x: fn()) {} | ^^ @@ -255,7 +219,7 @@ LL | const fn no_fn_ptrs(_x: fn()) {} = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: function pointers in const fn are unstable - --> $DIR/min_const_fn.rs:140:27 + --> $DIR/min_const_fn.rs:132:27 | LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo } | ^^^^ @@ -263,7 +227,7 @@ LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo } = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error: aborting due to 30 previous errors +error: aborting due to 26 previous errors Some errors have detailed explanations: E0013, E0493, E0658, E0723. For more information about an error, try `rustc --explain E0013`. From 659028f48b7b47ee3e16a4d110b1379ed8524121 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 23 Sep 2020 13:08:20 -0700 Subject: [PATCH 0986/1052] Use proper issue for `const_fn_floating_point_arithmetic` --- compiler/rustc_feature/src/active.rs | 2 +- .../const-extern-fn-min-const-fn.stderr | 2 +- .../const_fn_floating_point_arithmetic.stock.stderr | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 720fa9939f399..17b9e1ee7e8ba 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -585,7 +585,7 @@ declare_features! ( (active, const_evaluatable_checked, "1.48.0", Some(76560), None), /// Allows basic arithmetic on floating point types in a `const fn`. - (active, const_fn_floating_point_arithmetic, "1.48.0", Some(57563), None), + (active, const_fn_floating_point_arithmetic, "1.48.0", Some(57241), None), // ------------------------------------------------------------------------- // feature-group-end: actual feature gates diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr index 49caac00ca884..fcc34f358f9f9 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr @@ -13,7 +13,7 @@ error[E0658]: floating point arithmetic is not allowed in constant functions LL | const unsafe extern fn use_float() { 1.0 + 1.0; } | ^^^^^^^^^ | - = note: see issue #57563 for more information + = note: see issue #57241 for more information = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable error[E0658]: casting pointers to integers in constant functions is unstable diff --git a/src/test/ui/consts/const_fn_floating_point_arithmetic.stock.stderr b/src/test/ui/consts/const_fn_floating_point_arithmetic.stock.stderr index 7461007fc2aa5..ef7a60faf3f5c 100644 --- a/src/test/ui/consts/const_fn_floating_point_arithmetic.stock.stderr +++ b/src/test/ui/consts/const_fn_floating_point_arithmetic.stock.stderr @@ -4,7 +4,7 @@ error[E0658]: floating point arithmetic is not allowed in constant functions LL | const fn add(f: f32) -> f32 { f + 2.0 } | ^^^^^^^ | - = note: see issue #57563 for more information + = note: see issue #57241 for more information = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable error[E0658]: floating point arithmetic is not allowed in constant functions @@ -13,7 +13,7 @@ error[E0658]: floating point arithmetic is not allowed in constant functions LL | const fn sub(f: f32) -> f32 { 2.0 - f } | ^^^^^^^ | - = note: see issue #57563 for more information + = note: see issue #57241 for more information = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable error[E0658]: floating point arithmetic is not allowed in constant functions @@ -22,7 +22,7 @@ error[E0658]: floating point arithmetic is not allowed in constant functions LL | const fn mul(f: f32, g: f32) -> f32 { f * g } | ^^^^^ | - = note: see issue #57563 for more information + = note: see issue #57241 for more information = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable error[E0658]: floating point arithmetic is not allowed in constant functions @@ -31,7 +31,7 @@ error[E0658]: floating point arithmetic is not allowed in constant functions LL | const fn div(f: f32, g: f32) -> f32 { f / g } | ^^^^^ | - = note: see issue #57563 for more information + = note: see issue #57241 for more information = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable error[E0658]: floating point arithmetic is not allowed in constant functions @@ -40,7 +40,7 @@ error[E0658]: floating point arithmetic is not allowed in constant functions LL | const fn neg(f: f32) -> f32 { -f } | ^^ | - = note: see issue #57563 for more information + = note: see issue #57241 for more information = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable error: aborting due to 5 previous errors From 323a27967abe75da79e44132e449fb36cefd240b Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 25 Sep 2020 19:46:06 +0100 Subject: [PATCH 0987/1052] Improve ::get_unchecked` safety comment --- library/alloc/src/vec.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index c54b3aef95ed4..e973c3287ede0 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -2985,8 +2985,14 @@ impl Iterator for IntoIter { where Self: TrustedRandomAccess, { - // SAFETY: the caller must uphold the contract for - // `Iterator::get_unchecked`. + // SAFETY: the caller must guarantee that `i` is in bounds of the + // `Vec`, so `i` cannot overflow an `isize`, and the `self.ptr.add(i)` + // is guaranteed to pointer to an element of the `Vec` and + // thus guaranteed to be valid to dereference. + // + // Also note the implementation of `Self: TrustedRandomAccess` requires + // that `T: Copy` so reading elements from the buffer doesn't invalidate + // them for `Drop`. unsafe { if mem::size_of::() == 0 { mem::zeroed() } else { ptr::read(self.ptr.add(i)) } } From 04a0b1d0879f7872b09cd8058a15479589ccd352 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 25 Sep 2020 19:48:24 +0100 Subject: [PATCH 0988/1052] Rename Iterator::get_unchecked It's possible for method resolution to pick this method over a lower priority stable method, causing compilation errors. Since this method is permanently unstable, give it a name that is very unlikely to be used in user code. --- library/alloc/src/vec.rs | 2 +- library/core/src/iter/adapters/fuse.rs | 5 ++- library/core/src/iter/adapters/mod.rs | 16 ++++---- library/core/src/iter/adapters/zip.rs | 42 +++++++++++---------- library/core/src/iter/traits/iterator.rs | 4 +- library/core/src/slice/iter.rs | 47 ++++++++++++------------ library/core/src/slice/iter/macros.rs | 2 +- library/core/src/str/mod.rs | 6 +-- 8 files changed, 66 insertions(+), 58 deletions(-) diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index e973c3287ede0..6e001b0d60a31 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -2981,7 +2981,7 @@ impl Iterator for IntoIter { self.len() } - unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item + unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item where Self: TrustedRandomAccess, { diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index c5b3bd5cf11f2..a78da369c241b 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -115,12 +115,13 @@ where } #[inline] - unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item where Self: TrustedRandomAccess, { match self.iter { - // SAFETY: the caller must uphold the contract for `Iterator::get_unchecked`. + // SAFETY: the caller must uphold the contract for + // `Iterator::__iterator_get_unchecked`. Some(ref mut iter) => unsafe { try_get_unchecked(iter, idx) }, // SAFETY: the caller asserts there is an item at `i`, so we're not exhausted. None => unsafe { intrinsics::unreachable() }, diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index ab27fe15a8e2c..422e449b176b7 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -285,12 +285,12 @@ where self.it.count() } - unsafe fn get_unchecked(&mut self, idx: usize) -> T + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T where Self: TrustedRandomAccess, { // SAFETY: the caller must uphold the contract for - // `Iterator::get_unchecked`. + // `Iterator::__iterator_get_unchecked`. *unsafe { try_get_unchecked(&mut self.it, idx) } } } @@ -420,12 +420,12 @@ where self.it.map(T::clone).fold(init, f) } - unsafe fn get_unchecked(&mut self, idx: usize) -> T + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T where Self: TrustedRandomAccess, { // SAFETY: the caller must uphold the contract for - // `Iterator::get_unchecked`. + // `Iterator::__iterator_get_unchecked`. unsafe { try_get_unchecked(&mut self.it, idx).clone() } } } @@ -935,12 +935,12 @@ where self.iter.fold(init, map_fold(self.f, g)) } - unsafe fn get_unchecked(&mut self, idx: usize) -> B + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> B where Self: TrustedRandomAccess, { // SAFETY: the caller must uphold the contract for - // `Iterator::get_unchecked`. + // `Iterator::__iterator_get_unchecked`. unsafe { (self.f)(try_get_unchecked(&mut self.iter, idx)) } } } @@ -1431,12 +1431,12 @@ where self.iter.fold(init, enumerate(self.count, fold)) } - unsafe fn get_unchecked(&mut self, idx: usize) -> ::Item + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> ::Item where Self: TrustedRandomAccess, { // SAFETY: the caller must uphold the contract for - // `Iterator::get_unchecked`. + // `Iterator::__iterator_get_unchecked`. let value = unsafe { try_get_unchecked(&mut self.iter, idx) }; (Add::add(self.count, idx), value) } diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index a854f70dcd0ba..78712988eaea7 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -59,12 +59,12 @@ where } #[inline] - unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item where Self: TrustedRandomAccess, { - // SAFETY: `ZipImpl::get_unchecked` has same safety requirements as - // `Iterator::get_unchecked`. + // SAFETY: `ZipImpl::__iterator_get_unchecked` has same safety + // requirements as `Iterator::__iterator_get_unchecked`. unsafe { ZipImpl::get_unchecked(self, idx) } } } @@ -93,7 +93,7 @@ trait ZipImpl { where A: DoubleEndedIterator + ExactSizeIterator, B: DoubleEndedIterator + ExactSizeIterator; - // This has the same safety requirements as `Iterator::get_unchecked` + // This has the same safety requirements as `Iterator::__iterator_get_unchecked` unsafe fn get_unchecked(&mut self, idx: usize) -> ::Item where Self: Iterator + TrustedRandomAccess; @@ -197,12 +197,14 @@ where let i = self.index; self.index += 1; // SAFETY: `i` is smaller than `self.len`, thus smaller than `self.a.len()` and `self.b.len()` - unsafe { Some((self.a.get_unchecked(i), self.b.get_unchecked(i))) } + unsafe { + Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i))) + } } else if A::may_have_side_effect() && self.index < self.a.size() { // match the base implementation's potential side effects // SAFETY: we just checked that `self.index` < `self.a.len()` unsafe { - self.a.get_unchecked(self.index); + self.a.__iterator_get_unchecked(self.index); } self.index += 1; None @@ -229,13 +231,13 @@ where // ensures that `end` is smaller than or equal to `self.len`, // so `i` is also smaller than `self.len`. unsafe { - self.a.get_unchecked(i); + self.a.__iterator_get_unchecked(i); } } if B::may_have_side_effect() { // SAFETY: same as above. unsafe { - self.b.get_unchecked(i); + self.b.__iterator_get_unchecked(i); } } } @@ -277,7 +279,9 @@ where let i = self.len; // SAFETY: `i` is smaller than the previous value of `self.len`, // which is also smaller than or equal to `self.a.len()` and `self.b.len()` - unsafe { Some((self.a.get_unchecked(i), self.b.get_unchecked(i))) } + unsafe { + Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i))) + } } else { None } @@ -286,8 +290,8 @@ where #[inline] unsafe fn get_unchecked(&mut self, idx: usize) -> ::Item { // SAFETY: the caller must uphold the contract for - // `Iterator::get_unchecked`. - unsafe { (self.a.get_unchecked(idx), self.b.get_unchecked(idx)) } + // `Iterator::__iterator_get_unchecked`. + unsafe { (self.a.__iterator_get_unchecked(idx), self.b.__iterator_get_unchecked(idx)) } } } @@ -386,8 +390,8 @@ impl ZipFmt::get_unchecked` must be safe to call provided the -/// following conditions are met. +/// `::__iterator_get_unchecked` must be safe to call +/// provided the following conditions are met. /// /// 1. `0 <= idx` and `idx < self.size()`. /// 2. If `self: !Clone`, then `get_unchecked` is never called with the same @@ -399,7 +403,7 @@ impl ZipFmt bool; } -/// Like `Iterator::get_unchecked`, but doesn't require the compiler to +/// Like `Iterator::__iterator_get_unchecked`, but doesn't require the compiler to /// know that `U: TrustedRandomAccess`. /// /// ## Safety @@ -436,13 +440,13 @@ where I: Iterator, { // SAFETY: the caller must uphold the contract for - // `Iterator::get_unchecked`. + // `Iterator::__iterator_get_unchecked`. unsafe { it.try_get_unchecked(idx) } } unsafe trait SpecTrustedRandomAccess: Iterator { /// If `Self: TrustedRandomAccess`, it must be safe to call a - /// `Iterator::get_unchecked(self, index)`. + /// `Iterator::__iterator_get_unchecked(self, index)`. unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item; } @@ -455,7 +459,7 @@ unsafe impl SpecTrustedRandomAccess for I { unsafe impl SpecTrustedRandomAccess for I { unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item { // SAFETY: the caller must uphold the contract for - // `Iterator::get_unchecked`. - unsafe { self.get_unchecked(index) } + // `Iterator::__iterator_get_unchecked`. + unsafe { self.__iterator_get_unchecked(index) } } } diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index f70e92f0ffafe..a75f1d56fb7e6 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -3241,10 +3241,12 @@ pub trait Iterator { } /// See [TrustedRandomAccess] + // The unusual name is to avoid name collisions in method resolution + // see #76479. #[inline] #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] - unsafe fn get_unchecked(&mut self, _idx: usize) -> Self::Item + unsafe fn __iterator_get_unchecked(&mut self, _idx: usize) -> Self::Item where Self: TrustedRandomAccess, { diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 546edef7f5753..76b8aa7d82162 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -1178,7 +1178,7 @@ impl<'a, T> Iterator for Windows<'a, T> { } #[doc(hidden)] - unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { // SAFETY: since the caller guarantees that `i` is in bounds, // which means that `i` cannot overflow an `isize`, and the // slice created by `from_raw_parts` is a subslice of `self.v` @@ -1324,7 +1324,7 @@ impl<'a, T> Iterator for Chunks<'a, T> { } #[doc(hidden)] - unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let start = idx * self.chunk_size; let end = match start.checked_add(self.chunk_size) { None => self.v.len(), @@ -1480,13 +1480,13 @@ impl<'a, T> Iterator for ChunksMut<'a, T> { } #[doc(hidden)] - unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let start = idx * self.chunk_size; let end = match start.checked_add(self.chunk_size) { None => self.v.len(), Some(end) => cmp::min(end, self.v.len()), }; - // SAFETY: see comments for `Chunks::get_unchecked`. + // SAFETY: see comments for `Chunks::__iterator_get_unchecked`. // // Also note that the caller also guarantees that we're never called // with the same index again, and that no other methods that will @@ -1642,9 +1642,9 @@ impl<'a, T> Iterator for ChunksExact<'a, T> { } #[doc(hidden)] - unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let start = idx * self.chunk_size; - // SAFETY: mostly identical to `Chunks::get_unchecked`. + // SAFETY: mostly identical to `Chunks::__iterator_get_unchecked`. unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) } } } @@ -1785,9 +1785,9 @@ impl<'a, T> Iterator for ChunksExactMut<'a, T> { } #[doc(hidden)] - unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let start = idx * self.chunk_size; - // SAFETY: see comments for `ChunksMut::get_unchecked`. + // SAFETY: see comments for `ChunksMut::__iterator_get_unchecked`. unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) } } } @@ -2030,10 +2030,10 @@ impl<'a, T, const N: usize> Iterator for ArrayChunks<'a, T, N> { self.iter.last() } - unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T; N] { - // SAFETY: The safety guarantees of `get_unchecked` are transferred to - // the caller. - unsafe { self.iter.get_unchecked(i) } + unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> &'a [T; N] { + // SAFETY: The safety guarantees of `__iterator_get_unchecked` are + // transferred to the caller. + unsafe { self.iter.__iterator_get_unchecked(i) } } } @@ -2141,10 +2141,10 @@ impl<'a, T, const N: usize> Iterator for ArrayChunksMut<'a, T, N> { self.iter.last() } - unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T; N] { - // SAFETY: The safety guarantees of `get_unchecked` are transferred to + unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> &'a mut [T; N] { + // SAFETY: The safety guarantees of `__iterator_get_unchecked` are transferred to // the caller. - unsafe { self.iter.get_unchecked(i) } + unsafe { self.iter.__iterator_get_unchecked(i) } } } @@ -2278,13 +2278,13 @@ impl<'a, T> Iterator for RChunks<'a, T> { } #[doc(hidden)] - unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let end = self.v.len() - idx * self.chunk_size; let start = match end.checked_sub(self.chunk_size) { None => 0, Some(start) => start, }; - // SAFETY: mostly identical to `Chunks::get_unchecked`. + // SAFETY: mostly identical to `Chunks::__iterator_get_unchecked`. unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) } } } @@ -2431,13 +2431,14 @@ impl<'a, T> Iterator for RChunksMut<'a, T> { } #[doc(hidden)] - unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let end = self.v.len() - idx * self.chunk_size; let start = match end.checked_sub(self.chunk_size) { None => 0, Some(start) => start, }; - // SAFETY: see comments for `RChunks::get_unchecked` and `ChunksMut::get_unchecked` + // SAFETY: see comments for `RChunks::__iterator_get_unchecked` and + // `ChunksMut::__iterator_get_unchecked` unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) } } } @@ -2585,11 +2586,11 @@ impl<'a, T> Iterator for RChunksExact<'a, T> { } #[doc(hidden)] - unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let end = self.v.len() - idx * self.chunk_size; let start = end - self.chunk_size; // SAFETY: - // SAFETY: mostmy identical to `Chunks::get_unchecked`. + // SAFETY: mostmy identical to `Chunks::__iterator_get_unchecked`. unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) } } } @@ -2734,10 +2735,10 @@ impl<'a, T> Iterator for RChunksExactMut<'a, T> { } #[doc(hidden)] - unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let end = self.v.len() - idx * self.chunk_size; let start = end - self.chunk_size; - // SAFETY: see comments for `RChunksMut::get_unchecked`. + // SAFETY: see comments for `RChunksMut::__iterator_get_unchecked`. unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) } } } diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index 9fcc7a71af8ad..457b2a3605e8b 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -318,7 +318,7 @@ macro_rules! iterator { } #[doc(hidden)] - unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { // SAFETY: the caller must guarantee that `i` is in bounds of // the underlying slice, so `i` cannot overflow an `isize`, and // the returned references is guaranteed to refer to an element diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 6dc14f9125fef..e4a6b7e142a51 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -813,10 +813,10 @@ impl Iterator for Bytes<'_> { } #[inline] - unsafe fn get_unchecked(&mut self, idx: usize) -> u8 { + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> u8 { // SAFETY: the caller must uphold the safety contract - // for `Iterator::get_unchecked`. - unsafe { self.0.get_unchecked(idx) } + // for `Iterator::__iterator_get_unchecked`. + unsafe { self.0.__iterator_get_unchecked(idx) } } } From 187162e9917b6255c5eb12434362e6c4cc9c6976 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 22 Sep 2020 22:27:18 +0200 Subject: [PATCH 0989/1052] Add missing code examples on slice iter types --- library/core/src/slice/iter.rs | 164 +++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 84fa34c75e3a2..1bac35845dff0 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -270,6 +270,13 @@ pub(super) trait SplitIter: DoubleEndedIterator { /// /// This struct is created by the [`split`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let slice = [10, 40, 33, 20]; +/// let mut iter = slice.split(|num| num % 3 == 0); +/// ``` +/// /// [`split`]: ../../std/primitive.slice.html#method.split /// [slices]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] @@ -378,6 +385,15 @@ impl FusedIterator for Split<'_, T, P> where P: FnMut(&T) -> bool {} /// /// This struct is created by the [`split_inclusive`] method on [slices]. /// +/// # Example +/// +/// ``` +/// #![feature(split_inclusive)] +/// +/// let slice = [10, 40, 33, 20]; +/// let mut iter = slice.split_inclusive(|num| num % 3 == 0); +/// ``` +/// /// [`split_inclusive`]: ../../std/primitive.slice.html#method.split_inclusive /// [slices]: ../../std/primitive.slice.html #[unstable(feature = "split_inclusive", issue = "72360")] @@ -476,6 +492,13 @@ impl FusedIterator for SplitInclusive<'_, T, P> where P: FnMut(&T) -> bool /// /// This struct is created by the [`split_mut`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let mut v = [10, 40, 30, 20, 60, 50]; +/// let iter = v.split_mut(|num| *num % 3 == 0); +/// ``` +/// /// [`split_mut`]: ../../std/primitive.slice.html#method.split_mut /// [slices]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] @@ -591,6 +614,15 @@ impl FusedIterator for SplitMut<'_, T, P> where P: FnMut(&T) -> bool {} /// /// This struct is created by the [`split_inclusive_mut`] method on [slices]. /// +/// # Example +/// +/// ``` +/// #![feature(split_inclusive)] +/// +/// let mut v = [10, 40, 30, 20, 60, 50]; +/// let iter = v.split_inclusive_mut(|num| *num % 3 == 0); +/// ``` +/// /// [`split_inclusive_mut`]: ../../std/primitive.slice.html#method.split_inclusive_mut /// [slices]: ../../std/primitive.slice.html #[unstable(feature = "split_inclusive", issue = "72360")] @@ -698,6 +730,13 @@ impl FusedIterator for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> b /// /// This struct is created by the [`rsplit`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let slice = [11, 22, 33, 0, 44, 55]; +/// let iter = slice.rsplit(|num| *num == 0); +/// ``` +/// /// [`rsplit`]: ../../std/primitive.slice.html#method.rsplit /// [slices]: ../../std/primitive.slice.html #[stable(feature = "slice_rsplit", since = "1.27.0")] @@ -770,6 +809,13 @@ impl FusedIterator for RSplit<'_, T, P> where P: FnMut(&T) -> bool {} /// /// This struct is created by the [`rsplit_mut`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let mut slice = [11, 22, 33, 0, 44, 55]; +/// let iter = slice.rsplit_mut(|num| *num == 0); +/// ``` +/// /// [`rsplit_mut`]: ../../std/primitive.slice.html#method.rsplit_mut /// [slices]: ../../std/primitive.slice.html #[stable(feature = "slice_rsplit", since = "1.27.0")] @@ -875,6 +921,13 @@ impl> Iterator for GenericSplitN { /// /// This struct is created by the [`splitn`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let slice = [10, 40, 30, 20, 60, 50]; +/// let iter = slice.splitn(2, |num| *num % 3 == 0); +/// ``` +/// /// [`splitn`]: ../../std/primitive.slice.html#method.splitn /// [slices]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] @@ -901,6 +954,13 @@ where /// /// This struct is created by the [`rsplitn`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let slice = [10, 40, 30, 20, 60, 50]; +/// let iter = slice.rsplitn(2, |num| *num % 3 == 0); +/// ``` +/// /// [`rsplitn`]: ../../std/primitive.slice.html#method.rsplitn /// [slices]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] @@ -926,6 +986,13 @@ where /// /// This struct is created by the [`splitn_mut`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let mut slice = [10, 40, 30, 20, 60, 50]; +/// let iter = slice.splitn_mut(2, |num| *num % 3 == 0); +/// ``` +/// /// [`splitn_mut`]: ../../std/primitive.slice.html#method.splitn_mut /// [slices]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] @@ -952,6 +1019,13 @@ where /// /// This struct is created by the [`rsplitn_mut`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let mut slice = [10, 40, 30, 20, 60, 50]; +/// let iter = slice.rsplitn_mut(2, |num| *num % 3 == 0); +/// ``` +/// /// [`rsplitn_mut`]: ../../std/primitive.slice.html#method.rsplitn_mut /// [slices]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] @@ -981,6 +1055,13 @@ forward_iterator! { RSplitNMut: T, &'a mut [T] } /// /// This struct is created by the [`windows`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let slice = ['r', 'u', 's', 't']; +/// let iter = slice.windows(2); +/// ``` +/// /// [`windows`]: ../../std/primitive.slice.html#method.windows /// [slices]: ../../std/primitive.slice.html #[derive(Debug)] @@ -1113,6 +1194,13 @@ unsafe impl<'a, T> TrustedRandomAccess for Windows<'a, T> { /// /// This struct is created by the [`chunks`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.chunks(2); +/// ``` +/// /// [`chunks`]: ../../std/primitive.slice.html#method.chunks /// [slices]: ../../std/primitive.slice.html #[derive(Debug)] @@ -1267,6 +1355,13 @@ unsafe impl<'a, T> TrustedRandomAccess for Chunks<'a, T> { /// /// This struct is created by the [`chunks_mut`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let mut slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.chunks_mut(2); +/// ``` +/// /// [`chunks_mut`]: ../../std/primitive.slice.html#method.chunks_mut /// [slices]: ../../std/primitive.slice.html #[derive(Debug)] @@ -1419,6 +1514,13 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> { /// /// This struct is created by the [`chunks_exact`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.chunks_exact(2); +/// ``` +/// /// [`chunks_exact`]: ../../std/primitive.slice.html#method.chunks_exact /// [`remainder`]: ChunksExact::remainder /// [slices]: ../../std/primitive.slice.html @@ -1559,6 +1661,13 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> { /// /// This struct is created by the [`chunks_exact_mut`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let mut slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.chunks_exact_mut(2); +/// ``` +/// /// [`chunks_exact_mut`]: ../../std/primitive.slice.html#method.chunks_exact_mut /// [`into_remainder`]: ChunksExactMut::into_remainder /// [slices]: ../../std/primitive.slice.html @@ -1692,6 +1801,15 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> { /// /// This struct is created by the [`array_windows`] method on [slices]. /// +/// # Example +/// +/// ``` +/// #![feature(array_windows)] +/// +/// let slice = [0, 1, 2, 3]; +/// let iter = slice.array_windows::<2>(); +/// ``` +/// /// [`array_windows`]: ../../std/primitive.slice.html#method.array_windows /// [slices]: ../../std/primitive.slice.html #[derive(Debug, Clone, Copy)] @@ -1796,6 +1914,15 @@ impl ExactSizeIterator for ArrayWindows<'_, T, N> { /// /// This struct is created by the [`array_chunks`] method on [slices]. /// +/// # Example +/// +/// ``` +/// #![feature(array_chunks)] +/// +/// let slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.array_chunks::<2>(); +/// ``` +/// /// [`array_chunks`]: ../../std/primitive.slice.html#method.array_chunks /// [`remainder`]: ArrayChunks::remainder /// [slices]: ../../std/primitive.slice.html @@ -1903,6 +2030,15 @@ unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> /// /// This struct is created by the [`array_chunks_mut`] method on [slices]. /// +/// # Example +/// +/// ``` +/// #![feature(array_chunks)] +/// +/// let mut slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.array_chunks_mut::<2>(); +/// ``` +/// /// [`array_chunks_mut`]: ../../std/primitive.slice.html#method.array_chunks_mut /// [`into_remainder`]: ../../std/slice/struct.ArrayChunksMut.html#method.into_remainder /// [slices]: ../../std/primitive.slice.html @@ -2001,6 +2137,13 @@ unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunksMut<'a, T, /// /// This struct is created by the [`rchunks`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.rchunks(2); +/// ``` +/// /// [`rchunks`]: ../../std/primitive.slice.html#method.rchunks /// [slices]: ../../std/primitive.slice.html #[derive(Debug)] @@ -2151,6 +2294,13 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> { /// /// This struct is created by the [`rchunks_mut`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let mut slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.rchunks_mut(2); +/// ``` +/// /// [`rchunks_mut`]: ../../std/primitive.slice.html#method.rchunks_mut /// [slices]: ../../std/primitive.slice.html #[derive(Debug)] @@ -2300,6 +2450,13 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> { /// /// This struct is created by the [`rchunks_exact`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.rchunks_exact(2); +/// ``` +/// /// [`rchunks_exact`]: ../../std/primitive.slice.html#method.rchunks_exact /// [`remainder`]: ChunksExact::remainder /// [slices]: ../../std/primitive.slice.html @@ -2445,6 +2602,13 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> { /// /// This struct is created by the [`rchunks_exact_mut`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let mut slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.rchunks_exact_mut(2); +/// ``` +/// /// [`rchunks_exact_mut`]: ../../std/primitive.slice.html#method.rchunks_exact_mut /// [`into_remainder`]: ChunksExactMut::into_remainder /// [slices]: ../../std/primitive.slice.html From 61d86fa06ca4d7c93109fc857300abbd25a19a0a Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 25 Sep 2020 13:48:48 -0700 Subject: [PATCH 0990/1052] Check for missing const-stability attributes in `stability` This used to happen as a side-effect of `is_min_const_fn`, which was subtle. --- compiler/rustc_passes/src/stability.rs | 38 +++++++++++++++++++++----- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 4ca52f405fb94..24972b5cc6a6f 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -368,6 +368,21 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { self.tcx.sess.span_err(span, &format!("{} has missing stability attribute", descr)); } } + + fn check_missing_const_stability(&self, hir_id: HirId, span: Span) { + let stab_map = self.tcx.stability(); + let stab = stab_map.local_stability(hir_id); + if stab.map_or(false, |stab| stab.level.is_stable()) { + let const_stab = stab_map.local_const_stability(hir_id); + if const_stab.is_none() { + self.tcx.sess.span_err( + span, + "`#[stable]` const functions must also be either \ + `#[rustc_const_stable]` or `#[rustc_const_unstable]`", + ); + } + } + } } impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { @@ -378,14 +393,23 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } fn visit_item(&mut self, i: &'tcx Item<'tcx>) { - match i.kind { - // Inherent impls and foreign modules serve only as containers for other items, - // 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(..) => {} + // Inherent impls and foreign modules serve only as containers for other items, + // 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. + if !matches!( + i.kind, + hir::ItemKind::Impl { of_trait: None, .. } | hir::ItemKind::ForeignMod(..) + ) { + self.check_missing_stability(i.hir_id, i.span); + } - _ => self.check_missing_stability(i.hir_id, i.span), + // Ensure `const fn` that are `stable` have one of `rustc_const_unstable` or + // `rustc_const_stable`. + if self.tcx.features().staged_api + && matches!(&i.kind, hir::ItemKind::Fn(sig, ..) if sig.header.is_const()) + { + self.check_missing_const_stability(i.hir_id, i.span); } intravisit::walk_item(self, i) From 11bfc60a4b5fa111527a69e5f511cb69ae5325af Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 25 Sep 2020 14:08:44 -0700 Subject: [PATCH 0991/1052] Change error in `fn_queries` to `delay_span_bug` This should be caught by the new check in `rustc_passes`. At some point, this function will be removed entirely. --- compiler/rustc_mir/src/const_eval/fn_queries.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/const_eval/fn_queries.rs b/compiler/rustc_mir/src/const_eval/fn_queries.rs index 9ef63b3322dd5..1db1f6ceedac5 100644 --- a/compiler/rustc_mir/src/const_eval/fn_queries.rs +++ b/compiler/rustc_mir/src/const_eval/fn_queries.rs @@ -50,7 +50,7 @@ pub fn is_min_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { None => { if let Some(stab) = tcx.lookup_stability(def_id) { if stab.level.is_stable() { - tcx.sess.span_err( + tcx.sess.delay_span_bug( tcx.def_span(def_id), "stable const functions must have either `rustc_const_stable` or \ `rustc_const_unstable` attribute", From 76c6f2dc3f0769653e80c58bd3f288594fa11dc6 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 25 Sep 2020 13:50:18 -0700 Subject: [PATCH 0992/1052] No need to call `is_min_const_fn` for side-effects --- compiler/rustc_mir/src/transform/check_consts/validation.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index dc28ba46d7cbb..3a5ae4c8348f5 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -204,9 +204,6 @@ impl Validator<'mir, 'tcx> { pub fn check_body(&mut self) { let ConstCx { tcx, body, def_id, .. } = *self.ccx; - // HACK: This function has side-effects???? Make sure we call it. - let _ = crate::const_eval::is_min_const_fn(tcx, def_id.to_def_id()); - // The local type and predicate checks are not free and only relevant for `const fn`s. if self.const_kind() == hir::ConstContext::ConstFn { // Prevent const trait methods from being annotated as `stable`. From 6ce178f60eec86cfd9245e6289598938df519359 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 25 Sep 2020 13:51:52 -0700 Subject: [PATCH 0993/1052] Test for missing const-stability attributes --- .../stability-attribute/missing-const-stability.rs | 12 ++++++++++++ .../missing-const-stability.stderr | 8 ++++++++ 2 files changed, 20 insertions(+) create mode 100644 src/test/ui/stability-attribute/missing-const-stability.rs create mode 100644 src/test/ui/stability-attribute/missing-const-stability.stderr diff --git a/src/test/ui/stability-attribute/missing-const-stability.rs b/src/test/ui/stability-attribute/missing-const-stability.rs new file mode 100644 index 0000000000000..7d499c611a43c --- /dev/null +++ b/src/test/ui/stability-attribute/missing-const-stability.rs @@ -0,0 +1,12 @@ +#![feature(staged_api)] + +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "foo", since = "1.0.0")] +pub const fn foo() {} +//~^ ERROR rustc_const_stable + +#[unstable(feature = "bar", issue = "none")] +pub const fn bar() {} // ok + +fn main() {} diff --git a/src/test/ui/stability-attribute/missing-const-stability.stderr b/src/test/ui/stability-attribute/missing-const-stability.stderr new file mode 100644 index 0000000000000..450a5303fd86f --- /dev/null +++ b/src/test/ui/stability-attribute/missing-const-stability.stderr @@ -0,0 +1,8 @@ +error: `#[stable]` const functions must also be either `#[rustc_const_stable]` or `#[rustc_const_unstable]` + --> $DIR/missing-const-stability.rs:6:1 + | +LL | pub const fn foo() {} + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + From 900daba2cbcc077f26b45c31c6a853ef5d4d6e9f Mon Sep 17 00:00:00 2001 From: LingMan Date: Fri, 25 Sep 2020 23:35:07 +0200 Subject: [PATCH 0994/1052] Remove stray word from `ClosureKind::extends` docs --- compiler/rustc_middle/src/ty/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 637ef4c17ebc8..492afa54445bc 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2675,7 +2675,7 @@ impl<'tcx> ClosureKind { } } - /// Returns `true` if this a type that impls this closure kind + /// Returns `true` if a type that impls this closure kind /// must also implement `other`. pub fn extends(self, other: ty::ClosureKind) -> bool { match (self, other) { From f1878d19faf9472f8860a3ff4fe605fdf93cef2c Mon Sep 17 00:00:00 2001 From: marmeladema Date: Mon, 31 Aug 2020 18:11:44 +0100 Subject: [PATCH 0995/1052] Move from {{closure}}#0 syntax to {closure#0} for (def) path components --- .../src/debuginfo/namespace.rs | 10 +++- .../src/debuginfo/type_names.rs | 10 +++- compiler/rustc_hir/src/definitions.rs | 57 ++++++++++++------- .../src/infer/error_reporting/mod.rs | 2 +- compiler/rustc_lint/src/context.rs | 9 ++- compiler/rustc_middle/src/ty/print/pretty.rs | 21 +++---- .../src/ty/query/profiling_support.rs | 30 ++++++---- .../src/interpret/intrinsics/type_name.rs | 9 ++- .../src/monomorphize/partitioning/default.rs | 8 ++- compiler/rustc_span/src/symbol.rs | 4 ++ compiler/rustc_symbol_mangling/src/legacy.rs | 7 ++- .../unused_type_parameters.rs | 46 +++++++-------- ...motion_extern_static.BAR.PromoteTemps.diff | 4 +- ...motion_extern_static.FOO.PromoteTemps.diff | 4 +- ...e_oob_for_slices.main.ConstProp.32bit.diff | 4 +- ...e_oob_for_slices.main.ConstProp.64bit.diff | 4 +- ..._prop_fails_gracefully.main.ConstProp.diff | 4 +- .../const_prop/ref_deref.main.ConstProp.diff | 4 +- .../ref_deref.main.PromoteTemps.diff | 4 +- .../ref_deref_project.main.ConstProp.diff | 4 +- .../ref_deref_project.main.PromoteTemps.diff | 4 +- .../slice_len.main.ConstProp.32bit.diff | 4 +- .../slice_len.main.ConstProp.64bit.diff | 4 +- src/test/mir-opt/generator-drop-cleanup.rs | 2 +- .../mir-opt/generator-storage-dead-unwind.rs | 2 +- src/test/mir-opt/generator-tiny.rs | 2 +- ...nup.main-{closure#0}.generator_drop.0.mir} | 4 +- ...ain-{closure#0}.StateTransform.before.mir} | 4 +- ...y.main-{closure#0}.generator_resume.0.mir} | 4 +- .../inline_closure.foo.Inline.after.mir | 4 +- ...e_closure_borrows_arg.foo.Inline.after.mir | 4 +- ...line_closure_captures.foo.Inline.after.mir | 4 +- .../inline/inline_retag.bar.Inline.after.mir | 8 +-- src/test/mir-opt/issue-41697.rs | 2 +- ...implifyCfg-promote-consts.after.32bit.mir} | 4 +- ...implifyCfg-promote-consts.after.64bit.mir} | 4 +- ..._73223.main.SimplifyArmIdentity.32bit.diff | 8 +-- ..._73223.main.SimplifyArmIdentity.64bit.diff | 8 +-- ...s.full_tested_match.PromoteTemps.after.mir | 4 +- ...#0}.SimplifyCfg-elaborate-drops.after.mir} | 4 +- ...main.SimplifyCfg-elaborate-drops.after.mir | 10 ++-- src/test/mir-opt/retag.rs | 6 +- ...foo.SimplifyCfg-elaborate-drops.after.mir} | 0 ...shr.SimplifyCfg-elaborate-drops.after.mir} | 0 src/test/mir-opt/simplify_try_if_let.rs | 2 +- ....{impl#0}-append.SimplifyArmIdentity.diff} | 0 src/test/mir-opt/unusual-item-types.rs | 6 +- ...ypes.E-V-{constant#0}.mir_map.0.32bit.mir} | 4 +- ...ypes.E-V-{constant#0}.mir_map.0.64bit.mir} | 4 +- ...est-X-{constructor#0}.mir_map.0.32bit.mir} | 0 ...est-X-{constructor#0}.mir_map.0.64bit.mir} | 0 ...}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir} | 0 ...}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir} | 0 ...finite-recursive-type-impl-trait-return.rs | 2 +- .../ui/async-await/issues/issue-67893.stderr | 4 +- .../ui/const-generics/nested-type.full.stderr | 2 +- .../ui/const-generics/nested-type.min.stderr | 2 +- src/test/ui/consts/const-size_of-cycle.stderr | 8 +-- .../issue-68542-closure-in-array-len.stderr | 2 +- src/test/ui/consts/miri_unleashed/tls.stderr | 4 +- src/test/ui/deprecation/deprecation-lint.rs | 2 +- .../ui/deprecation/deprecation-lint.stderr | 2 +- src/test/ui/impl-trait/auto-trait-leak.stderr | 6 +- .../infinite-recursion-const-fn.stderr | 2 +- src/test/ui/issues/issue-17252.stderr | 2 +- src/test/ui/issues/issue-23302-1.stderr | 8 +-- src/test/ui/issues/issue-23302-2.stderr | 8 +-- src/test/ui/issues/issue-36163.stderr | 8 +-- .../escape-argument-callee.stderr | 2 +- .../escape-argument.stderr | 2 +- .../escape-upvar-nested.stderr | 4 +- .../escape-upvar-ref.stderr | 2 +- ...pagate-approximated-fail-no-postdom.stderr | 2 +- .../propagate-approximated-ref.stderr | 2 +- ...er-to-static-comparing-against-free.stderr | 4 +- ...oximated-shorter-to-static-no-bound.stderr | 2 +- ...mated-shorter-to-static-wrong-bound.stderr | 2 +- .../propagate-approximated-val.stderr | 2 +- .../propagate-despite-same-free-region.stderr | 2 +- ...ail-to-approximate-longer-no-bounds.stderr | 2 +- ...-to-approximate-longer-wrong-bounds.stderr | 2 +- .../propagate-from-trait-match.stderr | 2 +- .../return-wrong-bound-region.stderr | 2 +- .../projection-no-regions-closure.stderr | 8 +-- .../projection-one-region-closure.stderr | 8 +-- ...tion-one-region-trait-bound-closure.stderr | 10 ++-- ...e-region-trait-bound-static-closure.stderr | 10 ++-- ...tion-two-region-trait-bound-closure.stderr | 16 +++--- ...ram-closure-approximate-lower-bound.stderr | 4 +- ...m-closure-outlives-from-return-type.stderr | 2 +- ...-closure-outlives-from-where-clause.stderr | 8 +-- .../repeated_projection_type.stderr | 2 +- .../self-in-enum-definition.stderr | 8 +-- 93 files changed, 298 insertions(+), 235 deletions(-) rename src/test/mir-opt/{generator_drop_cleanup.main-{{closure}}.generator_drop.0.mir => generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir} (95%) rename src/test/mir-opt/{generator_storage_dead_unwind.main-{{closure}}.StateTransform.before.mir => generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir} (97%) rename src/test/mir-opt/{generator_tiny.main-{{closure}}.generator_resume.0.mir => generator_tiny.main-{closure#0}.generator_resume.0.mir} (95%) rename src/test/mir-opt/{issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.64bit.mir => issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir} (82%) rename src/test/mir-opt/{issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.32bit.mir => issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir} (82%) rename src/test/mir-opt/{retag.main-{{closure}}.SimplifyCfg-elaborate-drops.after.mir => retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir} (88%) rename src/test/mir-opt/{retag.{{impl}}-foo.SimplifyCfg-elaborate-drops.after.mir => retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir} (100%) rename src/test/mir-opt/{retag.{{impl}}-foo_shr.SimplifyCfg-elaborate-drops.after.mir => retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir} (100%) rename src/test/mir-opt/{simplify_try_if_let.{{impl}}-append.SimplifyArmIdentity.diff => simplify_try_if_let.{impl#0}-append.SimplifyArmIdentity.diff} (100%) rename src/test/mir-opt/{unusual_item_types.E-V-{{constant}}.mir_map.0.32bit.mir => unusual_item_types.E-V-{constant#0}.mir_map.0.32bit.mir} (85%) rename src/test/mir-opt/{unusual_item_types.E-V-{{constant}}.mir_map.0.64bit.mir => unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir} (85%) rename src/test/mir-opt/{unusual_item_types.Test-X-{{constructor}}.mir_map.0.32bit.mir => unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir} (100%) rename src/test/mir-opt/{unusual_item_types.Test-X-{{constructor}}.mir_map.0.64bit.mir => unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir} (100%) rename src/test/mir-opt/{unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir => unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir} (100%) rename src/test/mir-opt/{unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir => unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir} (100%) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs index d1a55335c44e7..835d0d2e12d66 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs @@ -7,7 +7,8 @@ use crate::common::CodegenCx; use crate::llvm; use crate::llvm::debuginfo::DIScope; use rustc_hir::def_id::DefId; -use rustc_hir::definitions::DefPathData; +use rustc_hir::definitions::{DefPathData, DefPathDataName}; +use rustc_span::symbol::Symbol; pub fn mangled_name_of_instance<'a, 'tcx>( cx: &CodegenCx<'a, 'tcx>, @@ -29,7 +30,12 @@ pub fn item_namespace(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope { let namespace_name = match def_key.disambiguated_data.data { DefPathData::CrateRoot => cx.tcx.crate_name(def_id.krate), - data => data.as_symbol(), + data => match data.get_name() { + DefPathDataName::Named(name) => name, + DefPathDataName::Anon { namespace } => { + Symbol::intern(&format!("{{{{{}}}}}", namespace)) + } + }, }; let namespace_name = namespace_name.as_str(); diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 0c0f1bc681cf8..e227f9df000e1 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -3,8 +3,11 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_hir::definitions::DefPathDataName; use rustc_middle::ty::{self, subst::SubstsRef, Ty, TyCtxt}; +use std::fmt::Write; + // Compute the name of the type as it should be stored in debuginfo. Does not do // any caching, i.e., calling the function twice with the same type will also do // the work twice. The `qualified` parameter only affects the first level of the @@ -229,7 +232,12 @@ pub fn push_debuginfo_type_name<'tcx>( output.push_str(&tcx.crate_name(def_id.krate).as_str()); for path_element in tcx.def_path(def_id).data { output.push_str("::"); - output.push_str(&path_element.data.as_symbol().as_str()); + match path_element.data.get_name() { + DefPathDataName::Named(name) => output.push_str(&name.as_str()), + DefPathDataName::Anon { namespace } => { + write!(output, "{{{{{}}}}}", namespace).unwrap() + } + } } } else { output.push_str(&tcx.item_name(def_id).as_str()); diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 45befc7b11586..c825042bdcd02 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -13,7 +13,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::StableHasher; use rustc_index::vec::IndexVec; use rustc_span::hygiene::ExpnId; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{kw, sym, Symbol}; use std::fmt::Write; use std::hash::Hash; @@ -202,7 +202,12 @@ impl DefPath { let mut s = String::with_capacity(self.data.len() * 16); for component in &self.data { - write!(s, "::{}[{}]", component.data.as_symbol(), component.disambiguator).unwrap(); + match component.data.get_name() { + DefPathDataName::Named(name) => write!(s, "::{}", name).unwrap(), + DefPathDataName::Anon { namespace } => { + write!(s, "::{{{}#{}}}", namespace, component.disambiguator).unwrap() + } + } } s @@ -220,10 +225,11 @@ impl DefPath { write!(s, "::{}", crate_name_str).unwrap(); for component in &self.data { - if component.disambiguator == 0 { - write!(s, "::{}", component.data.as_symbol()).unwrap(); - } else { - write!(s, "{}[{}]", component.data.as_symbol(), component.disambiguator).unwrap(); + match component.data.get_name() { + DefPathDataName::Named(name) => write!(s, "::{}", name).unwrap(), + DefPathDataName::Anon { namespace } => { + write!(s, "{{{}#{}}}", namespace, component.disambiguator).unwrap() + } } } @@ -240,10 +246,11 @@ impl DefPath { for component in &self.data { s.extend(opt_delimiter); opt_delimiter = Some('-'); - if component.disambiguator == 0 { - write!(s, "{}", component.data.as_symbol()).unwrap(); - } else { - write!(s, "{}[{}]", component.data.as_symbol(), component.disambiguator).unwrap(); + match component.data.get_name() { + DefPathDataName::Named(name) => write!(s, "{}", name).unwrap(), + DefPathDataName::Anon { namespace } => { + write!(s, "{{{}#{}}}", namespace, component.disambiguator).unwrap() + } } } s @@ -427,6 +434,11 @@ impl Definitions { } } +pub enum DefPathDataName { + Named(Symbol), + Anon { namespace: Symbol }, +} + impl DefPathData { pub fn get_opt_name(&self) -> Option { use self::DefPathData::*; @@ -437,22 +449,27 @@ impl DefPathData { } } - pub fn as_symbol(&self) -> Symbol { + pub fn get_name(&self) -> DefPathDataName { use self::DefPathData::*; match *self { - TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => name, + TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => { + DefPathDataName::Named(name) + } // Note that this does not show up in user print-outs. - CrateRoot => sym::double_braced_crate, - Impl => sym::double_braced_impl, - Misc => sym::double_braced_misc, - ClosureExpr => sym::double_braced_closure, - Ctor => sym::double_braced_constructor, - AnonConst => sym::double_braced_constant, - ImplTrait => sym::double_braced_opaque, + CrateRoot => DefPathDataName::Anon { namespace: kw::Crate }, + Impl => DefPathDataName::Anon { namespace: kw::Impl }, + Misc => DefPathDataName::Anon { namespace: sym::misc }, + ClosureExpr => DefPathDataName::Anon { namespace: sym::closure }, + Ctor => DefPathDataName::Anon { namespace: sym::constructor }, + AnonConst => DefPathDataName::Anon { namespace: sym::constant }, + ImplTrait => DefPathDataName::Anon { namespace: sym::opaque }, } } pub fn to_string(&self) -> String { - self.as_symbol().to_string() + match self.get_name() { + DefPathDataName::Named(name) => name.to_string(), + DefPathDataName::Anon { namespace } => format!("{{{{{}}}}}", namespace), + } } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index bcfcee23d13fe..a99193c972bd4 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -531,7 +531,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { disambiguated_data: &DisambiguatedDefPathData, ) -> Result { let mut path = print_prefix(self)?; - path.push(disambiguated_data.data.as_symbol().to_string()); + path.push(disambiguated_data.data.to_string()); Ok(path) } fn path_generic_args( diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 0265fc323b3b3..e4b72847638cd 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -26,7 +26,7 @@ use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::{CrateNum, DefId}; -use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; +use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData}; use rustc_middle::lint::LintDiagnosticBuilder; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::middle::stability; @@ -846,7 +846,12 @@ impl<'tcx> LateContext<'tcx> { return Ok(path); } - path.push(disambiguated_data.data.as_symbol()); + path.push(match disambiguated_data.data.get_name() { + DefPathDataName::Named(name) => name, + DefPathDataName::Anon { namespace } => { + Symbol::intern(&format!("{{{{{}}}}}", namespace)) + } + }); Ok(path) } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index c9cc9bfc9fa26..91986289099d3 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -11,7 +11,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::def::{self, CtorKind, DefKind, Namespace}; use rustc_hir::def_id::{CrateNum, DefId, DefIdSet, CRATE_DEF_INDEX, LOCAL_CRATE}; -use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; +use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData}; use rustc_hir::ItemKind; use rustc_session::config::TrimmedDefPaths; use rustc_span::symbol::{kw, Ident, Symbol}; @@ -1496,9 +1496,13 @@ impl Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { return Ok(self); } + let name = match disambiguated_data.data.get_name() { + DefPathDataName::Named(name) => name, + DefPathDataName::Anon { namespace } => namespace, + }; + // FIXME(eddyb) `name` should never be empty, but it // currently is for `extern { ... }` "foreign modules". - let name = disambiguated_data.data.as_symbol(); if name != kw::Invalid { if !self.empty_path { write!(self, "::")?; @@ -1506,15 +1510,12 @@ impl Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { if Ident::with_dummy_span(name).is_raw_guess() { write!(self, "r#")?; } - write!(self, "{}", name)?; - // FIXME(eddyb) this will print e.g. `{{closure}}#3`, but it - // might be nicer to use something else, e.g. `{closure#3}`. - let dis = disambiguated_data.disambiguator; - let print_dis = disambiguated_data.data.get_opt_name().is_none() - || dis != 0 && self.tcx.sess.verbose(); - if print_dis { - write!(self, "#{}", dis)?; + match disambiguated_data.data.get_name() { + DefPathDataName::Named(name) => self.write_str(&name.as_str())?, + DefPathDataName::Anon { namespace } => { + write!(self, "{{{}#{}}}", namespace, disambiguated_data.disambiguator)? + } } self.empty_path = false; diff --git a/compiler/rustc_middle/src/ty/query/profiling_support.rs b/compiler/rustc_middle/src/ty/query/profiling_support.rs index 9b1837356e305..cecb58eb024c0 100644 --- a/compiler/rustc_middle/src/ty/query/profiling_support.rs +++ b/compiler/rustc_middle/src/ty/query/profiling_support.rs @@ -4,7 +4,7 @@ use measureme::{StringComponent, StringId}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::profiling::SelfProfiler; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; -use rustc_hir::definitions::DefPathData; +use rustc_hir::definitions::{DefPathData, DefPathDataName}; use rustc_query_system::query::QueryCache; use rustc_query_system::query::QueryState; use std::fmt::Debug; @@ -66,17 +66,25 @@ impl<'p, 'c, 'tcx> QueryKeyStringBuilder<'p, 'c, 'tcx> { end_index = 3; } other => { - name = other.as_symbol(); - if def_key.disambiguated_data.disambiguator == 0 { - dis = ""; - end_index = 3; - } else { - write!(&mut dis_buffer[..], "[{}]", def_key.disambiguated_data.disambiguator) + name = match other.get_name() { + DefPathDataName::Named(name) => { + dis = ""; + end_index = 3; + name + } + DefPathDataName::Anon { namespace } => { + write!( + &mut dis_buffer[..], + "[{}]", + def_key.disambiguated_data.disambiguator + ) .unwrap(); - let end_of_dis = dis_buffer.iter().position(|&c| c == b']').unwrap(); - dis = std::str::from_utf8(&dis_buffer[..end_of_dis + 1]).unwrap(); - end_index = 4; - } + let end_of_dis = dis_buffer.iter().position(|&c| c == b']').unwrap(); + dis = std::str::from_utf8(&dis_buffer[..end_of_dis + 1]).unwrap(); + end_index = 4; + namespace + } + }; } } diff --git a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs index 8c0014e10d0e6..8cf768a006bbf 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs @@ -1,5 +1,5 @@ use rustc_hir::def_id::CrateNum; -use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; +use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData}; use rustc_middle::mir::interpret::Allocation; use rustc_middle::ty::{ self, @@ -134,7 +134,12 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { self.path.push_str("::"); - self.path.push_str(&disambiguated_data.data.as_symbol().as_str()); + match disambiguated_data.data.get_name() { + DefPathDataName::Named(name) => self.path.write_str(&name.as_str()).unwrap(), + DefPathDataName::Anon { namespace } => { + write!(self.path, "{{{{{}}}}}", namespace).unwrap() + } + } Ok(self) } diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs index 827d037f31988..c9622df099f83 100644 --- a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs @@ -3,6 +3,7 @@ use std::collections::hash_map::Entry; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc_hir::definitions::DefPathDataName; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::exported_symbols::SymbolExportLevel; use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, Linkage, Visibility}; @@ -354,7 +355,12 @@ fn compute_codegen_unit_name( *cache.entry((cgu_def_id, volatile)).or_insert_with(|| { let def_path = tcx.def_path(cgu_def_id); - let components = def_path.data.iter().map(|part| part.data.as_symbol()); + let components = def_path.data.iter().map(|part| match part.data.get_name() { + DefPathDataName::Named(name) => name, + DefPathDataName::Anon { namespace } => { + Symbol::intern(&format!("{{{{{}}}}}", namespace)) + } + }); let volatile_suffix = volatile.then_some("volatile"); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 2d5c6451d1a52..a63e9e933aebe 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -333,6 +333,7 @@ symbols! { clone, clone_closures, clone_from, + closure, closure_to_fn_coercion, cmp, cmpxchg16b_target_feature, @@ -369,6 +370,8 @@ symbols! { const_trait_bound_opt_out, const_trait_impl, const_transmute, + constant, + constructor, contents, context, convert, @@ -679,6 +682,7 @@ symbols! { minnumf32, minnumf64, mips_target_feature, + misc, module, module_path, more_struct_aliases, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 6f9fc115cae9b..15eab8bb8572b 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -1,6 +1,6 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::def_id::CrateNum; -use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; +use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData}; use rustc_middle::ich::NodeIdHashingMode; use rustc_middle::mir::interpret::{ConstValue, Scalar}; use rustc_middle::ty::print::{PrettyPrinter, Print, Printer}; @@ -316,7 +316,10 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> { self.path.finalize_pending_component(); } - self.write_str(&disambiguated_data.data.as_symbol().as_str())?; + match disambiguated_data.data.get_name() { + DefPathDataName::Named(name) => self.write_str(&name.as_str())?, + DefPathDataName::Anon { namespace } => write!(self, "{{{{{}}}}}", namespace)?, + } Ok(self) } fn path_generic_args( diff --git a/src/test/codegen-units/polymorphization/unused_type_parameters.rs b/src/test/codegen-units/polymorphization/unused_type_parameters.rs index 13be99635a518..c2e06d067dc6e 100644 --- a/src/test/codegen-units/polymorphization/unused_type_parameters.rs +++ b/src/test/codegen-units/polymorphization/unused_type_parameters.rs @@ -64,7 +64,7 @@ mod closures { add_one(3) } -//~ MONO_ITEM fn closures::unused::::{{closure}}#0 +//~ MONO_ITEM fn closures::unused::::{closure#0} //~ MONO_ITEM fn closures::unused:: // Function has an unused type parameter in closure, but not in parent. @@ -74,7 +74,7 @@ mod closures { add_one(3) } -//~ MONO_ITEM fn closures::used_parent::::{{closure}}#0 +//~ MONO_ITEM fn closures::used_parent::::{closure#0} //~ MONO_ITEM fn closures::used_parent:: //~ MONO_ITEM fn closures::used_parent:: @@ -88,8 +88,8 @@ mod closures { x() } -//~ MONO_ITEM fn closures::used_binding_value::::{{closure}}#0 -//~ MONO_ITEM fn closures::used_binding_value::::{{closure}}#0 +//~ MONO_ITEM fn closures::used_binding_value::::{closure#0} +//~ MONO_ITEM fn closures::used_binding_value::::{closure#0} //~ MONO_ITEM fn closures::used_binding_value:: //~ MONO_ITEM fn closures::used_binding_value:: @@ -103,8 +103,8 @@ mod closures { x() } -//~ MONO_ITEM fn closures::used_binding_type::::{{closure}}#0 -//~ MONO_ITEM fn closures::used_binding_type::::{{closure}}#0 +//~ MONO_ITEM fn closures::used_binding_type::::{closure#0} +//~ MONO_ITEM fn closures::used_binding_type::::{closure#0} //~ MONO_ITEM fn closures::used_binding_type:: //~ MONO_ITEM fn closures::used_binding_type:: @@ -114,8 +114,8 @@ mod closures { x(t) } -//~ MONO_ITEM fn closures::used_argument::::{{closure}}#0 -//~ MONO_ITEM fn closures::used_argument::::{{closure}}#0 +//~ MONO_ITEM fn closures::used_argument::::{closure#0} +//~ MONO_ITEM fn closures::used_argument::::{closure#0} //~ MONO_ITEM fn closures::used_argument:: //~ MONO_ITEM fn closures::used_argument:: @@ -126,8 +126,8 @@ mod closures { x(t) } -//~ MONO_ITEM fn closures::used_argument_closure::::{{closure}}#0 -//~ MONO_ITEM fn closures::used_argument_closure::::{{closure}}#0 +//~ MONO_ITEM fn closures::used_argument_closure::::{closure#0} +//~ MONO_ITEM fn closures::used_argument_closure::::{closure#0} //~ MONO_ITEM fn closures::used_argument_closure:: //~ MONO_ITEM fn closures::used_argument_closure:: @@ -138,8 +138,8 @@ mod closures { y() } -//~ MONO_ITEM fn closures::used_upvar::::{{closure}}#0 -//~ MONO_ITEM fn closures::used_upvar::::{{closure}}#0 +//~ MONO_ITEM fn closures::used_upvar::::{closure#0} +//~ MONO_ITEM fn closures::used_upvar::::{closure#0} //~ MONO_ITEM fn closures::used_upvar:: //~ MONO_ITEM fn closures::used_upvar:: @@ -149,8 +149,8 @@ mod closures { x() } -//~ MONO_ITEM fn closures::used_substs::::{{closure}}#0 -//~ MONO_ITEM fn closures::used_substs::::{{closure}}#0 +//~ MONO_ITEM fn closures::used_substs::::{closure#0} +//~ MONO_ITEM fn closures::used_substs::::{closure#0} //~ MONO_ITEM fn closures::used_substs:: //~ MONO_ITEM fn closures::used_substs:: } @@ -210,7 +210,7 @@ mod methods { add_one(3) } -//~ MONO_ITEM fn methods::Foo::::closure_unused_all::::{{closure}}#0 +//~ MONO_ITEM fn methods::Foo::::closure_unused_all::::{closure#0} //~ MONO_ITEM fn methods::Foo::::closure_unused_all:: // Function uses type parameter from impl and fn in closure. @@ -224,8 +224,8 @@ mod methods { add_one(3) } -//~ MONO_ITEM fn methods::Foo::::closure_used_both::::{{closure}}#0 -//~ MONO_ITEM fn methods::Foo::::closure_used_both::::{{closure}}#0 +//~ MONO_ITEM fn methods::Foo::::closure_used_both::::{closure#0} +//~ MONO_ITEM fn methods::Foo::::closure_used_both::::{closure#0} //~ MONO_ITEM fn methods::Foo::::closure_used_both:: //~ MONO_ITEM fn methods::Foo::::closure_used_both:: @@ -239,8 +239,8 @@ mod methods { add_one(3) } -//~ MONO_ITEM fn methods::Foo::::closure_used_fn::::{{closure}}#0 -//~ MONO_ITEM fn methods::Foo::::closure_used_fn::::{{closure}}#0 +//~ MONO_ITEM fn methods::Foo::::closure_used_fn::::{closure#0} +//~ MONO_ITEM fn methods::Foo::::closure_used_fn::::{closure#0} //~ MONO_ITEM fn methods::Foo::::closure_used_fn:: //~ MONO_ITEM fn methods::Foo::::closure_used_fn:: @@ -254,8 +254,8 @@ mod methods { add_one(3) } -//~ MONO_ITEM fn methods::Foo::::closure_used_impl::::{{closure}}#0 -//~ MONO_ITEM fn methods::Foo::::closure_used_impl::::{{closure}}#0 +//~ MONO_ITEM fn methods::Foo::::closure_used_impl::::{closure#0} +//~ MONO_ITEM fn methods::Foo::::closure_used_impl::::{closure#0} //~ MONO_ITEM fn methods::Foo::::closure_used_impl:: //~ MONO_ITEM fn methods::Foo::::closure_used_impl:: @@ -265,8 +265,8 @@ mod methods { x() } -//~ MONO_ITEM fn methods::Foo::::closure_used_substs::{{closure}}#0 -//~ MONO_ITEM fn methods::Foo::::closure_used_substs::{{closure}}#0 +//~ MONO_ITEM fn methods::Foo::::closure_used_substs::{closure#0} +//~ MONO_ITEM fn methods::Foo::::closure_used_substs::{closure#0} //~ MONO_ITEM fn methods::Foo::::closure_used_substs //~ MONO_ITEM fn methods::Foo::::closure_used_substs } diff --git a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff index 6acb8e46e75c1..c8c15792a2b33 100644 --- a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff +++ b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff @@ -22,7 +22,7 @@ - // + ty: &i32 - // + val: Value(Scalar(alloc0)) + // + ty: &[&i32; 1] -+ // + val: Unevaluated(WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[317d]::BAR[0]), const_param_did: None }, [], Some(promoted[0])) ++ // + val: Unevaluated(WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[317d]::BAR), const_param_did: None }, [], Some(promoted[0])) // mir::Constant - // + span: $DIR/const-promotion-extern-static.rs:9:33: 9:34 - // + literal: Const { ty: &i32, val: Value(Scalar(alloc0)) } @@ -30,7 +30,7 @@ - _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 - _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 + // + span: $DIR/const-promotion-extern-static.rs:9:31: 9:35 -+ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[317d]::BAR[0]), const_param_did: None }, [], Some(promoted[0])) } ++ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[317d]::BAR), const_param_did: None }, [], Some(promoted[0])) } + _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 _0 = core::slice::::as_ptr(move _1) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff index 2f7a2d7288447..ddf79fca9f639 100644 --- a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff +++ b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff @@ -24,7 +24,7 @@ - // + ty: &i32 - // + val: Value(Scalar(alloc2)) + // + ty: &[&i32; 1] -+ // + val: Unevaluated(WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO[0]), const_param_did: None }, [], Some(promoted[0])) ++ // + val: Unevaluated(WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO), const_param_did: None }, [], Some(promoted[0])) // mir::Constant - // + span: $DIR/const-promotion-extern-static.rs:13:42: 13:43 - // + literal: Const { ty: &i32, val: Value(Scalar(alloc2)) } @@ -32,7 +32,7 @@ - _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 - _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 + // + span: $DIR/const-promotion-extern-static.rs:13:31: 13:46 -+ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO[0]), const_param_did: None }, [], Some(promoted[0])) } ++ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO), const_param_did: None }, [], Some(promoted[0])) } + _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 _0 = core::slice::::as_ptr(move _1) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff index 245a7de5e9925..5f81cb6e9129f 100644 --- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff +++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff @@ -28,10 +28,10 @@ _9 = const main::promoted[0]; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 // ty::Const // + ty: &[i32; 3] - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 - // + literal: Const { ty: &[i32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &[i32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main), const_param_did: None }, [], Some(promoted[0])) } _3 = _9; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 _2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff index 245a7de5e9925..5f81cb6e9129f 100644 --- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff +++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff @@ -28,10 +28,10 @@ _9 = const main::promoted[0]; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 // ty::Const // + ty: &[i32; 3] - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 - // + literal: Const { ty: &[i32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &[i32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main), const_param_did: None }, [], Some(promoted[0])) } _3 = _9; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 _2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 diff --git a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff index 916a876b58288..6034645864656 100644 --- a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff @@ -19,10 +19,10 @@ _3 = const FOO; // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 // ty::Const // + ty: &i32 - // + val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[317d]::main[0]::FOO[0]), const_param_did: None }, [], None) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[317d]::main::FOO), const_param_did: None }, [], None) // mir::Constant // + span: $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 - // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[317d]::main[0]::FOO[0]), const_param_did: None }, [], None) } + // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[317d]::main::FOO), const_param_did: None }, [], None) } _2 = &raw const (*_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 _1 = move _2 as usize (Misc); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39 StorageDead(_2); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:38: 7:39 diff --git a/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff index e8168c98f0bcd..feef65f52ebe0 100644 --- a/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff @@ -14,10 +14,10 @@ _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 // ty::Const // + ty: &i32 - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/ref_deref.rs:5:6: 5:10 - // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main), const_param_did: None }, [], Some(promoted[0])) } _2 = _4; // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 - _1 = (*_4); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10 + _1 = const 4_i32; // scope 0 at $DIR/ref_deref.rs:5:5: 5:10 diff --git a/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff b/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff index c9caf07a737ff..e7ebfee7f3e01 100644 --- a/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff +++ b/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff @@ -17,10 +17,10 @@ + _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 + // ty::Const + // + ty: &i32 -+ // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) ++ // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main), const_param_did: None }, [], Some(promoted[0])) + // mir::Constant + // + span: $DIR/ref_deref.rs:5:6: 5:10 -+ // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } ++ // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main), const_param_did: None }, [], Some(promoted[0])) } + _2 = &(*_4); // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10 - StorageDead(_3); // scope 0 at $DIR/ref_deref.rs:5:10: 5:11 diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff index fd6388b95e477..7ec0751263fb1 100644 --- a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff @@ -14,10 +14,10 @@ _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 // ty::Const // + ty: &(i32, i32) - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/ref_deref_project.rs:5:6: 5:17 - // + literal: Const { ty: &(i32, i32), val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &(i32, i32), val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main), const_param_did: None }, [], Some(promoted[0])) } _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 _1 = ((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17 StorageDead(_2); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18 diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff index 43e4b32a6cdbe..588c291bcc37a 100644 --- a/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff +++ b/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff @@ -17,10 +17,10 @@ + _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 + // ty::Const + // + ty: &(i32, i32) -+ // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) ++ // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main), const_param_did: None }, [], Some(promoted[0])) + // mir::Constant + // + span: $DIR/ref_deref_project.rs:5:6: 5:17 -+ // + literal: Const { ty: &(i32, i32), val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } ++ // + literal: Const { ty: &(i32, i32), val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main), const_param_did: None }, [], Some(promoted[0])) } + _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 _1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17 - StorageDead(_3); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18 diff --git a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff index 02c4391baf560..f15dcf2338841 100644 --- a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff +++ b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff @@ -21,10 +21,10 @@ _9 = const main::promoted[0]; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 // ty::Const // + ty: &[u32; 3] - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/slice_len.rs:5:6: 5:19 - // + literal: Const { ty: &[u32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &[u32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main), const_param_did: None }, [], Some(promoted[0])) } _4 = _9; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _3 = _4; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 diff --git a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff index 02c4391baf560..f15dcf2338841 100644 --- a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff +++ b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff @@ -21,10 +21,10 @@ _9 = const main::promoted[0]; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 // ty::Const // + ty: &[u32; 3] - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/slice_len.rs:5:6: 5:19 - // + literal: Const { ty: &[u32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &[u32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main), const_param_did: None }, [], Some(promoted[0])) } _4 = _9; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _3 = _4; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 diff --git a/src/test/mir-opt/generator-drop-cleanup.rs b/src/test/mir-opt/generator-drop-cleanup.rs index f4fc2aec706a3..82c1292cbd05c 100644 --- a/src/test/mir-opt/generator-drop-cleanup.rs +++ b/src/test/mir-opt/generator-drop-cleanup.rs @@ -5,7 +5,7 @@ // Regression test for #58892, generator drop shims should not have blocks // spuriously marked as cleanup -// EMIT_MIR generator_drop_cleanup.main-{{closure}}.generator_drop.0.mir +// EMIT_MIR generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir fn main() { let gen = || { let _s = String::new(); diff --git a/src/test/mir-opt/generator-storage-dead-unwind.rs b/src/test/mir-opt/generator-storage-dead-unwind.rs index ae9faaefdd5c9..b72170adec37a 100644 --- a/src/test/mir-opt/generator-storage-dead-unwind.rs +++ b/src/test/mir-opt/generator-storage-dead-unwind.rs @@ -17,7 +17,7 @@ struct Bar(i32); fn take(_x: T) {} -// EMIT_MIR generator_storage_dead_unwind.main-{{closure}}.StateTransform.before.mir +// EMIT_MIR generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir fn main() { let _gen = || { let a = Foo(5); diff --git a/src/test/mir-opt/generator-tiny.rs b/src/test/mir-opt/generator-tiny.rs index 0e79f16255b47..7dad63a61d6d8 100644 --- a/src/test/mir-opt/generator-tiny.rs +++ b/src/test/mir-opt/generator-tiny.rs @@ -14,7 +14,7 @@ impl Drop for HasDrop { fn callee() {} -// EMIT_MIR generator_tiny.main-{{closure}}.generator_resume.0.mir +// EMIT_MIR generator_tiny.main-{closure#0}.generator_resume.0.mir fn main() { let _gen = |_x: u8| { let _d = HasDrop; diff --git a/src/test/mir-opt/generator_drop_cleanup.main-{{closure}}.generator_drop.0.mir b/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir similarity index 95% rename from src/test/mir-opt/generator_drop_cleanup.main-{{closure}}.generator_drop.0.mir rename to src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir index 89396b64fce43..31f85469c2606 100644 --- a/src/test/mir-opt/generator_drop_cleanup.main-{{closure}}.generator_drop.0.mir +++ b/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir @@ -1,4 +1,4 @@ -// MIR for `main::{{closure}}#0` 0 generator_drop +// MIR for `main::{closure#0}` 0 generator_drop /* generator_layout = GeneratorLayout { field_tys: { _0: std::string::String, @@ -14,7 +14,7 @@ }, } */ -fn main::{{closure}}#0(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 13:6 {String, ()}]) -> () { +fn main::{closure#0}(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 13:6 {String, ()}]) -> () { let mut _0: (); // return place in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 let mut _2: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 let _3: std::string::String; // in scope 0 at $DIR/generator-drop-cleanup.rs:11:13: 11:15 diff --git a/src/test/mir-opt/generator_storage_dead_unwind.main-{{closure}}.StateTransform.before.mir b/src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir similarity index 97% rename from src/test/mir-opt/generator_storage_dead_unwind.main-{{closure}}.StateTransform.before.mir rename to src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir index b6cda80683171..b76e41230e4c0 100644 --- a/src/test/mir-opt/generator_storage_dead_unwind.main-{{closure}}.StateTransform.before.mir +++ b/src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir @@ -1,6 +1,6 @@ -// MIR for `main::{{closure}}#0` before StateTransform +// MIR for `main::{closure#0}` before StateTransform -fn main::{{closure}}#0(_1: [generator@$DIR/generator-storage-dead-unwind.rs:22:16: 28:6 {Foo, Bar, ()}], _2: ()) -> () +fn main::{closure#0}(_1: [generator@$DIR/generator-storage-dead-unwind.rs:22:16: 28:6 {Foo, Bar, ()}], _2: ()) -> () yields () { let mut _0: (); // return place in scope 0 at $DIR/generator-storage-dead-unwind.rs:22:19: 22:19 diff --git a/src/test/mir-opt/generator_tiny.main-{{closure}}.generator_resume.0.mir b/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir similarity index 95% rename from src/test/mir-opt/generator_tiny.main-{{closure}}.generator_resume.0.mir rename to src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir index 87889460e7eec..990aa1ec08775 100644 --- a/src/test/mir-opt/generator_tiny.main-{{closure}}.generator_resume.0.mir +++ b/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir @@ -1,4 +1,4 @@ -// MIR for `main::{{closure}}#0` 0 generator_resume +// MIR for `main::{closure#0}` 0 generator_resume /* generator_layout = GeneratorLayout { field_tys: {}, variant_fields: { @@ -10,7 +10,7 @@ storage_conflicts: BitMatrix(0x0) {}, } */ -fn main::{{closure}}#0(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}]>, _2: u8) -> GeneratorState<(), ()> { +fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}]>, _2: u8) -> GeneratorState<(), ()> { debug _x => _10; // in scope 0 at $DIR/generator-tiny.rs:19:17: 19:19 let mut _0: std::ops::GeneratorState<(), ()>; // return place in scope 0 at $DIR/generator-tiny.rs:19:16: 25:6 let _3: HasDrop; // in scope 0 at $DIR/generator-tiny.rs:20:13: 20:15 diff --git a/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir index 6ecbd3022e389..c970b1bfac490 100644 --- a/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir @@ -4,8 +4,8 @@ fn foo(_1: T, _2: i32) -> i32 { debug _t => _1; // in scope 0 at $DIR/inline-closure.rs:10:17: 10:19 debug q => _2; // in scope 0 at $DIR/inline-closure.rs:10:24: 10:25 let mut _0: i32; // return place in scope 0 at $DIR/inline-closure.rs:10:35: 10:38 - let _3: [closure@foo::{{closure}}#0]; // in scope 0 at $DIR/inline-closure.rs:11:9: 11:10 - let mut _4: &[closure@foo::{{closure}}#0]; // in scope 0 at $DIR/inline-closure.rs:12:5: 12:6 + let _3: [closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure.rs:11:9: 11:10 + let mut _4: &[closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure.rs:12:5: 12:6 let mut _5: (i32, i32); // in scope 0 at $DIR/inline-closure.rs:12:5: 12:12 let mut _6: i32; // in scope 0 at $DIR/inline-closure.rs:12:7: 12:8 let mut _7: i32; // in scope 0 at $DIR/inline-closure.rs:12:10: 12:11 diff --git a/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir index c49e0218327de..2f2db51ec8627 100644 --- a/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir @@ -4,8 +4,8 @@ fn foo(_1: T, _2: &i32) -> i32 { debug _t => _1; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:11:17: 11:19 debug q => _2; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:11:24: 11:25 let mut _0: i32; // return place in scope 0 at $DIR/inline-closure-borrows-arg.rs:11:36: 11:39 - let _3: [closure@foo::{{closure}}#0]; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:12:9: 12:10 - let mut _4: &[closure@foo::{{closure}}#0]; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:6 + let _3: [closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:12:9: 12:10 + let mut _4: &[closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:6 let mut _5: (&i32, &i32); // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 let mut _6: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:7: 16:8 let mut _7: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:10: 16:11 diff --git a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir index ab194cf532ff3..cb222a997b6d9 100644 --- a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir @@ -4,10 +4,10 @@ fn foo(_1: T, _2: i32) -> (i32, T) { debug t => _1; // in scope 0 at $DIR/inline-closure-captures.rs:10:17: 10:18 debug q => _2; // in scope 0 at $DIR/inline-closure-captures.rs:10:23: 10:24 let mut _0: (i32, T); // return place in scope 0 at $DIR/inline-closure-captures.rs:10:34: 10:42 - let _3: [closure@foo::{{closure}}#0 q:&i32, t:&T]; // in scope 0 at $DIR/inline-closure-captures.rs:11:9: 11:10 + let _3: [closure@foo::{closure#0} q:&i32, t:&T]; // in scope 0 at $DIR/inline-closure-captures.rs:11:9: 11:10 let mut _4: &i32; // in scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24 let mut _5: &T; // in scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24 - let mut _6: &[closure@foo::{{closure}}#0 q:&i32, t:&T]; // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:6 + let mut _6: &[closure@foo::{closure#0} q:&i32, t:&T]; // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:6 let mut _7: (i32,); // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:9 let mut _8: i32; // in scope 0 at $DIR/inline-closure-captures.rs:12:7: 12:8 let mut _10: i32; // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:9 diff --git a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir index 29327108f3e0e..5258f67ebde6f 100644 --- a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir @@ -35,10 +35,10 @@ fn bar() -> bool { _10 = const bar::promoted[1]; // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 // ty::Const // + ty: &i32 - // + val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar[0]), const_param_did: None }, [], Some(promoted[1])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar), const_param_did: None }, [], Some(promoted[1])) // mir::Constant // + span: $DIR/inline-retag.rs:12:7: 12:9 - // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar[0]), const_param_did: None }, [], Some(promoted[1])) } + // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar), const_param_did: None }, [], Some(promoted[1])) } Retag(_10); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 _4 = &(*_10); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 Retag(_4); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 @@ -49,10 +49,10 @@ fn bar() -> bool { _9 = const bar::promoted[0]; // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 // ty::Const // + ty: &i32 - // + val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/inline-retag.rs:12:11: 12:14 - // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar), const_param_did: None }, [], Some(promoted[0])) } Retag(_9); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 _7 = &(*_9); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 Retag(_7); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 diff --git a/src/test/mir-opt/issue-41697.rs b/src/test/mir-opt/issue-41697.rs index 2c4f7544844d0..5c34d8e68d0c0 100644 --- a/src/test/mir-opt/issue-41697.rs +++ b/src/test/mir-opt/issue-41697.rs @@ -14,7 +14,7 @@ trait Foo { } // EMIT_MIR_FOR_EACH_BIT_WIDTH -// EMIT_MIR issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir +// EMIT_MIR issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir impl Foo for [u8; 1+1] { fn get(&self) -> [u8; 2] { *self diff --git a/src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.64bit.mir b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir similarity index 82% rename from src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.64bit.mir rename to src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir index 1cef88fd1096b..26d1f9402c687 100644 --- a/src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.64bit.mir +++ b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir @@ -1,6 +1,6 @@ -// MIR for `::{{constant}}#0` after SimplifyCfg-promote-consts +// MIR for `::{constant#0}` after SimplifyCfg-promote-consts -::{{constant}}#0: usize = { +::{constant#0}: usize = { let mut _0: usize; // return place in scope 0 at $DIR/issue-41697.rs:18:19: 18:22 let mut _1: (usize, bool); // in scope 0 at $DIR/issue-41697.rs:18:19: 18:22 diff --git a/src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.32bit.mir b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir similarity index 82% rename from src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.32bit.mir rename to src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir index 1cef88fd1096b..26d1f9402c687 100644 --- a/src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.32bit.mir +++ b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir @@ -1,6 +1,6 @@ -// MIR for `::{{constant}}#0` after SimplifyCfg-promote-consts +// MIR for `::{constant#0}` after SimplifyCfg-promote-consts -::{{constant}}#0: usize = { +::{constant#0}: usize = { let mut _0: usize; // return place in scope 0 at $DIR/issue-41697.rs:18:19: 18:22 let mut _1: (usize, bool); // in scope 0 at $DIR/issue-41697.rs:18:19: 18:22 diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff index 302612f5a0a28..b68fc83320de6 100644 --- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff +++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff @@ -129,10 +129,10 @@ _45 = 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[0]), const_param_did: None }, [], Some(promoted[1])) + // + 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[0]), const_param_did: None }, [], Some(promoted[1])) } + // + 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 (_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 @@ -184,10 +184,10 @@ _44 = 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[0]), const_param_did: None }, [], Some(promoted[0])) + // + 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[0]), const_param_did: None }, [], Some(promoted[0])) } + // + 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 diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff index 302612f5a0a28..b68fc83320de6 100644 --- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff +++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff @@ -129,10 +129,10 @@ _45 = 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[0]), const_param_did: None }, [], Some(promoted[1])) + // + 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[0]), const_param_did: None }, [], Some(promoted[1])) } + // + 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 (_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 @@ -184,10 +184,10 @@ _44 = 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[0]), const_param_did: None }, [], Some(promoted[0])) + // + 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[0]), const_param_did: None }, [], Some(promoted[0])) } + // + 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 diff --git a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir index 14b1508f60827..e09d32c729c78 100644 --- a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir +++ b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir @@ -58,10 +58,10 @@ fn full_tested_match() -> () { _11 = const full_tested_match::promoted[0]; // scope 0 at $DIR/match_false_edges.rs:16:14: 16:15 // ty::Const // + ty: &std::option::Option - // + val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ match_false_edges[317d]::full_tested_match[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ match_false_edges[317d]::full_tested_match), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/match_false_edges.rs:16:14: 16:15 - // + literal: Const { ty: &std::option::Option, val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ match_false_edges[317d]::full_tested_match[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &std::option::Option, val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ match_false_edges[317d]::full_tested_match), const_param_did: None }, [], Some(promoted[0])) } _6 = &(((*_11) as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:16:14: 16:15 _4 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27 StorageLive(_7); // scope 0 at $DIR/match_false_edges.rs:16:20: 16:27 diff --git a/src/test/mir-opt/retag.main-{{closure}}.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir similarity index 88% rename from src/test/mir-opt/retag.main-{{closure}}.SimplifyCfg-elaborate-drops.after.mir rename to src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir index 01f5fbb7d236c..0b8c4d25d2d3c 100644 --- a/src/test/mir-opt/retag.main-{{closure}}.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir @@ -1,6 +1,6 @@ -// MIR for `main::{{closure}}#0` after SimplifyCfg-elaborate-drops +// MIR for `main::{closure#0}` after SimplifyCfg-elaborate-drops -fn main::{{closure}}#0(_1: &[closure@main::{{closure}}#0], _2: &i32) -> &i32 { +fn main::{closure#0}(_1: &[closure@main::{closure#0}], _2: &i32) -> &i32 { debug x => _2; // in scope 0 at $DIR/retag.rs:40:32: 40:33 let mut _0: &i32; // return place in scope 0 at $DIR/retag.rs:40:44: 40:48 let _3: &i32; // in scope 0 at $DIR/retag.rs:41:13: 41:15 diff --git a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir index 5a79466ede532..52f422d8315e6 100644 --- a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir @@ -10,7 +10,7 @@ fn main() -> () { let mut _7: &mut i32; // in scope 0 at $DIR/retag.rs:32:29: 32:35 let mut _9: &mut i32; // in scope 0 at $DIR/retag.rs:33:19: 33:20 let mut _12: *mut i32; // in scope 0 at $DIR/retag.rs:36:18: 36:29 - let mut _14: [closure@main::{{closure}}#0]; // in scope 0 at $DIR/retag.rs:40:31: 43:6 + let mut _14: [closure@main::{closure#0}]; // in scope 0 at $DIR/retag.rs:40:31: 43:6 let mut _16: for<'r> fn(&'r i32) -> &'r i32; // in scope 0 at $DIR/retag.rs:44:14: 44:15 let mut _17: &i32; // in scope 0 at $DIR/retag.rs:44:16: 44:18 let _18: &i32; // in scope 0 at $DIR/retag.rs:44:16: 44:18 @@ -118,9 +118,9 @@ fn main() -> () { StorageDead(_2); // scope 1 at $DIR/retag.rs:37:5: 37:6 StorageLive(_13); // scope 1 at $DIR/retag.rs:40:9: 40:10 StorageLive(_14); // scope 1 at $DIR/retag.rs:40:31: 43:6 - _14 = [closure@main::{{closure}}#0]; // scope 1 at $DIR/retag.rs:40:31: 43:6 + _14 = [closure@main::{closure#0}]; // scope 1 at $DIR/retag.rs:40:31: 43:6 // closure - // + def_id: DefId(0:14 ~ retag[317d]::main[0]::{{closure}}[0]) + // + def_id: DefId(0:14 ~ retag[317d]::main::{closure#0}) // + substs: [ // i8, // for<'r> extern "rust-call" fn((&'r i32,)) -> &'r i32, @@ -157,10 +157,10 @@ fn main() -> () { _27 = const main::promoted[0]; // scope 7 at $DIR/retag.rs:47:21: 47:23 // ty::Const // + ty: &i32 - // + val: Unevaluated(WithOptConstParam { did: DefId(0:13 ~ retag[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:13 ~ retag[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/retag.rs:47:21: 47:23 - // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:13 ~ retag[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:13 ~ retag[317d]::main), const_param_did: None }, [], Some(promoted[0])) } Retag(_27); // scope 7 at $DIR/retag.rs:47:21: 47:23 _23 = &(*_27); // scope 7 at $DIR/retag.rs:47:21: 47:23 Retag(_23); // scope 7 at $DIR/retag.rs:47:21: 47:23 diff --git a/src/test/mir-opt/retag.rs b/src/test/mir-opt/retag.rs index 12d7cb30d977e..d0ea2cfb18ba2 100644 --- a/src/test/mir-opt/retag.rs +++ b/src/test/mir-opt/retag.rs @@ -6,8 +6,8 @@ struct Test(i32); -// EMIT_MIR retag.{{impl}}-foo.SimplifyCfg-elaborate-drops.after.mir -// EMIT_MIR retag.{{impl}}-foo_shr.SimplifyCfg-elaborate-drops.after.mir +// EMIT_MIR retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir +// EMIT_MIR retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir impl Test { // Make sure we run the pass on a method, not just on bare functions. fn foo<'x>(&self, x: &'x mut i32) -> &'x mut i32 { @@ -25,7 +25,7 @@ impl Drop for Test { } // EMIT_MIR retag.main.SimplifyCfg-elaborate-drops.after.mir -// EMIT_MIR retag.main-{{closure}}.SimplifyCfg-elaborate-drops.after.mir +// EMIT_MIR retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir fn main() { let mut x = 0; { diff --git a/src/test/mir-opt/retag.{{impl}}-foo.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir similarity index 100% rename from src/test/mir-opt/retag.{{impl}}-foo.SimplifyCfg-elaborate-drops.after.mir rename to src/test/mir-opt/retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir diff --git a/src/test/mir-opt/retag.{{impl}}-foo_shr.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir similarity index 100% rename from src/test/mir-opt/retag.{{impl}}-foo_shr.SimplifyCfg-elaborate-drops.after.mir rename to src/test/mir-opt/retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir diff --git a/src/test/mir-opt/simplify_try_if_let.rs b/src/test/mir-opt/simplify_try_if_let.rs index b37db73842113..0c4d8c8f4d029 100644 --- a/src/test/mir-opt/simplify_try_if_let.rs +++ b/src/test/mir-opt/simplify_try_if_let.rs @@ -1,5 +1,5 @@ // compile-flags: -Zmir-opt-level=1 -// EMIT_MIR simplify_try_if_let.{{impl}}-append.SimplifyArmIdentity.diff +// EMIT_MIR simplify_try_if_let.{impl#0}-append.SimplifyArmIdentity.diff use std::ptr::NonNull; diff --git a/src/test/mir-opt/simplify_try_if_let.{{impl}}-append.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_try_if_let.{impl#0}-append.SimplifyArmIdentity.diff similarity index 100% rename from src/test/mir-opt/simplify_try_if_let.{{impl}}-append.SimplifyArmIdentity.diff rename to src/test/mir-opt/simplify_try_if_let.{impl#0}-append.SimplifyArmIdentity.diff diff --git a/src/test/mir-opt/unusual-item-types.rs b/src/test/mir-opt/unusual-item-types.rs index 9a6b82272391e..c68ec21a039fd 100644 --- a/src/test/mir-opt/unusual-item-types.rs +++ b/src/test/mir-opt/unusual-item-types.rs @@ -5,19 +5,19 @@ struct A; -// EMIT_MIR unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.mir +// EMIT_MIR unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.mir impl A { const ASSOCIATED_CONSTANT: i32 = 2; } // See #59021 -// EMIT_MIR unusual_item_types.Test-X-{{constructor}}.mir_map.0.mir +// EMIT_MIR unusual_item_types.Test-X-{constructor#0}.mir_map.0.mir enum Test { X(usize), Y { a: usize }, } -// EMIT_MIR unusual_item_types.E-V-{{constant}}.mir_map.0.mir +// EMIT_MIR unusual_item_types.E-V-{constant#0}.mir_map.0.mir enum E { V = 5, } diff --git a/src/test/mir-opt/unusual_item_types.E-V-{{constant}}.mir_map.0.32bit.mir b/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.32bit.mir similarity index 85% rename from src/test/mir-opt/unusual_item_types.E-V-{{constant}}.mir_map.0.32bit.mir rename to src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.32bit.mir index 315525e08c21c..f11fce891f4c5 100644 --- a/src/test/mir-opt/unusual_item_types.E-V-{{constant}}.mir_map.0.32bit.mir +++ b/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.32bit.mir @@ -1,6 +1,6 @@ -// MIR for `E::V::{{constant}}#0` 0 mir_map +// MIR for `E::V::{constant#0}` 0 mir_map -E::V::{{constant}}#0: isize = { +E::V::{constant#0}: isize = { let mut _0: isize; // return place in scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10 bb0: { diff --git a/src/test/mir-opt/unusual_item_types.E-V-{{constant}}.mir_map.0.64bit.mir b/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir similarity index 85% rename from src/test/mir-opt/unusual_item_types.E-V-{{constant}}.mir_map.0.64bit.mir rename to src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir index 315525e08c21c..f11fce891f4c5 100644 --- a/src/test/mir-opt/unusual_item_types.E-V-{{constant}}.mir_map.0.64bit.mir +++ b/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir @@ -1,6 +1,6 @@ -// MIR for `E::V::{{constant}}#0` 0 mir_map +// MIR for `E::V::{constant#0}` 0 mir_map -E::V::{{constant}}#0: isize = { +E::V::{constant#0}: isize = { let mut _0: isize; // return place in scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10 bb0: { diff --git a/src/test/mir-opt/unusual_item_types.Test-X-{{constructor}}.mir_map.0.32bit.mir b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir similarity index 100% rename from src/test/mir-opt/unusual_item_types.Test-X-{{constructor}}.mir_map.0.32bit.mir rename to src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir diff --git a/src/test/mir-opt/unusual_item_types.Test-X-{{constructor}}.mir_map.0.64bit.mir b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir similarity index 100% rename from src/test/mir-opt/unusual_item_types.Test-X-{{constructor}}.mir_map.0.64bit.mir rename to src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir diff --git a/src/test/mir-opt/unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir b/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir similarity index 100% rename from src/test/mir-opt/unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir rename to src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir diff --git a/src/test/mir-opt/unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir b/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir similarity index 100% rename from src/test/mir-opt/unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir rename to src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir diff --git a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs index acce0f77a258e..2319de5568366 100644 --- a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs +++ b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs @@ -5,7 +5,7 @@ pub async fn f() -> impl std::fmt::Debug { #[derive(Debug)] enum E { - //~^ ERROR recursive type `f::{{closure}}#0::E` has infinite size + //~^ ERROR recursive type `f::{closure#0}::E` has infinite size This(E), Unit, } diff --git a/src/test/ui/async-await/issues/issue-67893.stderr b/src/test/ui/async-await/issues/issue-67893.stderr index a6f50a6657e7c..af09f0a27bf21 100644 --- a/src/test/ui/async-await/issues/issue-67893.stderr +++ b/src/test/ui/async-await/issues/issue-67893.stderr @@ -14,8 +14,8 @@ LL | pub async fn run() { | = help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, ()>` = note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3> {ResumeTy, Arc>, &'r Mutex<()>, std::result::Result, PoisonError>>, &'t1 MutexGuard<'t2, ()>, MutexGuard<'t3, ()>, (), impl Future}` - = note: required because it appears within the type `[static generator@run::{{closure}}#0 for<'r, 's, 't0, 't1, 't2, 't3> {ResumeTy, Arc>, &'r Mutex<()>, std::result::Result, PoisonError>>, &'t1 MutexGuard<'t2, ()>, MutexGuard<'t3, ()>, (), impl Future}]` - = note: required because it appears within the type `from_generator::GenFuture<[static generator@run::{{closure}}#0 for<'r, 's, 't0, 't1, 't2, 't3> {ResumeTy, Arc>, &'r Mutex<()>, std::result::Result, PoisonError>>, &'t1 MutexGuard<'t2, ()>, MutexGuard<'t3, ()>, (), impl Future}]>` + = note: required because it appears within the type `[static generator@run::{closure#0} for<'r, 's, 't0, 't1, 't2, 't3> {ResumeTy, Arc>, &'r Mutex<()>, std::result::Result, PoisonError>>, &'t1 MutexGuard<'t2, ()>, MutexGuard<'t3, ()>, (), impl Future}]` + = note: required because it appears within the type `from_generator::GenFuture<[static generator@run::{closure#0} for<'r, 's, 't0, 't1, 't2, 't3> {ResumeTy, Arc>, &'r Mutex<()>, std::result::Result, PoisonError>>, &'t1 MutexGuard<'t2, ()>, MutexGuard<'t3, ()>, (), impl Future}]>` = note: required because it appears within the type `impl Future` = note: required because it appears within the type `impl Future` diff --git a/src/test/ui/const-generics/nested-type.full.stderr b/src/test/ui/const-generics/nested-type.full.stderr index ded6f882caf42..075bdceccfaeb 100644 --- a/src/test/ui/const-generics/nested-type.full.stderr +++ b/src/test/ui/const-generics/nested-type.full.stderr @@ -8,7 +8,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/nested-type.rs:16:5 | LL | Foo::<17>::value() - | ^^^^^^^^^^^^^^^^^^ calling non-const function `Foo::{{constant}}#0::Foo::<17_usize>::value` + | ^^^^^^^^^^^^^^^^^^ calling non-const function `Foo::{constant#0}::Foo::<17_usize>::value` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/nested-type.min.stderr b/src/test/ui/const-generics/nested-type.min.stderr index 55f6fe7cc16e8..733b02fa8571d 100644 --- a/src/test/ui/const-generics/nested-type.min.stderr +++ b/src/test/ui/const-generics/nested-type.min.stderr @@ -24,7 +24,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/nested-type.rs:16:5 | LL | Foo::<17>::value() - | ^^^^^^^^^^^^^^^^^^ calling non-const function `Foo::{{constant}}#0::Foo::<17_usize>::value` + | ^^^^^^^^^^^^^^^^^^ calling non-const function `Foo::{constant#0}::Foo::<17_usize>::value` error: aborting due to 3 previous errors diff --git a/src/test/ui/consts/const-size_of-cycle.stderr b/src/test/ui/consts/const-size_of-cycle.stderr index 58d5e9ac58c2e..42e2749b20d28 100644 --- a/src/test/ui/consts/const-size_of-cycle.stderr +++ b/src/test/ui/consts/const-size_of-cycle.stderr @@ -1,15 +1,15 @@ -error[E0391]: cycle detected when simplifying constant for the type system `Foo::bytes::{{constant}}#0` +error[E0391]: cycle detected when simplifying constant for the type system `Foo::bytes::{constant#0}` --> $DIR/const-size_of-cycle.rs:4:17 | LL | bytes: [u8; std::mem::size_of::()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires simplifying constant for the type system `Foo::bytes::{{constant}}#0`... +note: ...which requires simplifying constant for the type system `Foo::bytes::{constant#0}`... --> $DIR/const-size_of-cycle.rs:4:17 | LL | bytes: [u8; std::mem::size_of::()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}#0`... +note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`... --> $DIR/const-size_of-cycle.rs:4:17 | LL | bytes: [u8; std::mem::size_of::()] @@ -26,7 +26,7 @@ LL | pub fn size_of() -> usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires computing layout of `Foo`... = note: ...which requires normalizing `[u8; _]`... - = note: ...which again requires simplifying constant for the type system `Foo::bytes::{{constant}}#0`, completing the cycle + = note: ...which again requires simplifying constant for the type system `Foo::bytes::{constant#0}`, completing the cycle note: cycle used when checking that `Foo` is well-formed --> $DIR/const-size_of-cycle.rs:3:1 | diff --git a/src/test/ui/consts/issue-68542-closure-in-array-len.stderr b/src/test/ui/consts/issue-68542-closure-in-array-len.stderr index 815cc9d836f92..8c839f94e3b4a 100644 --- a/src/test/ui/consts/issue-68542-closure-in-array-len.stderr +++ b/src/test/ui/consts/issue-68542-closure-in-array-len.stderr @@ -8,7 +8,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/issue-68542-closure-in-array-len.rs:6:13 | LL | a: [(); (|| { 0 })()] - | ^^^^^^^^^^^^ calling non-const function `Bug::a::{{constant}}#0::{{closure}}#0` + | ^^^^^^^^^^^^ calling non-const function `Bug::a::{constant#0}::{closure#0}` error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/miri_unleashed/tls.stderr b/src/test/ui/consts/miri_unleashed/tls.stderr index 27d2b2df4d8ae..5cef636e0a817 100644 --- a/src/test/ui/consts/miri_unleashed/tls.stderr +++ b/src/test/ui/consts/miri_unleashed/tls.stderr @@ -2,13 +2,13 @@ error[E0080]: could not evaluate static initializer --> $DIR/tls.rs:12:25 | LL | unsafe { let _val = A; } - | ^ cannot access thread local static (DefId(0:4 ~ tls[317d]::A[0])) + | ^ cannot access thread local static (DefId(0:4 ~ tls[317d]::A)) error[E0080]: could not evaluate static initializer --> $DIR/tls.rs:19:26 | LL | unsafe { let _val = &A; } - | ^ cannot access thread local static (DefId(0:4 ~ tls[317d]::A[0])) + | ^ cannot access thread local static (DefId(0:4 ~ tls[317d]::A)) warning: skipping const checks | diff --git a/src/test/ui/deprecation/deprecation-lint.rs b/src/test/ui/deprecation/deprecation-lint.rs index 1932344fc5723..560e29688864a 100644 --- a/src/test/ui/deprecation/deprecation-lint.rs +++ b/src/test/ui/deprecation/deprecation-lint.rs @@ -314,7 +314,7 @@ mod this_crate { let _ = || { #[deprecated] fn bar() { } - bar(); //~ ERROR use of deprecated function `this_crate::test_fn_closure_body::{{closure}}#0::bar` + bar(); //~ ERROR use of deprecated function `this_crate::test_fn_closure_body::{closure#0}::bar` }; } diff --git a/src/test/ui/deprecation/deprecation-lint.stderr b/src/test/ui/deprecation/deprecation-lint.stderr index 03a2ec7edc916..12c76f0f4a5d7 100644 --- a/src/test/ui/deprecation/deprecation-lint.stderr +++ b/src/test/ui/deprecation/deprecation-lint.stderr @@ -298,7 +298,7 @@ error: use of deprecated associated function `this_crate::Trait::trait_deprecate LL | ... ::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: use of deprecated function `this_crate::test_fn_closure_body::{{closure}}#0::bar` +error: use of deprecated function `this_crate::test_fn_closure_body::{closure#0}::bar` --> $DIR/deprecation-lint.rs:317:13 | LL | bar(); diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index 4ecc9c34324a4..e578c4b4f819e 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -1,4 +1,4 @@ -error[E0391]: cycle detected when computing type of `cycle1::{{opaque}}#0` +error[E0391]: cycle detected when computing type of `cycle1::{opaque#0}` --> $DIR/auto-trait-leak.rs:12:16 | LL | fn cycle1() -> impl Clone { @@ -35,7 +35,7 @@ note: ...which requires type-checking `cycle1`... LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... -note: ...which requires computing type of `cycle2::{{opaque}}#0`... +note: ...which requires computing type of `cycle2::{opaque#0}`... --> $DIR/auto-trait-leak.rs:20:16 | LL | fn cycle2() -> impl Clone { @@ -71,7 +71,7 @@ note: ...which requires type-checking `cycle2`... LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... - = note: ...which again requires computing type of `cycle1::{{opaque}}#0`, completing the cycle + = note: ...which again requires computing type of `cycle1::{opaque#0}`, completing the cycle note: cycle used when checking item types in top-level module --> $DIR/auto-trait-leak.rs:1:1 | diff --git a/src/test/ui/infinite/infinite-recursion-const-fn.stderr b/src/test/ui/infinite/infinite-recursion-const-fn.stderr index 3c106895305dc..7ccc7cc987f4e 100644 --- a/src/test/ui/infinite/infinite-recursion-const-fn.stderr +++ b/src/test/ui/infinite/infinite-recursion-const-fn.stderr @@ -10,7 +10,7 @@ note: ...which requires const-evaluating + checking `b`... LL | const fn b() -> usize { | ^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires const-evaluating + checking `a`, completing the cycle -note: cycle used when const-evaluating + checking `ARR::{{constant}}#0` +note: cycle used when const-evaluating + checking `ARR::{constant#0}` --> $DIR/infinite-recursion-const-fn.rs:10:18 | LL | const ARR: [i32; a()] = [5; 6]; diff --git a/src/test/ui/issues/issue-17252.stderr b/src/test/ui/issues/issue-17252.stderr index 0a27848b801c9..1148577016ab4 100644 --- a/src/test/ui/issues/issue-17252.stderr +++ b/src/test/ui/issues/issue-17252.stderr @@ -16,7 +16,7 @@ note: ...which requires const-evaluating + checking `FOO`... LL | const FOO: usize = FOO; | ^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires normalizing `FOO`, completing the cycle -note: cycle used when const-evaluating + checking `main::{{constant}}#0` +note: cycle used when const-evaluating + checking `main::{constant#0}` --> $DIR/issue-17252.rs:4:18 | LL | let _x: [u8; FOO]; // caused stack overflow prior to fix diff --git a/src/test/ui/issues/issue-23302-1.stderr b/src/test/ui/issues/issue-23302-1.stderr index 45372c7f53bd4..d3a1993536a00 100644 --- a/src/test/ui/issues/issue-23302-1.stderr +++ b/src/test/ui/issues/issue-23302-1.stderr @@ -1,21 +1,21 @@ -error[E0391]: cycle detected when simplifying constant for the type system `X::A::{{constant}}#0` +error[E0391]: cycle detected when simplifying constant for the type system `X::A::{constant#0}` --> $DIR/issue-23302-1.rs:4:9 | LL | A = X::A as isize, | ^^^^^^^^^^^^^ | -note: ...which requires simplifying constant for the type system `X::A::{{constant}}#0`... +note: ...which requires simplifying constant for the type system `X::A::{constant#0}`... --> $DIR/issue-23302-1.rs:4:9 | LL | A = X::A as isize, | ^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `X::A::{{constant}}#0`... +note: ...which requires const-evaluating + checking `X::A::{constant#0}`... --> $DIR/issue-23302-1.rs:4:9 | LL | A = X::A as isize, | ^^^^^^^^^^^^^ = note: ...which requires normalizing `X::A as isize`... - = note: ...which again requires simplifying constant for the type system `X::A::{{constant}}#0`, completing the cycle + = note: ...which again requires simplifying constant for the type system `X::A::{constant#0}`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/issue-23302-1.rs:3:1 | diff --git a/src/test/ui/issues/issue-23302-2.stderr b/src/test/ui/issues/issue-23302-2.stderr index 33bc1f6c48d5e..d3b78ea1af5f5 100644 --- a/src/test/ui/issues/issue-23302-2.stderr +++ b/src/test/ui/issues/issue-23302-2.stderr @@ -1,21 +1,21 @@ -error[E0391]: cycle detected when simplifying constant for the type system `Y::A::{{constant}}#0` +error[E0391]: cycle detected when simplifying constant for the type system `Y::A::{constant#0}` --> $DIR/issue-23302-2.rs:4:9 | LL | A = Y::B as isize, | ^^^^^^^^^^^^^ | -note: ...which requires simplifying constant for the type system `Y::A::{{constant}}#0`... +note: ...which requires simplifying constant for the type system `Y::A::{constant#0}`... --> $DIR/issue-23302-2.rs:4:9 | LL | A = Y::B as isize, | ^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `Y::A::{{constant}}#0`... +note: ...which requires const-evaluating + checking `Y::A::{constant#0}`... --> $DIR/issue-23302-2.rs:4:9 | LL | A = Y::B as isize, | ^^^^^^^^^^^^^ = note: ...which requires normalizing `Y::B as isize`... - = note: ...which again requires simplifying constant for the type system `Y::A::{{constant}}#0`, completing the cycle + = note: ...which again requires simplifying constant for the type system `Y::A::{constant#0}`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/issue-23302-2.rs:3:1 | diff --git a/src/test/ui/issues/issue-36163.stderr b/src/test/ui/issues/issue-36163.stderr index 3fd1f4b59beca..113f86cf0f99f 100644 --- a/src/test/ui/issues/issue-36163.stderr +++ b/src/test/ui/issues/issue-36163.stderr @@ -1,15 +1,15 @@ -error[E0391]: cycle detected when simplifying constant for the type system `Foo::B::{{constant}}#0` +error[E0391]: cycle detected when simplifying constant for the type system `Foo::B::{constant#0}` --> $DIR/issue-36163.rs:4:9 | LL | B = A, | ^ | -note: ...which requires simplifying constant for the type system `Foo::B::{{constant}}#0`... +note: ...which requires simplifying constant for the type system `Foo::B::{constant#0}`... --> $DIR/issue-36163.rs:4:9 | LL | B = A, | ^ -note: ...which requires const-evaluating + checking `Foo::B::{{constant}}#0`... +note: ...which requires const-evaluating + checking `Foo::B::{constant#0}`... --> $DIR/issue-36163.rs:4:9 | LL | B = A, @@ -31,7 +31,7 @@ note: ...which requires const-evaluating + checking `A`... LL | const A: isize = Foo::B as isize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `A`... - = note: ...which again requires simplifying constant for the type system `Foo::B::{{constant}}#0`, completing the cycle + = note: ...which again requires simplifying constant for the type system `Foo::B::{constant#0}`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/issue-36163.rs:1:1 | diff --git a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr index f0d169f419c73..799ed89dcce3c 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr @@ -4,7 +4,7 @@ note: no external requirements LL | let mut closure = expect_sig(|p, y| *p = y); | ^^^^^^^^^^^^^ | - = note: defining type: test::{{closure}}#0 with closure substs [ + = note: defining type: test::{closure#0} with closure substs [ i16, for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) mut &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) i32)), (), diff --git a/src/test/ui/nll/closure-requirements/escape-argument.stderr b/src/test/ui/nll/closure-requirements/escape-argument.stderr index e251e69997eba..a094fc45178f7 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument.stderr @@ -4,7 +4,7 @@ note: no external requirements LL | let mut closure = expect_sig(|p, y| *p = y); | ^^^^^^^^^^^^^ | - = note: defining type: test::{{closure}}#0 with closure substs [ + = note: defining type: test::{closure#0} with closure substs [ i16, for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) mut &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32, &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32)), (), diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr index 36257700bef0c..1a8258376142a 100644 --- a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr +++ b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr @@ -4,7 +4,7 @@ note: external requirements LL | let mut closure1 = || p = &y; | ^^^^^^^^^ | - = note: defining type: test::{{closure}}#0::{{closure}}#0 with closure substs [ + = note: defining type: test::{closure#0}::{closure#0} with closure substs [ i16, extern "rust-call" fn(()), (&'_#1r i32, &'_#2r mut &'_#3r i32), @@ -22,7 +22,7 @@ LL | | closure1(); LL | | }; | |_________^ | - = note: defining type: test::{{closure}}#0 with closure substs [ + = note: defining type: test::{closure#0} with closure substs [ i16, extern "rust-call" fn(()), (&'_#1r i32, &'_#2r mut &'_#3r i32), diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr index d1c64fac3c1e3..29fd796882b6a 100644 --- a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr +++ b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr @@ -4,7 +4,7 @@ note: external requirements LL | let mut closure = || p = &y; | ^^^^^^^^^ | - = note: defining type: test::{{closure}}#0 with closure substs [ + = note: defining type: test::{closure#0} with closure substs [ i16, extern "rust-call" fn(()), (&'_#1r i32, &'_#2r mut &'_#3r i32), diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr index 25a730a0808df..c4f4facae1fb5 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr @@ -8,7 +8,7 @@ LL | | demand_y(x, y, p) LL | | }, | |_________^ | - = note: defining type: supply::{{closure}}#0 with closure substs [ + = note: defining type: supply::{closure#0} with closure substs [ i16, for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)), (), diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr index 346b4af6caac8..c1450564c45d3 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr @@ -9,7 +9,7 @@ LL | | LL | | }); | |_____^ | - = note: defining type: supply::{{closure}}#0 with closure substs [ + = note: defining type: supply::{closure#0} with closure substs [ i16, for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>)), (), diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr index 3b1769ed3a2ee..e7b8dff4e7ecb 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr @@ -8,7 +8,7 @@ LL | | LL | | }) | |_____^ | - = note: defining type: case1::{{closure}}#0 with closure substs [ + = note: defining type: case1::{closure#0} with closure substs [ i32, for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>)), (), @@ -47,7 +47,7 @@ LL | | cell_x.set(cell_a.get()); // forces 'a: 'x, implies 'a = 'static LL | | }) | |_____^ | - = note: defining type: case2::{{closure}}#0 with closure substs [ + = note: defining type: case2::{closure#0} with closure substs [ i32, for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>)), (), diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr index b167dafff0136..c7e68d02dcf1b 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr @@ -10,7 +10,7 @@ LL | | demand_y(x, y, x.get()) LL | | }); | |_____^ | - = note: defining type: supply::{{closure}}#0 with closure substs [ + = note: defining type: supply::{closure#0} with closure substs [ i16, for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t1)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t2)) u32>)), (), diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr index 91aacc3dff60f..abbc76eaf4ddf 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr @@ -10,7 +10,7 @@ LL | | demand_y(x, y, x.get()) LL | | }); | |_____^ | - = note: defining type: supply::{{closure}}#0 with closure substs [ + = note: defining type: supply::{closure#0} with closure substs [ i16, for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>)), (), diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr index ae447708621ed..c91b514a796ce 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr @@ -9,7 +9,7 @@ LL | | LL | | }); | |_____^ | - = note: defining type: test::{{closure}}#0 with closure substs [ + = note: defining type: test::{closure#0} with closure substs [ i16, for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)), (), diff --git a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr index 256446a6e8d8d..4ddf6f8323f63 100644 --- a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr @@ -8,7 +8,7 @@ LL | | demand_y(x, y, p) LL | | }, | |_________^ | - = note: defining type: supply::{{closure}}#0 with closure substs [ + = note: defining type: supply::{closure#0} with closure substs [ i16, for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)), (), diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr index 4b1dba47d9251..6dc6f4568058b 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr @@ -9,7 +9,7 @@ LL | | LL | | }); | |_____^ | - = note: defining type: supply::{{closure}}#0 with closure substs [ + = note: defining type: supply::{closure#0} with closure substs [ i16, for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)), (), diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr index b0fb6d66845cf..6bcada5c26c83 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr @@ -9,7 +9,7 @@ LL | | LL | | }); | |_____^ | - = note: defining type: supply::{{closure}}#0 with closure substs [ + = note: defining type: supply::{closure#0} with closure substs [ i16, for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>)), (), diff --git a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr index ef941472894b2..4b860a55057b6 100644 --- a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr @@ -11,7 +11,7 @@ LL | | require(value); LL | | }); | |_____^ | - = note: defining type: supply::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: supply::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((T,)), (), diff --git a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr index 2a382030f935c..1da6c6d2c6857 100644 --- a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr +++ b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr @@ -4,7 +4,7 @@ note: no external requirements LL | expect_sig(|a, b| b); // ought to return `a` | ^^^^^^^^ | - = note: defining type: test::{{closure}}#0 with closure substs [ + = note: defining type: test::{closure#0} with closure substs [ i16, for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) i32, &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32)) -> &ReLateBound(DebruijnIndex(0), BrNamed('r)) i32, (), diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr index 50e7a81bb1fee..983d6a06afada 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr @@ -4,7 +4,7 @@ note: external requirements LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_region::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_region::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#2r)>, (), @@ -40,7 +40,7 @@ note: external requirements LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: correct_region::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: correct_region::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#2r)>, (), @@ -67,7 +67,7 @@ note: external requirements LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: wrong_region::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: wrong_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#3r)>, (), @@ -103,7 +103,7 @@ note: external requirements LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#3r)>, (), diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr index d551ccf9cf669..2513b0bfccbf1 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr @@ -4,7 +4,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_relationships_late::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), @@ -55,7 +55,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -105,7 +105,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -133,7 +133,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr index 3e17de1bf0f56..4eebe682d4fbc 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr @@ -4,7 +4,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_relationships_late::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), @@ -46,7 +46,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -87,7 +87,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -115,7 +115,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -143,7 +143,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: one_region::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr index 3d9a01fec101d..46a02598e19bc 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr @@ -4,7 +4,7 @@ note: no external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_relationships_late::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), @@ -30,7 +30,7 @@ note: no external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -56,7 +56,7 @@ note: no external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -82,7 +82,7 @@ note: no external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -108,7 +108,7 @@ note: no external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: one_region::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr index e354f1b5f7e63..4e0155bdf2cd0 100644 --- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr @@ -4,7 +4,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_relationships_late::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_relationships_late::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -41,7 +41,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_relationships_early::<'_#1r, '_#2r, '_#3r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_relationships_early::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), (), @@ -77,7 +77,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: projection_outlives::<'_#1r, '_#2r, '_#3r, T>::{{closure}}#0 with closure substs [ + = note: defining type: projection_outlives::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), (), @@ -105,7 +105,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: elements_outlive1::<'_#1r, '_#2r, '_#3r, T>::{{closure}}#0 with closure substs [ + = note: defining type: elements_outlive1::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), (), @@ -133,7 +133,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: elements_outlive2::<'_#1r, '_#2r, '_#3r, T>::{{closure}}#0 with closure substs [ + = note: defining type: elements_outlive2::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), (), @@ -161,7 +161,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: two_regions::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: two_regions::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), @@ -203,7 +203,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: two_regions_outlive::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: two_regions_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -231,7 +231,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: one_region::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr index 167ca740c657c..7c0d63c368be5 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr @@ -4,7 +4,7 @@ note: external requirements LL | twice(cell, value, |a, b| invoke(a, b)); | ^^^^^^^^^^^^^^^^^^^ | - = note: defining type: generic::::{{closure}}#0 with closure substs [ + = note: defining type: generic::::{closure#0} with closure substs [ i16, for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BrNamed('s)) T)), (), @@ -29,7 +29,7 @@ note: external requirements LL | twice(cell, value, |a, b| invoke(a, b)); | ^^^^^^^^^^^^^^^^^^^ | - = note: defining type: generic_fail::::{{closure}}#0 with closure substs [ + = note: defining type: generic_fail::::{closure#0} with closure substs [ i16, for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BrNamed('s)) T)), (), diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr index 528da502b9d40..88d73e7a729a9 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr @@ -4,7 +4,7 @@ note: external requirements LL | with_signature(x, |y| y) | ^^^^^ | - = note: defining type: no_region::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_region::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn std::fmt::Debug + '_#2r)>, (), diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr index e341ee48291a9..5b175aac1e1cb 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr @@ -11,7 +11,7 @@ LL | | require(&x, &y) LL | | }) | |_____^ | - = note: defining type: no_region::::{{closure}}#0 with closure substs [ + = note: defining type: no_region::::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#1r ()>, T)), (), @@ -62,7 +62,7 @@ LL | | require(&x, &y) LL | | }) | |_____^ | - = note: defining type: correct_region::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: correct_region::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), @@ -95,7 +95,7 @@ LL | | require(&x, &y) LL | | }) | |_____^ | - = note: defining type: wrong_region::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: wrong_region::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), @@ -141,7 +141,7 @@ LL | | require(&x, &y) LL | | }) | |_____^ | - = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), diff --git a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr index 1361117f6c4da..fee8b06e94c0b 100644 --- a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr +++ b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr @@ -1,4 +1,4 @@ -error: cannot specialize on `ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[317d]::Id[0]::This[0]) }, (I,))` +error: cannot specialize on `ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[317d]::Id::This) }, (I,))` --> $DIR/repeated_projection_type.rs:19:1 | LL | / impl> X for V { diff --git a/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr b/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr index fbe6279ca9226..277f4e8424030 100644 --- a/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr +++ b/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr @@ -1,21 +1,21 @@ -error[E0391]: cycle detected when simplifying constant for the type system `Alpha::V3::{{constant}}#0` +error[E0391]: cycle detected when simplifying constant for the type system `Alpha::V3::{constant#0}` --> $DIR/self-in-enum-definition.rs:5:10 | LL | V3 = Self::V1 {} as u8 + 2, | ^^^^^^^^ | -note: ...which requires simplifying constant for the type system `Alpha::V3::{{constant}}#0`... +note: ...which requires simplifying constant for the type system `Alpha::V3::{constant#0}`... --> $DIR/self-in-enum-definition.rs:5:10 | LL | V3 = Self::V1 {} as u8 + 2, | ^^^^^^^^ -note: ...which requires const-evaluating + checking `Alpha::V3::{{constant}}#0`... +note: ...which requires const-evaluating + checking `Alpha::V3::{constant#0}`... --> $DIR/self-in-enum-definition.rs:5:10 | LL | V3 = Self::V1 {} as u8 + 2, | ^^^^^^^^ = note: ...which requires computing layout of `Alpha`... - = note: ...which again requires simplifying constant for the type system `Alpha::V3::{{constant}}#0`, completing the cycle + = note: ...which again requires simplifying constant for the type system `Alpha::V3::{constant#0}`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/self-in-enum-definition.rs:1:1 | From 9f50c49117684c2806c54e94ee6aff7d11ca724f Mon Sep 17 00:00:00 2001 From: marmeladema Date: Mon, 31 Aug 2020 22:57:48 +0100 Subject: [PATCH 0996/1052] Implement `Display` for `DisambiguatedDefPathData` and `DefPathData` --- compiler/rustc_hir/src/definitions.rs | 65 ++++++++----------- .../src/infer/error_reporting/mod.rs | 2 +- compiler/rustc_middle/src/hir/map/mod.rs | 6 +- .../src/interpret/intrinsics/type_name.rs | 10 +-- compiler/rustc_symbol_mangling/src/legacy.rs | 8 +-- 5 files changed, 33 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index c825042bdcd02..4b803447eed99 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -15,7 +15,7 @@ use rustc_index::vec::IndexVec; use rustc_span::hygiene::ExpnId; use rustc_span::symbol::{kw, sym, Symbol}; -use std::fmt::Write; +use std::fmt::{self, Write}; use std::hash::Hash; use tracing::debug; @@ -155,6 +155,23 @@ pub struct DisambiguatedDefPathData { pub disambiguator: u32, } +impl fmt::Display for DisambiguatedDefPathData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.data.get_name() { + DefPathDataName::Named(name) => { + if self.disambiguator == 0 { + f.write_str(&name.as_str()) + } else { + write!(f, "{}#{}", name, self.disambiguator) + } + } + DefPathDataName::Anon { namespace } => { + write!(f, "{{{}#{}}}", namespace, self.disambiguator) + } + } + } +} + #[derive(Clone, Debug, Encodable, Decodable)] pub struct DefPath { /// The path leading from the crate root to the item. @@ -202,35 +219,7 @@ impl DefPath { let mut s = String::with_capacity(self.data.len() * 16); for component in &self.data { - match component.data.get_name() { - DefPathDataName::Named(name) => write!(s, "::{}", name).unwrap(), - DefPathDataName::Anon { namespace } => { - write!(s, "::{{{}#{}}}", namespace, component.disambiguator).unwrap() - } - } - } - - s - } - - /// Returns a filename-friendly string for the `DefPath`, with the - /// crate-prefix. - pub fn to_string_friendly(&self, crate_imported_name: F) -> String - where - F: FnOnce(CrateNum) -> Symbol, - { - let crate_name_str = crate_imported_name(self.krate).as_str(); - let mut s = String::with_capacity(crate_name_str.len() + self.data.len() * 16); - - write!(s, "::{}", crate_name_str).unwrap(); - - for component in &self.data { - match component.data.get_name() { - DefPathDataName::Named(name) => write!(s, "::{}", name).unwrap(), - DefPathDataName::Anon { namespace } => { - write!(s, "{{{}#{}}}", namespace, component.disambiguator).unwrap() - } - } + write!(s, "::{}", component).unwrap(); } s @@ -246,13 +235,9 @@ impl DefPath { for component in &self.data { s.extend(opt_delimiter); opt_delimiter = Some('-'); - match component.data.get_name() { - DefPathDataName::Named(name) => write!(s, "{}", name).unwrap(), - DefPathDataName::Anon { namespace } => { - write!(s, "{{{}#{}}}", namespace, component.disambiguator).unwrap() - } - } + write!(s, "{}", component).unwrap(); } + s } } @@ -465,11 +450,13 @@ impl DefPathData { ImplTrait => DefPathDataName::Anon { namespace: sym::opaque }, } } +} - pub fn to_string(&self) -> String { +impl fmt::Display for DefPathData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.get_name() { - DefPathDataName::Named(name) => name.to_string(), - DefPathDataName::Anon { namespace } => format!("{{{{{}}}}}", namespace), + DefPathDataName::Named(name) => f.write_str(&name.as_str()), + DefPathDataName::Anon { namespace } => write!(f, "{{{{{}}}}}", namespace), } } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index a99193c972bd4..795c5a64d26b7 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -531,7 +531,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { disambiguated_data: &DisambiguatedDefPathData, ) -> Result { let mut path = print_prefix(self)?; - path.push(disambiguated_data.data.to_string()); + path.push(disambiguated_data.to_string()); Ok(path) } fn path_generic_args( diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 1e57411f9c54f..ceb873adf5cb6 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1002,11 +1002,7 @@ fn hir_id_to_string(map: &Map<'_>, id: HirId) -> String { let def_id = map.local_def_id(id); tcx.def_path_str(def_id.to_def_id()) } else if let Some(path) = map.def_path_from_hir_id(id) { - path.data - .into_iter() - .map(|elem| elem.data.to_string()) - .collect::>() - .join("::") + path.data.into_iter().map(|elem| elem.to_string()).collect::>().join("::") } else { String::from("") } diff --git a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs index 8cf768a006bbf..554ada1ab254c 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs @@ -1,5 +1,5 @@ use rustc_hir::def_id::CrateNum; -use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData}; +use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; use rustc_middle::mir::interpret::Allocation; use rustc_middle::ty::{ self, @@ -132,14 +132,8 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { return Ok(self); } - self.path.push_str("::"); + write!(self.path, "::{}", disambiguated_data.data).unwrap(); - match disambiguated_data.data.get_name() { - DefPathDataName::Named(name) => self.path.write_str(&name.as_str()).unwrap(), - DefPathDataName::Anon { namespace } => { - write!(self.path, "{{{{{}}}}}", namespace).unwrap() - } - } Ok(self) } diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 15eab8bb8572b..b96e318bd3ea1 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -1,6 +1,6 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::def_id::CrateNum; -use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData}; +use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; use rustc_middle::ich::NodeIdHashingMode; use rustc_middle::mir::interpret::{ConstValue, Scalar}; use rustc_middle::ty::print::{PrettyPrinter, Print, Printer}; @@ -316,10 +316,8 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> { self.path.finalize_pending_component(); } - match disambiguated_data.data.get_name() { - DefPathDataName::Named(name) => self.write_str(&name.as_str())?, - DefPathDataName::Anon { namespace } => write!(self, "{{{{{}}}}}", namespace)?, - } + write!(self, "{}", disambiguated_data.data)?; + Ok(self) } fn path_generic_args( From 2708ad8bb441fb500bbd2486779c215ffd57bcd2 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Mon, 31 Aug 2020 23:26:15 +0100 Subject: [PATCH 0997/1052] Fix pretty-printing of `DisambiguatedDefPathData` --- compiler/rustc_hir/src/definitions.rs | 28 +++++++++++++------- compiler/rustc_middle/src/ty/print/pretty.rs | 19 +++---------- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 4b803447eed99..ae2ce6f176a85 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -13,7 +13,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::StableHasher; use rustc_index::vec::IndexVec; use rustc_span::hygiene::ExpnId; -use rustc_span::symbol::{kw, sym, Symbol}; +use rustc_span::symbol::{kw, sym, Ident, Symbol}; use std::fmt::{self, Write}; use std::hash::Hash; @@ -155,23 +155,32 @@ pub struct DisambiguatedDefPathData { pub disambiguator: u32, } -impl fmt::Display for DisambiguatedDefPathData { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl DisambiguatedDefPathData { + pub fn fmt_maybe_verbose(&self, writer: &mut impl Write, verbose: bool) -> fmt::Result { match self.data.get_name() { DefPathDataName::Named(name) => { - if self.disambiguator == 0 { - f.write_str(&name.as_str()) + if Ident::with_dummy_span(name).is_raw_guess() { + writer.write_str("r#")?; + } + if self.disambiguator == 0 || !verbose { + writer.write_str(&name.as_str()) } else { - write!(f, "{}#{}", name, self.disambiguator) + write!(writer, "{}#{}", name, self.disambiguator) } } DefPathDataName::Anon { namespace } => { - write!(f, "{{{}#{}}}", namespace, self.disambiguator) + write!(writer, "{{{}#{}}}", namespace, self.disambiguator) } } } } +impl fmt::Display for DisambiguatedDefPathData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.fmt_maybe_verbose(f, true) + } +} + #[derive(Clone, Debug, Encodable, Decodable)] pub struct DefPath { /// The path leading from the crate root to the item. @@ -419,6 +428,7 @@ impl Definitions { } } +#[derive(Copy, Clone, PartialEq, Debug)] pub enum DefPathDataName { Named(Symbol), Anon { namespace: Symbol }, @@ -434,7 +444,7 @@ impl DefPathData { } } - pub fn get_name(&self) -> DefPathDataName { + pub fn name(&self) -> DefPathDataName { use self::DefPathData::*; match *self { TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => { @@ -454,7 +464,7 @@ impl DefPathData { impl fmt::Display for DefPathData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.get_name() { + match self.name() { DefPathDataName::Named(name) => f.write_str(&name.as_str()), DefPathDataName::Anon { namespace } => write!(f, "{{{{{}}}}}", namespace), } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 91986289099d3..7ec14d43892a5 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1496,27 +1496,16 @@ impl Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { return Ok(self); } - let name = match disambiguated_data.data.get_name() { - DefPathDataName::Named(name) => name, - DefPathDataName::Anon { namespace } => namespace, - }; - // FIXME(eddyb) `name` should never be empty, but it // currently is for `extern { ... }` "foreign modules". - if name != kw::Invalid { + let name = disambiguated_data.data.get_name(); + if name != DefPathDataName::Named(kw::Invalid) { if !self.empty_path { write!(self, "::")?; } - if Ident::with_dummy_span(name).is_raw_guess() { - write!(self, "r#")?; - } - match disambiguated_data.data.get_name() { - DefPathDataName::Named(name) => self.write_str(&name.as_str())?, - DefPathDataName::Anon { namespace } => { - write!(self, "{{{}#{}}}", namespace, disambiguated_data.disambiguator)? - } - } + let verbose = self.tcx.sess.verbose(); + disambiguated_data.fmt_maybe_verbose(&mut self, verbose)?; self.empty_path = false; } From 657ecdb75e2a9f8e8295bc75d9fe810f02605130 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Tue, 1 Sep 2020 00:42:30 +0100 Subject: [PATCH 0998/1052] Rename `DefPathData::get_name()` to `DefPathData::name()` --- compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs | 2 +- compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs | 2 +- compiler/rustc_hir/src/definitions.rs | 2 +- compiler/rustc_lint/src/context.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 2 +- compiler/rustc_middle/src/ty/query/profiling_support.rs | 2 +- compiler/rustc_mir/src/monomorphize/partitioning/default.rs | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs index 835d0d2e12d66..661d13ead838c 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs @@ -30,7 +30,7 @@ pub fn item_namespace(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope { let namespace_name = match def_key.disambiguated_data.data { DefPathData::CrateRoot => cx.tcx.crate_name(def_id.krate), - data => match data.get_name() { + data => match data.name() { DefPathDataName::Named(name) => name, DefPathDataName::Anon { namespace } => { Symbol::intern(&format!("{{{{{}}}}}", namespace)) diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index e227f9df000e1..5642cc526aea3 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -232,7 +232,7 @@ pub fn push_debuginfo_type_name<'tcx>( output.push_str(&tcx.crate_name(def_id.krate).as_str()); for path_element in tcx.def_path(def_id).data { output.push_str("::"); - match path_element.data.get_name() { + match path_element.data.name() { DefPathDataName::Named(name) => output.push_str(&name.as_str()), DefPathDataName::Anon { namespace } => { write!(output, "{{{{{}}}}}", namespace).unwrap() diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index ae2ce6f176a85..5d1c6b78f361c 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -157,7 +157,7 @@ pub struct DisambiguatedDefPathData { impl DisambiguatedDefPathData { pub fn fmt_maybe_verbose(&self, writer: &mut impl Write, verbose: bool) -> fmt::Result { - match self.data.get_name() { + match self.data.name() { DefPathDataName::Named(name) => { if Ident::with_dummy_span(name).is_raw_guess() { writer.write_str("r#")?; diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index e4b72847638cd..776c3c83e028d 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -846,7 +846,7 @@ impl<'tcx> LateContext<'tcx> { return Ok(path); } - path.push(match disambiguated_data.data.get_name() { + path.push(match disambiguated_data.data.name() { DefPathDataName::Named(name) => name, DefPathDataName::Anon { namespace } => { Symbol::intern(&format!("{{{{{}}}}}", namespace)) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 7ec14d43892a5..0e1d5c8fee7d5 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1498,7 +1498,7 @@ impl Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { // FIXME(eddyb) `name` should never be empty, but it // currently is for `extern { ... }` "foreign modules". - let name = disambiguated_data.data.get_name(); + let name = disambiguated_data.data.name(); if name != DefPathDataName::Named(kw::Invalid) { if !self.empty_path { write!(self, "::")?; diff --git a/compiler/rustc_middle/src/ty/query/profiling_support.rs b/compiler/rustc_middle/src/ty/query/profiling_support.rs index cecb58eb024c0..f8269fe372efc 100644 --- a/compiler/rustc_middle/src/ty/query/profiling_support.rs +++ b/compiler/rustc_middle/src/ty/query/profiling_support.rs @@ -66,7 +66,7 @@ impl<'p, 'c, 'tcx> QueryKeyStringBuilder<'p, 'c, 'tcx> { end_index = 3; } other => { - name = match other.get_name() { + name = match other.name() { DefPathDataName::Named(name) => { dis = ""; end_index = 3; diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs index c9622df099f83..62805a973f571 100644 --- a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs @@ -355,7 +355,7 @@ fn compute_codegen_unit_name( *cache.entry((cgu_def_id, volatile)).or_insert_with(|| { let def_path = tcx.def_path(cgu_def_id); - let components = def_path.data.iter().map(|part| match part.data.get_name() { + let components = def_path.data.iter().map(|part| match part.data.name() { DefPathDataName::Named(name) => name, DefPathDataName::Anon { namespace } => { Symbol::intern(&format!("{{{{{}}}}}", namespace)) From 75130b06bff9cf4af528cf19513f802a837bdd23 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Tue, 1 Sep 2020 09:31:02 +0100 Subject: [PATCH 0999/1052] Avoid calling `Symbol::interner` in `compute_codegen_unit_name` --- compiler/rustc_mir/src/monomorphize/partitioning/default.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs index 62805a973f571..3c89111a659f5 100644 --- a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs @@ -357,9 +357,7 @@ fn compute_codegen_unit_name( let components = def_path.data.iter().map(|part| match part.data.name() { DefPathDataName::Named(name) => name, - DefPathDataName::Anon { namespace } => { - Symbol::intern(&format!("{{{{{}}}}}", namespace)) - } + DefPathDataName::Anon { .. } => unreachable!(), }); let volatile_suffix = volatile.then_some("volatile"); From bb8e1764bb31bc63a6b61f446e28bb567015de01 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Tue, 1 Sep 2020 13:11:28 +0100 Subject: [PATCH 1000/1052] Simplify some match statements on `DefPathDataName' --- compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs | 9 ++------- compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs | 9 +-------- compiler/rustc_lint/src/context.rs | 9 ++------- 3 files changed, 5 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs index 661d13ead838c..512fc87905e09 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs @@ -7,7 +7,7 @@ use crate::common::CodegenCx; use crate::llvm; use crate::llvm::debuginfo::DIScope; use rustc_hir::def_id::DefId; -use rustc_hir::definitions::{DefPathData, DefPathDataName}; +use rustc_hir::definitions::DefPathData; use rustc_span::symbol::Symbol; pub fn mangled_name_of_instance<'a, 'tcx>( @@ -30,12 +30,7 @@ pub fn item_namespace(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope { let namespace_name = match def_key.disambiguated_data.data { DefPathData::CrateRoot => cx.tcx.crate_name(def_id.krate), - data => match data.name() { - DefPathDataName::Named(name) => name, - DefPathDataName::Anon { namespace } => { - Symbol::intern(&format!("{{{{{}}}}}", namespace)) - } - }, + data => Symbol::intern(&data.to_string()), }; let namespace_name = namespace_name.as_str(); diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 5642cc526aea3..45ecb793387d0 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -3,7 +3,6 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_hir::definitions::DefPathDataName; use rustc_middle::ty::{self, subst::SubstsRef, Ty, TyCtxt}; use std::fmt::Write; @@ -231,13 +230,7 @@ pub fn push_debuginfo_type_name<'tcx>( if qualified { output.push_str(&tcx.crate_name(def_id.krate).as_str()); for path_element in tcx.def_path(def_id).data { - output.push_str("::"); - match path_element.data.name() { - DefPathDataName::Named(name) => output.push_str(&name.as_str()), - DefPathDataName::Anon { namespace } => { - write!(output, "{{{{{}}}}}", namespace).unwrap() - } - } + write!(output, "::{}", path_element.data).unwrap(); } } else { output.push_str(&tcx.item_name(def_id).as_str()); diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 776c3c83e028d..7a3035e5b4631 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -26,7 +26,7 @@ use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::{CrateNum, DefId}; -use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData}; +use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; use rustc_middle::lint::LintDiagnosticBuilder; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::middle::stability; @@ -846,12 +846,7 @@ impl<'tcx> LateContext<'tcx> { return Ok(path); } - path.push(match disambiguated_data.data.name() { - DefPathDataName::Named(name) => name, - DefPathDataName::Anon { namespace } => { - Symbol::intern(&format!("{{{{{}}}}}", namespace)) - } - }); + path.push(Symbol::intern(&disambiguated_data.data.to_string())); Ok(path) } From 23085b6360088758a55c12503864e6c1297e8dd5 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Tue, 1 Sep 2020 19:34:46 +0100 Subject: [PATCH 1001/1052] Fix profiling query key creation --- .../src/ty/query/profiling_support.rs | 31 +++++++------------ 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_middle/src/ty/query/profiling_support.rs b/compiler/rustc_middle/src/ty/query/profiling_support.rs index f8269fe372efc..d1257a1c39434 100644 --- a/compiler/rustc_middle/src/ty/query/profiling_support.rs +++ b/compiler/rustc_middle/src/ty/query/profiling_support.rs @@ -4,9 +4,10 @@ use measureme::{StringComponent, StringId}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::profiling::SelfProfiler; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; -use rustc_hir::definitions::{DefPathData, DefPathDataName}; +use rustc_hir::definitions::DefPathData; use rustc_query_system::query::QueryCache; use rustc_query_system::query::QueryState; +use rustc_span::symbol::Symbol; use std::fmt::Debug; use std::io::Write; @@ -66,25 +67,17 @@ impl<'p, 'c, 'tcx> QueryKeyStringBuilder<'p, 'c, 'tcx> { end_index = 3; } other => { - name = match other.name() { - DefPathDataName::Named(name) => { - dis = ""; - end_index = 3; - name - } - DefPathDataName::Anon { namespace } => { - write!( - &mut dis_buffer[..], - "[{}]", - def_key.disambiguated_data.disambiguator - ) + name = Symbol::intern(&other.to_string()); + if def_key.disambiguated_data.disambiguator == 0 { + dis = ""; + end_index = 3; + } else { + write!(&mut dis_buffer[..], "[{}]", def_key.disambiguated_data.disambiguator) .unwrap(); - let end_of_dis = dis_buffer.iter().position(|&c| c == b']').unwrap(); - dis = std::str::from_utf8(&dis_buffer[..end_of_dis + 1]).unwrap(); - end_index = 4; - namespace - } - }; + let end_of_dis = dis_buffer.iter().position(|&c| c == b']').unwrap(); + dis = std::str::from_utf8(&dis_buffer[..end_of_dis + 1]).unwrap(); + end_index = 4; + } } } From f25d0bc559b616376efece5ee8681552bcce44ab Mon Sep 17 00:00:00 2001 From: marmeladema Date: Tue, 1 Sep 2020 19:37:12 +0100 Subject: [PATCH 1002/1052] Remove now unused `double_braced_*` symbols --- compiler/rustc_span/src/symbol.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index a63e9e933aebe..602bb4a44a91b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -441,13 +441,6 @@ symbols! { document_private_items, dotdot_in_tuple_patterns, dotdoteq_in_patterns, - double_braced_closure: "{{closure}}", - double_braced_constant: "{{constant}}", - double_braced_constructor: "{{constructor}}", - double_braced_crate: "{{crate}}", - double_braced_impl: "{{impl}}", - double_braced_misc: "{{misc}}", - double_braced_opaque: "{{opaque}}", drop, drop_in_place, drop_types_in_const, From 601c284e1e551b618cd2dbb2cc8b9a602d20e887 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Mon, 21 Sep 2020 22:19:44 +0100 Subject: [PATCH 1003/1052] Fix tests --- src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff | 8 ++++---- src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff index 99ea92299c61a..f24bcfe5a1cb6 100644 --- a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff +++ b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff @@ -76,10 +76,10 @@ (_4.1: &i32) = 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[0]), const_param_did: None }, [], Some(promoted[1])) + // + 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[0]), const_param_did: None }, [], Some(promoted[1])) } + // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[1])) } StorageLive(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _5 = (_4.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _6 = (_4.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -106,10 +106,10 @@ _25 = const main::promoted[0] as &[&str] (Pointer(Unsize)); // 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[0]), const_param_did: None }, [], Some(promoted[0])) + // + 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[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0])) } StorageLive(_13); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL StorageLive(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _15 = _5; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff index 99ea92299c61a..f24bcfe5a1cb6 100644 --- a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff +++ b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff @@ -76,10 +76,10 @@ (_4.1: &i32) = 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[0]), const_param_did: None }, [], Some(promoted[1])) + // + 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[0]), const_param_did: None }, [], Some(promoted[1])) } + // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[1])) } StorageLive(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _5 = (_4.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _6 = (_4.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -106,10 +106,10 @@ _25 = const main::promoted[0] as &[&str] (Pointer(Unsize)); // 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[0]), const_param_did: None }, [], Some(promoted[0])) + // + 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[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0])) } StorageLive(_13); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL StorageLive(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _15 = _5; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL From 35bad3edbfd99ecf8698ac917a2582109bac5503 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Wed, 23 Sep 2020 23:38:38 +0100 Subject: [PATCH 1004/1052] Address review comment --- .../rustc_codegen_llvm/src/debuginfo/namespace.rs | 14 ++++++++++---- compiler/rustc_hir/src/definitions.rs | 9 +++++---- compiler/rustc_middle/src/hir/map/collector.rs | 8 +++++--- compiler/rustc_middle/src/ty/context.rs | 2 +- .../rustc_middle/src/ty/query/profiling_support.rs | 10 ++++++---- compiler/rustc_passes/src/hir_id_validator.rs | 8 ++++---- 6 files changed, 31 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs index 512fc87905e09..9945d4f428259 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs @@ -8,7 +8,6 @@ use crate::llvm; use crate::llvm::debuginfo::DIScope; use rustc_hir::def_id::DefId; use rustc_hir::definitions::DefPathData; -use rustc_span::symbol::Symbol; pub fn mangled_name_of_instance<'a, 'tcx>( cx: &CodegenCx<'a, 'tcx>, @@ -28,11 +27,18 @@ pub fn item_namespace(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope { .parent .map(|parent| item_namespace(cx, DefId { krate: def_id.krate, index: parent })); + let crate_name_as_str; + let name_to_string; let namespace_name = match def_key.disambiguated_data.data { - DefPathData::CrateRoot => cx.tcx.crate_name(def_id.krate), - data => Symbol::intern(&data.to_string()), + DefPathData::CrateRoot => { + crate_name_as_str = cx.tcx.crate_name(def_id.krate).as_str(); + &*crate_name_as_str + } + data => { + name_to_string = data.to_string(); + &*name_to_string + } }; - let namespace_name = namespace_name.as_str(); let scope = unsafe { llvm::LLVMRustDIBuilderCreateNameSpace( diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 5d1c6b78f361c..74c91f8a859be 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -162,10 +162,10 @@ impl DisambiguatedDefPathData { if Ident::with_dummy_span(name).is_raw_guess() { writer.write_str("r#")?; } - if self.disambiguator == 0 || !verbose { - writer.write_str(&name.as_str()) - } else { + if verbose && self.disambiguator != 0 { write!(writer, "{}#{}", name, self.disambiguator) + } else { + writer.write_str(&name.as_str()) } } DefPathDataName::Anon { namespace } => { @@ -224,7 +224,7 @@ impl DefPath { /// Returns a string representation of the `DefPath` without /// the crate-prefix. This method is useful if you don't have /// a `TyCtxt` available. - pub fn to_string_no_crate(&self) -> String { + pub fn to_string_no_crate_verbose(&self) -> String { let mut s = String::with_capacity(self.data.len() * 16); for component in &self.data { @@ -466,6 +466,7 @@ impl fmt::Display for DefPathData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.name() { DefPathDataName::Named(name) => f.write_str(&name.as_str()), + // FIXME(#70334): this will generate legacy {{closure}}, {{impl}}, etc DefPathDataName::Anon { namespace } => write!(f, "{{{{{}}}}}", namespace), } } diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs index dce06a5f7eeec..d6869ab88751a 100644 --- a/compiler/rustc_middle/src/hir/map/collector.rs +++ b/compiler/rustc_middle/src/hir/map/collector.rs @@ -244,7 +244,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { if cfg!(debug_assertions) { if hir_id.owner != self.current_dep_node_owner { let node_str = match self.definitions.opt_hir_id_to_local_def_id(hir_id) { - Some(def_id) => self.definitions.def_path(def_id).to_string_no_crate(), + Some(def_id) => self.definitions.def_path(def_id).to_string_no_crate_verbose(), None => format!("{:?}", node), }; @@ -254,9 +254,11 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})", self.source_map.span_to_string(span), node_str, - self.definitions.def_path(self.current_dep_node_owner).to_string_no_crate(), + self.definitions + .def_path(self.current_dep_node_owner) + .to_string_no_crate_verbose(), self.current_dep_node_owner, - self.definitions.def_path(hir_id.owner).to_string_no_crate(), + self.definitions.def_path(hir_id.owner).to_string_no_crate_verbose(), hir_id.owner, ) } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index ccc8ffd9a9c6e..22c3fd37be14d 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1272,7 +1272,7 @@ impl<'tcx> TyCtxt<'tcx> { // Don't print the whole crate disambiguator. That's just // annoying in debug output. &(crate_disambiguator.to_fingerprint().to_hex())[..4], - self.def_path(def_id).to_string_no_crate() + self.def_path(def_id).to_string_no_crate_verbose() ) } diff --git a/compiler/rustc_middle/src/ty/query/profiling_support.rs b/compiler/rustc_middle/src/ty/query/profiling_support.rs index d1257a1c39434..4e8db3194bdff 100644 --- a/compiler/rustc_middle/src/ty/query/profiling_support.rs +++ b/compiler/rustc_middle/src/ty/query/profiling_support.rs @@ -7,7 +7,6 @@ use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, use rustc_hir::definitions::DefPathData; use rustc_query_system::query::QueryCache; use rustc_query_system::query::QueryState; -use rustc_span::symbol::Symbol; use std::fmt::Debug; use std::io::Write; @@ -56,18 +55,22 @@ impl<'p, 'c, 'tcx> QueryKeyStringBuilder<'p, 'c, 'tcx> { }; let dis_buffer = &mut [0u8; 16]; + let crate_name; + let other_name; let name; let dis; let end_index; match def_key.disambiguated_data.data { DefPathData::CrateRoot => { - name = self.tcx.original_crate_name(def_id.krate); + crate_name = self.tcx.original_crate_name(def_id.krate).as_str(); + name = &*crate_name; dis = ""; end_index = 3; } other => { - name = Symbol::intern(&other.to_string()); + other_name = other.to_string(); + name = other_name.as_str(); if def_key.disambiguated_data.disambiguator == 0 { dis = ""; end_index = 3; @@ -81,7 +84,6 @@ impl<'p, 'c, 'tcx> QueryKeyStringBuilder<'p, 'c, 'tcx> { } } - let name = &*name.as_str(); let components = [ StringComponent::Ref(parent_string_id), StringComponent::Value("::"), diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs index 2edbc29b7efb6..24695f5cdfa04 100644 --- a/compiler/rustc_passes/src/hir_id_validator.rs +++ b/compiler/rustc_passes/src/hir_id_validator.rs @@ -112,14 +112,14 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> { missing_items.push(format!( "[local_id: {}, owner: {}]", local_id, - self.hir_map.def_path(owner).to_string_no_crate() + self.hir_map.def_path(owner).to_string_no_crate_verbose() )); } self.error(|| { format!( "ItemLocalIds not assigned densely in {}. \ Max ItemLocalId = {}, missing IDs = {:?}; seens IDs = {:?}", - self.hir_map.def_path(owner).to_string_no_crate(), + self.hir_map.def_path(owner).to_string_no_crate_verbose(), max, missing_items, self.hir_ids_seen @@ -148,8 +148,8 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { format!( "HirIdValidator: The recorded owner of {} is {} instead of {}", self.hir_map.node_to_string(hir_id), - self.hir_map.def_path(hir_id.owner).to_string_no_crate(), - self.hir_map.def_path(owner).to_string_no_crate() + self.hir_map.def_path(hir_id.owner).to_string_no_crate_verbose(), + self.hir_map.def_path(owner).to_string_no_crate_verbose() ) }); } From 5946c12476b488dbc4555741321321a1cbd4d68c Mon Sep 17 00:00:00 2001 From: marmeladema Date: Thu, 24 Sep 2020 10:23:01 +0100 Subject: [PATCH 1005/1052] Move `is_raw_guess` check in `ty::print::pretty` --- compiler/rustc_hir/src/definitions.rs | 5 +---- compiler/rustc_middle/src/ty/print/pretty.rs | 6 ++++++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 74c91f8a859be..afefde07f9297 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -13,7 +13,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::StableHasher; use rustc_index::vec::IndexVec; use rustc_span::hygiene::ExpnId; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::symbol::{kw, sym, Symbol}; use std::fmt::{self, Write}; use std::hash::Hash; @@ -159,9 +159,6 @@ impl DisambiguatedDefPathData { pub fn fmt_maybe_verbose(&self, writer: &mut impl Write, verbose: bool) -> fmt::Result { match self.data.name() { DefPathDataName::Named(name) => { - if Ident::with_dummy_span(name).is_raw_guess() { - writer.write_str("r#")?; - } if verbose && self.disambiguator != 0 { write!(writer, "{}#{}", name, self.disambiguator) } else { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 0e1d5c8fee7d5..cfc4b062885b8 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1504,6 +1504,12 @@ impl Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { write!(self, "::")?; } + if let DefPathDataName::Named(name) = name { + if Ident::with_dummy_span(name).is_raw_guess() { + write!(self, "r#")?; + } + } + let verbose = self.tcx.sess.verbose(); disambiguated_data.fmt_maybe_verbose(&mut self, verbose)?; From aa6a2f4035a8c02f85563e361fe3c760766c53f7 Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 25 Sep 2020 14:59:00 -0700 Subject: [PATCH 1006/1052] Rename `whence` to `span` It's called `span` elsewhere in the compiler and `span` is also less surprising. `whence` is whimsical, but not super clear :) --- src/librustdoc/clean/mod.rs | 38 ++++++++++++++++++------------------- src/librustdoc/doctree.rs | 34 ++++++++++++++++----------------- src/librustdoc/visit_ast.rs | 34 ++++++++++++++++----------------- 3 files changed, 53 insertions(+), 53 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 46ba14aa67e60..788bb5e787b82 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -256,7 +256,7 @@ impl Clean for doctree::Module<'_> { // determine if we should display the inner contents or // the outer `mod` item for the source code. - let whence = { + let span = { let sm = cx.sess().source_map(); let outer = sm.lookup_char_pos(self.where_outer.lo()); let inner = sm.lookup_char_pos(self.where_inner.lo()); @@ -272,7 +272,7 @@ impl Clean for doctree::Module<'_> { Item { name: Some(name), attrs, - source: whence.clean(cx), + source: span.clean(cx), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx), @@ -912,7 +912,7 @@ impl Clean for doctree::Function<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx), @@ -1020,7 +1020,7 @@ impl Clean for doctree::Trait<'_> { Item { name: Some(self.name.clean(cx)), attrs, - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -1044,7 +1044,7 @@ impl Clean for doctree::TraitAlias<'_> { Item { name: Some(self.name.clean(cx)), attrs, - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -1830,7 +1830,7 @@ impl Clean for doctree::Struct<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -1850,7 +1850,7 @@ impl Clean for doctree::Union<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -1880,7 +1880,7 @@ impl Clean for doctree::Enum<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -1899,7 +1899,7 @@ impl Clean for doctree::Variant<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), visibility: Inherited, stability: cx.stability(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx), @@ -2047,7 +2047,7 @@ impl Clean for doctree::Typedef<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -2062,7 +2062,7 @@ impl Clean for doctree::OpaqueTy<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -2093,7 +2093,7 @@ impl Clean for doctree::Static<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -2114,7 +2114,7 @@ impl Clean for doctree::Constant<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: def_id.to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -2168,7 +2168,7 @@ impl Clean> for doctree::Impl<'_> { let make_item = |trait_: Option, for_: Type, items: Vec| Item { name: None, attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: def_id.to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -2219,7 +2219,7 @@ impl Clean> for doctree::ExternCrate<'_> { vec![Item { name: None, attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: DefId { krate: self.cnum, index: CRATE_DEF_INDEX }, visibility: self.vis.clean(cx), stability: None, @@ -2284,7 +2284,7 @@ impl Clean> for doctree::Import<'_> { vec![Item { name: None, attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: DefId::local(CRATE_DEF_INDEX), visibility: self.vis.clean(cx), stability: None, @@ -2326,7 +2326,7 @@ impl Clean for doctree::ForeignItem<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -2342,7 +2342,7 @@ impl Clean for doctree::Macro<'_> { Item { name: Some(name.clone()), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), visibility: Public, stability: cx.stability(self.hid).clean(cx), deprecation: cx.deprecation(self.hid).clean(cx), @@ -2367,7 +2367,7 @@ impl Clean for doctree::ProcMacro<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), visibility: Public, stability: cx.stability(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx), diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 98125adbdea41..cfa51dcf4f1d1 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -89,7 +89,7 @@ pub struct Struct<'hir> { pub generics: &'hir hir::Generics<'hir>, pub attrs: &'hir [ast::Attribute], pub fields: &'hir [hir::StructField<'hir>], - pub whence: Span, + pub span: Span, } pub struct Union<'hir> { @@ -100,7 +100,7 @@ pub struct Union<'hir> { pub generics: &'hir hir::Generics<'hir>, pub attrs: &'hir [ast::Attribute], pub fields: &'hir [hir::StructField<'hir>], - pub whence: Span, + pub span: Span, } pub struct Enum<'hir> { @@ -109,7 +109,7 @@ pub struct Enum<'hir> { pub generics: &'hir hir::Generics<'hir>, pub attrs: &'hir [ast::Attribute], pub id: hir::HirId, - pub whence: Span, + pub span: Span, pub name: Symbol, } @@ -118,7 +118,7 @@ pub struct Variant<'hir> { pub id: hir::HirId, pub attrs: &'hir [ast::Attribute], pub def: &'hir hir::VariantData<'hir>, - pub whence: Span, + pub span: Span, } pub struct Function<'hir> { @@ -128,7 +128,7 @@ pub struct Function<'hir> { pub name: Symbol, pub vis: &'hir hir::Visibility<'hir>, pub header: hir::FnHeader, - pub whence: Span, + pub span: Span, pub generics: &'hir hir::Generics<'hir>, pub body: hir::BodyId, } @@ -139,7 +139,7 @@ pub struct Typedef<'hir> { pub name: Symbol, pub id: hir::HirId, pub attrs: &'hir [ast::Attribute], - pub whence: Span, + pub span: Span, pub vis: &'hir hir::Visibility<'hir>, } @@ -148,7 +148,7 @@ pub struct OpaqueTy<'hir> { pub name: Symbol, pub id: hir::HirId, pub attrs: &'hir [ast::Attribute], - pub whence: Span, + pub span: Span, pub vis: &'hir hir::Visibility<'hir>, } @@ -161,7 +161,7 @@ pub struct Static<'hir> { pub attrs: &'hir [ast::Attribute], pub vis: &'hir hir::Visibility<'hir>, pub id: hir::HirId, - pub whence: Span, + pub span: Span, } pub struct Constant<'hir> { @@ -171,7 +171,7 @@ pub struct Constant<'hir> { pub attrs: &'hir [ast::Attribute], pub vis: &'hir hir::Visibility<'hir>, pub id: hir::HirId, - pub whence: Span, + pub span: Span, } pub struct Trait<'hir> { @@ -183,7 +183,7 @@ pub struct Trait<'hir> { pub bounds: &'hir [hir::GenericBound<'hir>], pub attrs: &'hir [ast::Attribute], pub id: hir::HirId, - pub whence: Span, + pub span: Span, pub vis: &'hir hir::Visibility<'hir>, } @@ -193,7 +193,7 @@ pub struct TraitAlias<'hir> { pub bounds: &'hir [hir::GenericBound<'hir>], pub attrs: &'hir [ast::Attribute], pub id: hir::HirId, - pub whence: Span, + pub span: Span, pub vis: &'hir hir::Visibility<'hir>, } @@ -208,7 +208,7 @@ pub struct Impl<'hir> { pub for_: &'hir hir::Ty<'hir>, pub items: Vec<&'hir hir::ImplItem<'hir>>, pub attrs: &'hir [ast::Attribute], - pub whence: Span, + pub span: Span, pub vis: &'hir hir::Visibility<'hir>, pub id: hir::HirId, } @@ -219,7 +219,7 @@ pub struct ForeignItem<'hir> { pub name: Symbol, pub kind: &'hir hir::ForeignItemKind<'hir>, pub attrs: &'hir [ast::Attribute], - pub whence: Span, + pub span: Span, } // For Macro we store the DefId instead of the NodeId, since we also create @@ -229,7 +229,7 @@ pub struct Macro<'hir> { pub hid: hir::HirId, pub def_id: hir::def_id::DefId, pub attrs: &'hir [ast::Attribute], - pub whence: Span, + pub span: Span, pub matchers: Vec, pub imported_from: Option, } @@ -240,7 +240,7 @@ pub struct ExternCrate<'hir> { pub path: Option, pub vis: &'hir hir::Visibility<'hir>, pub attrs: &'hir [ast::Attribute], - pub whence: Span, + pub span: Span, } pub struct Import<'hir> { @@ -250,7 +250,7 @@ pub struct Import<'hir> { pub attrs: &'hir [ast::Attribute], pub path: &'hir hir::Path<'hir>, pub glob: bool, - pub whence: Span, + pub span: Span, } pub struct ProcMacro<'hir> { @@ -259,7 +259,7 @@ pub struct ProcMacro<'hir> { pub kind: MacroKind, pub helpers: Vec, pub attrs: &'hir [ast::Attribute], - pub whence: Span, + pub span: Span, } pub fn struct_type_from_def(vdata: &hir::VariantData<'_>) -> StructType { diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index ac9f839600baf..33578dc0619d1 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -99,7 +99,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { attrs: &item.attrs, generics, fields: sd.fields(), - whence: item.span, + span: item.span, } } @@ -120,7 +120,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { attrs: &item.attrs, generics, fields: sd.fields(), - whence: item.span, + span: item.span, } } @@ -142,14 +142,14 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { id: v.id, attrs: &v.attrs, def: &v.data, - whence: v.span, + span: v.span, }) .collect(), vis: &it.vis, generics, attrs: &it.attrs, id: it.hir_id, - whence: it.span, + span: it.span, } } @@ -208,7 +208,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { kind, helpers, attrs: &item.attrs, - whence: item.span, + span: item.span, }); } None => { @@ -218,7 +218,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { attrs: &item.attrs, decl, name, - whence: item.span, + span: item.span, generics, header, body, @@ -402,7 +402,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { path: orig_name.map(|x| x.to_string()), vis: &item.vis, attrs: &item.attrs, - whence: item.span, + span: item.span, }) } hir::ItemKind::Use(_, hir::UseKind::ListStem) => {} @@ -444,7 +444,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { attrs: &item.attrs, path, glob: is_glob, - whence: item.span, + span: item.span, }); } hir::ItemKind::Mod(ref m) => { @@ -476,7 +476,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { name: ident.name, id: item.hir_id, attrs: &item.attrs, - whence: item.span, + span: item.span, vis: &item.vis, }; om.typedefs.push(t); @@ -487,7 +487,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { name: ident.name, id: item.hir_id, attrs: &item.attrs, - whence: item.span, + span: item.span, vis: &item.vis, }; om.opaque_tys.push(t); @@ -500,7 +500,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { id: item.hir_id, name: ident.name, attrs: &item.attrs, - whence: item.span, + span: item.span, vis: &item.vis, }; om.statics.push(s); @@ -515,7 +515,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { id: item.hir_id, name: ident.name, attrs: &item.attrs, - whence: item.span, + span: item.span, vis: &item.vis, }; om.constants.push(s); @@ -532,7 +532,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { bounds, id: item.hir_id, attrs: &item.attrs, - whence: item.span, + span: item.span, vis: &item.vis, }; om.traits.push(t); @@ -544,7 +544,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { bounds, id: item.hir_id, attrs: &item.attrs, - whence: item.span, + span: item.span, vis: &item.vis, }; om.trait_aliases.push(t); @@ -577,7 +577,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { items, attrs: &item.attrs, id: item.hir_id, - whence: item.span, + span: item.span, vis: &item.vis, }; om.impls.push(i); @@ -603,7 +603,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { kind: &item.kind, vis: &item.vis, attrs: &item.attrs, - whence: item.span, + span: item.span, }); } @@ -623,7 +623,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { def_id: self.cx.tcx.hir().local_def_id(def.hir_id).to_def_id(), attrs: &def.attrs, name: renamed.unwrap_or(def.ident.name), - whence: def.span, + span: def.span, matchers, imported_from: None, } From 58d57f3f5ede1599ff913462396001571adbdca4 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 25 Sep 2020 18:54:05 -0400 Subject: [PATCH 1007/1052] Fix documentation highlighting in ty::BorrowKind Previously it looked a little odd: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.BorrowKind.html#variant.UniqueImmBorrow --- compiler/rustc_middle/src/ty/mod.rs | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 637ef4c17ebc8..2a4cbe538946a 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -682,25 +682,31 @@ pub enum BorrowKind { /// implicit closure bindings. It is needed when the closure /// is borrowing or mutating a mutable referent, e.g.: /// - /// let x: &mut isize = ...; - /// let y = || *x += 5; + /// ``` + /// let x: &mut isize = ...; + /// let y = || *x += 5; + /// ``` /// /// If we were to try to translate this closure into a more explicit /// form, we'd encounter an error with the code as written: /// - /// struct Env { x: & &mut isize } - /// let x: &mut isize = ...; - /// let y = (&mut Env { &x }, fn_ptr); // Closure is pair of env and fn - /// fn fn_ptr(env: &mut Env) { **env.x += 5; } + /// ``` + /// struct Env { x: & &mut isize } + /// let x: &mut isize = ...; + /// let y = (&mut Env { &x }, fn_ptr); // Closure is pair of env and fn + /// fn fn_ptr(env: &mut Env) { **env.x += 5; } + /// ``` /// /// This is then illegal because you cannot mutate a `&mut` found /// in an aliasable location. To solve, you'd have to translate with /// an `&mut` borrow: /// - /// struct Env { x: & &mut isize } - /// let x: &mut isize = ...; - /// let y = (&mut Env { &mut x }, fn_ptr); // changed from &x to &mut x - /// fn fn_ptr(env: &mut Env) { **env.x += 5; } + /// ``` + /// struct Env { x: & &mut isize } + /// let x: &mut isize = ...; + /// let y = (&mut Env { &mut x }, fn_ptr); // changed from &x to &mut x + /// fn fn_ptr(env: &mut Env) { **env.x += 5; } + /// ``` /// /// Now the assignment to `**env.x` is legal, but creating a /// mutable pointer to `x` is not because `x` is not mutable. We From 12187b7f860e8e823eb5e399946746c4d2c1b1a7 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 26 Sep 2020 01:17:54 +0200 Subject: [PATCH 1008/1052] Remove unused #[allow(...)] statements from compiler/ --- compiler/rustc_arena/src/lib.rs | 1 - compiler/rustc_codegen_llvm/src/builder.rs | 1 - compiler/rustc_codegen_llvm/src/common.rs | 2 -- compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs | 1 - compiler/rustc_codegen_llvm/src/va_arg.rs | 1 - compiler/rustc_codegen_ssa/src/common.rs | 4 +--- compiler/rustc_data_structures/src/lib.rs | 1 - compiler/rustc_hir/src/intravisit.rs | 3 --- compiler/rustc_infer/src/infer/mod.rs | 1 - compiler/rustc_lint/src/types.rs | 2 -- compiler/rustc_llvm/src/lib.rs | 1 - compiler/rustc_macros/src/query.rs | 1 - compiler/rustc_macros/src/symbols.rs | 1 - compiler/rustc_middle/src/util/common.rs | 2 -- compiler/rustc_mir/src/borrow_check/prefixes.rs | 1 - compiler/rustc_mir/src/dataflow/move_paths/mod.rs | 1 - compiler/rustc_session/src/filesearch.rs | 2 -- compiler/rustc_trait_selection/src/traits/auto_trait.rs | 1 + compiler/rustc_trait_selection/src/traits/mod.rs | 1 - compiler/rustc_trait_selection/src/traits/select/mod.rs | 1 - compiler/rustc_typeck/src/lib.rs | 1 - 21 files changed, 2 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index b4bf31b1abae5..166f7f53c41ac 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -15,7 +15,6 @@ #![feature(new_uninit)] #![feature(maybe_uninit_slice)] #![cfg_attr(test, feature(test))] -#![allow(deprecated)] use rustc_data_structures::cold_path; use smallvec::SmallVec; diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 23a3be1a2f2e8..67191ac0e4640 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -931,7 +931,6 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { unsafe { llvm::LLVMBuildSelect(self.llbuilder, cond, then_val, else_val, UNNAMED) } } - #[allow(dead_code)] fn va_arg(&mut self, list: &'ll Value, ty: &'ll Type) -> &'ll Value { unsafe { llvm::LLVMBuildVAArg(self.llbuilder, list, ty, UNNAMED) } } diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 0b1cf03fa7e42..0992410a728bd 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -1,5 +1,3 @@ -#![allow(non_camel_case_types, non_snake_case)] - //! Code that is useful in various codegen modules. use crate::consts::{self, const_alloc_to_llvm}; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 868eb74cf09cd..987149cb4c25c 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1845,7 +1845,6 @@ impl<'tcx> VariantInfo<'_, 'tcx> { None } - #[allow(dead_code)] fn is_artificial(&self) -> bool { match self { VariantInfo::Generator { .. } => true, diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index 54efa05aee81e..22ed4dd7576b5 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -11,7 +11,6 @@ use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::Ty; use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size}; -#[allow(dead_code)] fn round_pointer_up_to_alignment( bx: &mut Builder<'a, 'll, 'tcx>, addr: &'ll Value, diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index e04ed531bbff2..780b1d2cd9433 100644 --- a/compiler/rustc_codegen_ssa/src/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -1,4 +1,4 @@ -#![allow(non_camel_case_types, non_snake_case)] +#![allow(non_camel_case_types)] use rustc_errors::struct_span_err; use rustc_hir as hir; @@ -25,7 +25,6 @@ pub enum IntPredicate { IntSLE, } -#[allow(dead_code)] pub enum RealPredicate { RealPredicateFalse, RealOEQ, @@ -60,7 +59,6 @@ pub enum AtomicRmwBinOp { } pub enum AtomicOrdering { - #[allow(dead_code)] NotAtomic, Unordered, Monotonic, diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 9ded10e9c26ac..90b0f25475181 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -7,7 +7,6 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![allow(incomplete_features)] #![feature(array_windows)] #![feature(control_flow_enum)] #![feature(in_band_lifetimes)] diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 76cf6bd47769f..820d664c07d92 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -256,7 +256,6 @@ pub trait Visitor<'v>: Sized { /// patterns described on `itemlikevisit::ItemLikeVisitor`. The only /// reason to override this method is if you want a nested pattern /// but cannot supply a `Map`; see `nested_visit_map` for advice. - #[allow(unused_variables)] fn visit_nested_item(&mut self, id: ItemId) { let opt_item = self.nested_visit_map().inter().map(|map| map.item(id.id)); walk_list!(self, visit_item, opt_item); @@ -265,7 +264,6 @@ pub trait Visitor<'v>: Sized { /// Like `visit_nested_item()`, but for trait items. See /// `visit_nested_item()` for advice on when to override this /// method. - #[allow(unused_variables)] fn visit_nested_trait_item(&mut self, id: TraitItemId) { let opt_item = self.nested_visit_map().inter().map(|map| map.trait_item(id)); walk_list!(self, visit_trait_item, opt_item); @@ -274,7 +272,6 @@ pub trait Visitor<'v>: Sized { /// Like `visit_nested_item()`, but for impl items. See /// `visit_nested_item()` for advice on when to override this /// method. - #[allow(unused_variables)] fn visit_nested_impl_item(&mut self, id: ImplItemId) { let opt_item = self.nested_visit_map().inter().map(|map| map.impl_item(id)); walk_list!(self, visit_impl_item, opt_item); diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 2cbdc954e2007..95137410c6245 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1275,7 +1275,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } /// Gives temporary access to the region constraint data. - #[allow(non_camel_case_types)] // bug with impl trait pub fn with_region_constraints( &self, op: impl FnOnce(&RegionConstraintData<'tcx>) -> R, diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 6aa28d04ae197..9925444b869f9 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1,5 +1,3 @@ -#![allow(non_snake_case)] - use crate::{LateContext, LateLintPass, LintContext}; use rustc_ast as ast; use rustc_attr as attr; diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index a7a10b91b4eca..a381290d46f97 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -21,7 +21,6 @@ impl RustString { /// Appending to a Rust string -- used by RawRustStringOstream. #[no_mangle] -#[allow(improper_ctypes_definitions)] pub unsafe extern "C" fn LLVMRustStringWriteImpl( sr: &RustString, ptr: *const c_char, diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 204e8e800cd48..e7c054653accb 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -9,7 +9,6 @@ use syn::{ ReturnType, Token, Type, }; -#[allow(non_camel_case_types)] mod kw { syn::custom_keyword!(query); } diff --git a/compiler/rustc_macros/src/symbols.rs b/compiler/rustc_macros/src/symbols.rs index 352665f0ab199..94d4ad78e8d90 100644 --- a/compiler/rustc_macros/src/symbols.rs +++ b/compiler/rustc_macros/src/symbols.rs @@ -4,7 +4,6 @@ use std::collections::HashSet; use syn::parse::{Parse, ParseStream, Result}; use syn::{braced, parse_macro_input, Ident, LitStr, Token}; -#[allow(non_camel_case_types)] mod kw { syn::custom_keyword!(Keywords); syn::custom_keyword!(Symbols); diff --git a/compiler/rustc_middle/src/util/common.rs b/compiler/rustc_middle/src/util/common.rs index 1e09702bf27ca..da857b0a403b4 100644 --- a/compiler/rustc_middle/src/util/common.rs +++ b/compiler/rustc_middle/src/util/common.rs @@ -1,5 +1,3 @@ -#![allow(non_camel_case_types)] - use rustc_data_structures::sync::Lock; use std::fmt::Debug; diff --git a/compiler/rustc_mir/src/borrow_check/prefixes.rs b/compiler/rustc_mir/src/borrow_check/prefixes.rs index 5bfe02ff3b04e..6c5d42296f72b 100644 --- a/compiler/rustc_mir/src/borrow_check/prefixes.rs +++ b/compiler/rustc_mir/src/borrow_check/prefixes.rs @@ -33,7 +33,6 @@ pub(super) struct Prefixes<'cx, 'tcx> { } #[derive(Copy, Clone, PartialEq, Eq, Debug)] -#[allow(dead_code)] pub(super) enum PrefixSet { /// Doesn't stop until it returns the base case (a Local or /// Static prefix). diff --git a/compiler/rustc_mir/src/dataflow/move_paths/mod.rs b/compiler/rustc_mir/src/dataflow/move_paths/mod.rs index d66d2625d78ea..7c63025918603 100644 --- a/compiler/rustc_mir/src/dataflow/move_paths/mod.rs +++ b/compiler/rustc_mir/src/dataflow/move_paths/mod.rs @@ -144,7 +144,6 @@ impl<'tcx> fmt::Display for MovePath<'tcx> { } } -#[allow(unused)] struct MovePathLinearIter<'a, 'tcx, F> { next: Option<(MovePathIndex, &'a MovePath<'tcx>)>, fetch_next: F, diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index 284fca652ece7..12a268d5b1dda 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -1,5 +1,3 @@ -#![allow(non_camel_case_types)] - pub use self::FileMatch::*; use std::borrow::Cow; diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 35bfeff10b4aa..e40067202e112 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -32,6 +32,7 @@ pub enum AutoTraitResult { NegativeImpl, } +#[allow(dead_code)] impl AutoTraitResult { fn is_auto(&self) -> bool { match *self { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 79495ba7f9b30..c93087a18cf04 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -2,7 +2,6 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html -#[allow(dead_code)] pub mod auto_trait; mod chalk_fulfill; pub mod codegen; diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 5e2f7d81d000a..57f1fedacbe5a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2148,7 +2148,6 @@ trait TraitObligationExt<'tcx> { } impl<'tcx> TraitObligationExt<'tcx> for TraitObligation<'tcx> { - #[allow(unused_comparisons)] fn derived_cause( &self, variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>, diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 84efb92582ed2..e8fa2b13a9f24 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -56,7 +56,6 @@ This API is completely unstable and subject to change. */ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![allow(non_camel_case_types)] #![feature(bool_to_option)] #![feature(box_syntax)] #![feature(crate_visibility_modifier)] From 32195ac8f4271b8a05923859baa1d3411408effb Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 26 Sep 2020 10:28:15 +0200 Subject: [PATCH 1009/1052] rename functions --- .../infer/error_reporting/need_type_info.rs | 24 ++++++++-------- .../borrow_check/diagnostics/region_name.rs | 9 ++++-- .../src/traits/error_reporting/mod.rs | 28 ++++++++++++++----- compiler/rustc_typeck/src/check/fn_ctxt.rs | 2 +- compiler/rustc_typeck/src/check/writeback.rs | 4 +-- 5 files changed, 42 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index ce249404e8ead..6302139c27d82 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -221,7 +221,7 @@ impl Into for TypeAnnotationNeeded { } /// Information about a constant or a type containing inference variables. -pub struct InferDiagnosticsData { +pub struct InferenceDiagnosticsData { pub name: String, pub span: Option, pub description: Cow<'static, str>, @@ -232,11 +232,11 @@ pub struct InferDiagnosticsData { impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// Extracts data used by diagnostic for either types or constants /// which were stuck during inference. - pub fn extract_infer_data( + pub fn extract_inference_diagnostics_data( &self, arg: GenericArg<'tcx>, highlight: Option, - ) -> InferDiagnosticsData { + ) -> InferenceDiagnosticsData { match arg.unpack() { GenericArgKind::Type(ty) => { if let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind() { @@ -266,7 +266,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; if name != kw::SelfUpper { - return InferDiagnosticsData { + return InferenceDiagnosticsData { name: name.to_string(), span: Some(var_origin.span), description: "type parameter".into(), @@ -283,7 +283,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { printer.region_highlight_mode = highlight; } let _ = ty.print(printer); - InferDiagnosticsData { + InferenceDiagnosticsData { name: s, span: None, description: ty.prefix_string(), @@ -317,7 +317,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { (None, None) }; - return InferDiagnosticsData { + return InferenceDiagnosticsData { name: name.to_string(), span: Some(origin.span), description: "const parameter".into(), @@ -334,7 +334,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { printer.region_highlight_mode = highlight; } let _ = ct.print(printer); - InferDiagnosticsData { + InferenceDiagnosticsData { name: s, span: Some(origin.span), description: "the constant".into(), @@ -349,16 +349,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - pub fn need_type_info_err( + pub fn emit_inference_failure_err( &self, body_id: Option, span: Span, arg: GenericArg<'tcx>, error_code: TypeAnnotationNeeded, ) -> DiagnosticBuilder<'tcx> { - let ty = self.resolve_vars_if_possible(&arg); - let arg_data = self.extract_infer_data(arg, None); - let kind_str = match ty.unpack() { + 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"), @@ -700,7 +700,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty: Ty<'tcx>, ) -> DiagnosticBuilder<'tcx> { let ty = self.resolve_vars_if_possible(&ty); - let data = self.extract_infer_data(ty.into(), None); + let data = self.extract_inference_diagnostics_data(ty.into(), None); let mut err = struct_span_err!( self.tcx.sess, diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs index 86e8675afb2fb..5f64eb3dba8ac 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs @@ -396,7 +396,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { ) -> Option { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(needle_fr, counter); - let type_name = self.infcx.extract_infer_data(ty.into(), Some(highlight)).name; + let type_name = + self.infcx.extract_inference_diagnostics_data(ty.into(), Some(highlight)).name; debug!( "highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}", @@ -645,7 +646,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap()); - let type_name = self.infcx.extract_infer_data(return_ty.into(), Some(highlight)).name; + let type_name = + self.infcx.extract_inference_diagnostics_data(return_ty.into(), Some(highlight)).name; let mir_hir_id = tcx.hir().local_def_id_to_hir_id(self.mir_def_id); @@ -697,7 +699,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap()); - let type_name = self.infcx.extract_infer_data(yield_ty.into(), Some(highlight)).name; + let type_name = + self.infcx.extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)).name; let mir_hir_id = tcx.hir().local_def_id_to_hir_id(self.mir_def_id); 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 4cc9a1ecdc81b..1b234a1535c97 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1512,11 +1512,21 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { // check upstream for type errors and don't add the obligations to // begin with in those cases. if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) { - self.need_type_info_err(body_id, span, self_ty.into(), ErrorCode::E0282).emit(); + self.emit_inference_failure_err( + body_id, + span, + self_ty.into(), + ErrorCode::E0282, + ) + .emit(); return; } - let mut err = - self.need_type_info_err(body_id, span, self_ty.into(), ErrorCode::E0283); + let mut err = self.emit_inference_failure_err( + body_id, + span, + self_ty.into(), + ErrorCode::E0283, + ); err.note(&format!("cannot satisfy `{}`", predicate)); if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code { self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id()); @@ -1580,7 +1590,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { return; } - self.need_type_info_err(body_id, span, arg, ErrorCode::E0282) + self.emit_inference_failure_err(body_id, span, arg, ErrorCode::E0282) } ty::PredicateAtom::Subtype(data) => { @@ -1591,7 +1601,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { let SubtypePredicate { a_is_expected: _, a, b } = data; // both must be type variables, or the other would've been instantiated assert!(a.is_ty_var() && b.is_ty_var()); - self.need_type_info_err(body_id, span, a.into(), ErrorCode::E0282) + self.emit_inference_failure_err(body_id, span, a.into(), ErrorCode::E0282) } ty::PredicateAtom::Projection(data) => { let trait_ref = ty::Binder::bind(data).to_poly_trait_ref(self.tcx); @@ -1602,8 +1612,12 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { } if self_ty.needs_infer() && ty.needs_infer() { // We do this for the `foo.collect()?` case to produce a suggestion. - let mut err = - self.need_type_info_err(body_id, span, self_ty.into(), ErrorCode::E0284); + let mut err = self.emit_inference_failure_err( + body_id, + span, + self_ty.into(), + ErrorCode::E0284, + ); err.note(&format!("cannot satisfy `{}`", predicate)); err } else { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt.rs b/compiler/rustc_typeck/src/check/fn_ctxt.rs index 31010753474be..79d6c7dbfdae2 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt.rs @@ -2991,7 +2991,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } else { if !self.is_tainted_by_errors() { - self.need_type_info_err((**self).body_id, sp, ty.into(), E0282) + self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282) .note("type must be known at this point") .emit(); } diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index ccff9b5cdb4b4..6fd7277a1c332 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -653,7 +653,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { fn report_type_error(&self, t: Ty<'tcx>) { if !self.tcx.sess.has_errors() { self.infcx - .need_type_info_err( + .emit_inference_failure_err( Some(self.body.id()), self.span.to_span(self.tcx), t.into(), @@ -666,7 +666,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { fn report_const_error(&self, c: &'tcx ty::Const<'tcx>) { if !self.tcx.sess.has_errors() { self.infcx - .need_type_info_err( + .emit_inference_failure_err( Some(self.body.id()), self.span.to_span(self.tcx), c.into(), From 9a607c0a2781197b88ff2535b852b53d3f0e4145 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 26 Sep 2020 10:31:34 +0200 Subject: [PATCH 1010/1052] unused into --- .../rustc_infer/src/infer/error_reporting/need_type_info.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 6302139c27d82..2f3089f1a92c1 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -364,7 +364,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), }; - let mut local_visitor = FindHirNodeVisitor::new(&self, arg.into(), span); + let mut local_visitor = FindHirNodeVisitor::new(&self, arg, span); let ty_to_string = |ty: Ty<'tcx>| -> String { let mut s = String::new(); let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); From 21ee1716ee395398427f3bd8310d75de7e23e57e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 25 Sep 2020 14:08:38 +0200 Subject: [PATCH 1011/1052] Add doc alias for pointer primitive --- library/std/src/primitive_docs.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 2a4cb22cc52a2..81bbf37637875 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -384,6 +384,7 @@ mod prim_char {} #[stable(feature = "rust1", since = "1.0.0")] mod prim_unit {} +#[doc(alias = "ptr")] #[doc(primitive = "pointer")] // /// Raw, unsafe pointers, `*const T`, and `*mut T`. From 6b8b9c4adbd7d8d53d730a3c01d154dec3bd179f Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 26 Sep 2020 11:47:26 +0200 Subject: [PATCH 1012/1052] Disable stdout-during-shutdown test on emscripten. --- src/test/ui/stdout-during-shutdown.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/test/ui/stdout-during-shutdown.rs b/src/test/ui/stdout-during-shutdown.rs index c785fc0869610..a6cf812ca644e 100644 --- a/src/test/ui/stdout-during-shutdown.rs +++ b/src/test/ui/stdout-during-shutdown.rs @@ -1,5 +1,10 @@ // run-pass // check-run-results +// ignore-emscripten + +// Emscripten doesn't flush its own stdout buffers on exit, which would fail +// this test. So this test is disabled on this platform. +// See https://emscripten.org/docs/getting_started/FAQ.html#what-does-exiting-the-runtime-mean-why-don-t-atexit-s-run #![feature(rustc_private)] From 6f881b3b7db6e08d5ca3a940befc7898aab1568a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 18 Apr 2020 09:54:05 +0200 Subject: [PATCH 1013/1052] might_permit_raw_init: also check aggregate fields --- compiler/rustc_target/src/abi/mod.rs | 23 +++++++++-- .../intrinsics/panic-uninitialized-zeroed.rs | 40 ++++++++++++++++++- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index 4b565dd246f6d..3c1a2ea39d3fc 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -1135,16 +1135,31 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Abi::Scalar(s) => scalar_allows_raw_init(s), Abi::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2), Abi::Vector { element: s, count } => *count == 0 || scalar_allows_raw_init(s), - Abi::Aggregate { .. } => true, // Cannot be excluded *right now*. + Abi::Aggregate { .. } => true, // Fields are checked below. }; if !valid { // This is definitely not okay. - trace!("might_permit_raw_init({:?}, zero={}): not valid", self.layout, zero); return Ok(false); } - // If we have not found an error yet, we need to recursively descend. - // FIXME(#66151): For now, we are conservative and do not do this. + // If we have not found an error yet, we need to recursively descend into fields. + match &self.fields { + FieldsShape::Primitive | FieldsShape::Union { .. } => {} + FieldsShape::Array { .. } => { + // FIXME(#66151): For now, we are conservative and do not check arrays. + } + FieldsShape::Arbitrary { offsets, .. } => { + for idx in 0..offsets.len() { + let field = self.field(cx, idx).to_result()?; + if !field.might_permit_raw_init(cx, zero)? { + // We found a field that is unhappy with this kind of initialization. + return Ok(false); + } + } + } + } + + // FIXME(#66151): For now, we are conservative and do not check `self.variants`. Ok(true) } } diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs index 02f8ecaa4eec5..24474cabf1e37 100644 --- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs +++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs @@ -3,7 +3,7 @@ // This test checks panic emitted from `mem::{uninitialized,zeroed}`. -#![feature(never_type)] +#![feature(never_type, arbitrary_enum_discriminant)] #![allow(deprecated, invalid_value)] use std::{ @@ -24,6 +24,20 @@ enum Bar {} #[allow(dead_code)] enum OneVariant { Variant(i32) } +#[allow(dead_code, non_camel_case_types)] +enum OneVariant_NonZero { + Variant(i32, i32, num::NonZeroI32), + DeadVariant(Bar), +} + +// An `Aggregate` abi enum where 0 is not a valid discriminant. +#[allow(dead_code)] +#[repr(i32)] +enum NoNullVariant { + Variant1(i32, i32) = 1, + Variant2(i32, i32) = 2, +} + // An enum with ScalarPair layout #[allow(dead_code)] enum LR { @@ -125,6 +139,7 @@ fn main() { "attempted to zero-initialize type `std::mem::ManuallyDrop`, \ which is invalid" ); + */ test_panic_msg( || mem::uninitialized::<(NonNull, u32, u32)>(), @@ -136,7 +151,28 @@ fn main() { "attempted to zero-initialize type `(std::ptr::NonNull, u32, u32)`, \ which is invalid" ); - */ + + test_panic_msg( + || mem::uninitialized::(), + "attempted to leave type `OneVariant_NonZero` uninitialized, \ + which is invalid" + ); + test_panic_msg( + || mem::zeroed::(), + "attempted to zero-initialize type `OneVariant_NonZero`, \ + which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::(), + "attempted to leave type `NoNullVariant` uninitialized, \ + which is invalid" + ); + test_panic_msg( + || mem::zeroed::(), + "attempted to zero-initialize type `NoNullVariant`, \ + which is invalid" + ); // Types that can be zero, but not uninit. test_panic_msg( From 455f284496976c5a77e7f1cbdf1f382dc0a6d245 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 26 Sep 2020 14:55:42 +0200 Subject: [PATCH 1014/1052] Deduplicate and generalize some (de/)serializer impls --- compiler/rustc_serialize/src/lib.rs | 1 + compiler/rustc_serialize/src/serialize.rs | 34 ++++++++--------------- 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index ed48fbf40ac1f..fab29f29e8730 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -13,6 +13,7 @@ Core encoding and decoding interfaces. #![feature(never_type)] #![feature(nll)] #![feature(associated_type_bounds)] +#![feature(min_const_generics)] #![cfg_attr(test, feature(test))] #![allow(rustc::internal)] diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs index c0e23b89a60df..aa305f3c7fc3f 100644 --- a/compiler/rustc_serialize/src/serialize.rs +++ b/compiler/rustc_serialize/src/serialize.rs @@ -539,12 +539,8 @@ impl> Encodable for [T] { impl> Encodable for Vec { fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_seq(self.len(), |s| { - for (i, e) in self.iter().enumerate() { - s.emit_seq_elt(i, |s| e.encode(s))? - } - Ok(()) - }) + let slice: &[T] = self; + slice.encode(s) } } @@ -560,22 +556,18 @@ impl> Decodable for Vec { } } -impl Encodable for [u8; 20] { +impl, const N: usize> Encodable for [T; N] { fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_seq(self.len(), |s| { - for (i, e) in self.iter().enumerate() { - s.emit_seq_elt(i, |s| e.encode(s))? - } - Ok(()) - }) + let slice: &[T] = self; + slice.encode(s) } } -impl Decodable for [u8; 20] { - fn decode(d: &mut D) -> Result<[u8; 20], D::Error> { +impl Decodable for [u8; N] { + fn decode(d: &mut D) -> Result<[u8; N], D::Error> { d.read_seq(|d, len| { - assert!(len == 20); - let mut v = [0u8; 20]; + assert!(len == N); + let mut v = [0u8; N]; for i in 0..len { v[i] = d.read_seq_elt(i, |d| Decodable::decode(d))?; } @@ -589,12 +581,8 @@ where [T]: ToOwned>, { fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_seq(self.len(), |s| { - for (i, e) in self.iter().enumerate() { - s.emit_seq_elt(i, |s| e.encode(s))? - } - Ok(()) - }) + let slice: &[T] = self; + slice.encode(s) } } From 4c5acc4ed72f2cd6cf4d2c4ca682d52a117a98d0 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 21 Sep 2020 23:01:31 +0200 Subject: [PATCH 1015/1052] Return values up to 128 bits in registers --- compiler/rustc_middle/src/ty/layout.rs | 12 ++++++++---- compiler/rustc_target/src/abi/call/mod.rs | 12 ++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 0fda1473f6488..ee669ed228969 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2735,6 +2735,7 @@ where can_unwind: fn_can_unwind(cx.tcx().sess.panic_strategy(), codegen_fn_attr_flags, conv), }; fn_abi.adjust_for_abi(cx, sig.abi); + debug!("FnAbi::new_internal = {:?}", fn_abi); fn_abi } @@ -2748,7 +2749,7 @@ where || abi == SpecAbi::RustIntrinsic || abi == SpecAbi::PlatformIntrinsic { - let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>| { + let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>, is_ret: bool| { if arg.is_ignore() { return; } @@ -2786,8 +2787,11 @@ where _ => return, } + let max_by_val_size = + if is_ret { call::max_ret_by_val(cx) } else { Pointer.size(cx) }; let size = arg.layout.size; - if arg.layout.is_unsized() || size > Pointer.size(cx) { + + if arg.layout.is_unsized() || size > max_by_val_size { arg.make_indirect(); } else { // We want to pass small aggregates as immediates, but using @@ -2796,9 +2800,9 @@ where arg.cast_to(Reg { kind: RegKind::Integer, size }); } }; - fixup(&mut self.ret); + fixup(&mut self.ret, true); for arg in &mut self.args { - fixup(arg); + fixup(arg, false); } if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode { attrs.set(ArgAttribute::StructRet); diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 8f7e2bba5aa6d..602c424a043f7 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -610,3 +610,15 @@ impl<'a, Ty> FnAbi<'a, Ty> { Ok(()) } } + +/// Returns the maximum size of return values to be passed by value in the Rust ABI. +/// +/// Return values beyond this size will use an implicit out-pointer instead. +pub fn max_ret_by_val(spec: &C) -> Size { + match spec.target_spec().arch.as_str() { + // System-V will pass return values up to 128 bits in RAX/RDX. + "x86_64" => Size::from_bits(128), + + _ => spec.data_layout().pointer_size, + } +} From 9b5835ec7973a52f2e9d6f4ed9a2181bebfdc399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sat, 26 Sep 2020 00:00:00 +0000 Subject: [PATCH 1016/1052] liveness: Remove redundant debug logging The IrMaps::add_variable already contains debug logging. Don't duplicate it. --- compiler/rustc_passes/src/liveness.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index db9495201cf30..50ea4ed76b20f 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -367,7 +367,6 @@ fn visit_fn<'tcx>( if let Some(upvars) = ir.tcx.upvars_mentioned(def_id) { for (&var_hir_id, _upvar) in upvars { - debug!("adding upvar {:?}", var_hir_id); let var_name = ir.tcx.hir().name(var_hir_id); fn_maps.add_variable(Upvar(var_hir_id, var_name)); } @@ -379,7 +378,6 @@ fn visit_fn<'tcx>( _ => false, }; param.pat.each_binding(|_bm, hir_id, _x, ident| { - debug!("adding parameters {:?}", hir_id); let var = if is_shorthand { Local(LocalInfo { id: hir_id, name: ident.name, is_shorthand: true }) } else { From 2fb1564457b47bd31087e2aba1b8eb6f15c000ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sat, 26 Sep 2020 00:00:00 +0000 Subject: [PATCH 1017/1052] liveness: Remove redundant fields for a number of live nodes and variables --- compiler/rustc_passes/src/liveness.rs | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 50ea4ed76b20f..346980b4199ab 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -249,8 +249,6 @@ enum VarKind { struct IrMaps<'tcx> { tcx: TyCtxt<'tcx>, body_owner: LocalDefId, - num_live_nodes: usize, - num_vars: usize, live_node_map: HirIdMap, variable_map: HirIdMap, capture_info_map: HirIdMap>>, @@ -263,8 +261,6 @@ impl IrMaps<'tcx> { IrMaps { tcx, body_owner, - num_live_nodes: 0, - num_vars: 0, live_node_map: HirIdMap::default(), variable_map: HirIdMap::default(), capture_info_map: Default::default(), @@ -274,9 +270,8 @@ impl IrMaps<'tcx> { } fn add_live_node(&mut self, lnk: LiveNodeKind) -> LiveNode { - let ln = LiveNode(self.num_live_nodes as u32); + let ln = LiveNode(self.lnks.len() as u32); self.lnks.push(lnk); - self.num_live_nodes += 1; debug!("{:?} is of kind {}", ln, live_node_kind_to_string(lnk, self.tcx)); @@ -291,9 +286,8 @@ impl IrMaps<'tcx> { } fn add_variable(&mut self, vk: VarKind) -> Variable { - let v = Variable(self.num_vars as u32); + let v = Variable(self.var_kinds.len() as u32); self.var_kinds.push(vk); - self.num_vars += 1; match vk { Local(LocalInfo { id: node_id, .. }) | Param(node_id, _) | Upvar(node_id, _) => { @@ -672,8 +666,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let typeck_results = ir.tcx.typeck(def_id); let param_env = ir.tcx.param_env(def_id); - let num_live_nodes = ir.num_live_nodes; - let num_vars = ir.num_vars; + let num_live_nodes = ir.lnks.len(); + let num_vars = ir.var_kinds.len(); Liveness { ir, @@ -719,7 +713,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } fn idx(&self, ln: LiveNode, var: Variable) -> usize { - ln.get() * self.ir.num_vars + var.get() + ln.get() * self.ir.var_kinds.len() + var.get() } fn live_on_entry(&self, ln: LiveNode, var: Variable) -> Option { @@ -756,7 +750,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { { let node_base_idx = self.idx(ln, Variable(0)); let succ_base_idx = self.idx(succ_ln, Variable(0)); - for var_idx in 0..self.ir.num_vars { + for var_idx in 0..self.ir.var_kinds.len() { op(self, node_base_idx + var_idx, succ_base_idx + var_idx); } } @@ -766,7 +760,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { F: FnMut(usize) -> bool, { let node_base_idx = self.idx(ln, Variable(0)); - for var_idx in 0..self.ir.num_vars { + for var_idx in 0..self.ir.var_kinds.len() { let idx = node_base_idx + var_idx; if test(idx) { write!(wr, " {:?}", Variable(var_idx as u32))?; @@ -797,7 +791,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { debug!( "^^ liveness computation results for body {} (entry={:?})", { - for ln_idx in 0..self.ir.num_live_nodes { + for ln_idx in 0..self.ir.lnks.len() { debug!("{:?}", self.ln_str(LiveNode(ln_idx as u32))); } hir_id From 70f150b51e7d13e3bcd8977ff124a348057cf7ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sat, 26 Sep 2020 00:00:00 +0000 Subject: [PATCH 1018/1052] liveness: Delay conversion from a symbol to a string until linting --- compiler/rustc_passes/src/liveness.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 346980b4199ab..4f9ee6df4aaa5 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -96,7 +96,7 @@ use rustc_middle::hir::map::Map; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; use std::collections::VecDeque; @@ -309,9 +309,9 @@ impl IrMaps<'tcx> { } } - fn variable_name(&self, var: Variable) -> String { + fn variable_name(&self, var: Variable) -> Symbol { match self.var_kinds[var.get()] { - Local(LocalInfo { name, .. }) | Param(_, name) | Upvar(_, name) => name.to_string(), + Local(LocalInfo { name, .. }) | Param(_, name) | Upvar(_, name) => name, } } @@ -1587,7 +1587,14 @@ impl<'tcx> Liveness<'_, 'tcx> { fn should_warn(&self, var: Variable) -> Option { let name = self.ir.variable_name(var); - if name.is_empty() || name.as_bytes()[0] == b'_' { None } else { Some(name) } + if name == kw::Invalid { + return None; + } + let name: &str = &name.as_str(); + if name.as_bytes()[0] == b'_' { + return None; + } + Some(name.to_owned()) } fn warn_about_unused_upvars(&self, entry_ln: LiveNode) { @@ -1659,7 +1666,7 @@ impl<'tcx> Liveness<'_, 'tcx> { // bindings, and we also consider the first pattern to be the "authoritative" set of ids. // However, we should take the ids and spans of variables with the same name from the later // patterns so the suggestions to prefix with underscores will apply to those too. - let mut vars: FxIndexMap)> = <_>::default(); + let mut vars: FxIndexMap)> = <_>::default(); pat.each_binding(|_, hir_id, pat_sp, ident| { let ln = entry_ln.unwrap_or_else(|| self.live_node(hir_id, pat_sp)); From 141b91da6cb756ff5f36eebe9eee65922e295876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sat, 26 Sep 2020 00:00:00 +0000 Subject: [PATCH 1019/1052] liveness: Inline contents of specials struct --- compiler/rustc_passes/src/liveness.rs | 55 ++++++++++++--------------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 4f9ee6df4aaa5..cb452d3d04153 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -79,7 +79,7 @@ //! ## Special nodes and variables //! //! We generate various special nodes for various, well, special purposes. -//! These are described in the `Specials` struct. +//! These are described in the `Liveness` struct. use self::LiveNodeKind::*; use self::VarKind::*; @@ -626,17 +626,6 @@ impl RWUTable { } } -#[derive(Copy, Clone)] -struct Specials { - /// A live node representing a point of execution before closure entry & - /// after closure exit. Used to calculate liveness of captured variables - /// through calls to the same closure. Used for Fn & FnMut closures only. - closure_ln: LiveNode, - /// A live node representing every 'exit' from the function, whether it be - /// by explicit return, panic, or other means. - exit_ln: LiveNode, -} - const ACC_READ: u32 = 1; const ACC_WRITE: u32 = 2; const ACC_USE: u32 = 4; @@ -645,10 +634,17 @@ struct Liveness<'a, 'tcx> { ir: &'a mut IrMaps<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, param_env: ty::ParamEnv<'tcx>, - s: Specials, successors: Vec, rwu_table: RWUTable, + /// A live node representing a point of execution before closure entry & + /// after closure exit. Used to calculate liveness of captured variables + /// through calls to the same closure. Used for Fn & FnMut closures only. + closure_ln: LiveNode, + /// A live node representing every 'exit' from the function, whether it be + /// by explicit return, panic, or other means. + exit_ln: LiveNode, + // mappings from loop node ID to LiveNode // ("break" label should map to loop node ID, // it probably doesn't now) @@ -658,14 +654,12 @@ struct Liveness<'a, 'tcx> { impl<'a, 'tcx> Liveness<'a, 'tcx> { fn new(ir: &'a mut IrMaps<'tcx>, def_id: LocalDefId) -> Liveness<'a, 'tcx> { - let specials = Specials { - closure_ln: ir.add_live_node(ClosureNode), - exit_ln: ir.add_live_node(ExitNode), - }; - let typeck_results = ir.tcx.typeck(def_id); let param_env = ir.tcx.param_env(def_id); + let closure_ln = ir.add_live_node(ClosureNode); + let exit_ln = ir.add_live_node(ExitNode); + let num_live_nodes = ir.lnks.len(); let num_vars = ir.var_kinds.len(); @@ -673,9 +667,10 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { ir, typeck_results, param_env, - s: specials, successors: vec![invalid_node(); num_live_nodes], rwu_table: RWUTable::new(num_live_nodes * num_vars), + closure_ln, + exit_ln, break_ln: Default::default(), cont_ln: Default::default(), } @@ -935,14 +930,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { match self.typeck_results.upvar_capture(upvar_id) { ty::UpvarCapture::ByRef(_) => { let var = self.variable(var_hir_id, upvar.span); - self.acc(self.s.exit_ln, var, ACC_READ | ACC_USE); + self.acc(self.exit_ln, var, ACC_READ | ACC_USE); } ty::UpvarCapture::ByValue(_) => {} } } } - let succ = self.propagate_through_expr(&body.value, self.s.exit_ln); + let succ = self.propagate_through_expr(&body.value, self.exit_ln); match fk { FnKind::Method(..) | FnKind::ItemFn(..) => return succ, @@ -965,19 +960,19 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // Propagate through calls to the closure. let mut first_merge = true; loop { - self.init_from_succ(self.s.closure_ln, succ); + self.init_from_succ(self.closure_ln, succ); for param in body.params { param.pat.each_binding(|_bm, hir_id, _x, ident| { let var = self.variable(hir_id, ident.span); - self.define(self.s.closure_ln, var); + self.define(self.closure_ln, var); }) } - if !self.merge_from_succ(self.s.exit_ln, self.s.closure_ln, first_merge) { + if !self.merge_from_succ(self.exit_ln, self.closure_ln, first_merge) { break; } first_merge = false; - assert_eq!(succ, self.propagate_through_expr(&body.value, self.s.exit_ln)); + assert_eq!(succ, self.propagate_through_expr(&body.value, self.exit_ln)); } succ @@ -1099,7 +1094,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprKind::Ret(ref o_e) => { // ignore succ and subst exit_ln: - let exit_ln = self.s.exit_ln; + let exit_ln = self.exit_ln; self.propagate_through_opt_expr(o_e.as_ref().map(|e| &**e), exit_ln) } @@ -1174,7 +1169,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.typeck_results.expr_ty(expr), self.param_env, ) { - self.s.exit_ln + self.exit_ln } else { succ }; @@ -1189,7 +1184,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.typeck_results.expr_ty(expr), self.param_env, ) { - self.s.exit_ln + self.exit_ln } else { succ }; @@ -1226,7 +1221,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprKind::InlineAsm(ref asm) => { // Handle non-returning asm let mut succ = if asm.options.contains(InlineAsmOptions::NORETURN) { - self.s.exit_ln + self.exit_ln } else { succ }; @@ -1696,7 +1691,7 @@ impl<'tcx> Liveness<'_, 'tcx> { // {ret}`, there is only one node, so asking about // assigned_on_exit() is not meaningful. let is_assigned = - if ln == self.s.exit_ln { false } else { self.assigned_on_exit(ln, var).is_some() }; + if ln == self.exit_ln { false } else { self.assigned_on_exit(ln, var).is_some() }; if is_assigned { self.ir.tcx.struct_span_lint_hir( From 1b843896c8b0a994835e933e67ca4e3de042ce9f Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 26 Sep 2020 16:08:24 +0200 Subject: [PATCH 1020/1052] Move `qualify_min_const_fn` out of rustc into clippy --- compiler/rustc_mir/src/transform/mod.rs | 1 - src/tools/clippy/clippy_lints/src/lib.rs | 1 + .../clippy_lints/src/missing_const_for_fn.rs | 2 +- src/tools/clippy/clippy_lints/src/utils/mod.rs | 1 + .../src/utils}/qualify_min_const_fn.rs | 16 ++++++++-------- 5 files changed, 11 insertions(+), 10 deletions(-) rename {compiler/rustc_mir/src/transform => src/tools/clippy/clippy_lints/src/utils}/qualify_min_const_fn.rs (96%) diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index a622de9a8af3e..850cafcf89811 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -36,7 +36,6 @@ pub mod match_branches; pub mod no_landing_pads; pub mod nrvo; pub mod promote_consts; -pub mod qualify_min_const_fn; pub mod remove_noop_landing_pads; pub mod remove_unneeded_drops; pub mod required_consts; diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 58112ac8da5f1..c3ff34e6e1eed 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -6,6 +6,7 @@ #![feature(concat_idents)] #![feature(crate_visibility_modifier)] #![feature(drain_filter)] +#![feature(in_band_lifetimes)] #![feature(or_patterns)] #![feature(rustc_private)] #![feature(stmt_expr_attributes)] diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs index 1ad184dfc460b..e5f7cc5111120 100644 --- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs +++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs @@ -4,7 +4,7 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; -use rustc_mir::transform::qualify_min_const_fn::is_min_const_fn; +use crate::utils::qualify_min_const_fn::is_min_const_fn; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; use rustc_typeck::hir_ty_to_ty; diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index ea52741b7cc42..96d9905027b62 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -20,6 +20,7 @@ pub mod paths; pub mod ptr; pub mod sugg; pub mod usage; +pub mod qualify_min_const_fn; pub use self::attrs::*; pub use self::diagnostics::*; diff --git a/compiler/rustc_mir/src/transform/qualify_min_const_fn.rs b/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs similarity index 96% rename from compiler/rustc_mir/src/transform/qualify_min_const_fn.rs rename to src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs index f15a7f7c2c889..9fa9b0341b109 100644 --- a/compiler/rustc_mir/src/transform/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs @@ -14,7 +14,7 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - // Prevent const trait methods from being annotated as `stable`. if tcx.features().staged_api { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - if crate::const_eval::is_parent_const_impl_raw(tcx, hir_id) { + if rustc_mir::const_eval::is_parent_const_impl_raw(tcx, hir_id) { return Err((body.span, "trait methods cannot be stable const fn".into())); } } @@ -32,13 +32,13 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - | ty::PredicateAtom::ConstEquate(..) | ty::PredicateAtom::TypeWellFormedFromEnv(..) => continue, ty::PredicateAtom::ObjectSafe(_) => { - bug!("object safe predicate on function: {:#?}", predicate) + panic!("object safe predicate on function: {:#?}", predicate) } ty::PredicateAtom::ClosureKind(..) => { - bug!("closure kind predicate on function: {:#?}", predicate) + panic!("closure kind predicate on function: {:#?}", predicate) } ty::PredicateAtom::Subtype(_) => { - bug!("subtype predicate on function: {:#?}", predicate) + panic!("subtype predicate on function: {:#?}", predicate) } ty::PredicateAtom::Trait(pred, constness) => { if Some(pred.def_id()) == tcx.lang_items().sized_trait() { @@ -343,7 +343,7 @@ fn feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bo // However, we cannot allow stable `const fn`s to use unstable features without an explicit // opt-in via `allow_internal_unstable`. - super::check_consts::allow_internal_unstable(tcx, def_id, feature_gate) + rustc_mir::transform::check_consts::allow_internal_unstable(tcx, def_id, feature_gate) } /// Returns `true` if the given library feature gate is allowed within the function with the given `DefId`. @@ -362,7 +362,7 @@ pub fn lib_feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbo // However, we cannot allow stable `const fn`s to use unstable features without an explicit // opt-in via `allow_internal_unstable`. - super::check_consts::allow_internal_unstable(tcx, def_id, feature_gate) + rustc_mir::transform::check_consts::allow_internal_unstable(tcx, def_id, feature_gate) } fn check_terminator( @@ -407,8 +407,8 @@ fn check_terminator( if let ty::FnDef(fn_def_id, _) = *fn_ty.kind() { // Allow unstable const if we opt in by using #[allow_internal_unstable] // on function or macro declaration. - if !crate::const_eval::is_min_const_fn(tcx, fn_def_id) - && !crate::const_eval::is_unstable_const_fn(tcx, fn_def_id) + if !rustc_mir::const_eval::is_min_const_fn(tcx, fn_def_id) + && !rustc_mir::const_eval::is_unstable_const_fn(tcx, fn_def_id) .map(|feature| { span.allows_unstable(feature) || lib_feature_allowed(tcx, def_id, feature) From 5d359db9cf003ac05e989460e202137a0afa5cce Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 26 Sep 2020 16:23:56 +0200 Subject: [PATCH 1021/1052] Remove all unstable feature support in the `missing_const_for_fn` lint --- .../src/utils/qualify_min_const_fn.rs | 122 ++++-------------- 1 file changed, 25 insertions(+), 97 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs b/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs index 9fa9b0341b109..6809b1fa88d35 100644 --- a/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs @@ -3,7 +3,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::mir::*; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt}; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{sym}; use rustc_span::Span; use rustc_target::spec::abi::Abi::RustIntrinsic; use std::borrow::Cow; @@ -11,14 +11,6 @@ use std::borrow::Cow; type McfResult = Result<(), (Span, Cow<'static, str>)>; pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) -> McfResult { - // Prevent const trait methods from being annotated as `stable`. - if tcx.features().staged_api { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - if rustc_mir::const_eval::is_parent_const_impl_raw(tcx, hir_id) { - return Err((body.span, "trait methods cannot be stable const fn".into())); - } - } - let mut current = def_id; loop { let predicates = tcx.predicates_of(current); @@ -40,19 +32,12 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - ty::PredicateAtom::Subtype(_) => { panic!("subtype predicate on function: {:#?}", predicate) } - ty::PredicateAtom::Trait(pred, constness) => { + ty::PredicateAtom::Trait(pred, _) => { if Some(pred.def_id()) == tcx.lang_items().sized_trait() { continue; } match pred.self_ty().kind() { ty::Param(ref p) => { - // Allow `T: ?const Trait` - if constness == hir::Constness::NotConst - && feature_allowed(tcx, def_id, sym::const_trait_bound_opt_out) - { - continue; - } - let generics = tcx.generics_of(current); let def = generics.type_param(p, tcx); let span = tcx.def_span(def.def_id); @@ -77,18 +62,17 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - } for local in &body.local_decls { - check_ty(tcx, local.ty, local.source_info.span, def_id)?; + check_ty(tcx, local.ty, local.source_info.span)?; } // impl trait is gone in MIR, so check the return type manually check_ty( tcx, tcx.fn_sig(def_id).output().skip_binder(), body.local_decls.iter().next().unwrap().source_info.span, - def_id, )?; for bb in body.basic_blocks() { - check_terminator(tcx, body, def_id, bb.terminator())?; + check_terminator(tcx, body, bb.terminator())?; for stmt in &bb.statements { check_statement(tcx, body, def_id, stmt)?; } @@ -96,7 +80,7 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - Ok(()) } -fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, fn_def_id: DefId) -> McfResult { +fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult { for arg in ty.walk() { let ty = match arg.unpack() { GenericArgKind::Type(ty) => ty, @@ -108,15 +92,11 @@ fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, fn_def_id: DefId) -> Mc match ty.kind() { ty::Ref(_, _, hir::Mutability::Mut) => { - if !feature_allowed(tcx, fn_def_id, sym::const_mut_refs) { return Err((span, "mutable references in const fn are unstable".into())); - } } ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())), ty::FnPtr(..) => { - if !tcx.const_fn_is_allowed_fn_ptr(fn_def_id) { return Err((span, "function pointers in const fn are unstable".into())); - } } ty::Dynamic(preds, _) => { for pred in preds.iter() { @@ -161,12 +141,12 @@ fn check_rvalue( Err((span, "cannot access thread local storage in const fn".into())) } Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => { - check_operand(tcx, operand, span, def_id, body) + check_operand(tcx, operand, span, body) } Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) - | Rvalue::AddressOf(_, place) => check_place(tcx, *place, span, def_id, body), + | Rvalue::AddressOf(_, place) => check_place(tcx, *place, span, body), Rvalue::Cast(CastKind::Misc, operand, cast_ty) => { use rustc_middle::ty::cast::CastTy; let cast_in = CastTy::from_ty(operand.ty(body, tcx)).expect("bad input type for cast"); @@ -175,14 +155,14 @@ fn check_rvalue( (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => { Err((span, "casting pointers to ints is unstable in const fn".into())) } - _ => check_operand(tcx, operand, span, def_id, body), + _ => check_operand(tcx, operand, span, body), } } Rvalue::Cast( CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer), operand, _, - ) => check_operand(tcx, operand, span, def_id, body), + ) => check_operand(tcx, operand, span, body), Rvalue::Cast( CastKind::Pointer( PointerCast::UnsafeFnPointer @@ -204,7 +184,7 @@ fn check_rvalue( }; let unsized_ty = tcx.struct_tail_erasing_lifetimes(pointee_ty, tcx.param_env(def_id)); if let ty::Slice(_) | ty::Str = unsized_ty.kind() { - check_operand(tcx, op, span, def_id, body)?; + check_operand(tcx, op, span, body)?; // Casting/coercing things to slices is fine. Ok(()) } else { @@ -214,8 +194,8 @@ fn check_rvalue( } // binops are fine on integers Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => { - check_operand(tcx, lhs, span, def_id, body)?; - check_operand(tcx, rhs, span, def_id, body)?; + check_operand(tcx, lhs, span, body)?; + check_operand(tcx, rhs, span, body)?; let ty = lhs.ty(body, tcx); if ty.is_integral() || ty.is_bool() || ty.is_char() { Ok(()) @@ -230,14 +210,14 @@ fn check_rvalue( Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(body, tcx); if ty.is_integral() || ty.is_bool() { - check_operand(tcx, operand, span, def_id, body) + check_operand(tcx, operand, span, body) } else { Err((span, "only int and `bool` operations are stable in const fn".into())) } } Rvalue::Aggregate(_, operands) => { for operand in operands { - check_operand(tcx, operand, span, def_id, body)?; + check_operand(tcx, operand, span, body)?; } Ok(()) } @@ -253,15 +233,15 @@ fn check_statement( let span = statement.source_info.span; match &statement.kind { StatementKind::Assign(box (place, rval)) => { - check_place(tcx, *place, span, def_id, body)?; + check_place(tcx, *place, span, body)?; check_rvalue(tcx, body, def_id, rval, span) } - StatementKind::FakeRead(_, place) => check_place(tcx, **place, span, def_id, body), + StatementKind::FakeRead(_, place) => check_place(tcx, **place, span, body), // just an assignment StatementKind::SetDiscriminant { place, .. } => { - check_place(tcx, **place, span, def_id, body) + check_place(tcx, **place, span, body) } StatementKind::LlvmInlineAsm { .. } => { @@ -282,11 +262,10 @@ fn check_operand( tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, - def_id: DefId, body: &Body<'tcx>, ) -> McfResult { match operand { - Operand::Move(place) | Operand::Copy(place) => check_place(tcx, *place, span, def_id, body), + Operand::Move(place) | Operand::Copy(place) => check_place(tcx, *place, span, body), Operand::Constant(c) => match c.check_static_ptr(tcx) { Some(_) => Err((span, "cannot access `static` items in const fn".into())), None => Ok(()), @@ -298,7 +277,6 @@ fn check_place( tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, - def_id: DefId, body: &Body<'tcx>, ) -> McfResult { let mut cursor = place.projection.as_ref(); @@ -310,9 +288,7 @@ fn check_place( if let Some(def) = base_ty.ty_adt_def() { // No union field accesses in `const fn` if def.is_union() { - if !feature_allowed(tcx, def_id, sym::const_fn_union) { return Err((span, "accessing union fields is unstable".into())); - } } } } @@ -327,48 +303,9 @@ fn check_place( Ok(()) } -/// Returns `true` if the given feature gate is allowed within the function with the given `DefId`. -fn feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool { - // All features require that the corresponding gate be enabled, - // even if the function has `#[allow_internal_unstable(the_gate)]`. - if !tcx.features().enabled(feature_gate) { - return false; - } - - // If this crate is not using stability attributes, or this function is not claiming to be a - // stable `const fn`, that is all that is required. - if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) { - return true; - } - - // However, we cannot allow stable `const fn`s to use unstable features without an explicit - // opt-in via `allow_internal_unstable`. - rustc_mir::transform::check_consts::allow_internal_unstable(tcx, def_id, feature_gate) -} - -/// Returns `true` if the given library feature gate is allowed within the function with the given `DefId`. -pub fn lib_feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool { - // All features require that the corresponding gate be enabled, - // even if the function has `#[allow_internal_unstable(the_gate)]`. - if !tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == feature_gate) { - return false; - } - - // If this crate is not using stability attributes, or this function is not claiming to be a - // stable `const fn`, that is all that is required. - if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) { - return true; - } - - // However, we cannot allow stable `const fn`s to use unstable features without an explicit - // opt-in via `allow_internal_unstable`. - rustc_mir::transform::check_consts::allow_internal_unstable(tcx, def_id, feature_gate) -} - fn check_terminator( tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, - def_id: DefId, terminator: &Terminator<'tcx>, ) -> McfResult { let span = terminator.source_info.span; @@ -380,14 +317,14 @@ fn check_terminator( | TerminatorKind::Resume | TerminatorKind::Unreachable => Ok(()), - TerminatorKind::Drop { place, .. } => check_place(tcx, *place, span, def_id, body), + TerminatorKind::Drop { place, .. } => check_place(tcx, *place, span, body), TerminatorKind::DropAndReplace { place, value, .. } => { - check_place(tcx, *place, span, def_id, body)?; - check_operand(tcx, value, span, def_id, body) + check_place(tcx, *place, span, body)?; + check_operand(tcx, value, span, body) } TerminatorKind::SwitchInt { discr, switch_ty: _, values: _, targets: _ } => { - check_operand(tcx, discr, span, def_id, body) + check_operand(tcx, discr, span, body) } TerminatorKind::Abort => Err((span, "abort is not stable in const fn".into())), @@ -405,15 +342,7 @@ fn check_terminator( } => { let fn_ty = func.ty(body, tcx); if let ty::FnDef(fn_def_id, _) = *fn_ty.kind() { - // Allow unstable const if we opt in by using #[allow_internal_unstable] - // on function or macro declaration. if !rustc_mir::const_eval::is_min_const_fn(tcx, fn_def_id) - && !rustc_mir::const_eval::is_unstable_const_fn(tcx, fn_def_id) - .map(|feature| { - span.allows_unstable(feature) - || lib_feature_allowed(tcx, def_id, feature) - }) - .unwrap_or(false) { return Err(( span, @@ -432,7 +361,6 @@ fn check_terminator( // transmutes in const fn before we add more hacks to this. if tcx.fn_sig(fn_def_id).abi() == RustIntrinsic && tcx.item_name(fn_def_id) == sym::transmute - && !feature_allowed(tcx, def_id, sym::const_fn_transmute) { return Err(( span, @@ -440,10 +368,10 @@ fn check_terminator( )); } - check_operand(tcx, func, span, fn_def_id, body)?; + check_operand(tcx, func, span, body)?; for arg in args { - check_operand(tcx, arg, span, fn_def_id, body)?; + check_operand(tcx, arg, span, body)?; } Ok(()) } else { @@ -452,7 +380,7 @@ fn check_terminator( } TerminatorKind::Assert { cond, expected: _, msg: _, target: _, cleanup: _ } => { - check_operand(tcx, cond, span, def_id, body) + check_operand(tcx, cond, span, body) } TerminatorKind::InlineAsm { .. } => { From 49d1ce00f30a10e607dc30506d3e890d1efb6309 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sat, 26 Sep 2020 00:00:00 +0000 Subject: [PATCH 1022/1052] liveness: Remove unnecessary local variable exit_ln --- compiler/rustc_passes/src/liveness.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index cb452d3d04153..402f889ac8c49 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1093,9 +1093,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } hir::ExprKind::Ret(ref o_e) => { - // ignore succ and subst exit_ln: - let exit_ln = self.exit_ln; - self.propagate_through_opt_expr(o_e.as_ref().map(|e| &**e), exit_ln) + // Ignore succ and subst exit_ln. + self.propagate_through_opt_expr(o_e.as_ref().map(|e| &**e), self.exit_ln) } hir::ExprKind::Break(label, ref opt_expr) => { From 57d38975cc638bcdeb7e9bcd10621615e8f9f3c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sat, 26 Sep 2020 00:00:00 +0000 Subject: [PATCH 1023/1052] liveness: Use newtype_index for Variable and LiveNode --- Cargo.lock | 1 + compiler/rustc_passes/Cargo.toml | 1 + compiler/rustc_passes/src/lib.rs | 2 + compiler/rustc_passes/src/liveness.rs | 109 ++++++++++---------------- 4 files changed, 47 insertions(+), 66 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9a5ba74174948..2bd41e68f8b9d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3891,6 +3891,7 @@ dependencies = [ "rustc_hir", "rustc_index", "rustc_middle", + "rustc_serialize", "rustc_session", "rustc_span", "rustc_target", diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml index 4c3a96eed04c4..df6667a29d50b 100644 --- a/compiler/rustc_passes/Cargo.toml +++ b/compiler/rustc_passes/Cargo.toml @@ -15,5 +15,6 @@ rustc_index = { path = "../rustc_index" } rustc_session = { path = "../rustc_session" } rustc_target = { path = "../rustc_target" } rustc_ast = { path = "../rustc_ast" } +rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } rustc_trait_selection = { path = "../rustc_trait_selection" } diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index c14d6aace87e0..c32c9c8eaa68c 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -5,6 +5,8 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(const_fn)] +#![feature(const_panic)] #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(or_patterns)] diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 402f889ac8c49..8c6d47f992d78 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -62,13 +62,13 @@ //! - `reader`: the `LiveNode` ID of some node which will read the value //! that `V` holds on entry to `N`. Formally: a node `M` such //! that there exists a path `P` from `N` to `M` where `P` does not -//! write `V`. If the `reader` is `invalid_node()`, then the current +//! write `V`. If the `reader` is `INVALID_NODE`, then the current //! value will never be read (the variable is dead, essentially). //! //! - `writer`: the `LiveNode` ID of some node which will write the //! variable `V` and which is reachable from `N`. Formally: a node `M` //! such that there exists a path `P` from `N` to `M` and `M` writes -//! `V`. If the `writer` is `invalid_node()`, then there is no writer +//! `V`. If the `writer` is `INVALID_NODE`, then there is no writer //! of `V` that follows `N`. //! //! - `used`: a boolean value indicating whether `V` is *used*. We @@ -92,6 +92,7 @@ use rustc_hir::def::*; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, FnKind, NestedVisitorMap, Visitor}; use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet, Node}; +use rustc_index::vec::IndexVec; use rustc_middle::hir::map::Map; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt}; @@ -100,26 +101,20 @@ use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; use std::collections::VecDeque; -use std::fmt; use std::io; use std::io::prelude::*; use std::rc::Rc; -#[derive(Copy, Clone, PartialEq)] -struct Variable(u32); - -#[derive(Copy, Clone, PartialEq)] -struct LiveNode(u32); - -impl Variable { - fn get(&self) -> usize { - self.0 as usize +rustc_index::newtype_index! { + pub struct Variable { + DEBUG_FORMAT = "v({})", } } -impl LiveNode { - fn get(&self) -> usize { - self.0 as usize +rustc_index::newtype_index! { + pub struct LiveNode { + DEBUG_FORMAT = "ln({})", + const INVALID_NODE = LiveNode::MAX_AS_U32, } } @@ -183,18 +178,6 @@ pub fn provide(providers: &mut Providers) { *providers = Providers { check_mod_liveness, ..*providers }; } -impl fmt::Debug for LiveNode { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "ln({})", self.get()) - } -} - -impl fmt::Debug for Variable { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "v({})", self.get()) - } -} - // ______________________________________________________________________ // Creating ir_maps // @@ -218,15 +201,11 @@ impl fmt::Debug for Variable { // assignment. And so forth. impl LiveNode { - fn is_valid(&self) -> bool { - self.0 != u32::MAX + fn is_valid(self) -> bool { + self != INVALID_NODE } } -fn invalid_node() -> LiveNode { - LiveNode(u32::MAX) -} - struct CaptureInfo { ln: LiveNode, var_hid: HirId, @@ -252,8 +231,8 @@ struct IrMaps<'tcx> { live_node_map: HirIdMap, variable_map: HirIdMap, capture_info_map: HirIdMap>>, - var_kinds: Vec, - lnks: Vec, + var_kinds: IndexVec, + lnks: IndexVec, } impl IrMaps<'tcx> { @@ -264,14 +243,13 @@ impl IrMaps<'tcx> { live_node_map: HirIdMap::default(), variable_map: HirIdMap::default(), capture_info_map: Default::default(), - var_kinds: Vec::new(), - lnks: Vec::new(), + var_kinds: IndexVec::new(), + lnks: IndexVec::new(), } } fn add_live_node(&mut self, lnk: LiveNodeKind) -> LiveNode { - let ln = LiveNode(self.lnks.len() as u32); - self.lnks.push(lnk); + let ln = self.lnks.push(lnk); debug!("{:?} is of kind {}", ln, live_node_kind_to_string(lnk, self.tcx)); @@ -286,8 +264,7 @@ impl IrMaps<'tcx> { } fn add_variable(&mut self, vk: VarKind) -> Variable { - let v = Variable(self.var_kinds.len() as u32); - self.var_kinds.push(vk); + let v = self.var_kinds.push(vk); match vk { Local(LocalInfo { id: node_id, .. }) | Param(node_id, _) | Upvar(node_id, _) => { @@ -310,13 +287,13 @@ impl IrMaps<'tcx> { } fn variable_name(&self, var: Variable) -> Symbol { - match self.var_kinds[var.get()] { + match self.var_kinds[var] { Local(LocalInfo { name, .. }) | Param(_, name) | Upvar(_, name) => name, } } fn variable_is_shorthand(&self, var: Variable) -> bool { - match self.var_kinds[var.get()] { + match self.var_kinds[var] { Local(LocalInfo { is_shorthand, .. }) => is_shorthand, Param(..) | Upvar(..) => false, } @@ -327,7 +304,7 @@ impl IrMaps<'tcx> { } fn lnk(&self, ln: LiveNode) -> LiveNodeKind { - self.lnks[ln.get()] + self.lnks[ln] } } @@ -556,10 +533,10 @@ struct RWUTable { unpacked_rwus: Vec, } -// A constant representing `RWU { reader: invalid_node(); writer: invalid_node(); used: false }`. +// A constant representing `RWU { reader: INVALID_NODE; writer: INVALID_NODE; used: false }`. const INV_INV_FALSE: u32 = u32::MAX; -// A constant representing `RWU { reader: invalid_node(); writer: invalid_node(); used: true }`. +// A constant representing `RWU { reader: INVALID_NODE; writer: INVALID_NODE; used: true }`. const INV_INV_TRUE: u32 = u32::MAX - 1; impl RWUTable { @@ -570,8 +547,8 @@ impl RWUTable { fn get(&self, idx: usize) -> RWU { let packed_rwu = self.packed_rwus[idx]; match packed_rwu { - INV_INV_FALSE => RWU { reader: invalid_node(), writer: invalid_node(), used: false }, - INV_INV_TRUE => RWU { reader: invalid_node(), writer: invalid_node(), used: true }, + INV_INV_FALSE => RWU { reader: INVALID_NODE, writer: INVALID_NODE, used: false }, + INV_INV_TRUE => RWU { reader: INVALID_NODE, writer: INVALID_NODE, used: true }, _ => self.unpacked_rwus[packed_rwu as usize], } } @@ -579,7 +556,7 @@ impl RWUTable { fn get_reader(&self, idx: usize) -> LiveNode { let packed_rwu = self.packed_rwus[idx]; match packed_rwu { - INV_INV_FALSE | INV_INV_TRUE => invalid_node(), + INV_INV_FALSE | INV_INV_TRUE => INVALID_NODE, _ => self.unpacked_rwus[packed_rwu as usize].reader, } } @@ -587,7 +564,7 @@ impl RWUTable { fn get_writer(&self, idx: usize) -> LiveNode { let packed_rwu = self.packed_rwus[idx]; match packed_rwu { - INV_INV_FALSE | INV_INV_TRUE => invalid_node(), + INV_INV_FALSE | INV_INV_TRUE => INVALID_NODE, _ => self.unpacked_rwus[packed_rwu as usize].writer, } } @@ -607,7 +584,7 @@ impl RWUTable { } fn assign_unpacked(&mut self, idx: usize, rwu: RWU) { - if rwu.reader == invalid_node() && rwu.writer == invalid_node() { + if rwu.reader == INVALID_NODE && rwu.writer == INVALID_NODE { // When we overwrite an indexing entry in `self.packed_rwus` with // `INV_INV_{TRUE,FALSE}` we don't remove the corresponding entry // from `self.unpacked_rwus`; it's not worth the effort, and we @@ -634,7 +611,7 @@ struct Liveness<'a, 'tcx> { ir: &'a mut IrMaps<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, param_env: ty::ParamEnv<'tcx>, - successors: Vec, + successors: IndexVec, rwu_table: RWUTable, /// A live node representing a point of execution before closure entry & @@ -667,7 +644,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { ir, typeck_results, param_env, - successors: vec![invalid_node(); num_live_nodes], + successors: IndexVec::from_elem_n(INVALID_NODE, num_live_nodes), rwu_table: RWUTable::new(num_live_nodes * num_vars), closure_ln, exit_ln, @@ -708,7 +685,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } fn idx(&self, ln: LiveNode, var: Variable) -> usize { - ln.get() * self.ir.var_kinds.len() + var.get() + ln.index() * self.ir.var_kinds.len() + var.index() } fn live_on_entry(&self, ln: LiveNode, var: Variable) -> Option { @@ -719,7 +696,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // Is this variable live on entry to any of its successor nodes? fn live_on_exit(&self, ln: LiveNode, var: Variable) -> Option { - let successor = self.successors[ln.get()]; + let successor = self.successors[ln]; self.live_on_entry(successor, var) } @@ -735,7 +712,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } fn assigned_on_exit(&self, ln: LiveNode, var: Variable) -> Option { - let successor = self.successors[ln.get()]; + let successor = self.successors[ln]; self.assigned_on_entry(successor, var) } @@ -743,8 +720,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { where F: FnMut(&mut Liveness<'a, 'tcx>, usize, usize), { - let node_base_idx = self.idx(ln, Variable(0)); - let succ_base_idx = self.idx(succ_ln, Variable(0)); + let node_base_idx = self.idx(ln, Variable::from(0u32)); + let succ_base_idx = self.idx(succ_ln, Variable::from(0u32)); for var_idx in 0..self.ir.var_kinds.len() { op(self, node_base_idx + var_idx, succ_base_idx + var_idx); } @@ -754,11 +731,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { where F: FnMut(usize) -> bool, { - let node_base_idx = self.idx(ln, Variable(0)); + let node_base_idx = self.idx(ln, Variable::from(0u32)); for var_idx in 0..self.ir.var_kinds.len() { let idx = node_base_idx + var_idx; if test(idx) { - write!(wr, " {:?}", Variable(var_idx as u32))?; + write!(wr, " {:?}", Variable::from(var_idx))?; } } Ok(()) @@ -769,14 +746,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let mut wr = Vec::new(); { let wr = &mut wr as &mut dyn Write; - write!(wr, "[ln({:?}) of kind {:?} reads", ln.get(), self.ir.lnk(ln)); + write!(wr, "[{:?} of kind {:?} reads", ln, self.ir.lnk(ln)); self.write_vars(wr, ln, |idx| self.rwu_table.get_reader(idx).is_valid()); write!(wr, " writes"); self.write_vars(wr, ln, |idx| self.rwu_table.get_writer(idx).is_valid()); write!(wr, " uses"); self.write_vars(wr, ln, |idx| self.rwu_table.get_used(idx)); - write!(wr, " precedes {:?}]", self.successors[ln.get()]); + write!(wr, " precedes {:?}]", self.successors[ln]); } String::from_utf8(wr).unwrap() } @@ -787,7 +764,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { "^^ liveness computation results for body {} (entry={:?})", { for ln_idx in 0..self.ir.lnks.len() { - debug!("{:?}", self.ln_str(LiveNode(ln_idx as u32))); + debug!("{:?}", self.ln_str(LiveNode::from(ln_idx))); } hir_id }, @@ -796,7 +773,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } fn init_empty(&mut self, ln: LiveNode, succ_ln: LiveNode) { - self.successors[ln.get()] = succ_ln; + self.successors[ln] = succ_ln; // It is not necessary to initialize the RWUs here because they are all // set to INV_INV_FALSE when they are created, and the sets only grow @@ -805,7 +782,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn init_from_succ(&mut self, ln: LiveNode, succ_ln: LiveNode) { // more efficient version of init_empty() / merge_from_succ() - self.successors[ln.get()] = succ_ln; + self.successors[ln] = succ_ln; self.indices2(ln, succ_ln, |this, idx, succ_idx| { this.rwu_table.copy_packed(idx, succ_idx); @@ -878,7 +855,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let mut rwu = self.rwu_table.get(idx); if (acc & ACC_WRITE) != 0 { - rwu.reader = invalid_node(); + rwu.reader = INVALID_NODE; rwu.writer = ln; } From cc2ba3bd2753ec94adc93ec4aa9d8d093129cd2d Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 26 Sep 2020 16:37:13 +0200 Subject: [PATCH 1024/1052] Add a test for 128-bit return values --- src/test/codegen/return-value-in-reg.rs | 32 +++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/test/codegen/return-value-in-reg.rs diff --git a/src/test/codegen/return-value-in-reg.rs b/src/test/codegen/return-value-in-reg.rs new file mode 100644 index 0000000000000..4bc0136c5e325 --- /dev/null +++ b/src/test/codegen/return-value-in-reg.rs @@ -0,0 +1,32 @@ +//! This test checks that types of up to 128 bits are returned by-value instead of via out-pointer. + +// compile-flags: -C no-prepopulate-passes -O +// only-x86_64 + +#![crate_type = "lib"] + +pub struct S { + a: u64, + b: u32, + c: u32, +} + +// CHECK: define i128 @modify(%S* noalias nocapture dereferenceable(16) %s) +#[no_mangle] +pub fn modify(s: S) -> S { + S { a: s.a + s.a, b: s.b + s.b, c: s.c + s.c } +} + +#[repr(packed)] +pub struct TooBig { + a: u64, + b: u32, + c: u32, + d: u8, +} + +// CHECK: define void @m_big(%TooBig* [[ATTRS:.*sret.*]], %TooBig* [[ATTRS2:.*]] %s) +#[no_mangle] +pub fn m_big(s: TooBig) -> TooBig { + TooBig { a: s.a + s.a, b: s.b + s.b, c: s.c + s.c, d: s.d + s.d } +} From ef83742b2bf9cb26c54576dad76418d872b52a99 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 22 Aug 2020 18:25:09 +0100 Subject: [PATCH 1025/1052] Delay bug for non-universal regions in member constraints --- .../src/borrow_check/region_infer/mod.rs | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs index 081125cb625c2..3dc082a4413b3 100644 --- a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs @@ -551,7 +551,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { mir_def_id: DefId, polonius_output: Option>, ) -> (Option>, RegionErrors<'tcx>) { - self.propagate_constraints(body); + self.propagate_constraints(body, infcx.tcx); let mut errors_buffer = RegionErrors::new(); @@ -599,7 +599,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// for each region variable until all the constraints are /// satisfied. Note that some values may grow **too** large to be /// feasible, but we check this later. - fn propagate_constraints(&mut self, _body: &Body<'tcx>) { + fn propagate_constraints(&mut self, _body: &Body<'tcx>, tcx: TyCtxt<'tcx>) { debug!("propagate_constraints()"); debug!("propagate_constraints: constraints={:#?}", { @@ -617,7 +617,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // own. let constraint_sccs = self.constraint_sccs.clone(); for scc in constraint_sccs.all_sccs() { - self.compute_value_for_scc(scc); + self.compute_value_for_scc(scc, tcx); } // Sort the applied member constraints so we can binary search @@ -629,7 +629,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// computed, by unioning the values of its successors. /// Assumes that all successors have been computed already /// (which is assured by iterating over SCCs in dependency order). - fn compute_value_for_scc(&mut self, scc_a: ConstraintSccIndex) { + fn compute_value_for_scc(&mut self, scc_a: ConstraintSccIndex, tcx: TyCtxt<'tcx>) { let constraint_sccs = self.constraint_sccs.clone(); // Walk each SCC `B` such that `A: B`... @@ -652,7 +652,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Now take member constraints into account. let member_constraints = self.member_constraints.clone(); for m_c_i in member_constraints.indices(scc_a) { - self.apply_member_constraint(scc_a, m_c_i, member_constraints.choice_regions(m_c_i)); + self.apply_member_constraint( + tcx, + scc_a, + m_c_i, + member_constraints.choice_regions(m_c_i), + ); } debug!( @@ -675,6 +680,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// If we make any changes, returns true, else false. fn apply_member_constraint( &mut self, + tcx: TyCtxt<'tcx>, scc: ConstraintSccIndex, member_constraint_index: NllMemberConstraintIndex, choice_regions: &[ty::RegionVid], @@ -688,12 +694,15 @@ impl<'tcx> RegionInferenceContext<'tcx> { // `impl_trait_in_bindings`, I believe, and we are just // opting not to handle it for now. See #61773 for // details. - bug!( - "member constraint for `{:?}` has an option region `{:?}` \ - that is not a universal region", - self.member_constraints[member_constraint_index].opaque_type_def_id, - uh_oh, + tcx.sess.delay_span_bug( + self.member_constraints[member_constraint_index].definition_span, + &format!( + "member constraint for `{:?}` has an option region `{:?}` \ + that is not a universal region", + self.member_constraints[member_constraint_index].opaque_type_def_id, uh_oh, + ), ); + return false; } // Create a mutable vector of the options. We'll try to winnow From b9653568a78ff3936ce78a1c65b6c83ff53702a4 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 18 Sep 2020 16:18:10 -0400 Subject: [PATCH 1026/1052] Encode less metadata for proc-macro crates Currently, we serialize the same crate metadata for proc-macro crates as we do for normal crates. This is quite wasteful - almost none of this metadata is ever used, and much of it can't even be deserialized (if it contains a foreign `CrateNum`). This PR changes metadata encoding to skip encoding the majority of crate metadata for proc-macro crates. Most of the `Lazy<[T]>` fields are left completetly empty, while the non-lazy fields are left as-is. Additionally, proc-macros now have a def span that does not include their body. This was done for normal functions in #75465, but was missed for proc-macros. As a result of this PR, we should only ever encode local `CrateNum`s when encoding proc-macro crates. I've added a specialized serialization impl for `CrateNum` to assert this. --- compiler/rustc_metadata/src/rmeta/decoder.rs | 56 +++++--- .../src/rmeta/decoder/cstore_impl.rs | 7 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 136 +++++++++++++----- compiler/rustc_metadata/src/rmeta/mod.rs | 29 +++- 4 files changed, 168 insertions(+), 60 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 72d54a26b01d4..c31e941b3ffc6 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -707,7 +707,11 @@ impl CrateRoot<'_> { impl<'a, 'tcx> CrateMetadataRef<'a> { fn is_proc_macro(&self, id: DefIndex) -> bool { - self.root.proc_macro_data.and_then(|data| data.decode(self).find(|x| *x == id)).is_some() + 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 { @@ -729,7 +733,15 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn raw_proc_macro(&self, id: DefIndex) -> &ProcMacro { // DefIndex's in root.proc_macro_data have a one-to-one correspondence // with items in 'raw_proc_macros'. - let pos = self.root.proc_macro_data.unwrap().decode(self).position(|i| i == id).unwrap(); + let pos = self + .root + .proc_macro_data + .as_ref() + .unwrap() + .macros + .decode(self) + .position(|i| i == id) + .unwrap(); &self.raw_proc_macros.unwrap()[pos] } @@ -766,7 +778,12 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_span(&self, index: DefIndex, sess: &Session) -> Span { - self.root.tables.span.get(self, index).unwrap().decode((self, sess)) + self.root + .tables + .span + .get(self, index) + .unwrap_or_else(|| panic!("Missing span for {:?}", index)) + .decode((self, sess)) } fn load_proc_macro(&self, id: DefIndex, sess: &Session) -> SyntaxExtension { @@ -942,7 +959,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn get_stability(&self, id: DefIndex) -> Option { match self.is_proc_macro(id) { - true => self.root.proc_macro_stability, + true => self.root.proc_macro_data.as_ref().unwrap().stability, false => self.root.tables.stability.get(self, id).map(|stab| stab.decode(self)), } } @@ -1035,24 +1052,20 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { where F: FnMut(Export), { - if let Some(proc_macros_ids) = self.root.proc_macro_data.map(|d| d.decode(self)) { + if let Some(data) = &self.root.proc_macro_data { /* If we are loading as a proc macro, we want to return the view of this crate * as a proc macro crate. */ if id == CRATE_DEF_INDEX { - for def_index in proc_macros_ids { + let macros = data.macros.decode(self); + for def_index in macros { let raw_macro = self.raw_proc_macro(def_index); let res = Res::Def( DefKind::Macro(macro_kind(raw_macro)), self.local_def_id(def_index), ); let ident = self.item_ident(def_index, sess); - callback(Export { - ident, - res, - vis: ty::Visibility::Public, - span: self.get_span(def_index, sess), - }); + callback(Export { ident, res, vis: ty::Visibility::Public, span: ident.span }); } } return; @@ -1559,12 +1572,19 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn all_def_path_hashes_and_def_ids(&self) -> Vec<(DefPathHash, DefId)> { let mut def_path_hashes = self.def_path_hash_cache.lock(); - (0..self.num_def_ids()) - .map(|index| { - let index = DefIndex::from_usize(index); - (self.def_path_hash_unlocked(index, &mut def_path_hashes), self.local_def_id(index)) - }) - .collect() + let mut def_index_to_data = |index| { + (self.def_path_hash_unlocked(index, &mut def_path_hashes), self.local_def_id(index)) + }; + if let Some(data) = &self.root.proc_macro_data { + std::iter::once(CRATE_DEF_INDEX) + .chain(data.macros.decode(self)) + .map(def_index_to_data) + .collect() + } else { + (0..self.num_def_ids()) + .map(|index| def_index_to_data(DefIndex::from_usize(index))) + .collect() + } } /// Get the `DepNodeIndex` corresponding this crate. The result of this diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index d4f577a7d1b49..4102cf84a6775 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -179,8 +179,11 @@ provide! { <'tcx> tcx, def_id, other, cdata, }) } proc_macro_decls_static => { - cdata.root.proc_macro_decls_static.map(|index| { - DefId { krate: def_id.krate, index } + cdata.root.proc_macro_data.as_ref().map(|data| { + DefId { + krate: def_id.krate, + index: data.proc_macro_decls_static, + } }) } crate_disambiguator => { cdata.root.disambiguator } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 556cf41992076..c756715dbe513 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -68,6 +68,17 @@ pub(super) struct EncodeContext<'a, 'tcx> { hygiene_ctxt: &'a HygieneEncodeContext, } +/// If the current crate is a proc-macro, returns early with `Lazy:empty()`. +/// This is useful for skipping the encoding of things that aren't needed +/// for proc-macro crates. +macro_rules! empty_proc_macro { + ($self:ident) => { + if $self.is_proc_macro { + return Lazy::empty(); + } + }; +} + macro_rules! encoder_methods { ($($name:ident($ty:ty);)*) => { $(fn $name(&mut self, value: $ty) -> Result<(), Self::Error> { @@ -138,6 +149,15 @@ where } } +impl<'a, 'tcx> Encodable> for CrateNum { + fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { + if *self != LOCAL_CRATE && s.is_proc_macro { + panic!("Attempted to encode non-local CrateNum {:?} for proc-macro crate", self); + } + s.emit_u32(self.as_u32()) + } +} + impl<'a, 'tcx> Encodable> for DefIndex { fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { s.emit_u32(self.as_u32()) @@ -418,6 +438,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let krate = self.tcx.hir().krate(); let vis = Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Public }; self.encode_info_for_mod(hir::CRATE_HIR_ID, &krate.item.module, &krate.item.attrs, &vis); + + // Proc-macro crates only export proc-macro items, which are looked + // up using `proc_macro_data` + if self.is_proc_macro { + return; + } + krate.visit_all_item_likes(&mut self.as_deep_visitor()); for macro_def in krate.exported_macros { self.visit_macro_def(macro_def); @@ -426,11 +453,22 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_def_path_table(&mut self) { let table = self.tcx.hir().definitions().def_path_table(); - for (def_index, def_key, def_path_hash) in table.enumerated_keys_and_path_hashes() { - let def_key = self.lazy(def_key); - let def_path_hash = self.lazy(def_path_hash); - self.tables.def_keys.set(def_index, def_key); - self.tables.def_path_hashes.set(def_index, def_path_hash); + if self.is_proc_macro { + for def_index in std::iter::once(CRATE_DEF_INDEX) + .chain(self.tcx.hir().krate().proc_macros.iter().map(|p| p.owner.local_def_index)) + { + let def_key = self.lazy(table.def_key(def_index)); + let def_path_hash = self.lazy(table.def_path_hash(def_index)); + self.tables.def_keys.set(def_index, def_key); + self.tables.def_path_hashes.set(def_index, def_path_hash); + } + } else { + for (def_index, def_key, def_path_hash) in table.enumerated_keys_and_path_hashes() { + let def_key = self.lazy(def_key); + let def_path_hash = self.lazy(def_path_hash); + self.tables.def_keys.set(def_index, def_key); + self.tables.def_path_hashes.set(def_index, def_path_hash); + } } } @@ -497,13 +535,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy(adapted.iter().map(|rc| &**rc)) } - fn is_proc_macro(&self) -> bool { - self.tcx.sess.crate_types().contains(&CrateType::ProcMacro) - } - fn encode_crate_root(&mut self) -> Lazy> { - let is_proc_macro = self.is_proc_macro(); - let mut i = self.position(); // Encode the crate deps @@ -575,15 +607,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy(interpret_alloc_index) }; - i = self.position(); - let tables = self.tables.encode(&mut self.opaque); - let tables_bytes = self.position() - i; - - // Encode the proc macro data + // Encode the proc macro data. This affects 'tables', + // so we need to do this before we encode the tables i = self.position(); let proc_macro_data = self.encode_proc_macros(); let proc_macro_data_bytes = self.position() - i; + i = self.position(); + let tables = self.tables.encode(&mut self.opaque); + let tables_bytes = self.position() - i; + // Encode exported symbols info. This is prefetched in `encode_metadata` so we encode // this as late as possible to give the prefetching as much time as possible to complete. i = self.position(); @@ -624,18 +657,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE), has_default_lib_allocator, plugin_registrar_fn: tcx.plugin_registrar_fn(LOCAL_CRATE).map(|id| id.index), - proc_macro_decls_static: if is_proc_macro { - let id = tcx.proc_macro_decls_static(LOCAL_CRATE).unwrap(); - Some(id.index) - } else { - None - }, proc_macro_data, - proc_macro_stability: if is_proc_macro { - tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX)).copied() - } else { - None - }, compiler_builtins: tcx.sess.contains_name(&attrs, sym::compiler_builtins), needs_allocator: tcx.sess.contains_name(&attrs, sym::needs_allocator), needs_panic_runtime: tcx.sess.contains_name(&attrs, sym::needs_panic_runtime), @@ -800,8 +822,13 @@ impl EncodeContext<'a, 'tcx> { let def_id = local_def_id.to_def_id(); debug!("EncodeContext::encode_info_for_mod({:?})", def_id); - let data = ModData { - reexports: match tcx.module_exports(local_def_id) { + // If we are encoding a proc-macro crates, `encode_info_for_mod` will + // only ever get called for the crate root. We still want to encode + // the crate root for consistency with other crates (some of the resolver + // code uses it). However, we skip encoding anything relating to child + // items - we encode information about proc-macros later on. + let reexports = if !self.is_proc_macro { + match tcx.module_exports(local_def_id) { Some(exports) => { let hir = self.tcx.hir(); self.lazy( @@ -811,7 +838,13 @@ impl EncodeContext<'a, 'tcx> { ) } _ => Lazy::empty(), - }, + } + } else { + Lazy::empty() + }; + + let data = ModData { + reexports, expansion: tcx.hir().definitions().expansion_that_defined(local_def_id), }; @@ -819,9 +852,13 @@ impl EncodeContext<'a, 'tcx> { record!(self.tables.visibility[def_id] <- ty::Visibility::from_hir(vis, id, self.tcx)); record!(self.tables.span[def_id] <- self.tcx.def_span(def_id)); record!(self.tables.attributes[def_id] <- attrs); - record!(self.tables.children[def_id] <- md.item_ids.iter().map(|item_id| { - tcx.hir().local_def_id(item_id.id).local_def_index - })); + if self.is_proc_macro { + record!(self.tables.children[def_id] <- &[]); + } else { + record!(self.tables.children[def_id] <- md.item_ids.iter().map(|item_id| { + tcx.hir().local_def_id(item_id.id).local_def_index + })); + } self.encode_stability(def_id); self.encode_deprecation(def_id); } @@ -1481,11 +1518,13 @@ impl EncodeContext<'a, 'tcx> { } fn encode_native_libraries(&mut self) -> Lazy<[NativeLib]> { + empty_proc_macro!(self); let used_libraries = self.tcx.native_libraries(LOCAL_CRATE); self.lazy(used_libraries.iter().cloned()) } fn encode_foreign_modules(&mut self) -> Lazy<[ForeignModule]> { + empty_proc_macro!(self); let foreign_modules = self.tcx.foreign_modules(LOCAL_CRATE); self.lazy(foreign_modules.iter().cloned()) } @@ -1509,17 +1548,37 @@ impl EncodeContext<'a, 'tcx> { (syntax_contexts.encode(&mut self.opaque), expn_data_table.encode(&mut self.opaque)) } - fn encode_proc_macros(&mut self) -> Option> { + fn encode_proc_macros(&mut self) -> Option { let is_proc_macro = self.tcx.sess.crate_types().contains(&CrateType::ProcMacro); if is_proc_macro { let tcx = self.tcx; - Some(self.lazy(tcx.hir().krate().proc_macros.iter().map(|p| p.owner.local_def_index))) + let hir = tcx.hir(); + + let proc_macro_decls_static = tcx.proc_macro_decls_static(LOCAL_CRATE).unwrap().index; + let stability = tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX)).copied(); + let macros = self.lazy(hir.krate().proc_macros.iter().map(|p| p.owner.local_def_index)); + + // Normally, this information is encoded when we walk the items + // defined in this crate. However, we skip doing that for proc-macro crates, + // 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)); + // 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); + } + + Some(ProcMacroData { proc_macro_decls_static, stability, macros }) } else { None } } fn encode_crate_deps(&mut self) -> Lazy<[CrateDep]> { + empty_proc_macro!(self); let crates = self.tcx.crates(); let mut deps = crates @@ -1555,18 +1614,21 @@ impl EncodeContext<'a, 'tcx> { } fn encode_lib_features(&mut self) -> Lazy<[(Symbol, Option)]> { + empty_proc_macro!(self); let tcx = self.tcx; let lib_features = tcx.lib_features(); self.lazy(lib_features.to_vec()) } fn encode_diagnostic_items(&mut self) -> Lazy<[(Symbol, DefIndex)]> { + empty_proc_macro!(self); let tcx = self.tcx; let diagnostic_items = tcx.diagnostic_items(LOCAL_CRATE); self.lazy(diagnostic_items.iter().map(|(&name, def_id)| (name, def_id.index))) } fn encode_lang_items(&mut self) -> Lazy<[(DefIndex, usize)]> { + empty_proc_macro!(self); let tcx = self.tcx; let lang_items = tcx.lang_items(); let lang_items = lang_items.items().iter(); @@ -1581,12 +1643,14 @@ impl EncodeContext<'a, 'tcx> { } fn encode_lang_items_missing(&mut self) -> Lazy<[lang_items::LangItem]> { + empty_proc_macro!(self); let tcx = self.tcx; self.lazy(&tcx.lang_items().missing) } /// Encodes an index, mapping each trait to its (local) implementations. fn encode_impls(&mut self) -> Lazy<[TraitImpls]> { + empty_proc_macro!(self); debug!("EncodeContext::encode_impls()"); let tcx = self.tcx; let mut visitor = ImplVisitor { tcx, impls: FxHashMap::default() }; @@ -1625,6 +1689,7 @@ impl EncodeContext<'a, 'tcx> { &mut self, exported_symbols: &[(ExportedSymbol<'tcx>, SymbolExportLevel)], ) -> Lazy<[(ExportedSymbol<'tcx>, SymbolExportLevel)]> { + empty_proc_macro!(self); // The metadata symbol name is special. It should not show up in // downstream crates. let metadata_symbol_name = SymbolName::new(self.tcx, &metadata_symbol_name(self.tcx)); @@ -1641,6 +1706,7 @@ impl EncodeContext<'a, 'tcx> { } fn encode_dylib_dependency_formats(&mut self) -> Lazy<[Option]> { + empty_proc_macro!(self); let formats = self.tcx.dependency_formats(LOCAL_CRATE); for (ty, arr) in formats.iter() { if *ty != CrateType::Dylib { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index ba540c944117d..1a127035d4ff7 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -172,6 +172,29 @@ macro_rules! Lazy { type SyntaxContextTable = Lazy>>; type ExpnDataTable = Lazy>>; +#[derive(MetadataEncodable, MetadataDecodable)] +crate struct ProcMacroData { + proc_macro_decls_static: DefIndex, + stability: Option, + macros: Lazy<[DefIndex]>, +} + +/// Serialized metadata for a crate. +/// When compiling a proc-macro crate, we encode many of +/// the `Lazy<[T]>` fields as `Lazy::empty()`. This serves two purposes: +/// +/// 1. We avoid performing unnecessary work. Proc-macro crates can only +/// export proc-macros functions, which are compiled into a shared library. +/// As a result, a large amount of the information we normally store +/// (e.g. optimized MIR) is unneeded by downstream crates. +/// 2. We avoid serializing invalid `CrateNum`s. When we deserialize +/// a proc-macro crate, we don't load any of its dependencies (since we +/// just need to invoke a native function from the shared library). +/// This means that any foreign `CrateNum`s that we serialize cannot be +/// deserialized, since we will not know how to map them into the current +/// compilation session. If we were to serialize a proc-macro crate like +/// a normal crate, much of what we serialized would be unusable in addition +/// to being unused. #[derive(MetadataEncodable, MetadataDecodable)] crate struct CrateRoot<'tcx> { name: Symbol, @@ -185,8 +208,6 @@ crate struct CrateRoot<'tcx> { has_panic_handler: bool, has_default_lib_allocator: bool, plugin_registrar_fn: Option, - proc_macro_decls_static: Option, - proc_macro_stability: Option, crate_deps: Lazy<[CrateDep]>, dylib_dependency_formats: Lazy<[Option]>, @@ -198,12 +219,10 @@ crate struct CrateRoot<'tcx> { foreign_modules: Lazy<[ForeignModule]>, impls: Lazy<[TraitImpls]>, interpret_alloc_index: Lazy<[u32]>, + proc_macro_data: Option, tables: LazyTables<'tcx>, - /// The DefIndex's of any proc macros declared by this crate. - proc_macro_data: Option>, - exported_symbols: Lazy!([(ExportedSymbol<'tcx>, SymbolExportLevel)]), syntax_contexts: SyntaxContextTable, From 3a81adeca2b81a3c54bbbe07afafedea79f92c42 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 26 Sep 2020 17:56:03 +0100 Subject: [PATCH 1027/1052] Call `type_of` for opaque types later in compilation This ensures that various wf checks have already been done before we typeck item bodies. --- compiler/rustc_typeck/src/check/check.rs | 1 + compiler/rustc_typeck/src/collect.rs | 10 +- compiler/rustc_typeck/src/lib.rs | 2 +- .../ui/associated-type-bounds/duplicate.rs | 21 -- .../associated-type-bounds/duplicate.stderr | 224 ++++-------------- .../ui/associated-type-bounds/inside-adt.rs | 13 +- .../associated-type-bounds/inside-adt.stderr | 115 +++++---- src/test/ui/async-await/issues/issue-65159.rs | 2 +- src/test/ui/impl-trait/issue-55872-1.rs | 6 +- src/test/ui/impl-trait/issue-55872-1.stderr | 21 +- src/test/ui/impl-trait/where-allowed.rs | 2 + src/test/ui/impl-trait/where-allowed.stderr | 82 ++++--- .../type-alias-impl-trait/bound_reduction2.rs | 5 +- .../bound_reduction2.stderr | 16 +- .../declared_but_not_defined_in_scope.rs | 1 + .../declared_but_not_defined_in_scope.stderr | 17 +- .../generic_duplicate_param_use2.rs | 2 +- .../generic_duplicate_param_use2.stderr | 16 +- .../generic_duplicate_param_use3.rs | 2 +- .../generic_duplicate_param_use3.stderr | 16 +- .../generic_underconstrained.rs | 3 +- .../generic_underconstrained.stderr | 8 +- .../generic_underconstrained2.rs | 8 +- .../generic_underconstrained2.stderr | 18 +- .../impl-with-unconstrained-param.rs | 3 +- .../impl-with-unconstrained-param.stderr | 18 +- .../issue-57611-trait-alias.rs | 2 +- .../not_a_defining_use.rs | 5 +- .../not_a_defining_use.stderr | 16 +- ...alias-impl-trait-unconstrained-lifetime.rs | 18 ++ ...s-impl-trait-unconstrained-lifetime.stderr | 9 + .../typeck_type_placeholder_item.stderr | 94 ++++---- 32 files changed, 356 insertions(+), 420 deletions(-) create mode 100644 src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.rs create mode 100644 src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.stderr diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 2daa0354acb0b..0647be2dfde0b 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -385,6 +385,7 @@ pub(super) fn check_opaque<'tcx>( origin: &hir::OpaqueTyOrigin, ) { check_opaque_for_inheriting_lifetimes(tcx, def_id, span); + tcx.ensure().type_of(def_id); check_opaque_for_cycles(tcx, def_id, substs, span, origin); } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index a571bd58abc34..d6985f3bd4d63 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -693,8 +693,14 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::HirId) { // Desugared from `impl Trait`, so visited by the function's return type. hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(_), .. }) => {} - hir::ItemKind::OpaqueTy(..) - | hir::ItemKind::TyAlias(..) + // Don't call `type_of` on opaque types, since that depends on type + // checking function bodies. `check_item_type` ensures that it's called + // instead. + hir::ItemKind::OpaqueTy(..) => { + tcx.ensure().generics_of(def_id); + tcx.ensure().predicates_of(def_id); + } + hir::ItemKind::TyAlias(..) | hir::ItemKind::Static(..) | hir::ItemKind::Const(..) | hir::ItemKind::Fn(..) => { diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 84efb92582ed2..dd6621a3f11d4 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -360,7 +360,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> { // this ensures that later parts of type checking can assume that items // have valid types and not error - // FIXME(matthewjasper) We shouldn't need to do this. + // FIXME(matthewjasper) We shouldn't need to use `track_errors`. tcx.sess.track_errors(|| { tcx.sess.time("type_collecting", || { for &module in tcx.hir().krate().modules.keys() { diff --git a/src/test/ui/associated-type-bounds/duplicate.rs b/src/test/ui/associated-type-bounds/duplicate.rs index 6c86053083229..39df9ba02fdf5 100644 --- a/src/test/ui/associated-type-bounds/duplicate.rs +++ b/src/test/ui/associated-type-bounds/duplicate.rs @@ -60,11 +60,8 @@ fn FW3() where T: Iterator {} //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn FRPIT1() -> impl Iterator { iter::empty() } -//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn FRPIT2() -> impl Iterator { iter::empty() } -//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn FRPIT3() -> impl Iterator { iter::empty() } -//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn FAPIT1(_: impl Iterator) {} //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn FAPIT2(_: impl Iterator) {} @@ -107,28 +104,16 @@ type TAW3 where T: Iterator = T; type ETAI1> = impl Copy; //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses type ETAI2> = impl Copy; //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses type ETAI3> = impl Copy; //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses type ETAI4 = impl Iterator; //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses type ETAI5 = impl Iterator; //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses type ETAI6 = impl Iterator; //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses trait TRI1> {} //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] @@ -166,15 +151,9 @@ trait TRA3 { type A: Iterator; } type TADyn1 = dyn Iterator; //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses type TADyn2 = Box>; //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses type TADyn3 = dyn Iterator; //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses fn main() {} diff --git a/src/test/ui/associated-type-bounds/duplicate.stderr b/src/test/ui/associated-type-bounds/duplicate.stderr index ac59e1f2fba24..77cd88e524f5f 100644 --- a/src/test/ui/associated-type-bounds/duplicate.stderr +++ b/src/test/ui/associated-type-bounds/duplicate.stderr @@ -200,7 +200,7 @@ LL | fn FW3() where T: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:68:40 + --> $DIR/duplicate.rs:65:40 | LL | fn FAPIT1(_: impl Iterator) {} | ---------- ^^^^^^^^^^ re-bound here @@ -208,7 +208,7 @@ LL | fn FAPIT1(_: impl Iterator) {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:70:40 + --> $DIR/duplicate.rs:67:40 | LL | fn FAPIT2(_: impl Iterator) {} | ---------- ^^^^^^^^^^ re-bound here @@ -216,7 +216,7 @@ LL | fn FAPIT2(_: impl Iterator) {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:72:43 + --> $DIR/duplicate.rs:69:43 | LL | fn FAPIT3(_: impl Iterator) {} | ------------- ^^^^^^^^^^^^^ re-bound here @@ -224,7 +224,7 @@ LL | fn FAPIT3(_: impl Iterator) {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:75:39 + --> $DIR/duplicate.rs:72:39 | LL | const CIT1: impl Iterator = iter::empty(); | ---------- ^^^^^^^^^^ re-bound here @@ -232,7 +232,7 @@ LL | const CIT1: impl Iterator = iter::empty(); | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:77:39 + --> $DIR/duplicate.rs:74:39 | LL | const CIT2: impl Iterator = iter::empty(); | ---------- ^^^^^^^^^^ re-bound here @@ -240,7 +240,7 @@ LL | const CIT2: impl Iterator = iter::empty(); | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:79:42 + --> $DIR/duplicate.rs:76:42 | LL | const CIT3: impl Iterator = iter::empty(); | ------------- ^^^^^^^^^^^^^ re-bound here @@ -248,7 +248,7 @@ LL | const CIT3: impl Iterator = iter::empty(); | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:81:40 + --> $DIR/duplicate.rs:78:40 | LL | static SIT1: impl Iterator = iter::empty(); | ---------- ^^^^^^^^^^ re-bound here @@ -256,7 +256,7 @@ LL | static SIT1: impl Iterator = iter::empty(); | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:83:40 + --> $DIR/duplicate.rs:80:40 | LL | static SIT2: impl Iterator = iter::empty(); | ---------- ^^^^^^^^^^ re-bound here @@ -264,7 +264,7 @@ LL | static SIT2: impl Iterator = iter::empty(); | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:85:43 + --> $DIR/duplicate.rs:82:43 | LL | static SIT3: impl Iterator = iter::empty(); | ------------- ^^^^^^^^^^^^^ re-bound here @@ -272,7 +272,7 @@ LL | static SIT3: impl Iterator = iter::empty(); | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:88:46 + --> $DIR/duplicate.rs:85:46 | LL | fn lit1() { let _: impl Iterator = iter::empty(); } | ---------- ^^^^^^^^^^ re-bound here @@ -280,7 +280,7 @@ LL | fn lit1() { let _: impl Iterator = iter::empty(); } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:90:46 + --> $DIR/duplicate.rs:87:46 | LL | fn lit2() { let _: impl Iterator = iter::empty(); } | ---------- ^^^^^^^^^^ re-bound here @@ -288,7 +288,7 @@ LL | fn lit2() { let _: impl Iterator = iter::empty(); } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:92:49 + --> $DIR/duplicate.rs:89:49 | LL | fn lit3() { let _: impl Iterator = iter::empty(); } | ------------- ^^^^^^^^^^^^^ re-bound here @@ -296,7 +296,7 @@ LL | fn lit3() { let _: impl Iterator = iter::empt | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:95:35 + --> $DIR/duplicate.rs:92:35 | LL | type TAI1> = T; | ---------- ^^^^^^^^^^ re-bound here @@ -304,7 +304,7 @@ LL | type TAI1> = T; | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:97:35 + --> $DIR/duplicate.rs:94:35 | LL | type TAI2> = T; | ---------- ^^^^^^^^^^ re-bound here @@ -312,7 +312,7 @@ LL | type TAI2> = T; | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:99:38 + --> $DIR/duplicate.rs:96:38 | LL | type TAI3> = T; | ------------- ^^^^^^^^^^^^^ re-bound here @@ -320,7 +320,7 @@ LL | type TAI3> = T; | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:101:44 + --> $DIR/duplicate.rs:98:44 | LL | type TAW1 where T: Iterator = T; | ---------- ^^^^^^^^^^ re-bound here @@ -328,7 +328,7 @@ LL | type TAW1 where T: Iterator = T; | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:103:44 + --> $DIR/duplicate.rs:100:44 | LL | type TAW2 where T: Iterator = T; | ---------- ^^^^^^^^^^ re-bound here @@ -336,7 +336,7 @@ LL | type TAW2 where T: Iterator = T; | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:105:47 + --> $DIR/duplicate.rs:102:47 | LL | type TAW3 where T: Iterator = T; | ------------- ^^^^^^^^^^^^^ re-bound here @@ -344,7 +344,7 @@ LL | type TAW3 where T: Iterator = T; | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:108:36 + --> $DIR/duplicate.rs:105:36 | LL | type ETAI1> = impl Copy; | ---------- ^^^^^^^^^^ re-bound here @@ -352,99 +352,39 @@ LL | type ETAI1> = impl Copy; | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:62:42 - | -LL | fn FRPIT1() -> impl Iterator { iter::empty() } - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:64:42 - | -LL | fn FRPIT2() -> impl Iterator { iter::empty() } - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:66:45 - | -LL | fn FRPIT3() -> impl Iterator { iter::empty() } - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error: could not find defining uses - --> $DIR/duplicate.rs:108:51 - | -LL | type ETAI1> = impl Copy; - | ^^^^^^^^^ - -error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:111:36 + --> $DIR/duplicate.rs:107:36 | LL | type ETAI2> = impl Copy; | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error: could not find defining uses - --> $DIR/duplicate.rs:111:51 - | -LL | type ETAI2> = impl Copy; - | ^^^^^^^^^ - error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:114:39 + --> $DIR/duplicate.rs:109:39 | LL | type ETAI3> = impl Copy; | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error: could not find defining uses - --> $DIR/duplicate.rs:114:57 - | -LL | type ETAI3> = impl Copy; - | ^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:117:14 - | -LL | type ETAI4 = impl Iterator; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:117:40 + --> $DIR/duplicate.rs:111:40 | LL | type ETAI4 = impl Iterator; | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error: could not find defining uses - --> $DIR/duplicate.rs:122:14 - | -LL | type ETAI5 = impl Iterator; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:122:40 + --> $DIR/duplicate.rs:113:40 | LL | type ETAI5 = impl Iterator; | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error: could not find defining uses - --> $DIR/duplicate.rs:127:14 - | -LL | type ETAI6 = impl Iterator; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:127:43 + --> $DIR/duplicate.rs:115:43 | LL | type ETAI6 = impl Iterator; | ------------- ^^^^^^^^^^^^^ re-bound here @@ -452,7 +392,7 @@ LL | type ETAI6 = impl Iterator; | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:133:36 + --> $DIR/duplicate.rs:118:36 | LL | trait TRI1> {} | ---------- ^^^^^^^^^^ re-bound here @@ -460,7 +400,7 @@ LL | trait TRI1> {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:135:36 + --> $DIR/duplicate.rs:120:36 | LL | trait TRI2> {} | ---------- ^^^^^^^^^^ re-bound here @@ -468,7 +408,7 @@ LL | trait TRI2> {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:137:39 + --> $DIR/duplicate.rs:122:39 | LL | trait TRI3> {} | ------------- ^^^^^^^^^^^^^ re-bound here @@ -476,7 +416,7 @@ LL | trait TRI3> {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:139:34 + --> $DIR/duplicate.rs:124:34 | LL | trait TRS1: Iterator {} | ---------- ^^^^^^^^^^ re-bound here @@ -484,7 +424,7 @@ LL | trait TRS1: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:141:34 + --> $DIR/duplicate.rs:126:34 | LL | trait TRS2: Iterator {} | ---------- ^^^^^^^^^^ re-bound here @@ -492,7 +432,7 @@ LL | trait TRS2: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:143:37 + --> $DIR/duplicate.rs:128:37 | LL | trait TRS3: Iterator {} | ------------- ^^^^^^^^^^^^^ re-bound here @@ -500,7 +440,7 @@ LL | trait TRS3: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:145:45 + --> $DIR/duplicate.rs:130:45 | LL | trait TRW1 where T: Iterator {} | ---------- ^^^^^^^^^^ re-bound here @@ -508,7 +448,7 @@ LL | trait TRW1 where T: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:147:45 + --> $DIR/duplicate.rs:132:45 | LL | trait TRW2 where T: Iterator {} | ---------- ^^^^^^^^^^ re-bound here @@ -516,7 +456,7 @@ LL | trait TRW2 where T: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:149:48 + --> $DIR/duplicate.rs:134:48 | LL | trait TRW3 where T: Iterator {} | ------------- ^^^^^^^^^^^^^ re-bound here @@ -524,7 +464,7 @@ LL | trait TRW3 where T: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:151:46 + --> $DIR/duplicate.rs:136:46 | LL | trait TRSW1 where Self: Iterator {} | ---------- ^^^^^^^^^^ re-bound here @@ -532,7 +472,7 @@ LL | trait TRSW1 where Self: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:151:46 + --> $DIR/duplicate.rs:136:46 | LL | trait TRSW1 where Self: Iterator {} | ---------- ^^^^^^^^^^ re-bound here @@ -540,7 +480,7 @@ LL | trait TRSW1 where Self: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:154:46 + --> $DIR/duplicate.rs:139:46 | LL | trait TRSW2 where Self: Iterator {} | ---------- ^^^^^^^^^^ re-bound here @@ -548,7 +488,7 @@ LL | trait TRSW2 where Self: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:154:46 + --> $DIR/duplicate.rs:139:46 | LL | trait TRSW2 where Self: Iterator {} | ---------- ^^^^^^^^^^ re-bound here @@ -556,7 +496,7 @@ LL | trait TRSW2 where Self: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:157:49 + --> $DIR/duplicate.rs:142:49 | LL | trait TRSW3 where Self: Iterator {} | ------------- ^^^^^^^^^^^^^ re-bound here @@ -564,7 +504,7 @@ LL | trait TRSW3 where Self: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:157:49 + --> $DIR/duplicate.rs:142:49 | LL | trait TRSW3 where Self: Iterator {} | ------------- ^^^^^^^^^^^^^ re-bound here @@ -572,7 +512,7 @@ LL | trait TRSW3 where Self: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:160:43 + --> $DIR/duplicate.rs:145:43 | LL | trait TRA1 { type A: Iterator; } | ---------- ^^^^^^^^^^ re-bound here @@ -580,7 +520,7 @@ LL | trait TRA1 { type A: Iterator; } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:162:43 + --> $DIR/duplicate.rs:147:43 | LL | trait TRA2 { type A: Iterator; } | ---------- ^^^^^^^^^^ re-bound here @@ -588,7 +528,7 @@ LL | trait TRA2 { type A: Iterator; } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:164:46 + --> $DIR/duplicate.rs:149:46 | LL | trait TRA3 { type A: Iterator; } | ------------- ^^^^^^^^^^^^^ re-bound here @@ -596,7 +536,7 @@ LL | trait TRA3 { type A: Iterator; } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:167:40 + --> $DIR/duplicate.rs:152:40 | LL | type TADyn1 = dyn Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -604,7 +544,7 @@ LL | type TADyn1 = dyn Iterator; | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:171:44 + --> $DIR/duplicate.rs:154:44 | LL | type TADyn2 = Box>; | ---------- ^^^^^^^^^^ re-bound here @@ -612,85 +552,13 @@ LL | type TADyn2 = Box>; | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified - --> $DIR/duplicate.rs:175:43 + --> $DIR/duplicate.rs:156:43 | LL | type TADyn3 = dyn Iterator; | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error: could not find defining uses - --> $DIR/duplicate.rs:117:28 - | -LL | type ETAI4 = impl Iterator; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:117:40 - | -LL | type ETAI4 = impl Iterator; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:122:28 - | -LL | type ETAI5 = impl Iterator; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:122:40 - | -LL | type ETAI5 = impl Iterator; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:127:28 - | -LL | type ETAI6 = impl Iterator; - | ^^^^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:127:43 - | -LL | type ETAI6 = impl Iterator; - | ^^^^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:167:28 - | -LL | type TADyn1 = dyn Iterator; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:167:40 - | -LL | type TADyn1 = dyn Iterator; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:171:32 - | -LL | type TADyn2 = Box>; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:171:44 - | -LL | type TADyn2 = Box>; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:175:28 - | -LL | type TADyn3 = dyn Iterator; - | ^^^^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:175:43 - | -LL | type TADyn3 = dyn Iterator; - | ^^^^^^^^^^^^^ - -error: aborting due to 90 previous errors; 1 warning emitted +error: aborting due to 69 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0719`. diff --git a/src/test/ui/associated-type-bounds/inside-adt.rs b/src/test/ui/associated-type-bounds/inside-adt.rs index b74c03829b48b..5af057387509d 100644 --- a/src/test/ui/associated-type-bounds/inside-adt.rs +++ b/src/test/ui/associated-type-bounds/inside-adt.rs @@ -3,32 +3,27 @@ struct S1 { f: dyn Iterator } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses struct S2 { f: Box> } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses struct S3 { f: dyn Iterator } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses enum E1 { V(dyn Iterator) } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses +//~| ERROR the size for values of type `(dyn Iterator + 'static)` enum E2 { V(Box>) } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses enum E3 { V(dyn Iterator) } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses +//~| ERROR the size for values of type `(dyn Iterator + 'static)` union U1 { f: dyn Iterator } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses +//~| ERROR the size for values of type `(dyn Iterator + 'static)` union U2 { f: Box> } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses union U3 { f: dyn Iterator } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses +//~| ERROR the size for values of type `(dyn Iterator + 'static)` fn main() {} diff --git a/src/test/ui/associated-type-bounds/inside-adt.stderr b/src/test/ui/associated-type-bounds/inside-adt.stderr index a532bb0c76697..74e858ca8616f 100644 --- a/src/test/ui/associated-type-bounds/inside-adt.stderr +++ b/src/test/ui/associated-type-bounds/inside-adt.stderr @@ -5,106 +5,125 @@ LL | struct S1 { f: dyn Iterator } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:7:33 + --> $DIR/inside-adt.rs:6:33 | LL | struct S2 { f: Box> } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:10:29 + --> $DIR/inside-adt.rs:8:29 | LL | struct S3 { f: dyn Iterator } | ^^^^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:14:26 + --> $DIR/inside-adt.rs:11:26 | LL | enum E1 { V(dyn Iterator) } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:17:30 + --> $DIR/inside-adt.rs:14:30 | LL | enum E2 { V(Box>) } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:20:26 + --> $DIR/inside-adt.rs:16:26 | LL | enum E3 { V(dyn Iterator) } | ^^^^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:24:28 + --> $DIR/inside-adt.rs:20:28 | LL | union U1 { f: dyn Iterator } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:27:32 + --> $DIR/inside-adt.rs:23:32 | LL | union U2 { f: Box> } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:30:28 + --> $DIR/inside-adt.rs:25:28 | LL | union U3 { f: dyn Iterator } | ^^^^^^^^^^^^^ -error: could not find defining uses - --> $DIR/inside-adt.rs:4:29 +error[E0277]: the size for values of type `(dyn Iterator + 'static)` cannot be known at compilation time + --> $DIR/inside-adt.rs:11:13 | -LL | struct S1 { f: dyn Iterator } - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/inside-adt.rs:7:33 +LL | enum E1 { V(dyn Iterator) } + | ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | -LL | struct S2 { f: Box> } - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/inside-adt.rs:10:29 + = help: the trait `Sized` is not implemented for `(dyn Iterator + 'static)` + = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size | -LL | struct S3 { f: dyn Iterator } - | ^^^^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/inside-adt.rs:14:26 +LL | enum E1 { V(&dyn Iterator) } + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap | -LL | enum E1 { V(dyn Iterator) } - | ^^^^^^^^^^ +LL | enum E1 { V(Box>) } + | ^^^^ ^ -error: could not find defining uses - --> $DIR/inside-adt.rs:17:30 - | -LL | enum E2 { V(Box>) } - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/inside-adt.rs:20:26 +error[E0277]: the size for values of type `(dyn Iterator + 'static)` cannot be known at compilation time + --> $DIR/inside-adt.rs:16:13 | LL | enum E3 { V(dyn Iterator) } - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Iterator + 'static)` + = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | enum E3 { V(&dyn Iterator) } + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | enum E3 { V(Box>) } + | ^^^^ ^ -error: could not find defining uses - --> $DIR/inside-adt.rs:24:28 +error[E0277]: the size for values of type `(dyn Iterator + 'static)` cannot be known at compilation time + --> $DIR/inside-adt.rs:20:15 | LL | union U1 { f: dyn Iterator } - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/inside-adt.rs:27:32 + | ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | -LL | union U2 { f: Box> } - | ^^^^^^^^^^ + = help: the trait `Sized` is not implemented for `(dyn Iterator + 'static)` + = note: no field of a union may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | union U1 { f: &dyn Iterator } + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | union U1 { f: Box> } + | ^^^^ ^ -error: could not find defining uses - --> $DIR/inside-adt.rs:30:28 +error[E0277]: the size for values of type `(dyn Iterator + 'static)` cannot be known at compilation time + --> $DIR/inside-adt.rs:25:15 | LL | union U3 { f: dyn Iterator } - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Iterator + 'static)` + = note: no field of a union may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | union U3 { f: &dyn Iterator } + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | union U3 { f: Box> } + | ^^^^ ^ -error: aborting due to 18 previous errors +error: aborting due to 13 previous errors +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/issues/issue-65159.rs b/src/test/ui/async-await/issues/issue-65159.rs index 2f80435046bdf..4f160fccc0113 100644 --- a/src/test/ui/async-await/issues/issue-65159.rs +++ b/src/test/ui/async-await/issues/issue-65159.rs @@ -5,7 +5,7 @@ async fn copy() -> Result<()> //~ ERROR wrong number of type arguments { Ok(()) - //~^ type annotations needed + //~^ ERROR type annotations needed } fn main() { } diff --git a/src/test/ui/impl-trait/issue-55872-1.rs b/src/test/ui/impl-trait/issue-55872-1.rs index 99ac4617b4167..a746ed09af55b 100644 --- a/src/test/ui/impl-trait/issue-55872-1.rs +++ b/src/test/ui/impl-trait/issue-55872-1.rs @@ -1,8 +1,7 @@ // ignore-tidy-linelength #![feature(type_alias_impl_trait)] -pub trait Bar -{ +pub trait Bar { type E: Copy; fn foo() -> Self::E; @@ -14,7 +13,8 @@ impl Bar for S { //~^^ ERROR the trait bound `T: Copy` is not satisfied in `(S, T)` [E0277] fn foo() -> Self::E { - //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + //~| ERROR impl has stricter requirements than trait (S::default(), T::default()) } } diff --git a/src/test/ui/impl-trait/issue-55872-1.stderr b/src/test/ui/impl-trait/issue-55872-1.stderr index a9f73947853c7..db49d988bb8eb 100644 --- a/src/test/ui/impl-trait/issue-55872-1.stderr +++ b/src/test/ui/impl-trait/issue-55872-1.stderr @@ -1,5 +1,14 @@ +error[E0276]: impl has stricter requirements than trait + --> $DIR/issue-55872-1.rs:15:5 + | +LL | fn foo() -> Self::E; + | ----------------------- definition of `foo` from trait +... +LL | fn foo() -> Self::E { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: Default` + error[E0277]: the trait bound `S: Copy` is not satisfied in `(S, T)` - --> $DIR/issue-55872-1.rs:12:14 + --> $DIR/issue-55872-1.rs:11:14 | LL | type E = impl Copy; | ^^^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `S` @@ -12,7 +21,7 @@ LL | impl Bar for S { | ^^^^^^ error[E0277]: the trait bound `T: Copy` is not satisfied in `(S, T)` - --> $DIR/issue-55872-1.rs:12:14 + --> $DIR/issue-55872-1.rs:11:14 | LL | type E = impl Copy; | ^^^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `T` @@ -25,15 +34,17 @@ LL | fn foo() -> Self::E { | ^^^^^^ error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias - --> $DIR/issue-55872-1.rs:16:37 + --> $DIR/issue-55872-1.rs:15:37 | LL | fn foo() -> Self::E { | _____________________________________^ LL | | +LL | | LL | | (S::default(), T::default()) LL | | } | |_____^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0276, E0277. +For more information about an error, try `rustc --explain E0276`. diff --git a/src/test/ui/impl-trait/where-allowed.rs b/src/test/ui/impl-trait/where-allowed.rs index 211a14ed4dd99..72b880fb92c65 100644 --- a/src/test/ui/impl-trait/where-allowed.rs +++ b/src/test/ui/impl-trait/where-allowed.rs @@ -56,10 +56,12 @@ fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() } fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types //~| ERROR nested `impl Trait` is not allowed +//~| ERROR cannot resolve opaque type // Disallowed fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types +//~| ERROR cannot resolve opaque type // Disallowed fn in_Fn_parameter_in_generics (_: F) { panic!() } diff --git a/src/test/ui/impl-trait/where-allowed.stderr b/src/test/ui/impl-trait/where-allowed.stderr index 7addc006e1900..93f9724140ef6 100644 --- a/src/test/ui/impl-trait/where-allowed.stderr +++ b/src/test/ui/impl-trait/where-allowed.stderr @@ -17,7 +17,7 @@ LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic | outer `impl Trait` error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/where-allowed.rs:119:16 + --> $DIR/where-allowed.rs:121:16 | LL | type Out = impl Debug; | ^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | type Out = impl Debug; = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/where-allowed.rs:155:23 + --> $DIR/where-allowed.rs:157:23 | LL | type InTypeAlias = impl Debug; | ^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | type InTypeAlias = impl Debug; = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/where-allowed.rs:159:39 + --> $DIR/where-allowed.rs:161:39 | LL | type InReturnInTypeAlias = fn() -> impl Debug; | ^^^^^^^^^^ @@ -110,139 +110,139 @@ LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:61:59 + --> $DIR/where-allowed.rs:62:59 | LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:65:38 + --> $DIR/where-allowed.rs:67:38 | LL | fn in_Fn_parameter_in_generics (_: F) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:69:40 + --> $DIR/where-allowed.rs:71:40 | LL | fn in_Fn_return_in_generics impl Debug> (_: F) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:82:32 + --> $DIR/where-allowed.rs:84:32 | LL | struct InBraceStructField { x: impl Debug } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:86:41 + --> $DIR/where-allowed.rs:88:41 | LL | struct InAdtInBraceStructField { x: Vec } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:90:27 + --> $DIR/where-allowed.rs:92:27 | LL | struct InTupleStructField(impl Debug); | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:95:25 + --> $DIR/where-allowed.rs:97:25 | LL | InBraceVariant { x: impl Debug }, | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:97:20 + --> $DIR/where-allowed.rs:99:20 | LL | InTupleVariant(impl Debug), | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:108:23 + --> $DIR/where-allowed.rs:110:23 | LL | fn in_return() -> impl Debug; | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:126:34 + --> $DIR/where-allowed.rs:128:34 | LL | fn in_trait_impl_return() -> impl Debug { () } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:139:33 + --> $DIR/where-allowed.rs:141:33 | LL | fn in_foreign_parameters(_: impl Debug); | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:142:31 + --> $DIR/where-allowed.rs:144:31 | LL | fn in_foreign_return() -> impl Debug; | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:159:39 + --> $DIR/where-allowed.rs:161:39 | LL | type InReturnInTypeAlias = fn() -> impl Debug; | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:164:16 + --> $DIR/where-allowed.rs:166:16 | LL | impl PartialEq for () { | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:169:24 + --> $DIR/where-allowed.rs:171:24 | LL | impl PartialEq<()> for impl Debug { | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:174:6 + --> $DIR/where-allowed.rs:176:6 | LL | impl impl Debug { | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:180:24 + --> $DIR/where-allowed.rs:182:24 | LL | impl InInherentImplAdt { | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:186:11 + --> $DIR/where-allowed.rs:188:11 | LL | where impl Debug: Debug | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:193:15 + --> $DIR/where-allowed.rs:195:15 | LL | where Vec: Debug | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:200:24 + --> $DIR/where-allowed.rs:202:24 | LL | where T: PartialEq | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:207:17 + --> $DIR/where-allowed.rs:209:17 | LL | where T: Fn(impl Debug) | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:214:22 + --> $DIR/where-allowed.rs:216:22 | LL | where T: Fn() -> impl Debug | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:220:29 + --> $DIR/where-allowed.rs:222:29 | LL | let _in_local_variable: impl Fn() = || {}; | ^^^^^^^^^ @@ -250,24 +250,44 @@ LL | let _in_local_variable: impl Fn() = || {}; = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:222:46 + --> $DIR/where-allowed.rs:224:46 | LL | let _in_return_in_local_variable = || -> impl Fn() { || {} }; | ^^^^^^^^^ +error[E0720]: cannot resolve opaque type + --> $DIR/where-allowed.rs:56:49 + | +LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } + | ^^^^^^^^^^^^^^^^^^^ -------- this returned value is of `!` type + | | + | cannot resolve opaque type + | + = help: this error will resolve once the item's body returns a concrete type + +error[E0720]: cannot resolve opaque type + --> $DIR/where-allowed.rs:62:46 + | +LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } + | ^^^^^^^^^^^^^^^^^^^^^^^ -------- this returned value is of `!` type + | | + | cannot resolve opaque type + | + = help: this error will resolve once the item's body returns a concrete type + error: could not find defining uses - --> $DIR/where-allowed.rs:119:16 + --> $DIR/where-allowed.rs:121:16 | LL | type Out = impl Debug; | ^^^^^^^^^^ error: could not find defining uses - --> $DIR/where-allowed.rs:155:23 + --> $DIR/where-allowed.rs:157:23 | LL | type InTypeAlias = impl Debug; | ^^^^^^^^^^ -error: aborting due to 42 previous errors +error: aborting due to 44 previous errors -Some errors have detailed explanations: E0562, E0658, E0666. +Some errors have detailed explanations: E0562, E0658, E0666, E0720. For more information about an error, try `rustc --explain E0562`. diff --git a/src/test/ui/type-alias-impl-trait/bound_reduction2.rs b/src/test/ui/type-alias-impl-trait/bound_reduction2.rs index 0a4cc9b7fe8be..a15074c35936b 100644 --- a/src/test/ui/type-alias-impl-trait/bound_reduction2.rs +++ b/src/test/ui/type-alias-impl-trait/bound_reduction2.rs @@ -1,19 +1,18 @@ #![feature(type_alias_impl_trait)] -fn main() { -} +fn main() {} trait TraitWithAssoc { type Assoc; } type Foo = impl Trait; -//~^ ERROR the trait bound `T: TraitWithAssoc` is not satisfied trait Trait {} impl Trait for () {} fn foo_desugared(_: T) -> Foo { + //~^ ERROR non-defining opaque type use in defining scope () } diff --git a/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr b/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr index 9ebf63468e773..c9d6a43b9094a 100644 --- a/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr +++ b/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr @@ -1,14 +1,14 @@ -error[E0277]: the trait bound `T: TraitWithAssoc` is not satisfied - --> $DIR/bound_reduction2.rs:10:15 +error: non-defining opaque type use in defining scope + --> $DIR/bound_reduction2.rs:15:46 | -LL | type Foo = impl Trait; - | ^^^^^^^^^^^^^ the trait `TraitWithAssoc` is not implemented for `T` +LL | fn foo_desugared(_: T) -> Foo { + | ^^^^^^^^^^^^^ | -help: consider further restricting this bound +note: used non-generic type `::Assoc` for generic parameter + --> $DIR/bound_reduction2.rs:9:10 | -LL | fn foo_desugared(_: T) -> Foo { - | ^^^^^^^^^^^^^^^^ +LL | type Foo = impl Trait; + | ^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.rs b/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.rs index 09873a8c8c3da..7ea517eb734a4 100644 --- a/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.rs +++ b/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.rs @@ -9,4 +9,5 @@ mod boo { fn bomp() -> boo::Boo { "" + //~^ mismatched types } diff --git a/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr b/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr index c0cb94b15d033..0b4c262bbb43b 100644 --- a/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr +++ b/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr @@ -4,5 +4,20 @@ error: could not find defining uses LL | pub type Boo = impl ::std::fmt::Debug; | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error[E0308]: mismatched types + --> $DIR/declared_but_not_defined_in_scope.rs:11:5 + | +LL | pub type Boo = impl ::std::fmt::Debug; + | ---------------------- the expected opaque type +... +LL | fn bomp() -> boo::Boo { + | -------- expected `impl Debug` because of return type +LL | "" + | ^^ expected opaque type, found `&str` + | + = note: expected opaque type `impl Debug` + found reference `&'static str` + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs index 2b98d8fc63a11..a74731df69515 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs @@ -8,10 +8,10 @@ fn main() {} type Two = impl Debug; fn one(t: T) -> Two { + //~^ ERROR non-defining opaque type use in defining scope t } fn two(t: T, _: U) -> Two { -//~^ ERROR concrete type differs from previous defining opaque type use t } diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr index 7900da47ca23d..d87e8c5783b65 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr @@ -1,14 +1,14 @@ -error: concrete type differs from previous defining opaque type use - --> $DIR/generic_duplicate_param_use2.rs:14:1 +error: non-defining opaque type use in defining scope + --> $DIR/generic_duplicate_param_use2.rs:10:27 | -LL | fn two(t: T, _: U) -> Two { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `U`, got `T` +LL | fn one(t: T) -> Two { + | ^^^^^^^^^ | -note: previous use here - --> $DIR/generic_duplicate_param_use2.rs:10:1 +note: type used multiple times + --> $DIR/generic_duplicate_param_use2.rs:8:10 | -LL | fn one(t: T) -> Two { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | type Two = impl Debug; + | ^ ^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs index d9133fd11f7cd..0597b8385d252 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs @@ -8,11 +8,11 @@ fn main() {} type Two = impl Debug; fn one(t: T) -> Two { + //~^ ERROR non-defining opaque type use in defining scope t } fn two(t: T, _: U) -> Two { -//~^ ERROR concrete type differs from previous defining opaque type use t } diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr index ac5f7947d51e9..711de855f0d10 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr @@ -1,14 +1,14 @@ -error: concrete type differs from previous defining opaque type use - --> $DIR/generic_duplicate_param_use3.rs:14:1 +error: non-defining opaque type use in defining scope + --> $DIR/generic_duplicate_param_use3.rs:10:27 | -LL | fn two(t: T, _: U) -> Two { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `U`, got `T` +LL | fn one(t: T) -> Two { + | ^^^^^^^^^ | -note: previous use here - --> $DIR/generic_duplicate_param_use3.rs:10:1 +note: type used multiple times + --> $DIR/generic_duplicate_param_use3.rs:8:10 | -LL | fn one(t: T) -> Two { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | type Two = impl Debug; + | ^ ^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained.rs b/src/test/ui/type-alias-impl-trait/generic_underconstrained.rs index 589612d5ed69b..766ee36c02be2 100644 --- a/src/test/ui/type-alias-impl-trait/generic_underconstrained.rs +++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained.rs @@ -3,10 +3,11 @@ fn main() {} trait Trait {} -type Underconstrained = impl 'static; //~ ERROR the trait bound `T: Trait` +type Underconstrained = impl 'static; //~^ ERROR: at least one trait must be specified // no `Trait` bound fn underconstrain(_: T) -> Underconstrained { + //~^ ERROR the trait bound `T: Trait` unimplemented!() } diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr b/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr index 911f592f73f27..cefc5d99b379e 100644 --- a/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr @@ -5,12 +5,14 @@ LL | type Underconstrained = impl 'static; | ^^^^^^^^^^^^ error[E0277]: the trait bound `T: Trait` is not satisfied - --> $DIR/generic_underconstrained.rs:6:35 + --> $DIR/generic_underconstrained.rs:10:31 | LL | type Underconstrained = impl 'static; - | ^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` + | ----- required by this bound in `Underconstrained` +... +LL | fn underconstrain(_: T) -> Underconstrained { + | ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` | - = note: the return type of a function must have a statically known size help: consider restricting type parameter `T` | LL | fn underconstrain(_: T) -> Underconstrained { diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.rs b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.rs index 4ac32e8a87038..cd7c962e2d15b 100644 --- a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.rs +++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.rs @@ -3,19 +3,19 @@ fn main() {} type Underconstrained = impl 'static; -//~^ ERROR `U` doesn't implement `Debug` -//~^^ ERROR: at least one trait must be specified +//~^ ERROR: at least one trait must be specified // not a defining use, because it doesn't define *all* possible generics fn underconstrained(_: U) -> Underconstrained { + //~^ ERROR `U` doesn't implement `Debug` 5u32 } type Underconstrained2 = impl 'static; -//~^ ERROR `V` doesn't implement `Debug` -//~^^ ERROR: at least one trait must be specified +//~^ ERROR: at least one trait must be specified // not a defining use, because it doesn't define *all* possible generics fn underconstrained2(_: U, _: V) -> Underconstrained2 { + //~^ ERROR `V` doesn't implement `Debug` 5u32 } diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr index 5ff82d4ad25fd..669546aef8669 100644 --- a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr @@ -11,30 +11,28 @@ LL | type Underconstrained2 = impl 'static; | ^^^^^^^^^^^^ error[E0277]: `U` doesn't implement `Debug` - --> $DIR/generic_underconstrained2.rs:5:45 + --> $DIR/generic_underconstrained2.rs:9:33 | LL | type Underconstrained = impl 'static; - | ^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | --------------- required by this bound in `Underconstrained` ... -LL | 5u32 - | ---- this returned value is of type `u32` +LL | fn underconstrained(_: U) -> Underconstrained { + | ^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = note: the return type of a function must have a statically known size help: consider restricting type parameter `U` | LL | fn underconstrained(_: U) -> Underconstrained { | ^^^^^^^ error[E0277]: `V` doesn't implement `Debug` - --> $DIR/generic_underconstrained2.rs:14:46 + --> $DIR/generic_underconstrained2.rs:18:43 | LL | type Underconstrained2 = impl 'static; - | ^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | --------------- required by this bound in `Underconstrained2` ... -LL | 5u32 - | ---- this returned value is of type `u32` +LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { + | ^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = note: the return type of a function must have a statically known size help: consider restricting type parameter `V` | LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { diff --git a/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs b/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs index bc6543a9229db..851c2f66c475a 100644 --- a/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs +++ b/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs @@ -9,10 +9,9 @@ trait X { } impl X for () { + //~^ ERROR the type parameter `T` is not constrained type I = impl Sized; - //~^ ERROR could not find defining uses fn f() -> Self::I {} - //~^ ERROR type annotations needed } fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr b/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr index e8b677113dba7..8cf8fb1d16c4d 100644 --- a/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr +++ b/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr @@ -1,15 +1,9 @@ -error[E0282]: type annotations needed - --> $DIR/impl-with-unconstrained-param.rs:14:23 +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/impl-with-unconstrained-param.rs:11:6 | -LL | fn f() -> Self::I {} - | ^^ cannot infer type for type parameter `T` +LL | impl X for () { + | ^ unconstrained type parameter -error: could not find defining uses - --> $DIR/impl-with-unconstrained-param.rs:12:14 - | -LL | type I = impl Sized; - | ^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0207`. diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs index 41e019247c942..782eb0fb3df5e 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs @@ -22,6 +22,6 @@ impl Foo for X { } } -trait Baz = Fn(&A) -> &B; +trait Baz = Fn(&A) -> &B; fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs b/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs index 02485b24e7b8a..f29b980dfd0e5 100644 --- a/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs +++ b/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs @@ -7,6 +7,7 @@ fn main() {} type Two = impl Debug; fn two(t: T) -> Two { + //~^ ERROR non-defining opaque type use in defining scope (t, 4i8) } @@ -24,9 +25,7 @@ impl Bar for u32 { const FOO: i32 = 42; } -// this should work! But it requires `two` and `three` not to be defining uses, -// just restricting uses -fn four(t: T) -> Two { //~ concrete type differs from previous +fn four(t: T) -> Two { (t, ::FOO) } diff --git a/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr b/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr index 9ce07a879f058..2fa236b373a40 100644 --- a/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr +++ b/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr @@ -1,14 +1,14 @@ -error: concrete type differs from previous defining opaque type use - --> $DIR/not_a_defining_use.rs:29:1 +error: non-defining opaque type use in defining scope + --> $DIR/not_a_defining_use.rs:9:27 | -LL | fn four(t: T) -> Two { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(T, i8)`, got `(T, ::Blub)` +LL | fn two(t: T) -> Two { + | ^^^^^^^^^^^ | -note: previous use here - --> $DIR/not_a_defining_use.rs:9:1 +note: used non-generic type `u32` for generic parameter + --> $DIR/not_a_defining_use.rs:7:13 | -LL | fn two(t: T) -> Two { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | type Two = impl Debug; + | ^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.rs b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.rs new file mode 100644 index 0000000000000..efbf4f1e351f7 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.rs @@ -0,0 +1,18 @@ +// regression test for #74018 + +#![feature(type_alias_impl_trait)] + +trait Trait { + type Associated; + fn into(self) -> Self::Associated; +} + +impl<'a, I: Iterator> Trait for (i32, I) { + //~^ ERROR the lifetime parameter `'a` is not constrained + type Associated = (i32, impl Iterator); + fn into(self) -> Self::Associated { + (0_i32, [0_i32].iter().copied()) + } +} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.stderr b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.stderr new file mode 100644 index 0000000000000..8cdce2f8e81ca --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.stderr @@ -0,0 +1,9 @@ +error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates + --> $DIR/type-alias-impl-trait-unconstrained-lifetime.rs:10:6 + | +LL | impl<'a, I: Iterator> Trait for (i32, I) { + | ^^ unconstrained lifetime parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0207`. diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.stderr b/src/test/ui/typeck/typeck_type_placeholder_item.stderr index 48ff1a2c51351..684f451b7c3f6 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_item.stderr @@ -405,15 +405,10 @@ LL | type X = Box<_>; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:43:27 - | -LL | fn test10(&self, _x : _) { } - | ^ not allowed in type signatures - | -help: use type parameters instead + --> $DIR/typeck_type_placeholder_item.rs:182:21 | -LL | fn test10(&self, _x : T) { } - | ^^^ ^ +LL | type Y = impl Trait<_>; + | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:140:31 @@ -485,45 +480,6 @@ help: use type parameters instead LL | fn assoc_fn_test3() -> T; | ^^^ ^ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:61:37 - | -LL | fn clone_from(&mut self, other: _) { *self = Test9; } - | ^ not allowed in type signatures - | -help: use type parameters instead - | -LL | fn clone_from(&mut self, other: T) { *self = Test9; } - | ^^^ ^ - -error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:110:34 - | -LL | fn fn_test10(&self, _x : _) { } - | ^ not allowed in type signatures - | -help: use type parameters instead - | -LL | fn fn_test10(&self, _x : T) { } - | ^^^ ^ - -error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:118:41 - | -LL | fn clone_from(&mut self, other: _) { *self = FnTest9; } - | ^ not allowed in type signatures - | -help: use type parameters instead - | -LL | fn clone_from(&mut self, other: T) { *self = FnTest9; } - | ^^^ ^ - -error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:182:21 - | -LL | type Y = impl Trait<_>; - | ^ not allowed in type signatures - error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:190:14 | @@ -560,6 +516,17 @@ LL | fn test9(&self) -> _ { () } | not allowed in type signatures | help: replace with the correct return type: `()` +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:43:27 + | +LL | fn test10(&self, _x : _) { } + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | fn test10(&self, _x : T) { } + | ^^^ ^ + error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:58:24 | @@ -569,6 +536,17 @@ LL | fn clone(&self) -> _ { Test9 } | not allowed in type signatures | help: replace with the correct return type: `Test9` +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:61:37 + | +LL | fn clone_from(&mut self, other: _) { *self = Test9; } + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | fn clone_from(&mut self, other: T) { *self = Test9; } + | ^^^ ^ + error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:107:31 | @@ -578,6 +556,17 @@ LL | fn fn_test9(&self) -> _ { () } | not allowed in type signatures | help: replace with the correct return type: `()` +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:110:34 + | +LL | fn fn_test10(&self, _x : _) { } + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | fn fn_test10(&self, _x : T) { } + | ^^^ ^ + error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:115:28 | @@ -587,6 +576,17 @@ LL | fn clone(&self) -> _ { FnTest9 } | not allowed in type signatures | help: replace with the correct return type: `FnTest9` +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:118:41 + | +LL | fn clone_from(&mut self, other: _) { *self = FnTest9; } + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | fn clone_from(&mut self, other: T) { *self = FnTest9; } + | ^^^ ^ + error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:201:14 | From 275bf626f615f7f154249606ad369d6c142801a5 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 26 Sep 2020 18:46:19 +0300 Subject: [PATCH 1028/1052] pretty-print-reparse hack: Rename some variables for clarity --- compiler/rustc_parse/src/lib.rs | 37 +++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 21bbdc9ba8dce..a7c8eaa4b15e4 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -299,7 +299,7 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke // FIXME(#43081): Avoid this pretty-print + reparse hack let source = pprust::nonterminal_to_string(nt); let filename = FileName::macro_expansion_source_code(&source); - let tokens_for_real = parse_stream_from_source_str(filename, source, sess, Some(span)); + let reparsed_tokens = parse_stream_from_source_str(filename, source, 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 @@ -325,7 +325,7 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke // modifications, including adding/removing typically non-semantic // tokens such as extra braces and commas, don't happen. if let Some(tokens) = tokens { - if tokenstream_probably_equal_for_proc_macro(&tokens, &tokens_for_real, sess) { + if tokenstream_probably_equal_for_proc_macro(&tokens, &reparsed_tokens, sess) { return tokens; } info!( @@ -333,9 +333,9 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke going with stringified version" ); info!("cached tokens: {:?}", tokens); - info!("reparsed tokens: {:?}", tokens_for_real); + info!("reparsed tokens: {:?}", reparsed_tokens); } - tokens_for_real + reparsed_tokens } // See comments in `Nonterminal::to_tokenstream` for why we care about @@ -344,8 +344,8 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke // This is otherwise the same as `eq_unspanned`, only recursing with a // different method. pub fn tokenstream_probably_equal_for_proc_macro( - first: &TokenStream, - other: &TokenStream, + tokens: &TokenStream, + reparsed_tokens: &TokenStream, sess: &ParseSess, ) -> bool { // When checking for `probably_eq`, we ignore certain tokens that aren't @@ -460,10 +460,11 @@ pub fn tokenstream_probably_equal_for_proc_macro( // Break tokens after we expand any nonterminals, so that we break tokens // that are produced as a result of nonterminal expansion. - let t1 = first.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens); - let t2 = other.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens); + let tokens = tokens.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens); + let reparsed_tokens = + reparsed_tokens.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens); - t1.eq_by(t2, |t1, t2| tokentree_probably_equal_for_proc_macro(&t1, &t2, sess)) + tokens.eq_by(reparsed_tokens, |t, rt| tokentree_probably_equal_for_proc_macro(&t, &rt, sess)) } // See comments in `Nonterminal::to_tokenstream` for why we care about @@ -472,16 +473,20 @@ pub fn tokenstream_probably_equal_for_proc_macro( // This is otherwise the same as `eq_unspanned`, only recursing with a // different method. pub fn tokentree_probably_equal_for_proc_macro( - first: &TokenTree, - other: &TokenTree, + token: &TokenTree, + reparsed_token: &TokenTree, sess: &ParseSess, ) -> bool { - match (first, other) { - (TokenTree::Token(token), TokenTree::Token(token2)) => { - token_probably_equal_for_proc_macro(token, token2) + match (token, reparsed_token) { + (TokenTree::Token(token), TokenTree::Token(reparsed_token)) => { + token_probably_equal_for_proc_macro(token, reparsed_token) } - (TokenTree::Delimited(_, delim, tts), TokenTree::Delimited(_, delim2, tts2)) => { - delim == delim2 && tokenstream_probably_equal_for_proc_macro(&tts, &tts2, sess) + ( + TokenTree::Delimited(_, delim, tokens), + TokenTree::Delimited(_, reparsed_delim, reparsed_tokens), + ) => { + delim == reparsed_delim + && tokenstream_probably_equal_for_proc_macro(tokens, reparsed_tokens, sess) } _ => false, } From fe3e5aa729ee34749ae730bbb5fd9c906877b82a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 26 Sep 2020 20:27:14 +0300 Subject: [PATCH 1029/1052] pretty-print-reparse hack: Remove an impossible case Delimiters cannot appear as isolated tokens in a token stream --- compiler/rustc_parse/src/lib.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index a7c8eaa4b15e4..d59dd4016a9f9 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -7,7 +7,7 @@ #![feature(or_patterns)] use rustc_ast as ast; -use rustc_ast::token::{self, DelimToken, Nonterminal, Token, TokenKind}; +use rustc_ast::token::{self, Nonterminal, Token, TokenKind}; use rustc_ast::tokenstream::{self, Spacing, TokenStream, TokenTree}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; @@ -359,9 +359,6 @@ pub fn tokenstream_probably_equal_for_proc_macro( // The pretty printer tends to add trailing commas to // everything, and in particular, after struct fields. | token::Comma - // The pretty printer emits `NoDelim` as whitespace. - | token::OpenDelim(DelimToken::NoDelim) - | token::CloseDelim(DelimToken::NoDelim) // The pretty printer collapses many semicolons into one. | token::Semi // We don't preserve leading `|` tokens in patterns, so From a17175f4dd3b9c1b34e7afa09fa90b8e74ef45e3 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 26 Sep 2020 17:29:37 -0400 Subject: [PATCH 1030/1052] Test more attributes in test issue-75930-derive-cfg.rs Split out from #76130 This tests our handling of combining derives, derive helper attributes, attribute macros, and `cfg`/`cfg_attr` --- .../ui/proc-macro/issue-75930-derive-cfg.rs | 42 +- .../proc-macro/issue-75930-derive-cfg.stdout | 1616 ++++++++++++++++- 2 files changed, 1652 insertions(+), 6 deletions(-) diff --git a/src/test/ui/proc-macro/issue-75930-derive-cfg.rs b/src/test/ui/proc-macro/issue-75930-derive-cfg.rs index e0f248c67e8b3..a051d23bac0ae 100644 --- a/src/test/ui/proc-macro/issue-75930-derive-cfg.rs +++ b/src/test/ui/proc-macro/issue-75930-derive-cfg.rs @@ -1,29 +1,65 @@ // check-pass -// compile-flags: -Z span-debug +// compile-flags: -Z span-debug --error-format human // aux-build:test-macros.rs // Regression test for issue #75930 // Tests that we cfg-strip all targets before invoking // a derive macro +// We need '--error-format human' to stop compiletest from +// trying to interpret proc-macro output as JSON messages +// (a pretty-printed struct may cause a line to start with '{' ) +// FIXME: We currently lose spans here (see issue #43081) #[macro_use] extern crate test_macros; +#[print_helper(a)] +#[cfg_attr(not(FALSE), allow(dead_code))] +#[print_attr] #[derive(Print)] +#[print_helper(b)] struct Foo<#[cfg(FALSE)] A, B> { #[cfg(FALSE)] first: String, - second: bool, + #[cfg_attr(FALSE, deny(warnings))] second: bool, third: [u8; { #[cfg(FALSE)] struct Bar; #[cfg(not(FALSE))] struct Inner; #[cfg(FALSE)] let a = 25; match true { #[cfg(FALSE)] true => {}, - false => {}, + #[cfg_attr(not(FALSE), allow(warnings))] false => {}, _ => {} }; + + #[print_helper(should_be_removed)] + fn removed_fn() { + #![cfg(FALSE)] + } + + #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn() { + #![cfg(not(FALSE))] + let my_val = true; + } + + enum TupleEnum { + Foo( + #[cfg(FALSE)] u8, + #[cfg(FALSE)] bool, + #[cfg(not(FALSE))] i32, + #[cfg(FALSE)] String, u8 + ) + } + + struct TupleStruct( + #[cfg(FALSE)] String, + #[cfg(not(FALSE))] i32, + #[cfg(FALSE)] bool, + u8 + ); + 0 }], + #[print_helper(d)] fourth: B } diff --git a/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout b/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout index 0371133a3f705..f3daa56a49c45 100644 --- a/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout +++ b/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout @@ -1,13 +1,1288 @@ -PRINT-DERIVE INPUT (DISPLAY): struct Foo < B > +PRINT-ATTR INPUT (DISPLAY): #[allow(dead_code)] #[derive(Print)] #[print_helper(b)] #[print_helper(a)] +struct Foo < #[cfg(FALSE)] A, B > +{ + #[cfg(FALSE)] first : String, #[cfg_attr(FALSE, deny(warnings))] second : + bool, third : + [u8 ; + { + #[cfg(FALSE)] struct Bar ; #[cfg(not(FALSE))] struct Inner ; + #[cfg(FALSE)] let a = 25 ; match true + { + #[cfg(FALSE)] true => { }, + #[cfg_attr(not(FALSE), allow(warnings))] false => { }, _ => { } + } ; #[print_helper(should_be_removed)] fn removed_fn() + { # ! [cfg(FALSE)] } #[print_helper(c)] #[cfg(not(FALSE))] fn + kept_fn() { # ! [cfg(not(FALSE))] let my_val = true ; } enum + TupleEnum + { + Foo(#[cfg(FALSE)] u8, #[cfg(FALSE)] bool, #[cfg(not(FALSE))] i32, + #[cfg(FALSE)] String, u8) + } struct + TupleStruct(#[cfg(FALSE)] String, #[cfg(not(FALSE))] i32, + #[cfg(FALSE)] bool, u8) ; 0 + }], #[print_helper(d)] fourth : B +} +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:17:24: 17:40 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "allow", + span: $DIR/issue-75930-derive-cfg.rs:17:24: 17:29 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "dead_code", + span: $DIR/issue-75930-derive-cfg.rs:17:30: 17:39 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:17:29: 17:40 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:17:24: 17:40 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:19:1: 19:17 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "derive", + span: $DIR/issue-75930-derive-cfg.rs:19:3: 19:9 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "Print", + span: $DIR/issue-75930-derive-cfg.rs:19:10: 19:15 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:19:9: 19:16 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:19:1: 19:17 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:20:1: 20:19 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:20:3: 20:15 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "b", + span: $DIR/issue-75930-derive-cfg.rs:20:16: 20:17 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:20:15: 20:18 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:20:1: 20:19 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:16:1: 16:19 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:16:3: 16:15 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "a", + span: $DIR/issue-75930-derive-cfg.rs:16:16: 16:17 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:16:15: 16:18 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:16:1: 16:19 (#0), + }, + Ident { + ident: "struct", + span: $DIR/issue-75930-derive-cfg.rs:21:1: 21:7 (#0), + }, + Ident { + ident: "Foo", + span: $DIR/issue-75930-derive-cfg.rs:21:8: 21:11 (#0), + }, + Punct { + ch: '<', + spacing: Joint, + span: $DIR/issue-75930-derive-cfg.rs:21:11: 21:12 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:21:12: 21:13 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:21:14: 21:17 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:21:18: 21:23 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:21:17: 21:24 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:21:13: 21:25 (#0), + }, + Ident { + ident: "A", + span: $DIR/issue-75930-derive-cfg.rs:21:26: 21:27 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:21:27: 21:28 (#0), + }, + Ident { + ident: "B", + span: $DIR/issue-75930-derive-cfg.rs:21:29: 21:30 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:21:30: 21:31 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:22:5: 22:6 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:22:7: 22:10 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:22:11: 22:16 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:22:10: 22:17 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:22:6: 22:18 (#0), + }, + Ident { + ident: "first", + span: $DIR/issue-75930-derive-cfg.rs:22:19: 22:24 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:22:24: 22:25 (#0), + }, + Ident { + ident: "String", + span: $DIR/issue-75930-derive-cfg.rs:22:26: 22:32 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:22:32: 22:33 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:23:5: 23:6 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg_attr", + span: $DIR/issue-75930-derive-cfg.rs:23:7: 23:15 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:23:16: 23:21 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:23:21: 23:22 (#0), + }, + Ident { + ident: "deny", + span: $DIR/issue-75930-derive-cfg.rs:23:23: 23:27 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "warnings", + span: $DIR/issue-75930-derive-cfg.rs:23:28: 23:36 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:23:27: 23:37 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:23:15: 23:38 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:23:6: 23:39 (#0), + }, + Ident { + ident: "second", + span: $DIR/issue-75930-derive-cfg.rs:23:40: 23:46 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:23:46: 23:47 (#0), + }, + Ident { + ident: "bool", + span: $DIR/issue-75930-derive-cfg.rs:23:48: 23:52 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:23:52: 23:53 (#0), + }, + Ident { + ident: "third", + span: $DIR/issue-75930-derive-cfg.rs:24:5: 24:10 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:24:10: 24:11 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "u8", + span: $DIR/issue-75930-derive-cfg.rs:24:13: 24:15 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:24:15: 24:16 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:25:9: 25:10 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:25:11: 25:14 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:25:15: 25:20 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:25:14: 25:21 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:25:10: 25:22 (#0), + }, + Ident { + ident: "struct", + span: $DIR/issue-75930-derive-cfg.rs:25:23: 25:29 (#0), + }, + Ident { + ident: "Bar", + span: $DIR/issue-75930-derive-cfg.rs:25:30: 25:33 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:25:33: 25:34 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:26:9: 26:10 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:26:11: 26:14 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:26:15: 26:18 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:26:19: 26:24 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:26:18: 26:25 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:26:14: 26:26 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:26:10: 26:27 (#0), + }, + Ident { + ident: "struct", + span: $DIR/issue-75930-derive-cfg.rs:26:28: 26:34 (#0), + }, + Ident { + ident: "Inner", + span: $DIR/issue-75930-derive-cfg.rs:26:35: 26:40 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:26:40: 26:41 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:27:9: 27:10 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:27:11: 27:14 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:27:15: 27:20 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:27:14: 27:21 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:27:10: 27:22 (#0), + }, + Ident { + ident: "let", + span: $DIR/issue-75930-derive-cfg.rs:27:23: 27:26 (#0), + }, + Ident { + ident: "a", + span: $DIR/issue-75930-derive-cfg.rs:27:27: 27:28 (#0), + }, + Punct { + ch: '=', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:27:29: 27:30 (#0), + }, + Literal { + kind: Integer, + symbol: "25", + suffix: None, + span: $DIR/issue-75930-derive-cfg.rs:27:31: 27:33 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:27:33: 27:34 (#0), + }, + Ident { + ident: "match", + span: $DIR/issue-75930-derive-cfg.rs:28:9: 28:14 (#0), + }, + Ident { + ident: "true", + span: $DIR/issue-75930-derive-cfg.rs:28:15: 28:19 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:29:13: 29:14 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:29:15: 29:18 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:29:19: 29:24 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:29:18: 29:25 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:29:14: 29:26 (#0), + }, + Ident { + ident: "true", + span: $DIR/issue-75930-derive-cfg.rs:29:27: 29:31 (#0), + }, + Punct { + ch: '=', + spacing: Joint, + span: $DIR/issue-75930-derive-cfg.rs:29:32: 29:34 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:29:32: 29:34 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/issue-75930-derive-cfg.rs:29:35: 29:37 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:29:37: 29:38 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:30:13: 30:14 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg_attr", + span: $DIR/issue-75930-derive-cfg.rs:30:15: 30:23 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:30:24: 30:27 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:30:28: 30:33 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:30:27: 30:34 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:30:34: 30:35 (#0), + }, + Ident { + ident: "allow", + span: $DIR/issue-75930-derive-cfg.rs:30:36: 30:41 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "warnings", + span: $DIR/issue-75930-derive-cfg.rs:30:42: 30:50 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:30:41: 30:51 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:30:23: 30:52 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:30:14: 30:53 (#0), + }, + Ident { + ident: "false", + span: $DIR/issue-75930-derive-cfg.rs:30:54: 30:59 (#0), + }, + Punct { + ch: '=', + spacing: Joint, + span: $DIR/issue-75930-derive-cfg.rs:30:60: 30:62 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:30:60: 30:62 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/issue-75930-derive-cfg.rs:30:63: 30:65 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:30:65: 30:66 (#0), + }, + Ident { + ident: "_", + span: $DIR/issue-75930-derive-cfg.rs:31:13: 31:14 (#0), + }, + Punct { + ch: '=', + spacing: Joint, + span: $DIR/issue-75930-derive-cfg.rs:31:15: 31:17 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:31:15: 31:17 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/issue-75930-derive-cfg.rs:31:18: 31:20 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:28:20: 32:10 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:32:10: 32:11 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:34:9: 34:10 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:34:11: 34:23 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "should_be_removed", + span: $DIR/issue-75930-derive-cfg.rs:34:24: 34:41 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:34:23: 34:42 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:34:10: 34:43 (#0), + }, + Ident { + ident: "fn", + span: $DIR/issue-75930-derive-cfg.rs:35:9: 35:11 (#0), + }, + Ident { + ident: "removed_fn", + span: $DIR/issue-75930-derive-cfg.rs:35:12: 35:22 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-75930-derive-cfg.rs:35:22: 35:24 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Joint, + span: $DIR/issue-75930-derive-cfg.rs:36:13: 36:14 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:36:14: 36:15 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:36:16: 36:19 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:36:20: 36:25 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:36:19: 36:26 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:36:15: 36:27 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:35:25: 37:10 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:39:9: 39:10 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:39:11: 39:23 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "c", + span: $DIR/issue-75930-derive-cfg.rs:39:24: 39:25 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:39:23: 39:26 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:39:10: 39:27 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:39:28: 39:29 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:39:30: 39:33 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:39:34: 39:37 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:39:38: 39:43 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:39:37: 39:44 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:39:33: 39:45 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:39:29: 39:46 (#0), + }, + Ident { + ident: "fn", + span: $DIR/issue-75930-derive-cfg.rs:39:47: 39:49 (#0), + }, + Ident { + ident: "kept_fn", + span: $DIR/issue-75930-derive-cfg.rs:39:50: 39:57 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-75930-derive-cfg.rs:39:57: 39:59 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Joint, + span: $DIR/issue-75930-derive-cfg.rs:40:13: 40:14 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:40:14: 40:15 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:40:16: 40:19 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:40:20: 40:23 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:40:24: 40:29 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:40:23: 40:30 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:40:19: 40:31 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:40:15: 40:32 (#0), + }, + Ident { + ident: "let", + span: $DIR/issue-75930-derive-cfg.rs:41:13: 41:16 (#0), + }, + Ident { + ident: "my_val", + span: $DIR/issue-75930-derive-cfg.rs:41:17: 41:23 (#0), + }, + Punct { + ch: '=', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:41:24: 41:25 (#0), + }, + Ident { + ident: "true", + span: $DIR/issue-75930-derive-cfg.rs:41:26: 41:30 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:41:30: 41:31 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:39:60: 42:10 (#0), + }, + Ident { + ident: "enum", + span: $DIR/issue-75930-derive-cfg.rs:44:9: 44:13 (#0), + }, + Ident { + ident: "TupleEnum", + span: $DIR/issue-75930-derive-cfg.rs:44:14: 44:23 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Ident { + ident: "Foo", + span: $DIR/issue-75930-derive-cfg.rs:45:13: 45:16 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:46:17: 46:18 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:46:19: 46:22 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:46:23: 46:28 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:46:22: 46:29 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:46:18: 46:30 (#0), + }, + Ident { + ident: "u8", + span: $DIR/issue-75930-derive-cfg.rs:46:31: 46:33 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:46:33: 46:34 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:47:17: 47:18 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:47:19: 47:22 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:47:23: 47:28 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:47:22: 47:29 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:47:18: 47:30 (#0), + }, + Ident { + ident: "bool", + span: $DIR/issue-75930-derive-cfg.rs:47:31: 47:35 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:47:35: 47:36 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:48:17: 48:18 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:48:19: 48:22 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:48:23: 48:26 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:48:27: 48:32 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:48:26: 48:33 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:48:22: 48:34 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:48:18: 48:35 (#0), + }, + Ident { + ident: "i32", + span: $DIR/issue-75930-derive-cfg.rs:48:36: 48:39 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:48:39: 48:40 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:49:17: 49:18 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:49:19: 49:22 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:49:23: 49:28 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:49:22: 49:29 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:49:18: 49:30 (#0), + }, + Ident { + ident: "String", + span: $DIR/issue-75930-derive-cfg.rs:49:31: 49:37 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:49:37: 49:38 (#0), + }, + Ident { + ident: "u8", + span: $DIR/issue-75930-derive-cfg.rs:49:39: 49:41 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:45:16: 50:14 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:44:24: 51:10 (#0), + }, + Ident { + ident: "struct", + span: $DIR/issue-75930-derive-cfg.rs:53:9: 53:15 (#0), + }, + Ident { + ident: "TupleStruct", + span: $DIR/issue-75930-derive-cfg.rs:53:16: 53:27 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:54:13: 54:14 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:54:15: 54:18 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:54:19: 54:24 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:54:18: 54:25 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:54:14: 54:26 (#0), + }, + Ident { + ident: "String", + span: $DIR/issue-75930-derive-cfg.rs:54:27: 54:33 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:54:33: 54:34 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:55:13: 55:14 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:55:15: 55:18 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:55:19: 55:22 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:55:23: 55:28 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:55:22: 55:29 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:55:18: 55:30 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:55:14: 55:31 (#0), + }, + Ident { + ident: "i32", + span: $DIR/issue-75930-derive-cfg.rs:55:32: 55:35 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:55:35: 55:36 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:56:13: 56:14 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:56:15: 56:18 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:56:19: 56:24 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:56:18: 56:25 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:56:14: 56:26 (#0), + }, + Ident { + ident: "bool", + span: $DIR/issue-75930-derive-cfg.rs:56:27: 56:31 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:56:31: 56:32 (#0), + }, + Ident { + ident: "u8", + span: $DIR/issue-75930-derive-cfg.rs:57:13: 57:15 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:53:27: 58:10 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:58:10: 58:11 (#0), + }, + Literal { + kind: Integer, + symbol: "0", + suffix: None, + span: $DIR/issue-75930-derive-cfg.rs:60:9: 60:10 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:24:17: 61:6 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:24:12: 61:7 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:61:7: 61:8 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:62:5: 62:6 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:62:7: 62:19 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "d", + span: $DIR/issue-75930-derive-cfg.rs:62:20: 62:21 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:62:19: 62:22 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:62:6: 62:23 (#0), + }, + Ident { + ident: "fourth", + span: $DIR/issue-75930-derive-cfg.rs:63:5: 63:11 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:63:11: 63:12 (#0), + }, + Ident { + ident: "B", + span: $DIR/issue-75930-derive-cfg.rs:63:13: 63:14 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:21:32: 64:2 (#0), + }, +] +PRINT-DERIVE INPUT (DISPLAY): #[allow(dead_code)] #[print_helper(b)] #[print_helper(a)] struct Foo < B > { second : bool, third : [u8 ; { #[cfg(not(FALSE))] struct Inner ; match true - { false => { } _ => { } } ; 0 - }], fourth : B, + { #[allow(warnings)] false => { } _ => { } } ; #[print_helper(c)] + #[cfg(not(FALSE))] fn kept_fn() + { # ! [cfg(not(FALSE))] let my_val = true ; } enum TupleEnum + { Foo(#[cfg(not(FALSE))] i32, u8), } struct + TupleStruct(#[cfg(not(FALSE))] i32, u8) ; 0 + }], #[print_helper(d)] fourth : B, } PRINT-DERIVE INPUT (DEBUG): TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "allow", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "dead_code", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "b", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "a", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, Ident { ident: "struct", span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), @@ -134,6 +1409,31 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ Group { delimiter: Brace, stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "allow", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "warnings", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, Ident { ident: "false", span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), @@ -180,6 +1480,291 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ spacing: Alone, span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "c", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "fn", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "kept_fn", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Joint, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "let", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "my_val", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '=', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "true", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "enum", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "TupleEnum", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Ident { + ident: "Foo", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "i32", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "u8", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "struct", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "TupleStruct", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "i32", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "u8", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, Literal { kind: Integer, symbol: "0", @@ -197,6 +1782,31 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ spacing: Alone, span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "d", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, Ident { ident: "fourth", span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), From 4c5f9f742c0a8a4187116f1e443d6a0126990941 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 26 Sep 2020 12:34:37 -0700 Subject: [PATCH 1031/1052] Replace `discriminant_switch_effect` with more general version ...that allows arbitrary effects on each edge of a `SwitchInt` terminator. --- .../rustc_mir/src/dataflow/framework/mod.rs | 65 +++++++++++++------ 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_mir/src/dataflow/framework/mod.rs b/compiler/rustc_mir/src/dataflow/framework/mod.rs index eefa1395a621b..2804a10f074f4 100644 --- a/compiler/rustc_mir/src/dataflow/framework/mod.rs +++ b/compiler/rustc_mir/src/dataflow/framework/mod.rs @@ -37,8 +37,7 @@ use rustc_hir::def_id::DefId; use rustc_index::bit_set::{BitSet, HybridBitSet}; use rustc_index::vec::Idx; use rustc_middle::mir::{self, BasicBlock, Location}; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_target::abi::VariantIdx; +use rustc_middle::ty::TyCtxt; mod cursor; mod direction; @@ -152,6 +151,8 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { ) { } + /* Edge-specific effects */ + /// Updates the current dataflow state with the effect of a successful return from a `Call` /// terminator. /// @@ -183,20 +184,28 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { /// Updates the current dataflow state with the effect of taking a particular branch in a /// `SwitchInt` terminator. /// - /// Much like `apply_call_return_effect`, this effect is only propagated along a single - /// outgoing edge from this basic block. + /// Unlike the other edge-specific effects, which are allowed to mutate `Self::Domain` + /// directly, overriders of this method must pass a callback to + /// [`SwitchIntEdgeEffects::apply`]. The callback will be run once for each outgoing edge and + /// will have access to the dataflow state that will be propagated along that edge. + /// + /// This interface is somewhat more complex than the other visitor-like "effect" methods. + /// However, it is both more ergonomic—callers don't need to recompute or cache information + /// about a given `SwitchInt` terminator for each one of its edges—and more efficient—the + /// engine doesn't need to clone the exit state for a block unless + /// `SwitchIntEdgeEffects::apply` is actually called. /// /// FIXME: This class of effects is not supported for backward dataflow analyses. - fn apply_discriminant_switch_effect( + fn apply_switch_int_edge_effects( &self, - _state: &mut Self::Domain, _block: BasicBlock, - _enum_place: mir::Place<'tcx>, - _adt: &ty::AdtDef, - _variant: VariantIdx, + _discr: &mir::Operand<'tcx>, + _apply_edge_effects: &mut impl SwitchIntEdgeEffects, ) { } + /* Extension methods */ + /// Creates an `Engine` to find the fixpoint for this dataflow problem. /// /// You shouldn't need to override this outside this module, since the combination of the @@ -267,6 +276,8 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> { ) { } + /* Edge-specific effects */ + /// See `Analysis::apply_call_return_effect`. fn call_return_effect( &self, @@ -286,14 +297,12 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> { ) { } - /// See `Analysis::apply_discriminant_switch_effect`. - fn discriminant_switch_effect( + /// See `Analysis::apply_switch_int_edge_effects`. + fn switch_int_edge_effects>( &self, - _state: &mut impl GenKill, _block: BasicBlock, - _enum_place: mir::Place<'tcx>, - _adt: &ty::AdtDef, - _variant: VariantIdx, + _discr: &mir::Operand<'tcx>, + _edge_effects: &mut impl SwitchIntEdgeEffects, ) { } } @@ -339,6 +348,8 @@ where self.before_terminator_effect(state, terminator, location); } + /* Edge-specific effects */ + fn apply_call_return_effect( &self, state: &mut A::Domain, @@ -359,17 +370,17 @@ where self.yield_resume_effect(state, resume_block, resume_place); } - fn apply_discriminant_switch_effect( + fn apply_switch_int_edge_effects( &self, - state: &mut A::Domain, block: BasicBlock, - enum_place: mir::Place<'tcx>, - adt: &ty::AdtDef, - variant: VariantIdx, + discr: &mir::Operand<'tcx>, + edge_effects: &mut impl SwitchIntEdgeEffects, ) { - self.discriminant_switch_effect(state, block, enum_place, adt, variant); + self.switch_int_edge_effects(block, discr, edge_effects); } + /* Extension methods */ + fn into_engine( self, tcx: TyCtxt<'tcx>, @@ -531,5 +542,17 @@ impl EffectIndex { } } +pub struct SwitchIntTarget { + pub value: Option, + pub target: BasicBlock, +} + +/// A type that records the edge-specific effects for a `SwitchInt` terminator. +pub trait SwitchIntEdgeEffects { + /// Calls `apply_edge_effect` for each outgoing edge from a `SwitchInt` terminator and + /// records the results. + fn apply(&mut self, apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)); +} + #[cfg(test)] mod tests; From 43e6ef876f8d2aab6e7fe28c5d929686e81beac4 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 26 Sep 2020 13:12:51 -0700 Subject: [PATCH 1032/1052] Update engine to use new interface --- .../src/dataflow/framework/direction.rs | 146 ++++++++---------- 1 file changed, 68 insertions(+), 78 deletions(-) diff --git a/compiler/rustc_mir/src/dataflow/framework/direction.rs b/compiler/rustc_mir/src/dataflow/framework/direction.rs index 76c48100371ea..ca2bb6e0bf7e9 100644 --- a/compiler/rustc_mir/src/dataflow/framework/direction.rs +++ b/compiler/rustc_mir/src/dataflow/framework/direction.rs @@ -1,10 +1,10 @@ use rustc_index::bit_set::BitSet; use rustc_middle::mir::{self, BasicBlock, Location}; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::TyCtxt; use std::ops::RangeInclusive; use super::visitor::{ResultsVisitable, ResultsVisitor}; -use super::{Analysis, Effect, EffectIndex, GenKillAnalysis, GenKillSet}; +use super::{Analysis, Effect, EffectIndex, GenKillAnalysis, GenKillSet, SwitchIntTarget}; pub trait Direction { fn is_forward() -> bool; @@ -425,8 +425,8 @@ impl Direction for Forward { fn join_state_into_successors_of( analysis: &A, - tcx: TyCtxt<'tcx>, - body: &mir::Body<'tcx>, + _tcx: TyCtxt<'tcx>, + _body: &mir::Body<'tcx>, dead_unwinds: Option<&BitSet>, exit_state: &mut A::Domain, (bb, bb_data): (BasicBlock, &'_ mir::BasicBlockData<'tcx>), @@ -489,50 +489,23 @@ impl Direction for Forward { } SwitchInt { ref targets, ref values, ref discr, switch_ty: _ } => { - let enum_ = discr - .place() - .and_then(|discr| switch_on_enum_discriminant(tcx, &body, bb_data, discr)); - match enum_ { - // If this is a switch on an enum discriminant, a custom effect may be applied - // along each outgoing edge. - Some((enum_place, enum_def)) => { - // MIR building adds discriminants to the `values` array in the same order as they - // are yielded by `AdtDef::discriminants`. We rely on this to match each - // discriminant in `values` to its corresponding variant in linear time. - let mut tmp = analysis.bottom_value(body); - let mut discriminants = enum_def.discriminants(tcx); - for (value, target) in values.iter().zip(targets.iter().copied()) { - let (variant_idx, _) = - discriminants.find(|&(_, discr)| discr.val == *value).expect( - "Order of `AdtDef::discriminants` differed \ - from that of `SwitchInt::values`", - ); - - tmp.clone_from(exit_state); - analysis.apply_discriminant_switch_effect( - &mut tmp, - bb, - enum_place, - enum_def, - variant_idx, - ); - propagate(target, &tmp); - } - - // Move out of `tmp` so we don't accidentally use it below. - std::mem::drop(tmp); - - // Propagate dataflow state along the "otherwise" edge. - let otherwise = targets.last().copied().unwrap(); - propagate(otherwise, exit_state) - } - - // Otherwise, it's just a normal `SwitchInt`, and every successor sees the same - // exit state. - None => { - for target in targets.iter().copied() { - propagate(target, exit_state); - } + let mut applier = SwitchIntEdgeEffectApplier { + exit_state, + targets: targets.as_ref(), + values: values.as_ref(), + propagate, + effects_applied: false, + }; + + analysis.apply_switch_int_edge_effects(bb, discr, &mut applier); + + let SwitchIntEdgeEffectApplier { + exit_state, mut propagate, effects_applied, .. + } = applier; + + if !effects_applied { + for &target in targets.iter() { + propagate(target, exit_state); } } } @@ -540,37 +513,54 @@ impl Direction for Forward { } } -/// Inspect a `SwitchInt`-terminated basic block to see if the condition of that `SwitchInt` is -/// an enum discriminant. -/// -/// We expect such blocks to have a call to `discriminant` as their last statement like so: -/// _42 = discriminant(_1) -/// SwitchInt(_42, ..) -/// -/// If the basic block matches this pattern, this function returns the place corresponding to the -/// enum (`_1` in the example above) as well as the `AdtDef` of that enum. -fn switch_on_enum_discriminant( - tcx: TyCtxt<'tcx>, - body: &'mir mir::Body<'tcx>, - block: &'mir mir::BasicBlockData<'tcx>, - switch_on: mir::Place<'tcx>, -) -> Option<(mir::Place<'tcx>, &'tcx ty::AdtDef)> { - match block.statements.last().map(|stmt| &stmt.kind) { - Some(mir::StatementKind::Assign(box (lhs, mir::Rvalue::Discriminant(discriminated)))) - if *lhs == switch_on => - { - match &discriminated.ty(body, tcx).ty.kind() { - ty::Adt(def, _) => Some((*discriminated, def)), - - // `Rvalue::Discriminant` is also used to get the active yield point for a - // generator, but we do not need edge-specific effects in that case. This may - // change in the future. - ty::Generator(..) => None, - - t => bug!("`discriminant` called on unexpected type {:?}", t), - } +struct SwitchIntEdgeEffectApplier<'a, D, F> { + exit_state: &'a mut D, + values: &'a [u128], + targets: &'a [BasicBlock], + propagate: F, + + effects_applied: bool, +} + +impl super::SwitchIntEdgeEffects for SwitchIntEdgeEffectApplier<'_, D, F> +where + D: Clone, + F: FnMut(BasicBlock, &D), +{ + fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) { + assert!(!self.effects_applied); + + let mut tmp = None; + for (&value, &target) in self.values.iter().zip(self.targets.iter()) { + let tmp = opt_clone_from_or_clone(&mut tmp, self.exit_state); + apply_edge_effect(tmp, SwitchIntTarget { value: Some(value), target }); + (self.propagate)(target, tmp); } - _ => None, + // Once we get to the final, "otherwise" branch, there is no need to preserve `exit_state`, + // so pass it directly to `apply_edge_effect` to save a clone of the dataflow state. + let otherwise = self.targets.last().copied().unwrap(); + apply_edge_effect(self.exit_state, SwitchIntTarget { value: None, target: otherwise }); + (self.propagate)(otherwise, self.exit_state); + + self.effects_applied = true; + } +} + +/// An analogue of `Option::get_or_insert_with` that stores a clone of `val` into `opt`, but uses +/// the more efficient `clone_from` if `opt` was `Some`. +/// +/// Returns a mutable reference to the new clone that resides in `opt`. +// +// FIXME: Figure out how to express this using `Option::clone_from`, or maybe lift it into the +// standard library? +fn opt_clone_from_or_clone(opt: &'a mut Option, val: &T) -> &'a mut T { + if opt.is_some() { + let ret = opt.as_mut().unwrap(); + ret.clone_from(val); + ret + } else { + *opt = Some(val.clone()); + opt.as_mut().unwrap() } } From 2364b58b870926a25e0ddc25573e345c8fe049e6 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 26 Sep 2020 13:13:37 -0700 Subject: [PATCH 1033/1052] Update dataflow impls to reflect new interface --- compiler/rustc_mir/src/dataflow/impls/mod.rs | 149 +++++++++++++++---- 1 file changed, 116 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_mir/src/dataflow/impls/mod.rs b/compiler/rustc_mir/src/dataflow/impls/mod.rs index 1769feaf7a514..d4b9600f766f8 100644 --- a/compiler/rustc_mir/src/dataflow/impls/mod.rs +++ b/compiler/rustc_mir/src/dataflow/impls/mod.rs @@ -6,7 +6,6 @@ use rustc_index::bit_set::BitSet; use rustc_index::vec::Idx; use rustc_middle::mir::{self, Body, Location}; use rustc_middle::ty::{self, TyCtxt}; -use rustc_target::abi::VariantIdx; use super::MoveDataParamEnv; @@ -19,6 +18,7 @@ use super::drop_flag_effects_for_function_entry; use super::drop_flag_effects_for_location; use super::on_lookup_result_bits; use crate::dataflow::drop_flag_effects; +use crate::dataflow::framework::SwitchIntEdgeEffects; mod borrowed_locals; pub(super) mod borrows; @@ -352,24 +352,46 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { ); } - fn discriminant_switch_effect( + fn switch_int_edge_effects>( &self, - trans: &mut impl GenKill, - _block: mir::BasicBlock, - enum_place: mir::Place<'tcx>, - _adt: &ty::AdtDef, - variant: VariantIdx, + block: mir::BasicBlock, + discr: &mir::Operand<'tcx>, + edge_effects: &mut impl SwitchIntEdgeEffects, ) { - // Kill all move paths that correspond to variants we know to be inactive along this - // particular outgoing edge of a `SwitchInt`. - drop_flag_effects::on_all_inactive_variants( - self.tcx, - self.body, - self.move_data(), - enum_place, - variant, - |mpi| trans.kill(mpi), - ); + let enum_ = discr.place().and_then(|discr| { + switch_on_enum_discriminant(self.tcx, &self.body, &self.body[block], discr) + }); + + let (enum_place, enum_def) = match enum_ { + Some(x) => x, + None => return, + }; + + let mut discriminants = enum_def.discriminants(self.tcx); + edge_effects.apply(|trans, edge| { + let value = match edge.value { + Some(x) => x, + None => return, + }; + + // MIR building adds discriminants to the `values` array in the same order as they + // are yielded by `AdtDef::discriminants`. We rely on this to match each + // discriminant in `values` to its corresponding variant in linear time. + let (variant, _) = discriminants + .find(|&(_, discr)| discr.val == value) + .expect("Order of `AdtDef::discriminants` differed from `SwitchInt::values`"); + + // Kill all move paths that correspond to variants we know to be inactive along this + // particular outgoing edge of a `SwitchInt`. + drop_flag_effects::on_all_inactive_variants( + self.tcx, + self.body, + self.move_data(), + enum_place, + variant, + |mpi| trans.kill(mpi), + ); + }); } } @@ -441,28 +463,50 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { ); } - fn discriminant_switch_effect( + fn switch_int_edge_effects>( &self, - trans: &mut impl GenKill, - _block: mir::BasicBlock, - enum_place: mir::Place<'tcx>, - _adt: &ty::AdtDef, - variant: VariantIdx, + block: mir::BasicBlock, + discr: &mir::Operand<'tcx>, + edge_effects: &mut impl SwitchIntEdgeEffects, ) { if !self.mark_inactive_variants_as_uninit { return; } - // Mark all move paths that correspond to variants other than this one as maybe - // uninitialized (in reality, they are *definitely* uninitialized). - drop_flag_effects::on_all_inactive_variants( - self.tcx, - self.body, - self.move_data(), - enum_place, - variant, - |mpi| trans.gen(mpi), - ); + let enum_ = discr.place().and_then(|discr| { + switch_on_enum_discriminant(self.tcx, &self.body, &self.body[block], discr) + }); + + let (enum_place, enum_def) = match enum_ { + Some(x) => x, + None => return, + }; + + let mut discriminants = enum_def.discriminants(self.tcx); + edge_effects.apply(|trans, edge| { + let value = match edge.value { + Some(x) => x, + None => return, + }; + + // MIR building adds discriminants to the `values` array in the same order as they + // are yielded by `AdtDef::discriminants`. We rely on this to match each + // discriminant in `values` to its corresponding variant in linear time. + let (variant, _) = discriminants + .find(|&(_, discr)| discr.val == value) + .expect("Order of `AdtDef::discriminants` differed from `SwitchInt::values`"); + + // Mark all move paths that correspond to variants other than this one as maybe + // uninitialized (in reality, they are *definitely* uninitialized). + drop_flag_effects::on_all_inactive_variants( + self.tcx, + self.body, + self.move_data(), + enum_place, + variant, + |mpi| trans.gen(mpi), + ); + }); } } @@ -624,3 +668,42 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { } } } + +/// Inspect a `SwitchInt`-terminated basic block to see if the condition of that `SwitchInt` is +/// an enum discriminant. +/// +/// We expect such blocks to have a call to `discriminant` as their last statement like so: +/// +/// ```text +/// ... +/// _42 = discriminant(_1) +/// SwitchInt(_42, ..) +/// ``` +/// +/// If the basic block matches this pattern, this function returns the place corresponding to the +/// enum (`_1` in the example above) as well as the `AdtDef` of that enum. +fn switch_on_enum_discriminant( + tcx: TyCtxt<'tcx>, + body: &'mir mir::Body<'tcx>, + block: &'mir mir::BasicBlockData<'tcx>, + switch_on: mir::Place<'tcx>, +) -> Option<(mir::Place<'tcx>, &'tcx ty::AdtDef)> { + match block.statements.last().map(|stmt| &stmt.kind) { + Some(mir::StatementKind::Assign(box (lhs, mir::Rvalue::Discriminant(discriminated)))) + if *lhs == switch_on => + { + match &discriminated.ty(body, tcx).ty.kind() { + ty::Adt(def, _) => Some((*discriminated, def)), + + // `Rvalue::Discriminant` is also used to get the active yield point for a + // generator, but we do not need edge-specific effects in that case. This may + // change in the future. + ty::Generator(..) => None, + + t => bug!("`discriminant` called on unexpected type {:?}", t), + } + } + + _ => None, + } +} From d68aa227c6b7ab9c1cfa003e752c3600a7269485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sun, 27 Sep 2020 00:00:00 +0000 Subject: [PATCH 1034/1052] liveness: Access live nodes directly through self.lnks[ln] --- compiler/rustc_passes/src/liveness.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 8c6d47f992d78..9eac2f79e412c 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -302,10 +302,6 @@ impl IrMaps<'tcx> { fn set_captures(&mut self, hir_id: HirId, cs: Vec) { self.capture_info_map.insert(hir_id, Rc::new(cs)); } - - fn lnk(&self, ln: LiveNode) -> LiveNodeKind { - self.lnks[ln] - } } fn visit_fn<'tcx>( @@ -691,7 +687,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn live_on_entry(&self, ln: LiveNode, var: Variable) -> Option { assert!(ln.is_valid()); let reader = self.rwu_table.get_reader(self.idx(ln, var)); - if reader.is_valid() { Some(self.ir.lnk(reader)) } else { None } + if reader.is_valid() { Some(self.ir.lnks[reader]) } else { None } } // Is this variable live on entry to any of its successor nodes? @@ -708,7 +704,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn assigned_on_entry(&self, ln: LiveNode, var: Variable) -> Option { assert!(ln.is_valid()); let writer = self.rwu_table.get_writer(self.idx(ln, var)); - if writer.is_valid() { Some(self.ir.lnk(writer)) } else { None } + if writer.is_valid() { Some(self.ir.lnks[writer]) } else { None } } fn assigned_on_exit(&self, ln: LiveNode, var: Variable) -> Option { @@ -746,7 +742,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let mut wr = Vec::new(); { let wr = &mut wr as &mut dyn Write; - write!(wr, "[{:?} of kind {:?} reads", ln, self.ir.lnk(ln)); + write!(wr, "[{:?} of kind {:?} reads", ln, self.ir.lnks[ln]); self.write_vars(wr, ln, |idx| self.rwu_table.get_reader(idx).is_valid()); write!(wr, " writes"); self.write_vars(wr, ln, |idx| self.rwu_table.get_writer(idx).is_valid()); From c0cd1b0a26a2d1ebc82c23764f8017a30e145f58 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 26 Sep 2020 17:29:55 -0700 Subject: [PATCH 1035/1052] Remove intra-doc link --- compiler/rustc_mir/src/dataflow/framework/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/dataflow/framework/mod.rs b/compiler/rustc_mir/src/dataflow/framework/mod.rs index 2804a10f074f4..65c159e6a72a9 100644 --- a/compiler/rustc_mir/src/dataflow/framework/mod.rs +++ b/compiler/rustc_mir/src/dataflow/framework/mod.rs @@ -186,7 +186,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { /// /// Unlike the other edge-specific effects, which are allowed to mutate `Self::Domain` /// directly, overriders of this method must pass a callback to - /// [`SwitchIntEdgeEffects::apply`]. The callback will be run once for each outgoing edge and + /// `SwitchIntEdgeEffects::apply`. The callback will be run once for each outgoing edge and /// will have access to the dataflow state that will be propagated along that edge. /// /// This interface is somewhat more complex than the other visitor-like "effect" methods. From 58c232af6a86bfcde605ec4f2302af52f1cac139 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Sun, 27 Sep 2020 04:22:55 +0200 Subject: [PATCH 1036/1052] reduce overlong line --- src/bootstrap/defaults/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/defaults/README.md b/src/bootstrap/defaults/README.md index a91fc3538eb55..f5b96db1b0f47 100644 --- a/src/bootstrap/defaults/README.md +++ b/src/bootstrap/defaults/README.md @@ -4,7 +4,8 @@ These defaults are intended to be a good starting point for working with x.py, with the understanding that no one set of defaults make sense for everyone. They are still experimental, and we'd appreciate your help improving them! -If you use a setting that's not in these defaults that you think others would benefit from, please [file an issue] or make a PR with the changes. +If you use a setting that's not in these defaults that you think +others would benefit from, please [file an issue] or make a PR with the changes. Similarly, if one of these defaults doesn't match what you use personally, please open an issue to get it changed. From 9000710959b797986b3e14553e2261f62634929d Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Wed, 16 Sep 2020 15:35:58 +0000 Subject: [PATCH 1037/1052] Add MIPS asm! support This patch also: * Add soft-float supports: only f32 * zero-extend i8/i16 to i32 because MIPS only supports register-length arithmetic. * Update table in asm! chapter in unstable book. --- compiler/rustc_codegen_llvm/src/asm.rs | 25 +++ compiler/rustc_target/src/asm/mips.rs | 132 ++++++++++++ compiler/rustc_target/src/asm/mod.rs | 25 +++ .../unstable-book/src/library-features/asm.md | 17 +- src/test/assembly/asm/mips-types.rs | 191 ++++++++++++++++++ 5 files changed, 389 insertions(+), 1 deletion(-) create mode 100644 compiler/rustc_target/src/asm/mips.rs create mode 100644 src/test/assembly/asm/mips-types.rs diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index a468d09c2d93d..f801f845ac16c 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -259,6 +259,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {} InlineAsmArch::Nvptx64 => {} InlineAsmArch::Hexagon => {} + InlineAsmArch::Mips => {} } } if !options.contains(InlineAsmOptions::NOMEM) { @@ -505,6 +506,8 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>) InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "w", InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => "f", InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h", InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r", InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l", @@ -551,6 +554,7 @@ fn modifier_to_llvm( } } InlineAsmRegClass::Hexagon(_) => None, + InlineAsmRegClass::Mips(_) => None, InlineAsmRegClass::Nvptx(_) => None, InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) | InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => None, @@ -603,6 +607,8 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll cx.type_vector(cx.type_i64(), 2) } InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => cx.type_f32(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(), @@ -700,6 +706,12 @@ fn llvm_fixup_input( value } } + (InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => match s.value { + // MIPS only supports register-length arithmetics. + Primitive::Int(Integer::I8 | Integer::I16, _) => bx.zext(value, bx.cx.type_i32()), + Primitive::F32 => bx.bitcast(value, bx.cx.type_i32()), + _ => value, + }, _ => value, } } @@ -768,6 +780,13 @@ fn llvm_fixup_output( value } } + (InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => match s.value { + // MIPS only supports register-length arithmetics. + Primitive::Int(Integer::I8, _) => bx.trunc(value, bx.cx.type_i8()), + Primitive::Int(Integer::I16, _) => bx.trunc(value, bx.cx.type_i16()), + Primitive::F32 => bx.bitcast(value, bx.cx.type_f32()), + _ => value, + }, _ => value, } } @@ -831,6 +850,12 @@ fn llvm_fixup_output_type( layout.llvm_type(cx) } } + (InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => match s.value { + // MIPS only supports register-length arithmetics. + Primitive::Int(Integer::I8 | Integer::I16, _) => cx.type_i32(), + Primitive::F32 => cx.type_i32(), + _ => layout.llvm_type(cx), + }, _ => layout.llvm_type(cx), } } diff --git a/compiler/rustc_target/src/asm/mips.rs b/compiler/rustc_target/src/asm/mips.rs new file mode 100644 index 0000000000000..638c52d97f1e3 --- /dev/null +++ b/compiler/rustc_target/src/asm/mips.rs @@ -0,0 +1,132 @@ +use super::{InlineAsmArch, InlineAsmType}; +use rustc_macros::HashStable_Generic; +use std::fmt; + +def_reg_class! { + Mips MipsInlineAsmRegClass { + reg, + freg, + } +} + +impl MipsInlineAsmRegClass { + pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] { + &[] + } + + pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option { + None + } + + pub fn suggest_modifier( + self, + _arch: InlineAsmArch, + _ty: InlineAsmType, + ) -> Option<(char, &'static str)> { + None + } + + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + None + } + + pub fn supported_types( + self, + _arch: InlineAsmArch, + ) -> &'static [(InlineAsmType, Option<&'static str>)] { + match self { + Self::reg => types! { _: I8, I16, I32, F32; }, + Self::freg => types! { _: F32; }, + } + } +} + +// The reserved registers are somewhat taken from . +def_regs! { + Mips MipsInlineAsmReg MipsInlineAsmRegClass { + v0: reg = ["$2", "$v0"], + v1: reg = ["$3", "$v1"], + a0: reg = ["$4", "$a0"], + a1: reg = ["$5", "$a1"], + a2: reg = ["$6", "$a2"], + a3: reg = ["$7", "$a3"], + // FIXME: Reserve $t0, $t1 if in mips16 mode. + t0: reg = ["$8", "$t0"], + t1: reg = ["$9", "$t1"], + t2: reg = ["$10", "$t2"], + t3: reg = ["$11", "$t3"], + t4: reg = ["$12", "$t4"], + t5: reg = ["$13", "$t5"], + t6: reg = ["$14", "$t6"], + t7: reg = ["$15", "$t7"], + s0: reg = ["$16", "$s0"], + s1: reg = ["$17", "$s1"], + s2: reg = ["$18", "$s2"], + s3: reg = ["$19", "$s3"], + s4: reg = ["$20", "$s4"], + s5: reg = ["$21", "$s5"], + s6: reg = ["$22", "$s6"], + s7: reg = ["$23", "$s7"], + t8: reg = ["$24", "$t8"], + t9: reg = ["$25", "$t9"], + f0: freg = ["$f0"], + f1: freg = ["$f1"], + f2: freg = ["$f2"], + f3: freg = ["$f3"], + f4: freg = ["$f4"], + f5: freg = ["$f5"], + f6: freg = ["$f6"], + f7: freg = ["$f7"], + f8: freg = ["$f8"], + f9: freg = ["$f9"], + f10: freg = ["$f10"], + f11: freg = ["$f11"], + f12: freg = ["$f12"], + f13: freg = ["$f13"], + f14: freg = ["$f14"], + f15: freg = ["$f15"], + f16: freg = ["$f16"], + f17: freg = ["$f17"], + f18: freg = ["$f18"], + f19: freg = ["$f19"], + f20: freg = ["$f20"], + f21: freg = ["$f21"], + f22: freg = ["$f22"], + f23: freg = ["$f23"], + f24: freg = ["$f24"], + f25: freg = ["$f25"], + f26: freg = ["$f26"], + f27: freg = ["$f27"], + f28: freg = ["$f28"], + f29: freg = ["$f29"], + f30: freg = ["$f30"], + f31: freg = ["$f31"], + #error = ["$0", "$zero"] => + "constant zero cannot be used as an operand for inline asm", + #error = ["$1", "$at"] => + "reserved for assembler (Assembler Temp)", + #error = ["$26", "$k0"] => + "OS-reserved register cannot be used as an operand for inline asm", + #error = ["$27", "$k1"] => + "OS-reserved register cannot be used as an operand for inline asm", + #error = ["$28", "$gp"] => + "the global pointer cannot be used as an operand for inline asm", + #error = ["$29", "$sp"] => + "the stack pointer cannot be used as an operand for inline asm", + #error = ["$30", "$s8", "$fp"] => + "the frame pointer cannot be used as an operand for inline asm", + #error = ["$31", "$ra"] => + "the return address register cannot be used as an operand for inline asm", + } +} + +impl MipsInlineAsmReg { + pub fn emit( + self, + out: &mut dyn fmt::Write, + _arch: InlineAsmArch, + _modifier: Option, + ) -> fmt::Result { + out.write_str(self.name()) + } +} diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index c22644bf813a4..e2f8e91fa9574 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -152,6 +152,7 @@ macro_rules! types { mod aarch64; mod arm; mod hexagon; +mod mips; mod nvptx; mod riscv; mod x86; @@ -159,6 +160,7 @@ mod x86; pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass}; pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass}; pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass}; +pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass}; pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass}; pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass}; pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass}; @@ -173,6 +175,7 @@ pub enum InlineAsmArch { RiscV64, Nvptx64, Hexagon, + Mips, } impl FromStr for InlineAsmArch { @@ -188,6 +191,7 @@ impl FromStr for InlineAsmArch { "riscv64" => Ok(Self::RiscV64), "nvptx64" => Ok(Self::Nvptx64), "hexagon" => Ok(Self::Hexagon), + "mips" => Ok(Self::Mips), _ => Err(()), } } @@ -201,6 +205,7 @@ pub enum InlineAsmReg { RiscV(RiscVInlineAsmReg), Nvptx(NvptxInlineAsmReg), Hexagon(HexagonInlineAsmReg), + Mips(MipsInlineAsmReg), } impl InlineAsmReg { @@ -211,6 +216,7 @@ impl InlineAsmReg { Self::AArch64(r) => r.name(), Self::RiscV(r) => r.name(), Self::Hexagon(r) => r.name(), + Self::Mips(r) => r.name(), } } @@ -221,6 +227,7 @@ impl InlineAsmReg { Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()), Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()), Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()), + Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()), } } @@ -252,6 +259,9 @@ impl InlineAsmReg { InlineAsmArch::Hexagon => { Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?) } + InlineAsmArch::Mips => { + Self::Mips(MipsInlineAsmReg::parse(arch, has_feature, target, &name)?) + } }) } @@ -269,6 +279,7 @@ impl InlineAsmReg { Self::AArch64(r) => r.emit(out, arch, modifier), Self::RiscV(r) => r.emit(out, arch, modifier), Self::Hexagon(r) => r.emit(out, arch, modifier), + Self::Mips(r) => r.emit(out, arch, modifier), } } @@ -279,6 +290,7 @@ impl InlineAsmReg { Self::AArch64(_) => cb(self), Self::RiscV(_) => cb(self), Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))), + Self::Mips(_) => cb(self), } } } @@ -291,6 +303,7 @@ pub enum InlineAsmRegClass { RiscV(RiscVInlineAsmRegClass), Nvptx(NvptxInlineAsmRegClass), Hexagon(HexagonInlineAsmRegClass), + Mips(MipsInlineAsmRegClass), } impl InlineAsmRegClass { @@ -302,6 +315,7 @@ impl InlineAsmRegClass { Self::RiscV(r) => r.name(), Self::Nvptx(r) => r.name(), Self::Hexagon(r) => r.name(), + Self::Mips(r) => r.name(), } } @@ -316,6 +330,7 @@ impl InlineAsmRegClass { Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV), Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx), Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon), + Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips), } } @@ -337,6 +352,7 @@ impl InlineAsmRegClass { Self::RiscV(r) => r.suggest_modifier(arch, ty), Self::Nvptx(r) => r.suggest_modifier(arch, ty), Self::Hexagon(r) => r.suggest_modifier(arch, ty), + Self::Mips(r) => r.suggest_modifier(arch, ty), } } @@ -354,6 +370,7 @@ impl InlineAsmRegClass { Self::RiscV(r) => r.default_modifier(arch), Self::Nvptx(r) => r.default_modifier(arch), Self::Hexagon(r) => r.default_modifier(arch), + Self::Mips(r) => r.default_modifier(arch), } } @@ -370,6 +387,7 @@ impl InlineAsmRegClass { Self::RiscV(r) => r.supported_types(arch), Self::Nvptx(r) => r.supported_types(arch), Self::Hexagon(r) => r.supported_types(arch), + Self::Mips(r) => r.supported_types(arch), } } @@ -391,6 +409,7 @@ impl InlineAsmRegClass { InlineAsmArch::Hexagon => { Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?) } + InlineAsmArch::Mips => Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?), }) }) } @@ -405,6 +424,7 @@ impl InlineAsmRegClass { Self::RiscV(r) => r.valid_modifiers(arch), Self::Nvptx(r) => r.valid_modifiers(arch), Self::Hexagon(r) => r.valid_modifiers(arch), + Self::Mips(r) => r.valid_modifiers(arch), } } } @@ -545,5 +565,10 @@ pub fn allocatable_registers( hexagon::fill_reg_map(arch, has_feature, target, &mut map); map } + InlineAsmArch::Mips => { + let mut map = mips::regclass_map(); + mips::fill_reg_map(arch, has_feature, target, &mut map); + map + } } } diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md index 28a5fe31fc4b5..9b68f462dca70 100644 --- a/src/doc/unstable-book/src/library-features/asm.md +++ b/src/doc/unstable-book/src/library-features/asm.md @@ -27,6 +27,7 @@ Inline assembly is currently supported on the following architectures: - RISC-V - NVPTX - Hexagon +- MIPS32 ## Basic usage @@ -493,6 +494,8 @@ Here is the list of currently supported register classes: | ARM | `qreg` | `q[0-15]` | `w` | | ARM | `qreg_low8` | `q[0-7]` | `t` | | ARM | `qreg_low4` | `q[0-3]` | `x` | +| MIPS32 | `reg` | `$[2-25]` | `r` | +| MIPS32 | `freg` | `$f[0-31]` | `f` | | NVPTX | `reg16` | None\* | `h` | | NVPTX | `reg32` | None\* | `r` | | NVPTX | `reg64` | None\* | `l` | @@ -528,6 +531,8 @@ Each register class has constraints on which value types they can be used with. | ARM | `sreg` | `vfp2` | `i32`, `f32` | | ARM | `dreg` | `vfp2` | `i64`, `f64`, `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2` | | ARM | `qreg` | `neon` | `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4` | +| MIPS32 | `reg` | None | `i8`, `i16`, `i32`, `f32` | +| MIPS32 | `freg` | None | `f32` | | NVPTX | `reg16` | None | `i8`, `i16` | | NVPTX | `reg32` | None | `i8`, `i16`, `i32`, `f32` | | NVPTX | `reg64` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` | @@ -576,6 +581,7 @@ Some registers have multiple names. These are all treated by the compiler as ide | ARM | `r13` | `sp` | | ARM | `r14` | `lr` | | ARM | `r15` | `pc` | +| MIPS32 | `$[2-25]` | Please [see the Wikipedia page][mips-regs] | | RISC-V | `x0` | `zero` | | RISC-V | `x1` | `ra` | | RISC-V | `x2` | `sp` | @@ -596,12 +602,14 @@ Some registers have multiple names. These are all treated by the compiler as ide | Hexagon | `r30` | `fr` | | Hexagon | `r31` | `lr` | +[mips-regs]: https://en.wikibooks.org/wiki/MIPS_Assembly/Register_File#Registers + Some registers cannot be used for input or output operands: | Architecture | Unsupported register | Reason | | ------------ | -------------------- | ------ | | All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. | -| All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V), `fr` (Hexagon) | The frame pointer cannot be used as an input or output. | +| All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V), `fr` (Hexagon), `$fp` (MIPS) | The frame pointer cannot be used as an input or output. | | ARM | `r7` or `r11` | On ARM the frame pointer can be either `r7` or `r11` depending on the target. The frame pointer cannot be used as an input or output. | | ARM | `r6` | `r6` is used internally by LLVM as a base pointer and therefore cannot be used as an input or output. | | x86 | `k0` | This is a constant zero register which can't be modified. | @@ -610,6 +618,11 @@ Some registers cannot be used for input or output operands: | x86 | `st([0-7])` | x87 registers are not currently supported (but may be in the future). | | AArch64 | `xzr` | This is a constant zero register which can't be modified. | | ARM | `pc` | This is the program counter, not a real register. | +| MIPS32 | `$0` or `$zero` | This is a constant zero register which can't be modified. | +| MIPS32 | `$1` or `$at` | Reserved for assembler. | +| MIPS32 | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. | +| MIPS32 | `$28`/`$gp` | Global pointer cannot be used as inputs or outputs. | +| MIPS32 | `$ra` | Return address cannot be used as inputs or outputs. | | RISC-V | `x0` | This is a constant zero register which can't be modified. | | RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. | | Hexagon | `lr` | This is the link register which cannot be used as an input or output. | @@ -657,6 +670,8 @@ The supported modifiers are a subset of LLVM's (and GCC's) [asm template argumen | ARM | `dreg` | None | `d0` | `P` | | ARM | `qreg` | None | `q0` | `q` | | ARM | `qreg` | `e` / `f` | `d0` / `d1` | `e` / `f` | +| MIPS32 | `reg` | None | `$2` | None | +| MIPS32 | `freg` | None | `$f0` | None | | NVPTX | `reg16` | None | `rs0` | None | | NVPTX | `reg32` | None | `r0` | None | | NVPTX | `reg64` | None | `rd0` | None | diff --git a/src/test/assembly/asm/mips-types.rs b/src/test/assembly/asm/mips-types.rs new file mode 100644 index 0000000000000..b195ed88c7245 --- /dev/null +++ b/src/test/assembly/asm/mips-types.rs @@ -0,0 +1,191 @@ +// no-system-llvm +// assembly-output: emit-asm +// compile-flags: --target mips-unknown-linux-gnu +// needs-llvm-components: mips + +#![feature(no_core, lang_items, rustc_attrs, repr_simd)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! stringify { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *const i32; + +impl Copy for i8 {} +impl Copy for u8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for f32 {} +impl Copy for ptr {} +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +// Hack to avoid function merging +extern "Rust" { + fn dont_merge(s: &str); +} + +macro_rules! check { ($func:ident, $ty:ty, $class:ident) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + dont_merge(stringify!($func)); + + let y; + asm!("move {}, {}", out($class) y, in($class) x); + y + } +};} + +macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + dont_merge(stringify!($func)); + + let y; + asm!(concat!("move ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + y + } +};} + +// CHECK-LABEL: sym_static: +// CHECK: #APP +// CHECK: lw $3, %got(extern_static) +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_static() { + dont_merge(stringify!($func)); + + asm!("la $v1, {}", sym extern_static); +} + +// CHECK-LABEL: sym_fn: +// CHECK: #APP +// CHECK: lw $3, %got(extern_func) +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_fn() { + dont_merge(stringify!($func)); + + asm!("la $v1, {}", sym extern_func); +} + +// CHECK-LABEL: reg_f32: +// CHECK: #APP +// CHECK: mov.s $f{{[0-9]+}}, $f{{[0-9]+}} +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn reg_f32(x: f32) -> f32 { + dont_merge("reg_f32"); + let y; + asm!("mov.s {}, {}", out(freg) y, in(freg) x); + y +} + +// CHECK-LABEL: f0_f32: +// CHECK: #APP +// CHECK: mov.s $f0, $f0 +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn f0_f32(x: f32) -> f32 { + dont_merge("f0_f32"); + let y; + asm!("mov.s $f0, $f0", lateout("$f0") y, in("$f0") x); + y +} + +// CHECK-LABEL: reg_ptr: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_ptr, ptr, reg); + +// CHECK-LABEL: reg_i32: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i32, i32, reg); + +// CHECK-LABEL: reg_f32_soft: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_f32_soft, f32, reg); + +// CHECK-LABEL: reg_i8: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i8, i8, reg); + +// CHECK-LABEL: reg_u8: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_u8, u8, reg); + +// CHECK-LABEL: reg_i16: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i16, i16, reg); + +// CHECK-LABEL: t0_ptr: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(t0_ptr, ptr, "$t0"); + +// CHECK-LABEL: t0_i32: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(t0_i32, i32, "$t0"); + +// CHECK-LABEL: t0_f32: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(t0_f32, f32, "$t0"); + +// CHECK-LABEL: t0_i8: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(t0_i8, i8, "$t0"); + +// CHECK-LABEL: t0_u8: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(t0_u8, u8, "$t0"); + +// CHECK-LABEL: t0_i16: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(t0_i16, i16, "$t0"); + +// CHECK-LABEL: r8_i16: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(r8_i16, i16, "$8"); From d9fc5b5ea8e48e9d24a7dfb8cab1dacb60d5cb7f Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 27 Sep 2020 00:09:45 -0400 Subject: [PATCH 1038/1052] Fix typo in ExpnData documentation This mis-highlighted the entire documentation as code. --- compiler/rustc_span/src/hygiene.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 942c6648340ef..fe500355c1ed7 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -702,7 +702,7 @@ pub struct ExpnData { /// The `DefId` of the macro being invoked, /// if this `ExpnData` corresponds to a macro invocation pub macro_def_id: Option, - /// The crate that originally created this `ExpnData. During + /// The crate that originally created this `ExpnData`. During /// metadata serialization, we only encode `ExpnData`s that were /// created locally - when our serialized metadata is decoded, /// foreign `ExpnId`s will have their `ExpnData` looked up From 653fa5a7e627ae1700624793b067c52f432a3fd8 Mon Sep 17 00:00:00 2001 From: Dong Bo Date: Sun, 27 Sep 2020 13:41:08 +0800 Subject: [PATCH 1039/1052] update stdarch submodule --- library/stdarch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/stdarch b/library/stdarch index 718175b34a39e..7895ab191867b 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit 718175b34a39e4e3d59b40e35930326edc515b87 +Subproject commit 7895ab191867be7612aaaaeeea1b982749826504 From 2e64ff9e6a593180b5a367b5cc68599fdc832acf Mon Sep 17 00:00:00 2001 From: Dong Bo Date: Sun, 27 Sep 2020 15:13:32 +0800 Subject: [PATCH 1040/1052] fix redundant delarations of const_fn_transmute --- library/stdarch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/stdarch b/library/stdarch index 7895ab191867b..b422b0180f7c3 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit 7895ab191867be7612aaaaeeea1b982749826504 +Subproject commit b422b0180f7c3327375a63a3e6660e432b9ec75d From 3009c5260f292da6785c67af8c823d4fa0e870d9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 27 Sep 2020 10:58:42 +0200 Subject: [PATCH 1041/1052] update tokei and ripgrep in cargotest --- src/tools/cargotest/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs index b65163a3bc9f5..8aabe077cf183 100644 --- a/src/tools/cargotest/main.rs +++ b/src/tools/cargotest/main.rs @@ -22,14 +22,14 @@ const TEST_REPOS: &[Test] = &[ Test { name: "ripgrep", repo: "https://github.com/BurntSushi/ripgrep", - sha: "ad9befbc1d3b5c695e7f6b6734ee1b8e683edd41", + sha: "3de31f752729525d85a3d1575ac1978733b3f7e7", lock: None, packages: &[], }, Test { name: "tokei", repo: "https://github.com/XAMPPRocky/tokei", - sha: "a950ff128d5a435a8083b1c7577c0431f98360ca", + sha: "fdf3f8cb279a7aeac0696c87e5d8b0cd946e4f9e", lock: None, packages: &[], }, From 3d4a2e6bb93ce4d1ffd77be7eaf3e4b752104346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 27 Sep 2020 11:00:46 +0200 Subject: [PATCH 1042/1052] Remove duplicate comment --- compiler/rustc_session/src/session.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index ff67d3cb107d9..ff5e6156d846b 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1103,9 +1103,6 @@ impl Session { self.used_attrs.lock().is_marked(attr) } - /// Returns `true` if the attribute's path matches the argument. If it matches, then the - /// attribute is marked as used. - /// Returns `true` if the attribute's path matches the argument. If it /// matches, then the attribute is marked as used. /// From e4200512ff976b9c1afff8069ae66ace52dfbcb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 27 Sep 2020 11:54:50 +0200 Subject: [PATCH 1043/1052] Clean up trivial if let --- compiler/rustc_span/src/hygiene.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 942c6648340ef..3e28468171b2e 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -759,7 +759,7 @@ impl ExpnData { #[inline] pub fn is_root(&self) -> bool { - if let ExpnKind::Root = self.kind { true } else { false } + matches!(self.kind, ExpnKind::Root) } } From ef7377eb058e98d43454d8635855c39051d068ce Mon Sep 17 00:00:00 2001 From: Bram van den Heuvel Date: Sun, 27 Sep 2020 15:54:07 +0200 Subject: [PATCH 1044/1052] Update chalk to 0.29.0 --- Cargo.lock | 16 ++++++++-------- compiler/rustc_middle/Cargo.toml | 2 +- compiler/rustc_traits/Cargo.toml | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 05d77ec0c8fc9..24ec965ea629f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -427,9 +427,9 @@ dependencies = [ [[package]] name = "chalk-derive" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c85b013e2dc1b46ac4a279f54e62e55556a8c4d859f7b7c4e340a9b1d013640" +checksum = "3a7f257e3bcdc56d8877ae31c012bd69fba0be66929d588e603905f2632c0c59" dependencies = [ "proc-macro2", "quote", @@ -439,9 +439,9 @@ dependencies = [ [[package]] name = "chalk-engine" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a499f81860f6eadfe0c76c5bb606cd2df701939d5a596ed3724c7db04aec14b" +checksum = "c43fcc7edf4d51b42f44ed50e2337bd90ddc8e088d0cd78a71db92a6f780f782" dependencies = [ "chalk-derive", "chalk-ir", @@ -452,9 +452,9 @@ dependencies = [ [[package]] name = "chalk-ir" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2135d844688dc920e3ece3012c5d3d4f06e26986fe38bc041bc98f0e7a9f4e2b" +checksum = "03a4050029ecb2b5a1ff3bfc64c39279179b294821ec2e8891a4a5c6e3a08db0" dependencies = [ "chalk-derive", "lazy_static", @@ -462,9 +462,9 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc69e4e94ffd4b39f1a865824b431bb82a7b4c8f14a0ba3d461cd86e56a590ac" +checksum = "828c1f80d4eaf681027cce02050c54a3c97370f81988d31bf2a56df54048746c" dependencies = [ "chalk-derive", "chalk-ir", diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 5136e2743cdb1..e8ace361b219d 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -26,7 +26,7 @@ rustc_index = { path = "../rustc_index" } rustc_serialize = { path = "../rustc_serialize" } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } -chalk-ir = "0.28.0" +chalk-ir = "0.29.0" smallvec = { version = "1.0", features = ["union", "may_dangle"] } measureme = "0.7.1" rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml index 369d003eb22f7..6d49571827640 100644 --- a/compiler/rustc_traits/Cargo.toml +++ b/compiler/rustc_traits/Cargo.toml @@ -12,9 +12,9 @@ rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } -chalk-ir = "0.28.0" -chalk-solve = "0.28.0" -chalk-engine = "0.28.0" +chalk-ir = "0.29.0" +chalk-solve = "0.29.0" +chalk-engine = "0.29.0" smallvec = { version = "1.0", features = ["union", "may_dangle"] } rustc_infer = { path = "../rustc_infer" } rustc_trait_selection = { path = "../rustc_trait_selection" } From 03d8be08967e3fbc358bc9fe9fad9a06ddabb17f Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 26 Sep 2020 21:27:55 -0400 Subject: [PATCH 1045/1052] Separate `private_intra_doc_links` and `broken_intra_doc_links` into separate lints This is not ideal because it means `deny(broken_intra_doc_links)` will no longer `deny(private_intra_doc_links)`. However, it can't be fixed with a new lint group, because `broken` is already in the `rustdoc` lint group; there would need to be a way to nest groups somehow. This also removes the early `return` so that the link will be generated even though it gives a warning. --- compiler/rustc_lint/src/lib.rs | 1 + compiler/rustc_session/src/lint/builtin.rs | 11 ++++++++++ .../passes/collect_intra_doc_links.rs | 21 ++++++++++++------- .../intra-links-private.private.stderr | 2 +- .../intra-links-private.public.stderr | 2 +- .../rustdoc-ui/issue-74134.private.stderr | 2 +- src/test/rustdoc-ui/issue-74134.public.stderr | 2 +- src/test/rustdoc/intra-doc-link-private.rs | 6 ++++++ 8 files changed, 35 insertions(+), 12 deletions(-) create mode 100644 src/test/rustdoc/intra-doc-link-private.rs diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 7f7472d9283b8..33caedfc19826 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -305,6 +305,7 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { add_lint_group!( "rustdoc", BROKEN_INTRA_DOC_LINKS, + PRIVATE_INTRA_DOC_LINKS, INVALID_CODEBLOCK_ATTRIBUTES, MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS diff --git a/compiler/rustc_session/src/lint/builtin.rs b/compiler/rustc_session/src/lint/builtin.rs index 13a4057a35bdf..8c3218b8e806a 100644 --- a/compiler/rustc_session/src/lint/builtin.rs +++ b/compiler/rustc_session/src/lint/builtin.rs @@ -1826,6 +1826,17 @@ declare_lint! { "failures in resolving intra-doc link targets" } +declare_lint! { + /// This is a subset of `broken_intra_doc_links` that warns when linking from + /// a public item to a private one. This is a `rustdoc` only lint, see the + /// documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#broken_intra_doc_links + pub PRIVATE_INTRA_DOC_LINKS, + Warn, + "linking from a public item to a private one" +} + declare_lint! { /// The `invalid_codeblock_attributes` lint detects code block attributes /// in documentation examples that have potentially mis-typed values. This diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 5d74a3da9a205..cd6a7feb18029 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -11,7 +11,10 @@ use rustc_hir::def::{ use rustc_hir::def_id::DefId; use rustc_middle::ty; use rustc_resolve::ParentScope; -use rustc_session::lint; +use rustc_session::lint::{ + builtin::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS}, + Lint, +}; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::Ident; use rustc_span::symbol::Symbol; @@ -988,7 +991,7 @@ impl LinkCollector<'_, '_> { let report_mismatch = |specified: Disambiguator, resolved: Disambiguator| { // The resolved item did not match the disambiguator; give a better error than 'not found' let msg = format!("incompatible link kind for `{}`", path_str); - report_diagnostic(cx, &msg, &item, dox, &link_range, |diag, sp| { + let callback = |diag: &mut DiagnosticBuilder<'_>, sp| { let note = format!( "this link resolved to {} {}, which is not {} {}", resolved.article(), @@ -998,7 +1001,8 @@ impl LinkCollector<'_, '_> { ); diag.note(¬e); suggest_disambiguator(resolved, diag, path_str, dox, sp, &link_range); - }); + }; + report_diagnostic(cx, BROKEN_INTRA_DOC_LINKS, &msg, &item, dox, &link_range, callback); }; if let Res::PrimTy(..) = res { match disambiguator { @@ -1055,7 +1059,6 @@ impl LinkCollector<'_, '_> { && !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_dst) { privacy_error(cx, &item, &path_str, dox, link_range); - return; } } let id = register_res(cx, res); @@ -1417,6 +1420,7 @@ impl Suggestion { /// to it. fn report_diagnostic( cx: &DocContext<'_>, + lint: &'static Lint, msg: &str, item: &Item, dox: &str, @@ -1435,7 +1439,7 @@ fn report_diagnostic( let attrs = &item.attrs; let sp = span_of_attrs(attrs).unwrap_or(item.source.span()); - cx.tcx.struct_span_lint_hir(lint::builtin::BROKEN_INTRA_DOC_LINKS, hir_id, sp, |lint| { + cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |lint| { let mut diag = lint.build(msg); let span = link_range @@ -1482,6 +1486,7 @@ fn resolution_failure( ) { report_diagnostic( collector.cx, + BROKEN_INTRA_DOC_LINKS, &format!("unresolved link to `{}`", path_str), item, dox, @@ -1695,7 +1700,7 @@ fn anchor_failure( ), }; - report_diagnostic(cx, &msg, item, dox, &link_range, |diag, sp| { + report_diagnostic(cx, BROKEN_INTRA_DOC_LINKS, &msg, item, dox, &link_range, |diag, sp| { if let Some(sp) = sp { diag.span_label(sp, "contains invalid anchor"); } @@ -1734,7 +1739,7 @@ fn ambiguity_error( } } - report_diagnostic(cx, &msg, item, dox, &link_range, |diag, sp| { + report_diagnostic(cx, BROKEN_INTRA_DOC_LINKS, &msg, item, dox, &link_range, |diag, sp| { if let Some(sp) = sp { diag.span_label(sp, "ambiguous link"); } else { @@ -1784,7 +1789,7 @@ fn privacy_error( let msg = format!("public documentation for `{}` links to private item `{}`", item_name, path_str); - report_diagnostic(cx, &msg, item, dox, &link_range, |diag, sp| { + report_diagnostic(cx, PRIVATE_INTRA_DOC_LINKS, &msg, item, dox, &link_range, |diag, sp| { if let Some(sp) = sp { diag.span_label(sp, "this item is private"); } diff --git a/src/test/rustdoc-ui/intra-links-private.private.stderr b/src/test/rustdoc-ui/intra-links-private.private.stderr index 77c4b67a6528f..eeef24b479747 100644 --- a/src/test/rustdoc-ui/intra-links-private.private.stderr +++ b/src/test/rustdoc-ui/intra-links-private.private.stderr @@ -4,7 +4,7 @@ warning: public documentation for `DocMe` links to private item `DontDocMe` LL | /// docs [DontDocMe] | ^^^^^^^^^ this item is private | - = note: `#[warn(broken_intra_doc_links)]` on by default + = note: `#[warn(private_intra_doc_links)]` on by default = note: this link resolves only because you passed `--document-private-items`, but will break without warning: 1 warning emitted diff --git a/src/test/rustdoc-ui/intra-links-private.public.stderr b/src/test/rustdoc-ui/intra-links-private.public.stderr index 312a78e8c3ec7..3f7b17586f19e 100644 --- a/src/test/rustdoc-ui/intra-links-private.public.stderr +++ b/src/test/rustdoc-ui/intra-links-private.public.stderr @@ -4,7 +4,7 @@ warning: public documentation for `DocMe` links to private item `DontDocMe` LL | /// docs [DontDocMe] | ^^^^^^^^^ this item is private | - = note: `#[warn(broken_intra_doc_links)]` on by default + = note: `#[warn(private_intra_doc_links)]` on by default = note: this link will resolve properly if you pass `--document-private-items` warning: 1 warning emitted diff --git a/src/test/rustdoc-ui/issue-74134.private.stderr b/src/test/rustdoc-ui/issue-74134.private.stderr index 58772109140ca..b802d7e12523a 100644 --- a/src/test/rustdoc-ui/issue-74134.private.stderr +++ b/src/test/rustdoc-ui/issue-74134.private.stderr @@ -4,7 +4,7 @@ warning: public documentation for `public_item` links to private item `PrivateTy LL | /// [`PrivateType`] | ^^^^^^^^^^^^^ this item is private | - = note: `#[warn(broken_intra_doc_links)]` on by default + = note: `#[warn(private_intra_doc_links)]` on by default = note: this link resolves only because you passed `--document-private-items`, but will break without warning: 1 warning emitted diff --git a/src/test/rustdoc-ui/issue-74134.public.stderr b/src/test/rustdoc-ui/issue-74134.public.stderr index b5bea190941e6..40aa2ece1a373 100644 --- a/src/test/rustdoc-ui/issue-74134.public.stderr +++ b/src/test/rustdoc-ui/issue-74134.public.stderr @@ -4,7 +4,7 @@ warning: public documentation for `public_item` links to private item `PrivateTy LL | /// [`PrivateType`] | ^^^^^^^^^^^^^ this item is private | - = note: `#[warn(broken_intra_doc_links)]` on by default + = note: `#[warn(private_intra_doc_links)]` on by default = note: this link will resolve properly if you pass `--document-private-items` warning: 1 warning emitted diff --git a/src/test/rustdoc/intra-doc-link-private.rs b/src/test/rustdoc/intra-doc-link-private.rs new file mode 100644 index 0000000000000..f86ca44403d93 --- /dev/null +++ b/src/test/rustdoc/intra-doc-link-private.rs @@ -0,0 +1,6 @@ +#![crate_name = "private"] +// compile-flags: --document-private-items +/// docs [DontDocMe] +// @has private/struct.DocMe.html '//*a[@href="../private/struct.DontDocMe.html"]' 'DontDocMe' +pub struct DocMe; +struct DontDocMe; From 80ffaed809aa9bf659acf146a26d851f594c0b25 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 27 Sep 2020 10:07:00 -0400 Subject: [PATCH 1046/1052] Add documentation for `private_intra_doc_links` --- compiler/rustc_session/src/lint/builtin.rs | 2 +- src/doc/rustdoc/src/lints.md | 40 ++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_session/src/lint/builtin.rs b/compiler/rustc_session/src/lint/builtin.rs index 8c3218b8e806a..0cc97fb4541d1 100644 --- a/compiler/rustc_session/src/lint/builtin.rs +++ b/compiler/rustc_session/src/lint/builtin.rs @@ -1831,7 +1831,7 @@ declare_lint! { /// a public item to a private one. This is a `rustdoc` only lint, see the /// documentation in the [rustdoc book]. /// - /// [rustdoc book]: ../../../rustdoc/lints.html#broken_intra_doc_links + /// [rustdoc book]: ../../../rustdoc/lints.html#private_intra_doc_links pub PRIVATE_INTRA_DOC_LINKS, Warn, "linking from a public item to a private one" diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md index 9ff897710f650..3e632a0644a73 100644 --- a/src/doc/rustdoc/src/lints.md +++ b/src/doc/rustdoc/src/lints.md @@ -62,6 +62,46 @@ help: to link to the function, add parentheses ``` +## private_intra_doc_links + +This lint **warns by default**. This lint detects when [intra-doc links] from public to private items. +For example: + +```rust +/// [private] +pub fn public() {} +fn private() {} +``` + +This gives a warning that the link will be broken when it appears in your documentation: + +```text +warning: public documentation for `public` links to private item `private` + --> priv.rs:1:6 + | +1 | /// [private] + | ^^^^^^^ this item is private + | + = note: `#[warn(private_intra_doc_links)]` on by default + = note: this link will resolve properly if you pass `--document-private-items` +``` + +Note that this has different behavior depending on whether you pass `--document-private-items` or not! +If you document private items, then it will still generate a link, despite the warning: + +```text +warning: public documentation for `public` links to private item `private` + --> priv.rs:1:6 + | +1 | /// [private] + | ^^^^^^^ this item is private + | + = note: `#[warn(private_intra_doc_links)]` on by default + = note: this link resolves only because you passed `--document-private-items`, but will break without +``` + +[intra-doc links]: linking-to-items-by-name.html + ## missing_docs This lint is **allowed by default**. It detects items missing documentation. From 7d98d2207a20d95e731bfc742d89389a67d6618d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sun, 27 Sep 2020 00:00:00 +0000 Subject: [PATCH 1047/1052] Reopen standard streams when they are closed on Unix The syscalls returning a new file descriptors generally use lowest-numbered file descriptor not currently opened, without any exceptions for those corresponding to the standard streams. Previously when any of standard streams has been closed before starting the application, operations on std::io::{stderr,stdin,stdout} objects were likely to operate on other logically unrelated file resources opened afterwards. Avoid the issue by reopening the standard streams when they are closed. --- library/std/src/sys/unix/mod.rs | 62 +++++++++++++++++++++++++++++++++ src/test/ui/no-stdio.rs | 22 ++++++++++-- 2 files changed, 82 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index eddf00d3979f5..b48d2162eca92 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -75,6 +75,13 @@ pub use crate::sys_common::os_str_bytes as os_str; #[cfg(not(test))] pub fn init() { + // The standard streams might be closed on application startup. To prevent + // std::io::{stdin, stdout,stderr} objects from using other unrelated file + // resources opened later, we reopen standards streams when they are closed. + unsafe { + sanitize_standard_fds(); + } + // By default, some platforms will send a *signal* when an EPIPE error // would otherwise be delivered. This runtime doesn't install a SIGPIPE // handler, causing it to kill the program, which isn't exactly what we @@ -86,6 +93,61 @@ pub fn init() { reset_sigpipe(); } + // In the case when all file descriptors are open, the poll has been + // observed to perform better than fcntl (on GNU/Linux). + #[cfg(not(any( + miri, + target_os = "emscripten", + target_os = "fuchsia", + // The poll on Darwin doesn't set POLLNVAL for closed fds. + target_os = "macos", + target_os = "ios", + target_os = "redox", + )))] + unsafe fn sanitize_standard_fds() { + use crate::sys::os::errno; + let pfds: &mut [_] = &mut [ + libc::pollfd { fd: 0, events: 0, revents: 0 }, + libc::pollfd { fd: 1, events: 0, revents: 0 }, + libc::pollfd { fd: 2, events: 0, revents: 0 }, + ]; + while libc::poll(pfds.as_mut_ptr(), 3, 0) == -1 { + if errno() == libc::EINTR { + continue; + } + libc::abort(); + } + for pfd in pfds { + if pfd.revents & libc::POLLNVAL == 0 { + continue; + } + if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 { + // If the stream is closed but we failed to reopen it, abort the + // process. Otherwise we wouldn't preserve the safety of + // operations on the corresponding Rust object Stdin, Stdout, or + // Stderr. + libc::abort(); + } + } + } + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "redox"))] + unsafe fn sanitize_standard_fds() { + use crate::sys::os::errno; + for fd in 0..3 { + if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF { + if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 { + libc::abort(); + } + } + } + } + #[cfg(any( + // The standard fds are always available in Miri. + miri, + target_os = "emscripten", + target_os = "fuchsia"))] + unsafe fn sanitize_standard_fds() {} + #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia")))] unsafe fn reset_sigpipe() { assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR); diff --git a/src/test/ui/no-stdio.rs b/src/test/ui/no-stdio.rs index e72b7b26e2249..1b0ad930da6d7 100644 --- a/src/test/ui/no-stdio.rs +++ b/src/test/ui/no-stdio.rs @@ -36,6 +36,16 @@ unsafe fn without_stdio R>(f: F) -> R { return r } +#[cfg(unix)] +fn assert_fd_is_valid(fd: libc::c_int) { + if unsafe { libc::fcntl(fd, libc::F_GETFD) == -1 } { + panic!("file descriptor {} is not valid: {}", fd, io::Error::last_os_error()); + } +} + +#[cfg(windows)] +fn assert_fd_is_valid(_fd: libc::c_int) {} + #[cfg(windows)] unsafe fn without_stdio R>(f: F) -> R { type DWORD = u32; @@ -77,10 +87,18 @@ unsafe fn without_stdio R>(f: F) -> R { fn main() { if env::args().len() > 1 { + // Writing to stdout & stderr should not panic. println!("test"); assert!(io::stdout().write(b"test\n").is_ok()); assert!(io::stderr().write(b"test\n").is_ok()); + + // Stdin should be at EOF. assert_eq!(io::stdin().read(&mut [0; 10]).unwrap(), 0); + + // Standard file descriptors should be valid on UNIX: + assert_fd_is_valid(0); + assert_fd_is_valid(1); + assert_fd_is_valid(2); return } @@ -109,12 +127,12 @@ fn main() { .stdout(Stdio::null()) .stderr(Stdio::null()) .status().unwrap(); - assert!(status.success(), "{:?} isn't a success", status); + assert!(status.success(), "{} isn't a success", status); // Finally, close everything then spawn a child to make sure everything is // *still* ok. let status = unsafe { without_stdio(|| Command::new(&me).arg("next").status()) }.unwrap(); - assert!(status.success(), "{:?} isn't a success", status); + assert!(status.success(), "{} isn't a success", status); } From 1fefba5e0ba95a4ffe83efbeeb1cd56e978f2ab6 Mon Sep 17 00:00:00 2001 From: John Paul Adrian Glaubitz Date: Mon, 28 Sep 2020 00:05:40 +0200 Subject: [PATCH 1048/1052] library/{panic_,}unwind: Add definitions for sparc-unknow-linux-gnu --- library/panic_unwind/src/gcc.rs | 2 +- library/unwind/src/libunwind.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/panic_unwind/src/gcc.rs b/library/panic_unwind/src/gcc.rs index 1cfd527b5841a..6b88bab8277ee 100644 --- a/library/panic_unwind/src/gcc.rs +++ b/library/panic_unwind/src/gcc.rs @@ -114,7 +114,7 @@ const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4 / X3, X4 #[cfg(target_arch = "s390x")] const UNWIND_DATA_REG: (i32, i32) = (6, 7); // R6, R7 -#[cfg(target_arch = "sparc64")] +#[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] const UNWIND_DATA_REG: (i32, i32) = (24, 25); // I0, I1 #[cfg(target_arch = "hexagon")] diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index dcf4fcd4e5aab..806df572cf944 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -51,7 +51,7 @@ pub const unwinder_private_data_size: usize = 2; #[cfg(target_arch = "s390x")] pub const unwinder_private_data_size: usize = 2; -#[cfg(target_arch = "sparc64")] +#[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] pub const unwinder_private_data_size: usize = 2; #[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))] From d9de08d65ceb4d4e9d8d546186eae22ba4c57fa4 Mon Sep 17 00:00:00 2001 From: John Paul Adrian Glaubitz Date: Mon, 28 Sep 2020 00:08:42 +0200 Subject: [PATCH 1049/1052] library/std/sys_common: Define MIN_ALIGN for sparc-unknown-linux-gnu --- library/std/src/sys_common/alloc.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/sys_common/alloc.rs b/library/std/src/sys_common/alloc.rs index f22476be32560..6c1bc0d839ad3 100644 --- a/library/std/src/sys_common/alloc.rs +++ b/library/std/src/sys_common/alloc.rs @@ -12,6 +12,7 @@ use crate::ptr; target_arch = "mips", target_arch = "powerpc", target_arch = "powerpc64", + target_arch = "sparc", target_arch = "asmjs", target_arch = "wasm32", target_arch = "hexagon", From d25b0364e11064089f30af74da18aae5896a72ea Mon Sep 17 00:00:00 2001 From: John Paul Adrian Glaubitz Date: Mon, 28 Sep 2020 00:14:59 +0200 Subject: [PATCH 1050/1052] library/std: Set OS raw type definitions for sparc-unknown-linux-gnu --- library/std/src/os/linux/raw.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/os/linux/raw.rs b/library/std/src/os/linux/raw.rs index 4ff3a6e578984..617c4098aa959 100644 --- a/library/std/src/os/linux/raw.rs +++ b/library/std/src/os/linux/raw.rs @@ -29,6 +29,7 @@ pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t}; target_arch = "x86", target_arch = "le32", target_arch = "powerpc", + target_arch = "sparc", target_arch = "arm", target_arch = "asmjs", target_arch = "wasm32" From b9d0ea95c8d87310262f6f6cb88c16f6d3d323cc Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Fri, 18 Sep 2020 20:14:27 -0400 Subject: [PATCH 1051/1052] [mir-opt] Introduce a new flag to enable experimental/unsound mir opts --- compiler/rustc_mir/src/transform/copy_prop.rs | 4 +- compiler/rustc_session/src/options.rs | 2 + src/test/mir-opt/copy_propagation.rs | 1 + ...copy_propagation.test.CopyPropagation.diff | 18 +- .../mir-opt/early_otherwise_branch_68867.rs | 2 +- src/test/mir-opt/inline/inline-any-operand.rs | 2 +- .../inline/inline-closure-borrows-arg.rs | 2 +- .../mir-opt/inline/inline-trait-method_2.rs | 2 +- .../issue_73223.main.PreCodegen.32bit.diff | 207 ++++++++++-------- .../issue_73223.main.PreCodegen.64bit.diff | 207 ++++++++++-------- src/test/mir-opt/nrvo-simple.rs | 2 +- ...ocals-removes-unused-discriminant-reads.rs | 2 + ...minant_reads.map.SimplifyLocals.32bit.diff | 30 +-- ...minant_reads.map.SimplifyLocals.64bit.diff | 30 +-- src/test/mir-opt/simplify_try.rs | 1 + ...y.try_identity.DestinationPropagation.diff | 70 +++--- ..._try.try_identity.SimplifyArmIdentity.diff | 102 ++++----- ....try_identity.SimplifyBranchSame.after.mir | 56 ++--- ..._try.try_identity.SimplifyLocals.after.mir | 14 +- .../ui/mir/issue-76740-copy-propagation.rs | 2 +- 20 files changed, 397 insertions(+), 359 deletions(-) diff --git a/compiler/rustc_mir/src/transform/copy_prop.rs b/compiler/rustc_mir/src/transform/copy_prop.rs index ba406c72df848..74194467b38c5 100644 --- a/compiler/rustc_mir/src/transform/copy_prop.rs +++ b/compiler/rustc_mir/src/transform/copy_prop.rs @@ -31,9 +31,11 @@ pub struct CopyPropagation; impl<'tcx> MirPass<'tcx> for CopyPropagation { fn run_pass(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) { + let opts = &tcx.sess.opts.debugging_opts; // We only run when the MIR optimization level is > 1. // This avoids a slow pass, and messing up debug info. - if tcx.sess.opts.debugging_opts.mir_opt_level <= 1 { + // FIXME(76740): This optimization is buggy and can cause unsoundness. + if opts.mir_opt_level <= 1 || !opts.unsound_mir_opts { return; } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 8cc55f4ebe895..712c9cb87c9d5 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1115,6 +1115,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, `hir,typed` (HIR with types for each node), `hir-tree` (dump the raw HIR), `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"), + unsound_mir_opts: bool = (false, parse_bool, [TRACKED], + "enable unsound and buggy MIR optimizations (default: no)"), unstable_options: bool = (false, parse_bool, [UNTRACKED], "adds unstable command line options to rustc interface (default: no)"), use_ctors_section: Option = (None, parse_opt_bool, [TRACKED], diff --git a/src/test/mir-opt/copy_propagation.rs b/src/test/mir-opt/copy_propagation.rs index ee460a488b675..8283ec73d0f07 100644 --- a/src/test/mir-opt/copy_propagation.rs +++ b/src/test/mir-opt/copy_propagation.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zunsound-mir-opts // EMIT_MIR copy_propagation.test.CopyPropagation.diff fn test(x: u32) -> u32 { diff --git a/src/test/mir-opt/copy_propagation.test.CopyPropagation.diff b/src/test/mir-opt/copy_propagation.test.CopyPropagation.diff index 1f3e559c1b7f4..152d159063052 100644 --- a/src/test/mir-opt/copy_propagation.test.CopyPropagation.diff +++ b/src/test/mir-opt/copy_propagation.test.CopyPropagation.diff @@ -2,19 +2,19 @@ + // MIR for `test` after CopyPropagation fn test(_1: u32) -> u32 { - debug x => _1; // in scope 0 at $DIR/copy_propagation.rs:3:9: 3:10 - let mut _0: u32; // return place in scope 0 at $DIR/copy_propagation.rs:3:20: 3:23 - let _2: u32; // in scope 0 at $DIR/copy_propagation.rs:4:9: 4:10 + debug x => _1; // in scope 0 at $DIR/copy_propagation.rs:4:9: 4:10 + let mut _0: u32; // return place in scope 0 at $DIR/copy_propagation.rs:4:20: 4:23 + let _2: u32; // in scope 0 at $DIR/copy_propagation.rs:5:9: 5:10 scope 1 { - debug y => _0; // in scope 1 at $DIR/copy_propagation.rs:4:9: 4:10 + debug y => _0; // in scope 1 at $DIR/copy_propagation.rs:5:9: 5:10 } bb0: { - nop; // scope 0 at $DIR/copy_propagation.rs:4:9: 4:10 - _0 = _1; // scope 0 at $DIR/copy_propagation.rs:4:13: 4:14 - nop; // scope 1 at $DIR/copy_propagation.rs:5:5: 5:6 - nop; // scope 0 at $DIR/copy_propagation.rs:6:1: 6:2 - return; // scope 0 at $DIR/copy_propagation.rs:6:2: 6:2 + nop; // scope 0 at $DIR/copy_propagation.rs:5:9: 5:10 + _0 = _1; // scope 0 at $DIR/copy_propagation.rs:5:13: 5:14 + nop; // scope 1 at $DIR/copy_propagation.rs:6:5: 6:6 + nop; // scope 0 at $DIR/copy_propagation.rs:7:1: 7:2 + return; // scope 0 at $DIR/copy_propagation.rs:7:2: 7:2 } } diff --git a/src/test/mir-opt/early_otherwise_branch_68867.rs b/src/test/mir-opt/early_otherwise_branch_68867.rs index 5922e73e5d205..98a275c18acdc 100644 --- a/src/test/mir-opt/early_otherwise_branch_68867.rs +++ b/src/test/mir-opt/early_otherwise_branch_68867.rs @@ -1,5 +1,5 @@ // ignore-tidy-linelength -// compile-flags: -Z mir-opt-level=3 +// compile-flags: -Z mir-opt-level=3 -Zunsound-mir-opts // example from #68867 type CSSFloat = f32; diff --git a/src/test/mir-opt/inline/inline-any-operand.rs b/src/test/mir-opt/inline/inline-any-operand.rs index fb0de020f73a2..feac14eccd85f 100644 --- a/src/test/mir-opt/inline/inline-any-operand.rs +++ b/src/test/mir-opt/inline/inline-any-operand.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z span_free_formats +// compile-flags: -Z span_free_formats -Zunsound-mir-opts // Tests that MIR inliner works for any operand diff --git a/src/test/mir-opt/inline/inline-closure-borrows-arg.rs b/src/test/mir-opt/inline/inline-closure-borrows-arg.rs index 218bc3553a139..d76bc33f52e7d 100644 --- a/src/test/mir-opt/inline/inline-closure-borrows-arg.rs +++ b/src/test/mir-opt/inline/inline-closure-borrows-arg.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z span_free_formats +// compile-flags: -Z span_free_formats -Zunsound-mir-opts // Tests that MIR inliner can handle closure arguments, // even when (#45894) diff --git a/src/test/mir-opt/inline/inline-trait-method_2.rs b/src/test/mir-opt/inline/inline-trait-method_2.rs index 6e5de8315a1cb..9626ba123aadb 100644 --- a/src/test/mir-opt/inline/inline-trait-method_2.rs +++ b/src/test/mir-opt/inline/inline-trait-method_2.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z span_free_formats -Z mir-opt-level=3 +// compile-flags: -Z span_free_formats -Z mir-opt-level=3 -Zunsound-mir-opts // EMIT_MIR inline_trait_method_2.test2.Inline.after.mir fn test2(x: &dyn X) -> bool { diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff index f24bcfe5a1cb6..ef7c73068faf6 100644 --- a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff +++ b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff @@ -3,61 +3,65 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:1:11: 1:11 - let mut _1: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - let _2: i32; // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15 - let mut _4: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _7: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _8: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _9: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _10: &std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let _11: std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _12: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let _13: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _14: (&&i32, &&i32); // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let _15: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _16: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _17: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _18: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let _1: i32; // in scope 0 at $DIR/issue-73223.rs:2:9: 2:14 + let mut _2: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + let _3: i32; // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + let mut _5: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _6: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + 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 scope 1 { - debug split => _2; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14 - let _3: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14 + debug split => _1; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14 + let _4: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14 scope 3 { - debug _prev => _3; // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14 - let _5: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _6: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + debug _prev => _4; // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14 + let _7: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let _8: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 4 { - debug left_val => _5; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - debug right_val => _6; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + 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 => _21; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - debug arg1 => _24; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + 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 { - debug x => _21; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - debug f => _20; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _19: 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 _20: 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 _21: &&i32; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL + debug x => _25; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug f => _24; // in scope 6 at $SRC_DIR/core/src/fmt/mod.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 } scope 8 { - debug x => _24; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - debug f => _23; // in scope 8 at $SRC_DIR/core/src/fmt/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 8 at $SRC_DIR/std/src/macros.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 8 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _24: &&i32; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL + debug x => _28; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug f => _27; // in scope 8 at $SRC_DIR/core/src/fmt/mod.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 10 { - debug pieces => _25; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - debug args => _27; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _25: &[&str]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _26: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _27: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL + debug pieces => _29; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug args => _31; // in scope 10 at $SRC_DIR/core/src/fmt/mod.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 2 { - debug v => _2; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15 + debug v => _3; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15 } scope 7 { } @@ -65,114 +69,125 @@ } bb0: { - StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - ((_1 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - discriminant(_1) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - _2 = ((_1 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 - StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 - ((_3 as Some).0: i32) = _2; // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 - discriminant(_3) = 1; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 - (_4.0: &i32) = &_2; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_4.1: &i32) = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:2:9: 2:14 + StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + StorageLive(_3); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + _3 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + _1 = _3; // scope 2 at $DIR/issue-73223.rs:3:20: 3:21 + StorageDead(_3); // scope 0 at $DIR/issue-73223.rs:3:20: 3:21 + StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 + ((_4 as Some).0: i32) = _1; // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 + discriminant(_4) = 1; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 + (_5.0: &i32) = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _6 = 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])) } - StorageLive(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _5 = (_4.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _6 = (_4.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_7); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_8); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_5.1: &i32) = move _6; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _7 = (_5.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _8 = (_5.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _9 = (*_5); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _8 = Eq(move _9, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _7 = Not(move _8); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_8); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - switchInt(_7) -> [false: bb1, otherwise: bb2]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _11 = (*_7); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _10 = Eq(move _11, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _9 = Not(move _10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + switchInt(_9) -> [false: bb1, otherwise: bb2]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL } bb1: { - StorageDead(_7); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _0 = const (); // scope 0 at $DIR/issue-73223.rs:1:11: 9:2 + StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:9:1: 9:2 return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 } bb2: { - StorageLive(_11); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _25 = const main::promoted[0] as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + 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 // 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])) } - StorageLive(_13); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageLive(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _15 = _5; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_14.0: &&i32) = &_15; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _16 = &_6; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_14.1: &&i32) = move _16; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageDead(_16); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _21 = (_14.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _24 = (_14.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _20 = <&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 + _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 + 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 // 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()) } - StorageLive(_19); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _19 = transmute:: 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 _20) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageLive(_23); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _23 = transmute:: 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/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/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:: 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()) } } bb3: { - (_17.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _21) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_21.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _25) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/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()) } } bb4: { - (_17.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _19; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_19); // scope 7 at $SRC_DIR/core/src/fmt/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 + (_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/core/src/fmt/mod.rs:LL:COL + StorageDead(_23); // scope 7 at $SRC_DIR/core/src/fmt/mod.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 // 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()) } - StorageLive(_22); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _22 = transmute:: 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) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageLive(_26); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _26 = transmute:: 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/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/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:: 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()) } } bb5: { - (_18.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _24) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_22.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _28) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/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()) } } bb6: { - (_18.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 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_22); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _13 = [move _17, move _18]; // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL + (_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/core/src/fmt/mod.rs:LL:COL + StorageDead(_26); // scope 9 at $SRC_DIR/core/src/fmt/mod.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/core/src/fmt/mod.rs:LL:COL + discriminant(_30) = 0; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_13.0: &[&str]) = move _29; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_13.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _30; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_13.2: &[std::fmt::ArgumentV1]) = move _31; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_30); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _12 = &_13; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _27 = move _12 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageLive(_26); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - discriminant(_26) = 0; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_11.0: &[&str]) = move _25; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_11.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _26; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_11.2: &[std::fmt::ArgumentV1]) = move _27; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_26); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _10 = &_11; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - begin_panic_fmt(move _10); // 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 // 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()) } diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff index f24bcfe5a1cb6..ef7c73068faf6 100644 --- a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff +++ b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff @@ -3,61 +3,65 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:1:11: 1:11 - let mut _1: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - let _2: i32; // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15 - let mut _4: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _7: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _8: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _9: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _10: &std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let _11: std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _12: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let _13: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _14: (&&i32, &&i32); // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let _15: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _16: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _17: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _18: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let _1: i32; // in scope 0 at $DIR/issue-73223.rs:2:9: 2:14 + let mut _2: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + let _3: i32; // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + let mut _5: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _6: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + 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 scope 1 { - debug split => _2; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14 - let _3: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14 + debug split => _1; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14 + let _4: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14 scope 3 { - debug _prev => _3; // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14 - let _5: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _6: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + debug _prev => _4; // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14 + let _7: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let _8: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 4 { - debug left_val => _5; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - debug right_val => _6; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + 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 => _21; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - debug arg1 => _24; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + 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 { - debug x => _21; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - debug f => _20; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _19: 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 _20: 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 _21: &&i32; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL + debug x => _25; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug f => _24; // in scope 6 at $SRC_DIR/core/src/fmt/mod.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 } scope 8 { - debug x => _24; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - debug f => _23; // in scope 8 at $SRC_DIR/core/src/fmt/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 8 at $SRC_DIR/std/src/macros.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 8 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _24: &&i32; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL + debug x => _28; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug f => _27; // in scope 8 at $SRC_DIR/core/src/fmt/mod.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 10 { - debug pieces => _25; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - debug args => _27; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _25: &[&str]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _26: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _27: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL + debug pieces => _29; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug args => _31; // in scope 10 at $SRC_DIR/core/src/fmt/mod.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 2 { - debug v => _2; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15 + debug v => _3; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15 } scope 7 { } @@ -65,114 +69,125 @@ } bb0: { - StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - ((_1 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - discriminant(_1) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - _2 = ((_1 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 - StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 - ((_3 as Some).0: i32) = _2; // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 - discriminant(_3) = 1; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 - (_4.0: &i32) = &_2; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_4.1: &i32) = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:2:9: 2:14 + StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + StorageLive(_3); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + _3 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + _1 = _3; // scope 2 at $DIR/issue-73223.rs:3:20: 3:21 + StorageDead(_3); // scope 0 at $DIR/issue-73223.rs:3:20: 3:21 + StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 + ((_4 as Some).0: i32) = _1; // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 + discriminant(_4) = 1; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 + (_5.0: &i32) = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _6 = 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])) } - StorageLive(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _5 = (_4.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _6 = (_4.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_7); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_8); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_5.1: &i32) = move _6; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _7 = (_5.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _8 = (_5.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _9 = (*_5); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _8 = Eq(move _9, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _7 = Not(move _8); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_8); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - switchInt(_7) -> [false: bb1, otherwise: bb2]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _11 = (*_7); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _10 = Eq(move _11, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _9 = Not(move _10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + switchInt(_9) -> [false: bb1, otherwise: bb2]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL } bb1: { - StorageDead(_7); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _0 = const (); // scope 0 at $DIR/issue-73223.rs:1:11: 9:2 + StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:9:1: 9:2 return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 } bb2: { - StorageLive(_11); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _25 = const main::promoted[0] as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + 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 // 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])) } - StorageLive(_13); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageLive(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _15 = _5; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_14.0: &&i32) = &_15; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _16 = &_6; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_14.1: &&i32) = move _16; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageDead(_16); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _21 = (_14.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _24 = (_14.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _20 = <&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 + _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 + 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 // 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()) } - StorageLive(_19); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _19 = transmute:: 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 _20) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageLive(_23); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _23 = transmute:: 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/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/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:: 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()) } } bb3: { - (_17.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _21) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_21.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _25) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/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()) } } bb4: { - (_17.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _19; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_19); // scope 7 at $SRC_DIR/core/src/fmt/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 + (_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/core/src/fmt/mod.rs:LL:COL + StorageDead(_23); // scope 7 at $SRC_DIR/core/src/fmt/mod.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 // 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()) } - StorageLive(_22); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _22 = transmute:: 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) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageLive(_26); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _26 = transmute:: 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/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/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:: 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()) } } bb5: { - (_18.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _24) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_22.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _28) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/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()) } } bb6: { - (_18.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 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_22); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _13 = [move _17, move _18]; // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL + (_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/core/src/fmt/mod.rs:LL:COL + StorageDead(_26); // scope 9 at $SRC_DIR/core/src/fmt/mod.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/core/src/fmt/mod.rs:LL:COL + discriminant(_30) = 0; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_13.0: &[&str]) = move _29; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_13.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _30; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_13.2: &[std::fmt::ArgumentV1]) = move _31; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_30); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _12 = &_13; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _27 = move _12 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageLive(_26); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - discriminant(_26) = 0; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_11.0: &[&str]) = move _25; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_11.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _26; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_11.2: &[std::fmt::ArgumentV1]) = move _27; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_26); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _10 = &_11; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - begin_panic_fmt(move _10); // 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 // 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()) } diff --git a/src/test/mir-opt/nrvo-simple.rs b/src/test/mir-opt/nrvo-simple.rs index ab46d7b94c72c..22b18b107701e 100644 --- a/src/test/mir-opt/nrvo-simple.rs +++ b/src/test/mir-opt/nrvo-simple.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmir-opt-level=1 +// compile-flags: -Zmir-opt-level=1 -Zunsound-mir-opts // EMIT_MIR nrvo_simple.nrvo.RenameReturnPlace.diff fn nrvo(init: fn(&mut [u8; 1024])) -> [u8; 1024] { diff --git a/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs b/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs index cf8940ec33096..84f57deccf7e0 100644 --- a/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs +++ b/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zunsound-mir-opts + fn map(x: Option>) -> Option> { match x { None => None, diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff index 68a113f94efda..760fb747f7229 100644 --- a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff +++ b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff @@ -2,25 +2,25 @@ + // MIR for `map` after SimplifyLocals fn map(_1: Option>) -> Option> { - debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:8: 1:9 - let mut _0: std::option::Option>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:31: 1:46 -- let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 -- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15 -- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:25: 4:26 -- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 -- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 -- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 + debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:8: 3:9 + let mut _0: std::option::Option>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:31: 3:46 +- let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 +- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15 +- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:25: 6:26 +- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 +- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 +- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 scope 1 { - debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15 + debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15 } bb0: { -- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 -- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 -- _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 - _0 = move _1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:20: 4:27 -- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 - return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:2: 6:2 +- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 +- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 +- _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 + _0 = move _1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:20: 6:27 +- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 + return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:2: 8:2 } } diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff index 68a113f94efda..760fb747f7229 100644 --- a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff +++ b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff @@ -2,25 +2,25 @@ + // MIR for `map` after SimplifyLocals fn map(_1: Option>) -> Option> { - debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:8: 1:9 - let mut _0: std::option::Option>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:31: 1:46 -- let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 -- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15 -- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:25: 4:26 -- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 -- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 -- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 + debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:8: 3:9 + let mut _0: std::option::Option>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:31: 3:46 +- let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 +- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15 +- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:25: 6:26 +- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 +- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 +- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 scope 1 { - debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15 + debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15 } bb0: { -- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 -- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 -- _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 - _0 = move _1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:20: 4:27 -- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 - return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:2: 6:2 +- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 +- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 +- _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 + _0 = move _1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:20: 6:27 +- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 + return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:2: 8:2 } } diff --git a/src/test/mir-opt/simplify_try.rs b/src/test/mir-opt/simplify_try.rs index fca80bee89679..eb307de20744a 100644 --- a/src/test/mir-opt/simplify_try.rs +++ b/src/test/mir-opt/simplify_try.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zunsound-mir-opts // EMIT_MIR simplify_try.try_identity.SimplifyArmIdentity.diff // EMIT_MIR simplify_try.try_identity.SimplifyBranchSame.after.mir // EMIT_MIR simplify_try.try_identity.SimplifyLocals.after.mir diff --git a/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff b/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff index 187a3cfbb896d..b3a2b6fbf76b2 100644 --- a/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff +++ b/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff @@ -2,35 +2,35 @@ + // MIR for `try_identity` after DestinationPropagation fn try_identity(_1: std::result::Result) -> std::result::Result { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:6:17: 6:18 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:6:41: 6:57 - let _2: u32; // in scope 0 at $DIR/simplify_try.rs:7:9: 7:10 - let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15 - let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:14 - let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 - let _6: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 - let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 - let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 - let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 - let _10: u32; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15 - let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:8:8: 8:9 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:8:9: 8:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:14 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9 scope 1 { - debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10 + debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 } scope 2 { - debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15 + debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 scope 3 { scope 7 { debug t => ((_0 as Err).0: i32); // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL } scope 8 { debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:14: 8:15 } } } scope 4 { - debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15 + debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 scope 5 { } } @@ -40,33 +40,33 @@ } bb0: { - StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:7:9: 7:10 -- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:7:13: 7:15 -- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 -- _4 = _1; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 + StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:8:9: 8:10 +- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 +- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 +- _4 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 - _3 = move _4; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL -- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 -- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 -+ nop; // scope 0 at $DIR/simplify_try.rs:7:13: 7:15 -+ nop; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 -+ _0 = _1; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 +- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 +- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 ++ _0 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 + nop; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL -+ nop; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 -+ _5 = discriminant(_0); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 - goto -> bb1; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 ++ _5 = discriminant(_0); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + goto -> bb1; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 } bb1: { -- _0 = move _3; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10 -- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:7:15: 7:16 -+ nop; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10 -+ nop; // scope 0 at $DIR/simplify_try.rs:7:15: 7:16 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:9:1: 9:2 - goto -> bb2; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2 +- _0 = move _3; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 +- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 ++ nop; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 ++ nop; // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 + goto -> bb2; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 } bb2: { - return; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2 + return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 } } diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff index 0c687684c508e..14a4318c1bc6f 100644 --- a/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff @@ -2,25 +2,25 @@ + // MIR for `try_identity` after SimplifyArmIdentity fn try_identity(_1: std::result::Result) -> std::result::Result { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:6:17: 6:18 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:6:41: 6:57 - let _2: u32; // in scope 0 at $DIR/simplify_try.rs:7:9: 7:10 - let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15 - let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:14 - let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 - let _6: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 - let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 - let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 - let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 - let _10: u32; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15 - let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:8:8: 8:9 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:8:9: 8:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:14 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9 scope 1 { -- debug y => _2; // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10 -+ debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10 +- debug y => _2; // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 ++ debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 } scope 2 { -- debug err => _6; // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15 -+ debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15 +- debug err => _6; // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 ++ debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 scope 3 { scope 7 { - debug t => _9; // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL @@ -29,13 +29,13 @@ scope 8 { - debug v => _8; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL + debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:14: 8:15 } } } scope 4 { -- debug val => _10; // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15 -+ debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15 +- debug val => _10; // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 ++ debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 scope 5 { } } @@ -44,55 +44,55 @@ } bb0: { - StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:7:9: 7:10 - StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:7:13: 7:15 - StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 - _4 = _1; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 + StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:8:9: 8:10 + StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 + _4 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 _3 = move _4; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 - _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 - switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 } bb1: { -- StorageLive(_10); // scope 0 at $DIR/simplify_try.rs:7:13: 7:15 -- _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:7:13: 7:15 -- _2 = _10; // scope 5 at $DIR/simplify_try.rs:7:13: 7:15 -- StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 -+ _0 = move _3; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10 - StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:7:15: 7:16 -- StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:8:8: 8:9 -- _11 = _2; // scope 1 at $DIR/simplify_try.rs:8:8: 8:9 -- ((_0 as Ok).0: u32) = move _11; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10 -- discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10 -- StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:8:9: 8:10 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:9:1: 9:2 - goto -> bb3; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2 +- StorageLive(_10); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 +- _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 +- _2 = _10; // scope 5 at $DIR/simplify_try.rs:8:13: 8:15 +- StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 ++ _0 = move _3; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 +- StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:9:8: 9:9 +- _11 = _2; // scope 1 at $DIR/simplify_try.rs:9:8: 9:9 +- ((_0 as Ok).0: u32) = move _11; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 +- discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 +- StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:9:9: 9:10 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 + goto -> bb3; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 } bb2: { -- StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 -- _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 -- StorageLive(_8); // scope 3 at $DIR/simplify_try.rs:7:14: 7:15 -- StorageLive(_9); // scope 3 at $DIR/simplify_try.rs:7:14: 7:15 -- _9 = _6; // scope 3 at $DIR/simplify_try.rs:7:14: 7:15 +- StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 +- _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 +- StorageLive(_8); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 +- StorageLive(_9); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 +- _9 = _6; // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 - _8 = move _9; // scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL -- StorageDead(_9); // scope 3 at $DIR/simplify_try.rs:7:14: 7:15 +- StorageDead(_9); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 - StorageLive(_12); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - _12 = move _8; // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - ((_0 as Err).0: i32) = move _12; // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - discriminant(_0) = 1; // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_12); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL -- StorageDead(_8); // scope 3 at $DIR/simplify_try.rs:7:14: 7:15 -- StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 +- StorageDead(_8); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 +- StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + _0 = move _3; // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:7:15: 7:16 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:9:1: 9:2 - goto -> bb3; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 + goto -> bb3; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 } bb3: { - return; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2 + return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 } } diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir b/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir index 9428d305c8731..0ae89b855ba28 100644 --- a/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir +++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir @@ -1,35 +1,35 @@ // MIR for `try_identity` after SimplifyBranchSame fn try_identity(_1: std::result::Result) -> std::result::Result { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:6:17: 6:18 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:6:41: 6:57 - let _2: u32; // in scope 0 at $DIR/simplify_try.rs:7:9: 7:10 - let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15 - let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:14 - let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 - let _6: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 - let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 - let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 - let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 - let _10: u32; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15 - let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:8:8: 8:9 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:8:9: 8:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:14 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9 scope 1 { - debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10 + debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 } scope 2 { - debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15 + debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 scope 3 { scope 7 { debug t => ((_0 as Err).0: i32); // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL } scope 8 { debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:14: 8:15 } } } scope 4 { - debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15 + debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 scope 5 { } } @@ -38,24 +38,24 @@ fn try_identity(_1: std::result::Result) -> std::result::Result bb1; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + goto -> bb1; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 } bb1: { - _0 = move _3; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10 - StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:7:15: 7:16 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:9:1: 9:2 - goto -> bb2; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2 + _0 = move _3; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 + goto -> bb2; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 } bb2: { - return; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2 + return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 } } diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir b/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir index a25472f6a5e05..508f2705d0701 100644 --- a/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir +++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir @@ -1,13 +1,13 @@ // MIR for `try_identity` after SimplifyLocals fn try_identity(_1: std::result::Result) -> std::result::Result { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:6:17: 6:18 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:6:41: 6:57 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57 scope 1 { - debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10 + debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 } scope 2 { - debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15 + debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 scope 3 { scope 7 { debug t => ((_0 as Err).0: i32); // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL @@ -18,7 +18,7 @@ fn try_identity(_1: std::result::Result) -> std::result::Result ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15 + debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 scope 5 { } } @@ -27,7 +27,7 @@ fn try_identity(_1: std::result::Result) -> std::result::Result Date: Sat, 19 Sep 2020 09:58:13 -0400 Subject: [PATCH 1052/1052] Remove unnecessary -Zunsound-mir-opts uses in tests --- src/test/mir-opt/inline/inline-any-operand.rs | 2 +- .../mir-opt/inline/inline-trait-method_2.rs | 2 +- .../inline_any_operand.bar.Inline.after.mir | 28 +++-- ...line_trait_method_2.test2.Inline.after.mir | 6 +- src/test/mir-opt/nrvo-simple.rs | 2 +- ...ocals-removes-unused-discriminant-reads.rs | 2 - ...minant_reads.map.SimplifyLocals.32bit.diff | 30 +++--- ...minant_reads.map.SimplifyLocals.64bit.diff | 30 +++--- src/test/mir-opt/simplify_try.rs | 1 - ...y.try_identity.DestinationPropagation.diff | 70 ++++++------ ..._try.try_identity.SimplifyArmIdentity.diff | 102 +++++++++--------- ....try_identity.SimplifyBranchSame.after.mir | 56 +++++----- ..._try.try_identity.SimplifyLocals.after.mir | 14 +-- 13 files changed, 177 insertions(+), 168 deletions(-) diff --git a/src/test/mir-opt/inline/inline-any-operand.rs b/src/test/mir-opt/inline/inline-any-operand.rs index feac14eccd85f..fb0de020f73a2 100644 --- a/src/test/mir-opt/inline/inline-any-operand.rs +++ b/src/test/mir-opt/inline/inline-any-operand.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z span_free_formats -Zunsound-mir-opts +// compile-flags: -Z span_free_formats // Tests that MIR inliner works for any operand diff --git a/src/test/mir-opt/inline/inline-trait-method_2.rs b/src/test/mir-opt/inline/inline-trait-method_2.rs index 9626ba123aadb..6e5de8315a1cb 100644 --- a/src/test/mir-opt/inline/inline-trait-method_2.rs +++ b/src/test/mir-opt/inline/inline-trait-method_2.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z span_free_formats -Z mir-opt-level=3 -Zunsound-mir-opts +// compile-flags: -Z span_free_formats -Z mir-opt-level=3 // EMIT_MIR inline_trait_method_2.test2.Inline.after.mir fn test2(x: &dyn X) -> bool { diff --git a/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir b/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir index 756f31315f18a..4d623297f8d68 100644 --- a/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir @@ -4,13 +4,15 @@ fn bar() -> bool { let mut _0: bool; // return place in scope 0 at $DIR/inline-any-operand.rs:10:13: 10:17 let _1: fn(i32, i32) -> bool {foo}; // in scope 0 at $DIR/inline-any-operand.rs:11:9: 11:10 let mut _2: fn(i32, i32) -> bool {foo}; // in scope 0 at $DIR/inline-any-operand.rs:12:5: 12:6 - let mut _3: i32; // in scope 0 at $DIR/inline-any-operand.rs:12:5: 12:13 - let mut _4: i32; // in scope 0 at $DIR/inline-any-operand.rs:12:5: 12:13 + let mut _5: i32; // in scope 0 at $DIR/inline-any-operand.rs:12:5: 12:13 + let mut _6: i32; // in scope 0 at $DIR/inline-any-operand.rs:12:5: 12:13 scope 1 { debug f => _1; // in scope 1 at $DIR/inline-any-operand.rs:11:9: 11:10 scope 2 { - debug x => _3; // in scope 2 at $DIR/inline-any-operand.rs:16:8: 16:9 - debug y => _4; // in scope 2 at $DIR/inline-any-operand.rs:16:16: 16:17 + debug x => _5; // in scope 2 at $DIR/inline-any-operand.rs:16:8: 16:9 + debug y => _6; // in scope 2 at $DIR/inline-any-operand.rs:16:16: 16:17 + let mut _3: i32; // in scope 2 at $DIR/inline-any-operand.rs:12:5: 12:13 + let mut _4: i32; // in scope 2 at $DIR/inline-any-operand.rs:12:5: 12:13 } } @@ -22,13 +24,19 @@ fn bar() -> bool { // + literal: Const { ty: fn(i32, i32) -> bool {foo}, val: Value(Scalar()) } StorageLive(_2); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6 _2 = _1; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6 - StorageLive(_3); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 - _3 = const 1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 - StorageLive(_4); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 - _4 = const -1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + StorageLive(_5); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + _5 = const 1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + StorageLive(_6); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + _6 = const -1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + StorageLive(_3); // scope 2 at $DIR/inline-any-operand.rs:17:5: 17:6 + _3 = _5; // scope 2 at $DIR/inline-any-operand.rs:17:5: 17:6 + StorageLive(_4); // scope 2 at $DIR/inline-any-operand.rs:17:10: 17:11 + _4 = _6; // scope 2 at $DIR/inline-any-operand.rs:17:10: 17:11 _0 = Eq(move _3, move _4); // scope 2 at $DIR/inline-any-operand.rs:17:5: 17:11 - StorageDead(_4); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 - StorageDead(_3); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + StorageDead(_4); // scope 2 at $DIR/inline-any-operand.rs:17:10: 17:11 + StorageDead(_3); // scope 2 at $DIR/inline-any-operand.rs:17:10: 17:11 + StorageDead(_6); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + StorageDead(_5); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 StorageDead(_2); // scope 1 at $DIR/inline-any-operand.rs:12:12: 12:13 StorageDead(_1); // scope 0 at $DIR/inline-any-operand.rs:13:1: 13:2 return; // scope 0 at $DIR/inline-any-operand.rs:13:2: 13:2 diff --git a/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir b/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir index 00e3ef06a49e6..09546205962a4 100644 --- a/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir @@ -7,6 +7,7 @@ fn test2(_1: &dyn X) -> bool { let mut _3: &dyn X; // in scope 0 at $DIR/inline-trait-method_2.rs:5:10: 5:11 scope 1 { debug x => _2; // in scope 1 at $DIR/inline-trait-method_2.rs:9:9: 9:10 + let mut _4: &dyn X; // in scope 1 at $DIR/inline-trait-method_2.rs:5:5: 5:12 } bb0: { @@ -15,13 +16,16 @@ fn test2(_1: &dyn X) -> bool { _3 = &(*_1); // scope 0 at $DIR/inline-trait-method_2.rs:5:10: 5:11 _2 = move _3 as &dyn X (Pointer(Unsize)); // scope 0 at $DIR/inline-trait-method_2.rs:5:10: 5:11 StorageDead(_3); // scope 0 at $DIR/inline-trait-method_2.rs:5:10: 5:11 - _0 = ::y(move _2) -> bb1; // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:10 + StorageLive(_4); // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:6 + _4 = _2; // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:6 + _0 = ::y(move _4) -> bb1; // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:10 // mir::Constant // + span: $DIR/inline-trait-method_2.rs:10:7: 10:8 // + literal: Const { ty: for<'r> fn(&'r dyn X) -> bool {::y}, val: Value(Scalar()) } } bb1: { + StorageDead(_4); // scope 1 at $DIR/inline-trait-method_2.rs:10:9: 10:10 StorageDead(_2); // scope 0 at $DIR/inline-trait-method_2.rs:5:11: 5:12 return; // scope 0 at $DIR/inline-trait-method_2.rs:6:2: 6:2 } diff --git a/src/test/mir-opt/nrvo-simple.rs b/src/test/mir-opt/nrvo-simple.rs index 22b18b107701e..ab46d7b94c72c 100644 --- a/src/test/mir-opt/nrvo-simple.rs +++ b/src/test/mir-opt/nrvo-simple.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmir-opt-level=1 -Zunsound-mir-opts +// compile-flags: -Zmir-opt-level=1 // EMIT_MIR nrvo_simple.nrvo.RenameReturnPlace.diff fn nrvo(init: fn(&mut [u8; 1024])) -> [u8; 1024] { diff --git a/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs b/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs index 84f57deccf7e0..cf8940ec33096 100644 --- a/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs +++ b/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs @@ -1,5 +1,3 @@ -// compile-flags: -Zunsound-mir-opts - fn map(x: Option>) -> Option> { match x { None => None, diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff index 760fb747f7229..68a113f94efda 100644 --- a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff +++ b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff @@ -2,25 +2,25 @@ + // MIR for `map` after SimplifyLocals fn map(_1: Option>) -> Option> { - debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:8: 3:9 - let mut _0: std::option::Option>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:31: 3:46 -- let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 -- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15 -- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:25: 6:26 -- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 -- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 -- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 + debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:8: 1:9 + let mut _0: std::option::Option>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:31: 1:46 +- let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 +- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15 +- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:25: 4:26 +- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 +- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 +- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 scope 1 { - debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15 + debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15 } bb0: { -- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 -- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 -- _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 - _0 = move _1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:20: 6:27 -- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 - return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:2: 8:2 +- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 +- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 +- _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 + _0 = move _1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:20: 4:27 +- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 + return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff index 760fb747f7229..68a113f94efda 100644 --- a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff +++ b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff @@ -2,25 +2,25 @@ + // MIR for `map` after SimplifyLocals fn map(_1: Option>) -> Option> { - debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:8: 3:9 - let mut _0: std::option::Option>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:31: 3:46 -- let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 -- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15 -- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:25: 6:26 -- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 -- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 -- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 + debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:8: 1:9 + let mut _0: std::option::Option>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:31: 1:46 +- let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 +- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15 +- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:25: 4:26 +- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 +- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 +- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 scope 1 { - debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15 + debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15 } bb0: { -- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 -- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 -- _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 - _0 = move _1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:20: 6:27 -- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 - return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:2: 8:2 +- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 +- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 +- _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 + _0 = move _1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:20: 4:27 +- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 + return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/simplify_try.rs b/src/test/mir-opt/simplify_try.rs index eb307de20744a..fca80bee89679 100644 --- a/src/test/mir-opt/simplify_try.rs +++ b/src/test/mir-opt/simplify_try.rs @@ -1,4 +1,3 @@ -// compile-flags: -Zunsound-mir-opts // EMIT_MIR simplify_try.try_identity.SimplifyArmIdentity.diff // EMIT_MIR simplify_try.try_identity.SimplifyBranchSame.after.mir // EMIT_MIR simplify_try.try_identity.SimplifyLocals.after.mir diff --git a/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff b/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff index b3a2b6fbf76b2..187a3cfbb896d 100644 --- a/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff +++ b/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff @@ -2,35 +2,35 @@ + // MIR for `try_identity` after DestinationPropagation fn try_identity(_1: std::result::Result) -> std::result::Result { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57 - let _2: u32; // in scope 0 at $DIR/simplify_try.rs:8:9: 8:10 - let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 - let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:14 - let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let _6: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let _10: u32; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 - let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:6:17: 6:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:6:41: 6:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:7:9: 7:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:14 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:8:8: 8:9 scope 1 { - debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 + debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10 } scope 2 { - debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 + debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15 scope 3 { scope 7 { debug t => ((_0 as Err).0: i32); // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL } scope 8 { debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:7:14: 7:15 } } } scope 4 { - debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 + debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15 scope 5 { } } @@ -40,33 +40,33 @@ } bb0: { - StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:8:9: 8:10 -- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 -- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 -- _4 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 + StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:7:9: 7:10 +- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:7:13: 7:15 +- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 +- _4 = _1; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 - _3 = move _4; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL -- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 -- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 -+ nop; // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 -+ nop; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 -+ _0 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 +- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 +- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:7:13: 7:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 ++ _0 = _1; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 + nop; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL -+ nop; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 -+ _5 = discriminant(_0); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - goto -> bb1; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 ++ _5 = discriminant(_0); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + goto -> bb1; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 } bb1: { -- _0 = move _3; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 -- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 -+ nop; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 -+ nop; // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 - goto -> bb2; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 +- _0 = move _3; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10 +- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:7:15: 7:16 ++ nop; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10 ++ nop; // scope 0 at $DIR/simplify_try.rs:7:15: 7:16 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:9:1: 9:2 + goto -> bb2; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2 } bb2: { - return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 + return; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff index 14a4318c1bc6f..0c687684c508e 100644 --- a/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff @@ -2,25 +2,25 @@ + // MIR for `try_identity` after SimplifyArmIdentity fn try_identity(_1: std::result::Result) -> std::result::Result { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57 - let _2: u32; // in scope 0 at $DIR/simplify_try.rs:8:9: 8:10 - let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 - let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:14 - let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let _6: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let _10: u32; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 - let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:6:17: 6:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:6:41: 6:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:7:9: 7:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:14 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:8:8: 8:9 scope 1 { -- debug y => _2; // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 -+ debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 +- debug y => _2; // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10 ++ debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10 } scope 2 { -- debug err => _6; // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 -+ debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 +- debug err => _6; // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15 ++ debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15 scope 3 { scope 7 { - debug t => _9; // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL @@ -29,13 +29,13 @@ scope 8 { - debug v => _8; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL + debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:7:14: 7:15 } } } scope 4 { -- debug val => _10; // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 -+ debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 +- debug val => _10; // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15 ++ debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15 scope 5 { } } @@ -44,55 +44,55 @@ } bb0: { - StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:8:9: 8:10 - StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 - StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 - _4 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 + StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:7:9: 7:10 + StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:7:13: 7:15 + StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 + _4 = _1; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 _3 = move _4; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 } bb1: { -- StorageLive(_10); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 -- _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 -- _2 = _10; // scope 5 at $DIR/simplify_try.rs:8:13: 8:15 -- StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 -+ _0 = move _3; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 - StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 -- StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:9:8: 9:9 -- _11 = _2; // scope 1 at $DIR/simplify_try.rs:9:8: 9:9 -- ((_0 as Ok).0: u32) = move _11; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 -- discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 -- StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:9:9: 9:10 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 - goto -> bb3; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 +- StorageLive(_10); // scope 0 at $DIR/simplify_try.rs:7:13: 7:15 +- _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:7:13: 7:15 +- _2 = _10; // scope 5 at $DIR/simplify_try.rs:7:13: 7:15 +- StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 ++ _0 = move _3; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:7:15: 7:16 +- StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:8:8: 8:9 +- _11 = _2; // scope 1 at $DIR/simplify_try.rs:8:8: 8:9 +- ((_0 as Ok).0: u32) = move _11; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10 +- discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10 +- StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:8:9: 8:10 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:9:1: 9:2 + goto -> bb3; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2 } bb2: { -- StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 -- _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 -- StorageLive(_8); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 -- StorageLive(_9); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 -- _9 = _6; // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 +- StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 +- _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 +- StorageLive(_8); // scope 3 at $DIR/simplify_try.rs:7:14: 7:15 +- StorageLive(_9); // scope 3 at $DIR/simplify_try.rs:7:14: 7:15 +- _9 = _6; // scope 3 at $DIR/simplify_try.rs:7:14: 7:15 - _8 = move _9; // scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL -- StorageDead(_9); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 +- StorageDead(_9); // scope 3 at $DIR/simplify_try.rs:7:14: 7:15 - StorageLive(_12); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - _12 = move _8; // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - ((_0 as Err).0: i32) = move _12; // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - discriminant(_0) = 1; // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_12); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL -- StorageDead(_8); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 -- StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 +- StorageDead(_8); // scope 3 at $DIR/simplify_try.rs:7:14: 7:15 +- StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + _0 = move _3; // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 - goto -> bb3; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:7:15: 7:16 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:9:1: 9:2 + goto -> bb3; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 } bb3: { - return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 + return; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir b/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir index 0ae89b855ba28..9428d305c8731 100644 --- a/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir +++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir @@ -1,35 +1,35 @@ // MIR for `try_identity` after SimplifyBranchSame fn try_identity(_1: std::result::Result) -> std::result::Result { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57 - let _2: u32; // in scope 0 at $DIR/simplify_try.rs:8:9: 8:10 - let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 - let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:14 - let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let _6: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let _10: u32; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 - let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:6:17: 6:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:6:41: 6:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:7:9: 7:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:14 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:8:8: 8:9 scope 1 { - debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 + debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10 } scope 2 { - debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 + debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15 scope 3 { scope 7 { debug t => ((_0 as Err).0: i32); // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL } scope 8 { debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:7:14: 7:15 } } } scope 4 { - debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 + debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15 scope 5 { } } @@ -38,24 +38,24 @@ fn try_identity(_1: std::result::Result) -> std::result::Result bb1; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + goto -> bb1; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 } bb1: { - _0 = move _3; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 - StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 - goto -> bb2; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 + _0 = move _3; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:7:15: 7:16 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:9:1: 9:2 + goto -> bb2; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2 } bb2: { - return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 + return; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir b/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir index 508f2705d0701..a25472f6a5e05 100644 --- a/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir +++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir @@ -1,13 +1,13 @@ // MIR for `try_identity` after SimplifyLocals fn try_identity(_1: std::result::Result) -> std::result::Result { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:6:17: 6:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:6:41: 6:57 scope 1 { - debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 + debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10 } scope 2 { - debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 + debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15 scope 3 { scope 7 { debug t => ((_0 as Err).0: i32); // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL @@ -18,7 +18,7 @@ fn try_identity(_1: std::result::Result) -> std::result::Result ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 + debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15 scope 5 { } } @@ -27,7 +27,7 @@ fn try_identity(_1: std::result::Result) -> std::result::Result

(&mut self, mut predicate: P) -> Option where - P: FnMut(Self::Item) -> bool, - Self: Sized + ExactSizeIterator + DoubleEndedIterator - { - let n = len!(self); - let mut i = n; - while let Some(x) = self.next_back() { - i -= 1; - if predicate(x) { - // SAFETY: `i` must be lower than `n` since it starts at `n` - // and is only decreasing. - unsafe { assume(i < n) }; - return Some(i); - } - } - None - } - - #[doc(hidden)] - unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { - // SAFETY: the caller must guarantee that `i` is in bounds of - // the underlying slice, so `i` cannot overflow an `isize`, and - // the returned references is guaranteed to refer to an element - // of the slice and thus guaranteed to be valid. - // - // Also note that the caller also guarantees that we're never - // called with the same index again, and that no other methods - // that will access this subslice are called, so it is valid - // for the returned reference to be mutable in the case of - // `IterMut` - unsafe { & $( $mut_ )? * self.ptr.as_ptr().add(idx) } - } - - $($extra)* - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, T> DoubleEndedIterator for $name<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<$elem> { - // could be implemented with slices, but this avoids bounds checks - - // SAFETY: `assume` calls are safe since a slice's start pointer must be non-null, - // and slices over non-ZSTs must also have a non-null end pointer. - // The call to `next_back_unchecked!` is safe since we check if the iterator is - // empty first. - unsafe { - assume(!self.ptr.as_ptr().is_null()); - if mem::size_of::() != 0 { - assume(!self.end.is_null()); - } - if is_empty!(self) { - None - } else { - Some(next_back_unchecked!(self)) - } - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option<$elem> { - if n >= len!(self) { - // This iterator is now empty. - self.end = self.ptr.as_ptr(); - return None; - } - // SAFETY: We are in bounds. `pre_dec_end` does the right thing even for ZSTs. - unsafe { - self.pre_dec_end(n as isize); - Some(next_back_unchecked!(self)) - } - } - } - - #[stable(feature = "fused", since = "1.26.0")] - impl FusedIterator for $name<'_, T> {} - - #[unstable(feature = "trusted_len", issue = "37572")] - unsafe impl TrustedLen for $name<'_, T> {} - } -} - -/// Immutable slice iterator -/// -/// This struct is created by the [`iter`] method on [slices]. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// // First, we declare a type which has `iter` method to get the `Iter` struct (&[usize here]): -/// let slice = &[1, 2, 3]; -/// -/// // Then, we iterate over it: -/// for element in slice.iter() { -/// println!("{}", element); -/// } -/// ``` -/// -/// [`iter`]: ../../std/primitive.slice.html#method.iter -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Iter<'a, T: 'a> { - ptr: NonNull, - end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that - // ptr == end is a quick test for the Iterator being empty, that works - // for both ZST and non-ZST. - _marker: marker::PhantomData<&'a T>, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for Iter<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Iter").field(&self.as_slice()).finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Sync for Iter<'_, T> {} -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Send for Iter<'_, T> {} - -impl<'a, T> Iter<'a, T> { - /// Views the underlying data as a subslice of the original data. - /// - /// This has the same lifetime as the original slice, and so the - /// iterator can continue to be used while this exists. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// // First, we declare a type which has the `iter` method to get the `Iter` - /// // struct (&[usize here]): - /// let slice = &[1, 2, 3]; - /// - /// // Then, we get the iterator: - /// let mut iter = slice.iter(); - /// // So if we print what `as_slice` method returns here, we have "[1, 2, 3]": - /// println!("{:?}", iter.as_slice()); - /// - /// // Next, we move to the second element of the slice: - /// iter.next(); - /// // Now `as_slice` returns "[2, 3]": - /// println!("{:?}", iter.as_slice()); - /// ``` - #[stable(feature = "iter_to_slice", since = "1.4.0")] - pub fn as_slice(&self) -> &'a [T] { - self.make_slice() - } -} - -iterator! {struct Iter -> *const T, &'a T, const, {/* no mut */}, { - fn is_sorted_by(self, mut compare: F) -> bool - where - Self: Sized, - F: FnMut(&Self::Item, &Self::Item) -> Option, - { - self.as_slice().windows(2).all(|w| { - compare(&&w[0], &&w[1]).map(|o| o != Ordering::Greater).unwrap_or(false) - }) - } -}} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Iter<'_, T> { - fn clone(&self) -> Self { - Iter { ptr: self.ptr, end: self.end, _marker: self._marker } - } -} - -#[stable(feature = "slice_iter_as_ref", since = "1.13.0")] -impl AsRef<[T]> for Iter<'_, T> { - fn as_ref(&self) -> &[T] { - self.as_slice() - } -} - -/// Mutable slice iterator. -/// -/// This struct is created by the [`iter_mut`] method on [slices]. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// // First, we declare a type which has `iter_mut` method to get the `IterMut` -/// // struct (&[usize here]): -/// let mut slice = &mut [1, 2, 3]; -/// -/// // Then, we iterate over it and increment each element value: -/// for element in slice.iter_mut() { -/// *element += 1; -/// } -/// -/// // We now have "[2, 3, 4]": -/// println!("{:?}", slice); -/// ``` -/// -/// [`iter_mut`]: ../../std/primitive.slice.html#method.iter_mut -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct IterMut<'a, T: 'a> { - ptr: NonNull, - end: *mut T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that - // ptr == end is a quick test for the Iterator being empty, that works - // for both ZST and non-ZST. - _marker: marker::PhantomData<&'a mut T>, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for IterMut<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("IterMut").field(&self.make_slice()).finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Sync for IterMut<'_, T> {} -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Send for IterMut<'_, T> {} - -impl<'a, T> IterMut<'a, T> { - /// Views the underlying data as a subslice of the original data. - /// - /// To avoid creating `&mut` references that alias, this is forced - /// to consume the iterator. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// // First, we declare a type which has `iter_mut` method to get the `IterMut` - /// // struct (&[usize here]): - /// let mut slice = &mut [1, 2, 3]; - /// - /// { - /// // Then, we get the iterator: - /// let mut iter = slice.iter_mut(); - /// // We move to next element: - /// iter.next(); - /// // So if we print what `into_slice` method returns here, we have "[2, 3]": - /// println!("{:?}", iter.into_slice()); - /// } - /// - /// // Now let's modify a value of the slice: - /// { - /// // First we get back the iterator: - /// let mut iter = slice.iter_mut(); - /// // We change the value of the first element of the slice returned by the `next` method: - /// *iter.next().unwrap() += 1; - /// } - /// // Now slice is "[2, 2, 3]": - /// println!("{:?}", slice); - /// ``` - #[stable(feature = "iter_to_slice", since = "1.4.0")] - pub fn into_slice(self) -> &'a mut [T] { - // SAFETY: the iterator was created from a mutable slice with pointer - // `self.ptr` and length `len!(self)`. This guarantees that all the prerequisites - // for `from_raw_parts_mut` are fulfilled. - unsafe { from_raw_parts_mut(self.ptr.as_ptr(), len!(self)) } - } - - /// Views the underlying data as a subslice of the original data. - /// - /// To avoid creating `&mut [T]` references that alias, the returned slice - /// borrows its lifetime from the iterator the method is applied on. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// # #![feature(slice_iter_mut_as_slice)] - /// let mut slice: &mut [usize] = &mut [1, 2, 3]; - /// - /// // First, we get the iterator: - /// let mut iter = slice.iter_mut(); - /// // So if we check what the `as_slice` method returns here, we have "[1, 2, 3]": - /// assert_eq!(iter.as_slice(), &[1, 2, 3]); - /// - /// // Next, we move to the second element of the slice: - /// iter.next(); - /// // Now `as_slice` returns "[2, 3]": - /// assert_eq!(iter.as_slice(), &[2, 3]); - /// ``` - #[unstable(feature = "slice_iter_mut_as_slice", reason = "recently added", issue = "58957")] - pub fn as_slice(&self) -> &[T] { - self.make_slice() - } -} - -iterator! {struct IterMut -> *mut T, &'a mut T, mut, {mut}, {}} - -/// An internal abstraction over the splitting iterators, so that -/// splitn, splitn_mut etc can be implemented once. -#[doc(hidden)] -trait SplitIter: DoubleEndedIterator { - /// Marks the underlying iterator as complete, extracting the remaining - /// portion of the slice. - fn finish(&mut self) -> Option; -} - -/// An iterator over subslices separated by elements that match a predicate -/// function. -/// -/// This struct is created by the [`split`] method on [slices]. -/// -/// [`split`]: ../../std/primitive.slice.html#method.split -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Split<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - v: &'a [T], - pred: P, - finished: bool, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for Split<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Split").field("v", &self.v).field("finished", &self.finished).finish() - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Split<'_, T, P> -where - P: Clone + FnMut(&T) -> bool, -{ - fn clone(&self) -> Self { - Split { v: self.v, pred: self.pred.clone(), finished: self.finished } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, P> Iterator for Split<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - if self.finished { - return None; - } - - match self.v.iter().position(|x| (self.pred)(x)) { - None => self.finish(), - Some(idx) => { - let ret = Some(&self.v[..idx]); - self.v = &self.v[idx + 1..]; - ret - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.finished { (0, Some(0)) } else { (1, Some(self.v.len() + 1)) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, P> DoubleEndedIterator for Split<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.finished { - return None; - } - - match self.v.iter().rposition(|x| (self.pred)(x)) { - None => self.finish(), - Some(idx) => { - let ret = Some(&self.v[idx + 1..]); - self.v = &self.v[..idx]; - ret - } - } - } -} - -impl<'a, T, P> SplitIter for Split<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn finish(&mut self) -> Option<&'a [T]> { - if self.finished { - None - } else { - self.finished = true; - Some(self.v) - } - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Split<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An iterator over subslices separated by elements that match a predicate -/// function. Unlike `Split`, it contains the matched part as a terminator -/// of the subslice. -/// -/// This struct is created by the [`split_inclusive`] method on [slices]. -/// -/// [`split_inclusive`]: ../../std/primitive.slice.html#method.split_inclusive -/// [slices]: ../../std/primitive.slice.html -#[unstable(feature = "split_inclusive", issue = "72360")] -pub struct SplitInclusive<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - v: &'a [T], - pred: P, - finished: bool, -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl fmt::Debug for SplitInclusive<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitInclusive") - .field("v", &self.v) - .field("finished", &self.finished) - .finish() - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[unstable(feature = "split_inclusive", issue = "72360")] -impl Clone for SplitInclusive<'_, T, P> -where - P: Clone + FnMut(&T) -> bool, -{ - fn clone(&self) -> Self { - SplitInclusive { v: self.v, pred: self.pred.clone(), finished: self.finished } - } -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl<'a, T, P> Iterator for SplitInclusive<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - if self.finished { - return None; - } - - let idx = - self.v.iter().position(|x| (self.pred)(x)).map(|idx| idx + 1).unwrap_or(self.v.len()); - if idx == self.v.len() { - self.finished = true; - } - let ret = Some(&self.v[..idx]); - self.v = &self.v[idx..]; - ret - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.finished { (0, Some(0)) } else { (1, Some(self.v.len() + 1)) } - } -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl<'a, T, P> DoubleEndedIterator for SplitInclusive<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.finished { - return None; - } - - // The last index of self.v is already checked and found to match - // by the last iteration, so we start searching a new match - // one index to the left. - let remainder = if self.v.is_empty() { &[] } else { &self.v[..(self.v.len() - 1)] }; - let idx = remainder.iter().rposition(|x| (self.pred)(x)).map(|idx| idx + 1).unwrap_or(0); - if idx == 0 { - self.finished = true; - } - let ret = Some(&self.v[idx..]); - self.v = &self.v[..idx]; - ret - } -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl FusedIterator for SplitInclusive<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An iterator over the mutable subslices of the vector which are separated -/// by elements that match `pred`. -/// -/// This struct is created by the [`split_mut`] method on [slices]. -/// -/// [`split_mut`]: ../../std/primitive.slice.html#method.split_mut -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct SplitMut<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - v: &'a mut [T], - pred: P, - finished: bool, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for SplitMut<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitMut").field("v", &self.v).field("finished", &self.finished).finish() - } -} - -impl<'a, T, P> SplitIter for SplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn finish(&mut self) -> Option<&'a mut [T]> { - if self.finished { - None - } else { - self.finished = true; - Some(mem::replace(&mut self.v, &mut [])) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, P> Iterator for SplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - if self.finished { - return None; - } - - let idx_opt = { - // work around borrowck limitations - let pred = &mut self.pred; - self.v.iter().position(|x| (*pred)(x)) - }; - match idx_opt { - None => self.finish(), - Some(idx) => { - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(idx); - self.v = &mut tail[1..]; - Some(head) - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.finished { - (0, Some(0)) - } else { - // if the predicate doesn't match anything, we yield one slice - // if it matches every element, we yield len+1 empty slices. - (1, Some(self.v.len() + 1)) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, P> DoubleEndedIterator for SplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - if self.finished { - return None; - } - - let idx_opt = { - // work around borrowck limitations - let pred = &mut self.pred; - self.v.iter().rposition(|x| (*pred)(x)) - }; - match idx_opt { - None => self.finish(), - Some(idx) => { - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(idx); - self.v = head; - Some(&mut tail[1..]) - } - } - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for SplitMut<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An iterator over the mutable subslices of the vector which are separated -/// by elements that match `pred`. Unlike `SplitMut`, it contains the matched -/// parts in the ends of the subslices. -/// -/// This struct is created by the [`split_inclusive_mut`] method on [slices]. -/// -/// [`split_inclusive_mut`]: ../../std/primitive.slice.html#method.split_inclusive_mut -/// [slices]: ../../std/primitive.slice.html -#[unstable(feature = "split_inclusive", issue = "72360")] -pub struct SplitInclusiveMut<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - v: &'a mut [T], - pred: P, - finished: bool, -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl fmt::Debug for SplitInclusiveMut<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitInclusiveMut") - .field("v", &self.v) - .field("finished", &self.finished) - .finish() - } -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl<'a, T, P> Iterator for SplitInclusiveMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - if self.finished { - return None; - } - - let idx_opt = { - // work around borrowck limitations - let pred = &mut self.pred; - self.v.iter().position(|x| (*pred)(x)) - }; - let idx = idx_opt.map(|idx| idx + 1).unwrap_or(self.v.len()); - if idx == self.v.len() { - self.finished = true; - } - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(idx); - self.v = tail; - Some(head) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.finished { - (0, Some(0)) - } else { - // if the predicate doesn't match anything, we yield one slice - // if it matches every element, we yield len+1 empty slices. - (1, Some(self.v.len() + 1)) - } - } -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl<'a, T, P> DoubleEndedIterator for SplitInclusiveMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - if self.finished { - return None; - } - - let idx_opt = if self.v.is_empty() { - None - } else { - // work around borrowck limitations - let pred = &mut self.pred; - - // The last index of self.v is already checked and found to match - // by the last iteration, so we start searching a new match - // one index to the left. - let remainder = &self.v[..(self.v.len() - 1)]; - remainder.iter().rposition(|x| (*pred)(x)) - }; - let idx = idx_opt.map(|idx| idx + 1).unwrap_or(0); - if idx == 0 { - self.finished = true; - } - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(idx); - self.v = head; - Some(tail) - } -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl FusedIterator for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An iterator over subslices separated by elements that match a predicate -/// function, starting from the end of the slice. -/// -/// This struct is created by the [`rsplit`] method on [slices]. -/// -/// [`rsplit`]: ../../std/primitive.slice.html#method.rsplit -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "slice_rsplit", since = "1.27.0")] -#[derive(Clone)] // Is this correct, or does it incorrectly require `T: Clone`? -pub struct RSplit<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: Split<'a, T, P>, -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl fmt::Debug for RSplit<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RSplit") - .field("v", &self.inner.v) - .field("finished", &self.inner.finished) - .finish() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> Iterator for RSplit<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - self.inner.next_back() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> DoubleEndedIterator for RSplit<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - self.inner.next() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> SplitIter for RSplit<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn finish(&mut self) -> Option<&'a [T]> { - self.inner.finish() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl FusedIterator for RSplit<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An iterator over the subslices of the vector which are separated -/// by elements that match `pred`, starting from the end of the slice. -/// -/// This struct is created by the [`rsplit_mut`] method on [slices]. -/// -/// [`rsplit_mut`]: ../../std/primitive.slice.html#method.rsplit_mut -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "slice_rsplit", since = "1.27.0")] -pub struct RSplitMut<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: SplitMut<'a, T, P>, -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl fmt::Debug for RSplitMut<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RSplitMut") - .field("v", &self.inner.v) - .field("finished", &self.inner.finished) - .finish() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> SplitIter for RSplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn finish(&mut self) -> Option<&'a mut [T]> { - self.inner.finish() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> Iterator for RSplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - self.inner.next_back() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - self.inner.next() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl FusedIterator for RSplitMut<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An private iterator over subslices separated by elements that -/// match a predicate function, splitting at most a fixed number of -/// times. -#[derive(Debug)] -struct GenericSplitN { - iter: I, - count: usize, -} - -impl> Iterator for GenericSplitN { - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - match self.count { - 0 => None, - 1 => { - self.count -= 1; - self.iter.finish() - } - _ => { - self.count -= 1; - self.iter.next() - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (lower, upper_opt) = self.iter.size_hint(); - (lower, upper_opt.map(|upper| cmp::min(self.count, upper))) - } -} - -/// An iterator over subslices separated by elements that match a predicate -/// function, limited to a given number of splits. -/// -/// This struct is created by the [`splitn`] method on [slices]. -/// -/// [`splitn`]: ../../std/primitive.slice.html#method.splitn -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct SplitN<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: GenericSplitN>, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for SplitN<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitN").field("inner", &self.inner).finish() - } -} - -/// An iterator over subslices separated by elements that match a -/// predicate function, limited to a given number of splits, starting -/// from the end of the slice. -/// -/// This struct is created by the [`rsplitn`] method on [slices]. -/// -/// [`rsplitn`]: ../../std/primitive.slice.html#method.rsplitn -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct RSplitN<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: GenericSplitN>, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for RSplitN<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RSplitN").field("inner", &self.inner).finish() - } -} - -/// An iterator over subslices separated by elements that match a predicate -/// function, limited to a given number of splits. -/// -/// This struct is created by the [`splitn_mut`] method on [slices]. -/// -/// [`splitn_mut`]: ../../std/primitive.slice.html#method.splitn_mut -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct SplitNMut<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: GenericSplitN>, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for SplitNMut<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitNMut").field("inner", &self.inner).finish() - } -} - -/// An iterator over subslices separated by elements that match a -/// predicate function, limited to a given number of splits, starting -/// from the end of the slice. -/// -/// This struct is created by the [`rsplitn_mut`] method on [slices]. -/// -/// [`rsplitn_mut`]: ../../std/primitive.slice.html#method.rsplitn_mut -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct RSplitNMut<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: GenericSplitN>, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for RSplitNMut<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RSplitNMut").field("inner", &self.inner).finish() - } -} - -macro_rules! forward_iterator { - ($name:ident: $elem:ident, $iter_of:ty) => { - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, $elem, P> Iterator for $name<'a, $elem, P> - where - P: FnMut(&T) -> bool, - { - type Item = $iter_of; - - #[inline] - fn next(&mut self) -> Option<$iter_of> { - self.inner.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } - } - - #[stable(feature = "fused", since = "1.26.0")] - impl<'a, $elem, P> FusedIterator for $name<'a, $elem, P> where P: FnMut(&T) -> bool {} - }; -} - -forward_iterator! { SplitN: T, &'a [T] } -forward_iterator! { RSplitN: T, &'a [T] } -forward_iterator! { SplitNMut: T, &'a mut [T] } -forward_iterator! { RSplitNMut: T, &'a mut [T] } - -/// An iterator over overlapping subslices of length `size`. -/// -/// This struct is created by the [`windows`] method on [slices]. -/// -/// [`windows`]: ../../std/primitive.slice.html#method.windows -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Windows<'a, T: 'a> { - v: &'a [T], - size: usize, -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Windows<'_, T> { - fn clone(&self) -> Self { - Windows { v: self.v, size: self.size } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Iterator for Windows<'a, T> { - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - if self.size > self.v.len() { - None - } else { - let ret = Some(&self.v[..self.size]); - self.v = &self.v[1..]; - ret - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.size > self.v.len() { - (0, Some(0)) - } else { - let size = self.v.len() - self.size + 1; - (size, Some(size)) - } - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - let (end, overflow) = self.size.overflowing_add(n); - if end > self.v.len() || overflow { - self.v = &[]; - None - } else { - let nth = &self.v[n..end]; - self.v = &self.v[n + 1..]; - Some(nth) - } - } - - #[inline] - fn last(self) -> Option { - if self.size > self.v.len() { - None - } else { - let start = self.v.len() - self.size; - Some(&self.v[start..]) - } - } - - #[doc(hidden)] - unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { - // SAFETY: since the caller guarantees that `i` is in bounds, - // which means that `i` cannot overflow an `isize`, and the - // slice created by `from_raw_parts` is a subslice of `self.v` - // thus is guaranteed to be valid for the lifetime `'a` of `self.v`. - unsafe { from_raw_parts(self.v.as_ptr().add(idx), self.size) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> DoubleEndedIterator for Windows<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.size > self.v.len() { - None - } else { - let ret = Some(&self.v[self.v.len() - self.size..]); - self.v = &self.v[..self.v.len() - 1]; - ret - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let (end, overflow) = self.v.len().overflowing_sub(n); - if end < self.size || overflow { - self.v = &[]; - None - } else { - let ret = &self.v[end - self.size..end]; - self.v = &self.v[..end - 1]; - Some(ret) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Windows<'_, T> {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Windows<'_, T> {} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Windows<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for Windows<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a -/// time), starting at the beginning of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last slice -/// of the iteration will be the remainder. -/// -/// This struct is created by the [`chunks`] method on [slices]. -/// -/// [`chunks`]: ../../std/primitive.slice.html#method.chunks -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Chunks<'a, T: 'a> { - v: &'a [T], - chunk_size: usize, -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Chunks<'_, T> { - fn clone(&self) -> Self { - Chunks { v: self.v, chunk_size: self.chunk_size } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Iterator for Chunks<'a, T> { - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - if self.v.is_empty() { - None - } else { - let chunksz = cmp::min(self.v.len(), self.chunk_size); - let (fst, snd) = self.v.split_at(chunksz); - self.v = snd; - Some(fst) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.v.is_empty() { - (0, Some(0)) - } else { - let n = self.v.len() / self.chunk_size; - let rem = self.v.len() % self.chunk_size; - let n = if rem > 0 { n + 1 } else { n }; - (n, Some(n)) - } - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - let (start, overflow) = n.overflowing_mul(self.chunk_size); - if start >= self.v.len() || overflow { - self.v = &[]; - None - } else { - let end = match start.checked_add(self.chunk_size) { - Some(sum) => cmp::min(self.v.len(), sum), - None => self.v.len(), - }; - let nth = &self.v[start..end]; - self.v = &self.v[end..]; - Some(nth) - } - } - - #[inline] - fn last(self) -> Option { - if self.v.is_empty() { - None - } else { - let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size; - Some(&self.v[start..]) - } - } - - #[doc(hidden)] - unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { - let start = idx * self.chunk_size; - let end = match start.checked_add(self.chunk_size) { - None => self.v.len(), - Some(end) => cmp::min(end, self.v.len()), - }; - // SAFETY: the caller guarantees that `i` is in bounds, - // which means that `start` must be in bounds of the - // underlying `self.v` slice, and we made sure that `end` - // is also in bounds of `self.v`. Thus, `start` cannot overflow - // an `isize`, and the slice constructed by `from_raw_parts` - // is a subslice of `self.v` which is guaranteed to be valid - // for the lifetime `'a` of `self.v`. - unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> DoubleEndedIterator for Chunks<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.v.is_empty() { - None - } else { - let remainder = self.v.len() % self.chunk_size; - let chunksz = if remainder != 0 { remainder } else { self.chunk_size }; - let (fst, snd) = self.v.split_at(self.v.len() - chunksz); - self.v = fst; - Some(snd) - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.len(); - if n >= len { - self.v = &[]; - None - } else { - let start = (len - 1 - n) * self.chunk_size; - let end = match start.checked_add(self.chunk_size) { - Some(res) => cmp::min(res, self.v.len()), - None => self.v.len(), - }; - let nth_back = &self.v[start..end]; - self.v = &self.v[..start]; - Some(nth_back) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Chunks<'_, T> {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Chunks<'_, T> {} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Chunks<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for Chunks<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` -/// elements at a time), starting at the beginning of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last slice -/// of the iteration will be the remainder. -/// -/// This struct is created by the [`chunks_mut`] method on [slices]. -/// -/// [`chunks_mut`]: ../../std/primitive.slice.html#method.chunks_mut -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct ChunksMut<'a, T: 'a> { - v: &'a mut [T], - chunk_size: usize, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Iterator for ChunksMut<'a, T> { - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - if self.v.is_empty() { - None - } else { - let sz = cmp::min(self.v.len(), self.chunk_size); - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(sz); - self.v = tail; - Some(head) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.v.is_empty() { - (0, Some(0)) - } else { - let n = self.v.len() / self.chunk_size; - let rem = self.v.len() % self.chunk_size; - let n = if rem > 0 { n + 1 } else { n }; - (n, Some(n)) - } - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { - let (start, overflow) = n.overflowing_mul(self.chunk_size); - if start >= self.v.len() || overflow { - self.v = &mut []; - None - } else { - let end = match start.checked_add(self.chunk_size) { - Some(sum) => cmp::min(self.v.len(), sum), - None => self.v.len(), - }; - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(end); - let (_, nth) = head.split_at_mut(start); - self.v = tail; - Some(nth) - } - } - - #[inline] - fn last(self) -> Option { - if self.v.is_empty() { - None - } else { - let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size; - Some(&mut self.v[start..]) - } - } - - #[doc(hidden)] - unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { - let start = idx * self.chunk_size; - let end = match start.checked_add(self.chunk_size) { - None => self.v.len(), - Some(end) => cmp::min(end, self.v.len()), - }; - // SAFETY: see comments for `Chunks::get_unchecked`. - // - // Also note that the caller also guarantees that we're never called - // with the same index again, and that no other methods that will - // access this subslice are called, so it is valid for the returned - // slice to be mutable. - unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - if self.v.is_empty() { - None - } else { - let remainder = self.v.len() % self.chunk_size; - let sz = if remainder != 0 { remainder } else { self.chunk_size }; - let tmp = mem::replace(&mut self.v, &mut []); - let tmp_len = tmp.len(); - let (head, tail) = tmp.split_at_mut(tmp_len - sz); - self.v = head; - Some(tail) - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.len(); - if n >= len { - self.v = &mut []; - None - } else { - let start = (len - 1 - n) * self.chunk_size; - let end = match start.checked_add(self.chunk_size) { - Some(res) => cmp::min(res, self.v.len()), - None => self.v.len(), - }; - let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); - let (head, nth_back) = temp.split_at_mut(start); - self.v = head; - Some(nth_back) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for ChunksMut<'_, T> {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for ChunksMut<'_, T> {} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for ChunksMut<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a -/// time), starting at the beginning of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last -/// up to `chunk_size-1` elements will be omitted but can be retrieved from -/// the [`remainder`] function from the iterator. -/// -/// This struct is created by the [`chunks_exact`] method on [slices]. -/// -/// [`chunks_exact`]: ../../std/primitive.slice.html#method.chunks_exact -/// [`remainder`]: ChunksExact::remainder -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "chunks_exact", since = "1.31.0")] -pub struct ChunksExact<'a, T: 'a> { - v: &'a [T], - rem: &'a [T], - chunk_size: usize, -} - -impl<'a, T> ChunksExact<'a, T> { - /// Returns the remainder of the original slice that is not going to be - /// returned by the iterator. The returned slice has at most `chunk_size-1` - /// elements. - #[stable(feature = "chunks_exact", since = "1.31.0")] - pub fn remainder(&self) -> &'a [T] { - self.rem - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl Clone for ChunksExact<'_, T> { - fn clone(&self) -> Self { - ChunksExact { v: self.v, rem: self.rem, chunk_size: self.chunk_size } - } -} - -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl<'a, T> Iterator for ChunksExact<'a, T> { - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - if self.v.len() < self.chunk_size { - None - } else { - let (fst, snd) = self.v.split_at(self.chunk_size); - self.v = snd; - Some(fst) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let n = self.v.len() / self.chunk_size; - (n, Some(n)) - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - let (start, overflow) = n.overflowing_mul(self.chunk_size); - if start >= self.v.len() || overflow { - self.v = &[]; - None - } else { - let (_, snd) = self.v.split_at(start); - self.v = snd; - self.next() - } - } - - #[inline] - fn last(mut self) -> Option { - self.next_back() - } - - #[doc(hidden)] - unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { - let start = idx * self.chunk_size; - // SAFETY: mostly identical to `Chunks::get_unchecked`. - unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) } - } -} - -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl<'a, T> DoubleEndedIterator for ChunksExact<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.v.len() < self.chunk_size { - None - } else { - let (fst, snd) = self.v.split_at(self.v.len() - self.chunk_size); - self.v = fst; - Some(snd) - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.len(); - if n >= len { - self.v = &[]; - None - } else { - let start = (len - 1 - n) * self.chunk_size; - let end = start + self.chunk_size; - let nth_back = &self.v[start..end]; - self.v = &self.v[..start]; - Some(nth_back) - } - } -} - -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl ExactSizeIterator for ChunksExact<'_, T> { - fn is_empty(&self) -> bool { - self.v.is_empty() - } -} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for ChunksExact<'_, T> {} - -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl FusedIterator for ChunksExact<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` -/// elements at a time), starting at the beginning of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last up to -/// `chunk_size-1` elements will be omitted but can be retrieved from the -/// [`into_remainder`] function from the iterator. -/// -/// This struct is created by the [`chunks_exact_mut`] method on [slices]. -/// -/// [`chunks_exact_mut`]: ../../std/primitive.slice.html#method.chunks_exact_mut -/// [`into_remainder`]: ChunksExactMut::into_remainder -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "chunks_exact", since = "1.31.0")] -pub struct ChunksExactMut<'a, T: 'a> { - v: &'a mut [T], - rem: &'a mut [T], - chunk_size: usize, -} - -impl<'a, T> ChunksExactMut<'a, T> { - /// Returns the remainder of the original slice that is not going to be - /// returned by the iterator. The returned slice has at most `chunk_size-1` - /// elements. - #[stable(feature = "chunks_exact", since = "1.31.0")] - pub fn into_remainder(self) -> &'a mut [T] { - self.rem - } -} - -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl<'a, T> Iterator for ChunksExactMut<'a, T> { - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - if self.v.len() < self.chunk_size { - None - } else { - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(self.chunk_size); - self.v = tail; - Some(head) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let n = self.v.len() / self.chunk_size; - (n, Some(n)) - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { - let (start, overflow) = n.overflowing_mul(self.chunk_size); - if start >= self.v.len() || overflow { - self.v = &mut []; - None - } else { - let tmp = mem::replace(&mut self.v, &mut []); - let (_, snd) = tmp.split_at_mut(start); - self.v = snd; - self.next() - } - } - - #[inline] - fn last(mut self) -> Option { - self.next_back() - } - - #[doc(hidden)] - unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { - let start = idx * self.chunk_size; - // SAFETY: see comments for `ChunksMut::get_unchecked`. - unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) } - } -} - -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - if self.v.len() < self.chunk_size { - None - } else { - let tmp = mem::replace(&mut self.v, &mut []); - let tmp_len = tmp.len(); - let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size); - self.v = head; - Some(tail) - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.len(); - if n >= len { - self.v = &mut []; - None - } else { - let start = (len - 1 - n) * self.chunk_size; - let end = start + self.chunk_size; - let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); - let (head, nth_back) = temp.split_at_mut(start); - self.v = head; - Some(nth_back) - } - } -} - -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl ExactSizeIterator for ChunksExactMut<'_, T> { - fn is_empty(&self) -> bool { - self.v.is_empty() - } -} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for ChunksExactMut<'_, T> {} - -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl FusedIterator for ChunksExactMut<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) chunks (`N` elements at a -/// time), starting at the beginning of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last -/// up to `N-1` elements will be omitted but can be retrieved from -/// the [`remainder`] function from the iterator. -/// -/// This struct is created by the [`array_chunks`] method on [slices]. -/// -/// [`array_chunks`]: ../../std/primitive.slice.html#method.array_chunks -/// [`remainder`]: ArrayChunks::remainder -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[unstable(feature = "array_chunks", issue = "74985")] -pub struct ArrayChunks<'a, T: 'a, const N: usize> { - iter: Iter<'a, [T; N]>, - rem: &'a [T], -} - -impl<'a, T, const N: usize> ArrayChunks<'a, T, N> { - /// Returns the remainder of the original slice that is not going to be - /// returned by the iterator. The returned slice has at most `N-1` - /// elements. - #[unstable(feature = "array_chunks", issue = "74985")] - pub fn remainder(&self) -> &'a [T] { - self.rem - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[unstable(feature = "array_chunks", issue = "74985")] -impl Clone for ArrayChunks<'_, T, N> { - fn clone(&self) -> Self { - ArrayChunks { iter: self.iter.clone(), rem: self.rem } - } -} - -#[unstable(feature = "array_chunks", issue = "74985")] -impl<'a, T, const N: usize> Iterator for ArrayChunks<'a, T, N> { - type Item = &'a [T; N]; - - #[inline] - fn next(&mut self) -> Option<&'a [T; N]> { - self.iter.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - #[inline] - fn count(self) -> usize { - self.iter.count() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - self.iter.nth(n) - } - - #[inline] - fn last(self) -> Option { - self.iter.last() - } - - unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T; N] { - // SAFETY: The safety guarantees of `get_unchecked` are transferred to - // the caller. - unsafe { self.iter.get_unchecked(i) } - } -} - -#[unstable(feature = "array_chunks", issue = "74985")] -impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunks<'a, T, N> { - #[inline] - fn next_back(&mut self) -> Option<&'a [T; N]> { - self.iter.next_back() - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - self.iter.nth_back(n) - } -} - -#[unstable(feature = "array_chunks", issue = "74985")] -impl ExactSizeIterator for ArrayChunks<'_, T, N> { - fn is_empty(&self) -> bool { - self.iter.is_empty() - } -} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for ArrayChunks<'_, T, N> {} - -#[unstable(feature = "array_chunks", issue = "74985")] -impl FusedIterator for ArrayChunks<'_, T, N> {} - -#[doc(hidden)] -#[unstable(feature = "array_chunks", issue = "74985")] -unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) mutable chunks (`N` elements -/// at a time), starting at the beginning of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last -/// up to `N-1` elements will be omitted but can be retrieved from -/// the [`into_remainder`] function from the iterator. -/// -/// This struct is created by the [`array_chunks_mut`] method on [slices]. -/// -/// [`array_chunks_mut`]: ../../std/primitive.slice.html#method.array_chunks_mut -/// [`into_remainder`]: ../../std/slice/struct.ArrayChunksMut.html#method.into_remainder -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[unstable(feature = "array_chunks", issue = "74985")] -pub struct ArrayChunksMut<'a, T: 'a, const N: usize> { - iter: IterMut<'a, [T; N]>, - rem: &'a mut [T], -} - -impl<'a, T, const N: usize> ArrayChunksMut<'a, T, N> { - /// Returns the remainder of the original slice that is not going to be - /// returned by the iterator. The returned slice has at most `N-1` - /// elements. - #[unstable(feature = "array_chunks", issue = "74985")] - pub fn into_remainder(self) -> &'a mut [T] { - self.rem - } -} - -#[unstable(feature = "array_chunks", issue = "74985")] -impl<'a, T, const N: usize> Iterator for ArrayChunksMut<'a, T, N> { - type Item = &'a mut [T; N]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T; N]> { - self.iter.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - #[inline] - fn count(self) -> usize { - self.iter.count() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - self.iter.nth(n) - } - - #[inline] - fn last(self) -> Option { - self.iter.last() - } - - unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T; N] { - // SAFETY: The safety guarantees of `get_unchecked` are transferred to - // the caller. - unsafe { self.iter.get_unchecked(i) } - } -} - -#[unstable(feature = "array_chunks", issue = "74985")] -impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunksMut<'a, T, N> { - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T; N]> { - self.iter.next_back() - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - self.iter.nth_back(n) - } -} - -#[unstable(feature = "array_chunks", issue = "74985")] -impl ExactSizeIterator for ArrayChunksMut<'_, T, N> { - fn is_empty(&self) -> bool { - self.iter.is_empty() - } -} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for ArrayChunksMut<'_, T, N> {} - -#[unstable(feature = "array_chunks", issue = "74985")] -impl FusedIterator for ArrayChunksMut<'_, T, N> {} - -#[doc(hidden)] -#[unstable(feature = "array_chunks", issue = "74985")] -unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunksMut<'a, T, N> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a -/// time), starting at the end of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last slice -/// of the iteration will be the remainder. -/// -/// This struct is created by the [`rchunks`] method on [slices]. -/// -/// [`rchunks`]: ../../std/primitive.slice.html#method.rchunks -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "rchunks", since = "1.31.0")] -pub struct RChunks<'a, T: 'a> { - v: &'a [T], - chunk_size: usize, -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "rchunks", since = "1.31.0")] -impl Clone for RChunks<'_, T> { - fn clone(&self) -> Self { - RChunks { v: self.v, chunk_size: self.chunk_size } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> Iterator for RChunks<'a, T> { - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - if self.v.is_empty() { - None - } else { - let chunksz = cmp::min(self.v.len(), self.chunk_size); - let (fst, snd) = self.v.split_at(self.v.len() - chunksz); - self.v = fst; - Some(snd) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.v.is_empty() { - (0, Some(0)) - } else { - let n = self.v.len() / self.chunk_size; - let rem = self.v.len() % self.chunk_size; - let n = if rem > 0 { n + 1 } else { n }; - (n, Some(n)) - } - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - let (end, overflow) = n.overflowing_mul(self.chunk_size); - if end >= self.v.len() || overflow { - self.v = &[]; - None - } else { - // Can't underflow because of the check above - let end = self.v.len() - end; - let start = match end.checked_sub(self.chunk_size) { - Some(sum) => sum, - None => 0, - }; - let nth = &self.v[start..end]; - self.v = &self.v[0..start]; - Some(nth) - } - } - - #[inline] - fn last(self) -> Option { - if self.v.is_empty() { - None - } else { - let rem = self.v.len() % self.chunk_size; - let end = if rem == 0 { self.chunk_size } else { rem }; - Some(&self.v[0..end]) - } - } - - #[doc(hidden)] - unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { - let end = self.v.len() - idx * self.chunk_size; - let start = match end.checked_sub(self.chunk_size) { - None => 0, - Some(start) => start, - }; - // SAFETY: mostly identical to `Chunks::get_unchecked`. - unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> DoubleEndedIterator for RChunks<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.v.is_empty() { - None - } else { - let remainder = self.v.len() % self.chunk_size; - let chunksz = if remainder != 0 { remainder } else { self.chunk_size }; - let (fst, snd) = self.v.split_at(chunksz); - self.v = snd; - Some(fst) - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.len(); - if n >= len { - self.v = &[]; - None - } else { - // can't underflow because `n < len` - let offset_from_end = (len - 1 - n) * self.chunk_size; - let end = self.v.len() - offset_from_end; - let start = end.saturating_sub(self.chunk_size); - let nth_back = &self.v[start..end]; - self.v = &self.v[end..]; - Some(nth_back) - } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl ExactSizeIterator for RChunks<'_, T> {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for RChunks<'_, T> {} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl FusedIterator for RChunks<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` -/// elements at a time), starting at the end of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last slice -/// of the iteration will be the remainder. -/// -/// This struct is created by the [`rchunks_mut`] method on [slices]. -/// -/// [`rchunks_mut`]: ../../std/primitive.slice.html#method.rchunks_mut -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "rchunks", since = "1.31.0")] -pub struct RChunksMut<'a, T: 'a> { - v: &'a mut [T], - chunk_size: usize, -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> Iterator for RChunksMut<'a, T> { - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - if self.v.is_empty() { - None - } else { - let sz = cmp::min(self.v.len(), self.chunk_size); - let tmp = mem::replace(&mut self.v, &mut []); - let tmp_len = tmp.len(); - let (head, tail) = tmp.split_at_mut(tmp_len - sz); - self.v = head; - Some(tail) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.v.is_empty() { - (0, Some(0)) - } else { - let n = self.v.len() / self.chunk_size; - let rem = self.v.len() % self.chunk_size; - let n = if rem > 0 { n + 1 } else { n }; - (n, Some(n)) - } - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { - let (end, overflow) = n.overflowing_mul(self.chunk_size); - if end >= self.v.len() || overflow { - self.v = &mut []; - None - } else { - // Can't underflow because of the check above - let end = self.v.len() - end; - let start = match end.checked_sub(self.chunk_size) { - Some(sum) => sum, - None => 0, - }; - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(start); - let (nth, _) = tail.split_at_mut(end - start); - self.v = head; - Some(nth) - } - } - - #[inline] - fn last(self) -> Option { - if self.v.is_empty() { - None - } else { - let rem = self.v.len() % self.chunk_size; - let end = if rem == 0 { self.chunk_size } else { rem }; - Some(&mut self.v[0..end]) - } - } - - #[doc(hidden)] - unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { - let end = self.v.len() - idx * self.chunk_size; - let start = match end.checked_sub(self.chunk_size) { - None => 0, - Some(start) => start, - }; - // SAFETY: see comments for `RChunks::get_unchecked` and `ChunksMut::get_unchecked` - unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - if self.v.is_empty() { - None - } else { - let remainder = self.v.len() % self.chunk_size; - let sz = if remainder != 0 { remainder } else { self.chunk_size }; - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(sz); - self.v = tail; - Some(head) - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.len(); - if n >= len { - self.v = &mut []; - None - } else { - // can't underflow because `n < len` - let offset_from_end = (len - 1 - n) * self.chunk_size; - let end = self.v.len() - offset_from_end; - let start = end.saturating_sub(self.chunk_size); - let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); - let (_, nth_back) = tmp.split_at_mut(start); - self.v = tail; - Some(nth_back) - } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl ExactSizeIterator for RChunksMut<'_, T> {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for RChunksMut<'_, T> {} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl FusedIterator for RChunksMut<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a -/// time), starting at the end of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last -/// up to `chunk_size-1` elements will be omitted but can be retrieved from -/// the [`remainder`] function from the iterator. -/// -/// This struct is created by the [`rchunks_exact`] method on [slices]. -/// -/// [`rchunks_exact`]: ../../std/primitive.slice.html#method.rchunks_exact -/// [`remainder`]: ChunksExact::remainder -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "rchunks", since = "1.31.0")] -pub struct RChunksExact<'a, T: 'a> { - v: &'a [T], - rem: &'a [T], - chunk_size: usize, -} - -impl<'a, T> RChunksExact<'a, T> { - /// Returns the remainder of the original slice that is not going to be - /// returned by the iterator. The returned slice has at most `chunk_size-1` - /// elements. - #[stable(feature = "rchunks", since = "1.31.0")] - pub fn remainder(&self) -> &'a [T] { - self.rem - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> Clone for RChunksExact<'a, T> { - fn clone(&self) -> RChunksExact<'a, T> { - RChunksExact { v: self.v, rem: self.rem, chunk_size: self.chunk_size } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> Iterator for RChunksExact<'a, T> { - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - if self.v.len() < self.chunk_size { - None - } else { - let (fst, snd) = self.v.split_at(self.v.len() - self.chunk_size); - self.v = fst; - Some(snd) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let n = self.v.len() / self.chunk_size; - (n, Some(n)) - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - let (end, overflow) = n.overflowing_mul(self.chunk_size); - if end >= self.v.len() || overflow { - self.v = &[]; - None - } else { - let (fst, _) = self.v.split_at(self.v.len() - end); - self.v = fst; - self.next() - } - } - - #[inline] - fn last(mut self) -> Option { - self.next_back() - } - - #[doc(hidden)] - unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { - let end = self.v.len() - idx * self.chunk_size; - let start = end - self.chunk_size; - // SAFETY: - // SAFETY: mostmy identical to `Chunks::get_unchecked`. - unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> DoubleEndedIterator for RChunksExact<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.v.len() < self.chunk_size { - None - } else { - let (fst, snd) = self.v.split_at(self.chunk_size); - self.v = snd; - Some(fst) - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.len(); - if n >= len { - self.v = &[]; - None - } else { - // now that we know that `n` corresponds to a chunk, - // none of these operations can underflow/overflow - let offset = (len - n) * self.chunk_size; - let start = self.v.len() - offset; - let end = start + self.chunk_size; - let nth_back = &self.v[start..end]; - self.v = &self.v[end..]; - Some(nth_back) - } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> ExactSizeIterator for RChunksExact<'a, T> { - fn is_empty(&self) -> bool { - self.v.is_empty() - } -} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for RChunksExact<'_, T> {} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl FusedIterator for RChunksExact<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` -/// elements at a time), starting at the end of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last up to -/// `chunk_size-1` elements will be omitted but can be retrieved from the -/// [`into_remainder`] function from the iterator. -/// -/// This struct is created by the [`rchunks_exact_mut`] method on [slices]. -/// -/// [`rchunks_exact_mut`]: ../../std/primitive.slice.html#method.rchunks_exact_mut -/// [`into_remainder`]: ChunksExactMut::into_remainder -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "rchunks", since = "1.31.0")] -pub struct RChunksExactMut<'a, T: 'a> { - v: &'a mut [T], - rem: &'a mut [T], - chunk_size: usize, -} - -impl<'a, T> RChunksExactMut<'a, T> { - /// Returns the remainder of the original slice that is not going to be - /// returned by the iterator. The returned slice has at most `chunk_size-1` - /// elements. - #[stable(feature = "rchunks", since = "1.31.0")] - pub fn into_remainder(self) -> &'a mut [T] { - self.rem - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> Iterator for RChunksExactMut<'a, T> { - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - if self.v.len() < self.chunk_size { - None - } else { - let tmp = mem::replace(&mut self.v, &mut []); - let tmp_len = tmp.len(); - let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size); - self.v = head; - Some(tail) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let n = self.v.len() / self.chunk_size; - (n, Some(n)) - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { - let (end, overflow) = n.overflowing_mul(self.chunk_size); - if end >= self.v.len() || overflow { - self.v = &mut []; - None - } else { - let tmp = mem::replace(&mut self.v, &mut []); - let tmp_len = tmp.len(); - let (fst, _) = tmp.split_at_mut(tmp_len - end); - self.v = fst; - self.next() - } - } - - #[inline] - fn last(mut self) -> Option { - self.next_back() - } - - #[doc(hidden)] - unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { - let end = self.v.len() - idx * self.chunk_size; - let start = end - self.chunk_size; - // SAFETY: see comments for `RChunksMut::get_unchecked`. - unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - if self.v.len() < self.chunk_size { - None - } else { - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(self.chunk_size); - self.v = tail; - Some(head) - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.len(); - if n >= len { - self.v = &mut []; - None - } else { - // now that we know that `n` corresponds to a chunk, - // none of these operations can underflow/overflow - let offset = (len - n) * self.chunk_size; - let start = self.v.len() - offset; - let end = start + self.chunk_size; - let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); - let (_, nth_back) = tmp.split_at_mut(start); - self.v = tail; - Some(nth_back) - } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl ExactSizeIterator for RChunksExactMut<'_, T> { - fn is_empty(&self) -> bool { - self.v.is_empty() - } -} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for RChunksExactMut<'_, T> {} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl FusedIterator for RChunksExactMut<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -// -// Free functions -// - -/// Forms a slice from a pointer and a length. -/// -/// The `len` argument is the number of **elements**, not the number of bytes. -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `data` must be [valid] for reads for `len * mem::size_of::()` many bytes, -/// and it must be properly aligned. This means in particular: -/// -/// * The entire memory range of this slice must be contained within a single allocated object! -/// Slices can never span across multiple allocated objects. See [below](#incorrect-usage) -/// for an example incorrectly not taking this into account. -/// * `data` must be non-null and aligned even for zero-length slices. One -/// reason for this is that enum layout optimizations may rely on references -/// (including slices of any length) being aligned and non-null to distinguish -/// them from other data. You can obtain a pointer that is usable as `data` -/// for zero-length slices using [`NonNull::dangling()`]. -/// -/// * `data` must point to `len` consecutive properly initialized values of type `T`. -/// -/// * The memory referenced by the returned slice must not be mutated for the duration -/// of lifetime `'a`, except inside an `UnsafeCell`. -/// -/// * The total size `len * mem::size_of::()` of the slice must be no larger than `isize::MAX`. -/// See the safety documentation of [`pointer::offset`]. -/// -/// # Caveat -/// -/// The lifetime for the returned slice is inferred from its usage. To -/// prevent accidental misuse, it's suggested to tie the lifetime to whichever -/// source lifetime is safe in the context, such as by providing a helper -/// function taking the lifetime of a host value for the slice, or by explicit -/// annotation. -/// -/// # Examples -/// -/// ``` -/// use std::slice; -/// -/// // manifest a slice for a single element -/// let x = 42; -/// let ptr = &x as *const _; -/// let slice = unsafe { slice::from_raw_parts(ptr, 1) }; -/// assert_eq!(slice[0], 42); -/// ``` -/// -/// ### Incorrect usage -/// -/// The following `join_slices` function is **unsound** ⚠️ -/// -/// ```rust,no_run -/// use std::slice; -/// -/// fn join_slices<'a, T>(fst: &'a [T], snd: &'a [T]) -> &'a [T] { -/// let fst_end = fst.as_ptr().wrapping_add(fst.len()); -/// let snd_start = snd.as_ptr(); -/// assert_eq!(fst_end, snd_start, "Slices must be contiguous!"); -/// unsafe { -/// // The assertion above ensures `fst` and `snd` are contiguous, but they might -/// // still be contained within _different allocated objects_, in which case -/// // creating this slice is undefined behavior. -/// slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len()) -/// } -/// } -/// -/// fn main() { -/// // `a` and `b` are different allocated objects... -/// let a = 42; -/// let b = 27; -/// // ... which may nevertheless be laid out contiguously in memory: | a | b | -/// let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB -/// } -/// ``` -/// -/// [valid]: ptr#safety -/// [`NonNull::dangling()`]: ptr::NonNull::dangling -/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { - debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice"); - debug_assert!( - mem::size_of::().saturating_mul(len) <= isize::MAX as usize, - "attempt to create slice covering at least half the address space" - ); - // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. - unsafe { &*ptr::slice_from_raw_parts(data, len) } -} - -/// Performs the same functionality as [`from_raw_parts`], except that a -/// mutable slice is returned. -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `data` must be [valid] for boths reads and writes for `len * mem::size_of::()` many bytes, -/// and it must be properly aligned. This means in particular: -/// -/// * The entire memory range of this slice must be contained within a single allocated object! -/// Slices can never span across multiple allocated objects. -/// * `data` must be non-null and aligned even for zero-length slices. One -/// reason for this is that enum layout optimizations may rely on references -/// (including slices of any length) being aligned and non-null to distinguish -/// them from other data. You can obtain a pointer that is usable as `data` -/// for zero-length slices using [`NonNull::dangling()`]. -/// -/// * `data` must point to `len` consecutive properly initialized values of type `T`. -/// -/// * The memory referenced by the returned slice must not be accessed through any other pointer -/// (not derived from the return value) for the duration of lifetime `'a`. -/// Both read and write accesses are forbidden. -/// -/// * The total size `len * mem::size_of::()` of the slice must be no larger than `isize::MAX`. -/// See the safety documentation of [`pointer::offset`]. -/// -/// [valid]: ptr#safety -/// [`NonNull::dangling()`]: ptr::NonNull::dangling -/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] { - debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice"); - debug_assert!( - mem::size_of::().saturating_mul(len) <= isize::MAX as usize, - "attempt to create slice covering at least half the address space" - ); - // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. - unsafe { &mut *ptr::slice_from_raw_parts_mut(data, len) } -} - -/// Converts a reference to T into a slice of length 1 (without copying). -#[stable(feature = "from_ref", since = "1.28.0")] -pub fn from_ref(s: &T) -> &[T] { - // SAFETY: a reference is guaranteed to be valid for reads. The returned - // reference cannot be mutated as it is an immutable reference. - // `mem::size_of::()` cannot be larger than `isize::MAX`. - // Thus the call to `from_raw_parts` is safe. - unsafe { from_raw_parts(s, 1) } -} - -/// Converts a reference to T into a slice of length 1 (without copying). -#[stable(feature = "from_ref", since = "1.28.0")] -pub fn from_mut(s: &mut T) -> &mut [T] { - // SAFETY: a mutable reference is guaranteed to be valid for writes. - // The reference cannot be accessed by another pointer as it is an mutable reference. - // `mem::size_of::()` cannot be larger than `isize::MAX`. - // Thus the call to `from_raw_parts_mut` is safe. - unsafe { from_raw_parts_mut(s, 1) } -} - -// This function is public only because there is no other way to unit test heapsort. -#[unstable(feature = "sort_internals", reason = "internal to sort module", issue = "none")] -#[doc(hidden)] -pub fn heapsort(v: &mut [T], mut is_less: F) -where - F: FnMut(&T, &T) -> bool, -{ - sort::heapsort(v, &mut is_less); -} - -// -// Comparison traits -// - -extern "C" { - /// Calls implementation provided memcmp. - /// - /// Interprets the data as u8. - /// - /// Returns 0 for equal, < 0 for less than and > 0 for greater - /// than. - // FIXME(#32610): Return type should be c_int - fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq<[B]> for [A] -where - A: PartialEq, -{ - fn eq(&self, other: &[B]) -> bool { - SlicePartialEq::equal(self, other) - } - - fn ne(&self, other: &[B]) -> bool { - SlicePartialEq::not_equal(self, other) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for [T] {} - -/// Implements comparison of vectors lexicographically. -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for [T] { - fn cmp(&self, other: &[T]) -> Ordering { - SliceOrd::compare(self, other) - } -} - -/// Implements comparison of vectors lexicographically. -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for [T] { - fn partial_cmp(&self, other: &[T]) -> Option { - SlicePartialOrd::partial_compare(self, other) - } -} - -#[doc(hidden)] -// intermediate trait for specialization of slice's PartialEq -trait SlicePartialEq { - fn equal(&self, other: &[B]) -> bool; - - fn not_equal(&self, other: &[B]) -> bool { - !self.equal(other) - } -} - -// Generic slice equality -impl SlicePartialEq for [A] -where - A: PartialEq, -{ - default fn equal(&self, other: &[B]) -> bool { - if self.len() != other.len() { - return false; - } - - self.iter().zip(other.iter()).all(|(x, y)| x == y) - } -} - -// Use an equal-pointer optimization when types are `Eq` -// We can't make `A` and `B` the same type because `min_specialization` won't -// allow it. -impl SlicePartialEq for [A] -where - A: MarkerEq, -{ - default fn equal(&self, other: &[B]) -> bool { - if self.len() != other.len() { - return false; - } +// Use an equal-pointer optimization when types are `Eq` +// We can't make `A` and `B` the same type because `min_specialization` won't +// allow it. +impl SlicePartialEq for [A] +where + A: MarkerEq, +{ + default fn equal(&self, other: &[B]) -> bool { + if self.len() != other.len() { + return false; + } // While performance would suffer if `guaranteed_eq` just returned `false` // for all arguments, correctness and return value of this function are not affected. @@ -7074,22 +4224,6 @@ macro_rules! impl_marker_for { impl_marker_for!(BytewiseEquality, u8 i8 u16 i16 u32 i32 u64 i64 u128 i128 usize isize char bool); -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - trait SliceContains: Sized { fn slice_contains(&self, x: &[Self]) -> bool; } From bcd18f977bee4db79d42d54cc7edce19c942b963 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 4 Sep 2020 04:46:02 +0000 Subject: [PATCH 0412/1052] Move free functions to a new module --- library/core/src/slice/mod.rs | 184 +++------------------------------ library/core/src/slice/raw.rs | 158 ++++++++++++++++++++++++++++ library/core/src/slice/sort.rs | 3 +- 3 files changed, 172 insertions(+), 173 deletions(-) create mode 100644 library/core/src/slice/raw.rs diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index bbaf0fae05afb..87ce4e0e12b72 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -17,15 +17,12 @@ // // * Inherent methods. This is where most of the slice API resides. // * Implementations of a few common traits with important slice ops. -// * Definitions of a bunch of iterators. -// * Free functions. // * The `raw` and `bytes` submodules. // * Boilerplate trait implementations. use crate::cmp; use crate::cmp::Ordering::{self, Equal, Greater, Less}; -use crate::intrinsics::{assume, is_aligned_and_not_null}; -use crate::iter::*; +use crate::intrinsics::assume; use crate::marker::{self, Copy, Sized}; use crate::mem; use crate::ops::{self, Bound, FnMut, Range, RangeBounds}; @@ -44,6 +41,7 @@ use crate::result::Result::{Err, Ok}; pub mod memchr; mod iter; +mod raw; mod rotate; mod sort; @@ -71,6 +69,16 @@ pub use iter::{ArrayChunks, ArrayChunksMut}; #[unstable(feature = "split_inclusive", issue = "72360")] pub use iter::{SplitInclusive, SplitInclusiveMut}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use raw::{from_raw_parts, from_raw_parts_mut}; + +#[stable(feature = "from_ref", since = "1.28.0")] +pub use raw::{from_mut, from_ref}; + +// This function is public only because there is no other way to unit test heapsort. +#[unstable(feature = "sort_internals", reason = "internal to sort module", issue = "none")] +pub use sort::heapsort; + // // Extension traits // @@ -3806,174 +3814,6 @@ impl Default for &mut [T] { } } -// -// Free functions -// - -/// Forms a slice from a pointer and a length. -/// -/// The `len` argument is the number of **elements**, not the number of bytes. -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `data` must be [valid] for reads for `len * mem::size_of::()` many bytes, -/// and it must be properly aligned. This means in particular: -/// -/// * The entire memory range of this slice must be contained within a single allocated object! -/// Slices can never span across multiple allocated objects. See [below](#incorrect-usage) -/// for an example incorrectly not taking this into account. -/// * `data` must be non-null and aligned even for zero-length slices. One -/// reason for this is that enum layout optimizations may rely on references -/// (including slices of any length) being aligned and non-null to distinguish -/// them from other data. You can obtain a pointer that is usable as `data` -/// for zero-length slices using [`NonNull::dangling()`]. -/// -/// * `data` must point to `len` consecutive properly initialized values of type `T`. -/// -/// * The memory referenced by the returned slice must not be mutated for the duration -/// of lifetime `'a`, except inside an `UnsafeCell`. -/// -/// * The total size `len * mem::size_of::()` of the slice must be no larger than `isize::MAX`. -/// See the safety documentation of [`pointer::offset`]. -/// -/// # Caveat -/// -/// The lifetime for the returned slice is inferred from its usage. To -/// prevent accidental misuse, it's suggested to tie the lifetime to whichever -/// source lifetime is safe in the context, such as by providing a helper -/// function taking the lifetime of a host value for the slice, or by explicit -/// annotation. -/// -/// # Examples -/// -/// ``` -/// use std::slice; -/// -/// // manifest a slice for a single element -/// let x = 42; -/// let ptr = &x as *const _; -/// let slice = unsafe { slice::from_raw_parts(ptr, 1) }; -/// assert_eq!(slice[0], 42); -/// ``` -/// -/// ### Incorrect usage -/// -/// The following `join_slices` function is **unsound** ⚠️ -/// -/// ```rust,no_run -/// use std::slice; -/// -/// fn join_slices<'a, T>(fst: &'a [T], snd: &'a [T]) -> &'a [T] { -/// let fst_end = fst.as_ptr().wrapping_add(fst.len()); -/// let snd_start = snd.as_ptr(); -/// assert_eq!(fst_end, snd_start, "Slices must be contiguous!"); -/// unsafe { -/// // The assertion above ensures `fst` and `snd` are contiguous, but they might -/// // still be contained within _different allocated objects_, in which case -/// // creating this slice is undefined behavior. -/// slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len()) -/// } -/// } -/// -/// fn main() { -/// // `a` and `b` are different allocated objects... -/// let a = 42; -/// let b = 27; -/// // ... which may nevertheless be laid out contiguously in memory: | a | b | -/// let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB -/// } -/// ``` -/// -/// [valid]: ptr#safety -/// [`NonNull::dangling()`]: ptr::NonNull::dangling -/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { - debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice"); - debug_assert!( - mem::size_of::().saturating_mul(len) <= isize::MAX as usize, - "attempt to create slice covering at least half the address space" - ); - // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. - unsafe { &*ptr::slice_from_raw_parts(data, len) } -} - -/// Performs the same functionality as [`from_raw_parts`], except that a -/// mutable slice is returned. -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `data` must be [valid] for boths reads and writes for `len * mem::size_of::()` many bytes, -/// and it must be properly aligned. This means in particular: -/// -/// * The entire memory range of this slice must be contained within a single allocated object! -/// Slices can never span across multiple allocated objects. -/// * `data` must be non-null and aligned even for zero-length slices. One -/// reason for this is that enum layout optimizations may rely on references -/// (including slices of any length) being aligned and non-null to distinguish -/// them from other data. You can obtain a pointer that is usable as `data` -/// for zero-length slices using [`NonNull::dangling()`]. -/// -/// * `data` must point to `len` consecutive properly initialized values of type `T`. -/// -/// * The memory referenced by the returned slice must not be accessed through any other pointer -/// (not derived from the return value) for the duration of lifetime `'a`. -/// Both read and write accesses are forbidden. -/// -/// * The total size `len * mem::size_of::()` of the slice must be no larger than `isize::MAX`. -/// See the safety documentation of [`pointer::offset`]. -/// -/// [valid]: ptr#safety -/// [`NonNull::dangling()`]: ptr::NonNull::dangling -/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] { - debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice"); - debug_assert!( - mem::size_of::().saturating_mul(len) <= isize::MAX as usize, - "attempt to create slice covering at least half the address space" - ); - // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. - unsafe { &mut *ptr::slice_from_raw_parts_mut(data, len) } -} - -/// Converts a reference to T into a slice of length 1 (without copying). -#[stable(feature = "from_ref", since = "1.28.0")] -pub fn from_ref(s: &T) -> &[T] { - // SAFETY: a reference is guaranteed to be valid for reads. The returned - // reference cannot be mutated as it is an immutable reference. - // `mem::size_of::()` cannot be larger than `isize::MAX`. - // Thus the call to `from_raw_parts` is safe. - unsafe { from_raw_parts(s, 1) } -} - -/// Converts a reference to T into a slice of length 1 (without copying). -#[stable(feature = "from_ref", since = "1.28.0")] -pub fn from_mut(s: &mut T) -> &mut [T] { - // SAFETY: a mutable reference is guaranteed to be valid for writes. - // The reference cannot be accessed by another pointer as it is an mutable reference. - // `mem::size_of::()` cannot be larger than `isize::MAX`. - // Thus the call to `from_raw_parts_mut` is safe. - unsafe { from_raw_parts_mut(s, 1) } -} - -// This function is public only because there is no other way to unit test heapsort. -#[unstable(feature = "sort_internals", reason = "internal to sort module", issue = "none")] -#[doc(hidden)] -pub fn heapsort(v: &mut [T], mut is_less: F) -where - F: FnMut(&T, &T) -> bool, -{ - sort::heapsort(v, &mut is_less); -} - -// // Comparison traits // diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs new file mode 100644 index 0000000000000..a5811c5e47289 --- /dev/null +++ b/library/core/src/slice/raw.rs @@ -0,0 +1,158 @@ +//! Free functions to create `&[T]` and `&mut [T]`. + +use crate::intrinsics::is_aligned_and_not_null; +use crate::mem; +use crate::ptr; + +/// Forms a slice from a pointer and a length. +/// +/// The `len` argument is the number of **elements**, not the number of bytes. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `data` must be [valid] for reads for `len * mem::size_of::()` many bytes, +/// and it must be properly aligned. This means in particular: +/// +/// * The entire memory range of this slice must be contained within a single allocated object! +/// Slices can never span across multiple allocated objects. See [below](#incorrect-usage) +/// for an example incorrectly not taking this into account. +/// * `data` must be non-null and aligned even for zero-length slices. One +/// reason for this is that enum layout optimizations may rely on references +/// (including slices of any length) being aligned and non-null to distinguish +/// them from other data. You can obtain a pointer that is usable as `data` +/// for zero-length slices using [`NonNull::dangling()`]. +/// +/// * `data` must point to `len` consecutive properly initialized values of type `T`. +/// +/// * The memory referenced by the returned slice must not be mutated for the duration +/// of lifetime `'a`, except inside an `UnsafeCell`. +/// +/// * The total size `len * mem::size_of::()` of the slice must be no larger than `isize::MAX`. +/// See the safety documentation of [`pointer::offset`]. +/// +/// # Caveat +/// +/// The lifetime for the returned slice is inferred from its usage. To +/// prevent accidental misuse, it's suggested to tie the lifetime to whichever +/// source lifetime is safe in the context, such as by providing a helper +/// function taking the lifetime of a host value for the slice, or by explicit +/// annotation. +/// +/// # Examples +/// +/// ``` +/// use std::slice; +/// +/// // manifest a slice for a single element +/// let x = 42; +/// let ptr = &x as *const _; +/// let slice = unsafe { slice::from_raw_parts(ptr, 1) }; +/// assert_eq!(slice[0], 42); +/// ``` +/// +/// ### Incorrect usage +/// +/// The following `join_slices` function is **unsound** ⚠️ +/// +/// ```rust,no_run +/// use std::slice; +/// +/// fn join_slices<'a, T>(fst: &'a [T], snd: &'a [T]) -> &'a [T] { +/// let fst_end = fst.as_ptr().wrapping_add(fst.len()); +/// let snd_start = snd.as_ptr(); +/// assert_eq!(fst_end, snd_start, "Slices must be contiguous!"); +/// unsafe { +/// // The assertion above ensures `fst` and `snd` are contiguous, but they might +/// // still be contained within _different allocated objects_, in which case +/// // creating this slice is undefined behavior. +/// slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len()) +/// } +/// } +/// +/// fn main() { +/// // `a` and `b` are different allocated objects... +/// let a = 42; +/// let b = 27; +/// // ... which may nevertheless be laid out contiguously in memory: | a | b | +/// let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB +/// } +/// ``` +/// +/// [valid]: ptr#safety +/// [`NonNull::dangling()`]: ptr::NonNull::dangling +/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { + debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice"); + debug_assert!( + mem::size_of::().saturating_mul(len) <= isize::MAX as usize, + "attempt to create slice covering at least half the address space" + ); + // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. + unsafe { &*ptr::slice_from_raw_parts(data, len) } +} + +/// Performs the same functionality as [`from_raw_parts`], except that a +/// mutable slice is returned. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `data` must be [valid] for boths reads and writes for `len * mem::size_of::()` many bytes, +/// and it must be properly aligned. This means in particular: +/// +/// * The entire memory range of this slice must be contained within a single allocated object! +/// Slices can never span across multiple allocated objects. +/// * `data` must be non-null and aligned even for zero-length slices. One +/// reason for this is that enum layout optimizations may rely on references +/// (including slices of any length) being aligned and non-null to distinguish +/// them from other data. You can obtain a pointer that is usable as `data` +/// for zero-length slices using [`NonNull::dangling()`]. +/// +/// * `data` must point to `len` consecutive properly initialized values of type `T`. +/// +/// * The memory referenced by the returned slice must not be accessed through any other pointer +/// (not derived from the return value) for the duration of lifetime `'a`. +/// Both read and write accesses are forbidden. +/// +/// * The total size `len * mem::size_of::()` of the slice must be no larger than `isize::MAX`. +/// See the safety documentation of [`pointer::offset`]. +/// +/// [valid]: ptr#safety +/// [`NonNull::dangling()`]: ptr::NonNull::dangling +/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] { + debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice"); + debug_assert!( + mem::size_of::().saturating_mul(len) <= isize::MAX as usize, + "attempt to create slice covering at least half the address space" + ); + // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. + unsafe { &mut *ptr::slice_from_raw_parts_mut(data, len) } +} + +/// Converts a reference to T into a slice of length 1 (without copying). +#[stable(feature = "from_ref", since = "1.28.0")] +pub fn from_ref(s: &T) -> &[T] { + // SAFETY: a reference is guaranteed to be valid for reads. The returned + // reference cannot be mutated as it is an immutable reference. + // `mem::size_of::()` cannot be larger than `isize::MAX`. + // Thus the call to `from_raw_parts` is safe. + unsafe { from_raw_parts(s, 1) } +} + +/// Converts a reference to T into a slice of length 1 (without copying). +#[stable(feature = "from_ref", since = "1.28.0")] +pub fn from_mut(s: &mut T) -> &mut [T] { + // SAFETY: a mutable reference is guaranteed to be valid for writes. + // The reference cannot be accessed by another pointer as it is an mutable reference. + // `mem::size_of::()` cannot be larger than `isize::MAX`. + // Thus the call to `from_raw_parts_mut` is safe. + unsafe { from_raw_parts_mut(s, 1) } +} diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs index 4a00124fcff3e..8c14651bd826c 100644 --- a/library/core/src/slice/sort.rs +++ b/library/core/src/slice/sort.rs @@ -180,7 +180,8 @@ where /// Sorts `v` using heapsort, which guarantees *O*(*n* \* log(*n*)) worst-case. #[cold] -pub fn heapsort(v: &mut [T], is_less: &mut F) +#[unstable(feature = "sort_internals", reason = "internal to sort module", issue = "none")] +pub fn heapsort(v: &mut [T], mut is_less: F) where F: FnMut(&T, &T) -> bool, { From fbad684e2ff11f58dc94d9c19bf31c5787afd98e Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 4 Sep 2020 02:26:45 +0000 Subject: [PATCH 0413/1052] move indexing impl to new mod --- library/core/src/slice/cmp.rs | 286 ++++++++++++ library/core/src/slice/index.rs | 455 +++++++++++++++++++ library/core/src/slice/mod.rs | 749 +------------------------------- 3 files changed, 753 insertions(+), 737 deletions(-) create mode 100644 library/core/src/slice/cmp.rs create mode 100644 library/core/src/slice/index.rs diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs new file mode 100644 index 0000000000000..27a358bddaf4f --- /dev/null +++ b/library/core/src/slice/cmp.rs @@ -0,0 +1,286 @@ +//! Comparison traits for `[T]`. + +use crate::cmp; +use crate::cmp::Ordering::{self, Greater, Less}; +use crate::mem; + +use super::from_raw_parts; +use super::memchr; + +extern "C" { + /// Calls implementation provided memcmp. + /// + /// Interprets the data as u8. + /// + /// Returns 0 for equal, < 0 for less than and > 0 for greater + /// than. + // FIXME(#32610): Return type should be c_int + fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq<[B]> for [A] +where + A: PartialEq, +{ + fn eq(&self, other: &[B]) -> bool { + SlicePartialEq::equal(self, other) + } + + fn ne(&self, other: &[B]) -> bool { + SlicePartialEq::not_equal(self, other) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for [T] {} + +/// Implements comparison of vectors lexicographically. +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for [T] { + fn cmp(&self, other: &[T]) -> Ordering { + SliceOrd::compare(self, other) + } +} + +/// Implements comparison of vectors lexicographically. +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for [T] { + fn partial_cmp(&self, other: &[T]) -> Option { + SlicePartialOrd::partial_compare(self, other) + } +} + +#[doc(hidden)] +// intermediate trait for specialization of slice's PartialEq +trait SlicePartialEq { + fn equal(&self, other: &[B]) -> bool; + + fn not_equal(&self, other: &[B]) -> bool { + !self.equal(other) + } +} + +// Generic slice equality +impl SlicePartialEq for [A] +where + A: PartialEq, +{ + default fn equal(&self, other: &[B]) -> bool { + if self.len() != other.len() { + return false; + } + + self.iter().zip(other.iter()).all(|(x, y)| x == y) + } +} + +// Use an equal-pointer optimization when types are `Eq` +// We can't make `A` and `B` the same type because `min_specialization` won't +// allow it. +impl SlicePartialEq for [A] +where + A: MarkerEq, +{ + default fn equal(&self, other: &[B]) -> bool { + if self.len() != other.len() { + return false; + } + + // While performance would suffer if `guaranteed_eq` just returned `false` + // for all arguments, correctness and return value of this function are not affected. + if self.as_ptr().guaranteed_eq(other.as_ptr() as *const A) { + return true; + } + + self.iter().zip(other.iter()).all(|(x, y)| x == y) + } +} + +// Use memcmp for bytewise equality when the types allow +impl SlicePartialEq for [A] +where + A: BytewiseEquality, +{ + fn equal(&self, other: &[B]) -> bool { + if self.len() != other.len() { + return false; + } + + // While performance would suffer if `guaranteed_eq` just returned `false` + // for all arguments, correctness and return value of this function are not affected. + if self.as_ptr().guaranteed_eq(other.as_ptr() as *const A) { + return true; + } + // SAFETY: `self` and `other` are references and are thus guaranteed to be valid. + // The two slices have been checked to have the same size above. + unsafe { + let size = mem::size_of_val(self); + memcmp(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0 + } + } +} + +#[doc(hidden)] +// intermediate trait for specialization of slice's PartialOrd +trait SlicePartialOrd: Sized { + fn partial_compare(left: &[Self], right: &[Self]) -> Option; +} + +impl SlicePartialOrd for A { + default fn partial_compare(left: &[A], right: &[A]) -> Option { + let l = cmp::min(left.len(), right.len()); + + // Slice to the loop iteration range to enable bound check + // elimination in the compiler + let lhs = &left[..l]; + let rhs = &right[..l]; + + for i in 0..l { + match lhs[i].partial_cmp(&rhs[i]) { + Some(Ordering::Equal) => (), + non_eq => return non_eq, + } + } + + left.len().partial_cmp(&right.len()) + } +} + +// This is the impl that we would like to have. Unfortunately it's not sound. +// See `partial_ord_slice.rs`. +/* +impl SlicePartialOrd for A +where + A: Ord, +{ + default fn partial_compare(left: &[A], right: &[A]) -> Option { + Some(SliceOrd::compare(left, right)) + } +} +*/ + +impl SlicePartialOrd for A { + fn partial_compare(left: &[A], right: &[A]) -> Option { + Some(SliceOrd::compare(left, right)) + } +} + +#[rustc_specialization_trait] +trait AlwaysApplicableOrd: SliceOrd + Ord {} + +macro_rules! always_applicable_ord { + ($([$($p:tt)*] $t:ty,)*) => { + $(impl<$($p)*> AlwaysApplicableOrd for $t {})* + } +} + +always_applicable_ord! { + [] u8, [] u16, [] u32, [] u64, [] u128, [] usize, + [] i8, [] i16, [] i32, [] i64, [] i128, [] isize, + [] bool, [] char, + [T: ?Sized] *const T, [T: ?Sized] *mut T, + [T: AlwaysApplicableOrd] &T, + [T: AlwaysApplicableOrd] &mut T, + [T: AlwaysApplicableOrd] Option, +} + +#[doc(hidden)] +// intermediate trait for specialization of slice's Ord +trait SliceOrd: Sized { + fn compare(left: &[Self], right: &[Self]) -> Ordering; +} + +impl SliceOrd for A { + default fn compare(left: &[Self], right: &[Self]) -> Ordering { + let l = cmp::min(left.len(), right.len()); + + // Slice to the loop iteration range to enable bound check + // elimination in the compiler + let lhs = &left[..l]; + let rhs = &right[..l]; + + for i in 0..l { + match lhs[i].cmp(&rhs[i]) { + Ordering::Equal => (), + non_eq => return non_eq, + } + } + + left.len().cmp(&right.len()) + } +} + +// memcmp compares a sequence of unsigned bytes lexicographically. +// this matches the order we want for [u8], but no others (not even [i8]). +impl SliceOrd for u8 { + #[inline] + fn compare(left: &[Self], right: &[Self]) -> Ordering { + let order = + // SAFETY: `left` and `right` are references and are thus guaranteed to be valid. + // We use the minimum of both lengths which guarantees that both regions are + // valid for reads in that interval. + unsafe { memcmp(left.as_ptr(), right.as_ptr(), cmp::min(left.len(), right.len())) }; + if order == 0 { + left.len().cmp(&right.len()) + } else if order < 0 { + Less + } else { + Greater + } + } +} + +// Hack to allow specializing on `Eq` even though `Eq` has a method. +#[rustc_unsafe_specialization_marker] +trait MarkerEq: PartialEq {} + +impl MarkerEq for T {} + +#[doc(hidden)] +/// Trait implemented for types that can be compared for equality using +/// their bytewise representation +#[rustc_specialization_trait] +trait BytewiseEquality: MarkerEq + Copy {} + +macro_rules! impl_marker_for { + ($traitname:ident, $($ty:ty)*) => { + $( + impl $traitname<$ty> for $ty { } + )* + } +} + +impl_marker_for!(BytewiseEquality, + u8 i8 u16 i16 u32 i32 u64 i64 u128 i128 usize isize char bool); + +pub(super) trait SliceContains: Sized { + fn slice_contains(&self, x: &[Self]) -> bool; +} + +impl SliceContains for T +where + T: PartialEq, +{ + default fn slice_contains(&self, x: &[Self]) -> bool { + x.iter().any(|y| *y == *self) + } +} + +impl SliceContains for u8 { + fn slice_contains(&self, x: &[Self]) -> bool { + memchr::memchr(*self, x).is_some() + } +} + +impl SliceContains for i8 { + fn slice_contains(&self, x: &[Self]) -> bool { + let byte = *self as u8; + // SAFETY: `i8` and `u8` have the same memory layout, thus casting `x.as_ptr()` + // as `*const u8` is safe. The `x.as_ptr()` comes from a reference and is thus guaranteed + // to be valid for reads for the length of the slice `x.len()`, which cannot be larger + // than `isize::MAX`. The returned slice is never mutated. + let bytes: &[u8] = unsafe { from_raw_parts(x.as_ptr() as *const u8, x.len()) }; + memchr::memchr(byte, bytes).is_some() + } +} diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs new file mode 100644 index 0000000000000..d67e0ae536d9f --- /dev/null +++ b/library/core/src/slice/index.rs @@ -0,0 +1,455 @@ +//! Indexing implementations for `[T]`. + +use crate::ops; +use crate::ptr; + +#[stable(feature = "rust1", since = "1.0.0")] +impl ops::Index for [T] +where + I: SliceIndex<[T]>, +{ + type Output = I::Output; + + #[inline] + fn index(&self, index: I) -> &I::Output { + index.index(self) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ops::IndexMut for [T] +where + I: SliceIndex<[T]>, +{ + #[inline] + fn index_mut(&mut self, index: I) -> &mut I::Output { + index.index_mut(self) + } +} + +#[inline(never)] +#[cold] +#[track_caller] +fn slice_start_index_len_fail(index: usize, len: usize) -> ! { + panic!("range start index {} out of range for slice of length {}", index, len); +} + +#[inline(never)] +#[cold] +#[track_caller] +pub(super) fn slice_end_index_len_fail(index: usize, len: usize) -> ! { + panic!("range end index {} out of range for slice of length {}", index, len); +} + +#[inline(never)] +#[cold] +#[track_caller] +pub(super) fn slice_index_order_fail(index: usize, end: usize) -> ! { + panic!("slice index starts at {} but ends at {}", index, end); +} + +#[inline(never)] +#[cold] +#[track_caller] +pub(super) fn slice_start_index_overflow_fail() -> ! { + panic!("attempted to index slice from after maximum usize"); +} + +#[inline(never)] +#[cold] +#[track_caller] +pub(super) fn slice_end_index_overflow_fail() -> ! { + panic!("attempted to index slice up to maximum usize"); +} + +mod private_slice_index { + use super::ops; + #[stable(feature = "slice_get_slice", since = "1.28.0")] + pub trait Sealed {} + + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for usize {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::Range {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::RangeTo {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::RangeFrom {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::RangeFull {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::RangeInclusive {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::RangeToInclusive {} +} + +/// A helper trait used for indexing operations. +/// +/// Implementations of this trait have to promise that if the argument +/// to `get_(mut_)unchecked` is a safe reference, then so is the result. +#[stable(feature = "slice_get_slice", since = "1.28.0")] +#[rustc_on_unimplemented( + on(T = "str", label = "string indices are ranges of `usize`",), + on( + all(any(T = "str", T = "&str", T = "std::string::String"), _Self = "{integer}"), + note = "you can use `.chars().nth()` or `.bytes().nth()`\n\ + for more information, see chapter 8 in The Book: \ + " + ), + message = "the type `{T}` cannot be indexed by `{Self}`", + label = "slice indices are of type `usize` or ranges of `usize`" +)] +pub unsafe trait SliceIndex: private_slice_index::Sealed { + /// The output type returned by methods. + #[stable(feature = "slice_get_slice", since = "1.28.0")] + type Output: ?Sized; + + /// Returns a shared reference to the output at this location, if in + /// bounds. + #[unstable(feature = "slice_index_methods", issue = "none")] + fn get(self, slice: &T) -> Option<&Self::Output>; + + /// Returns a mutable reference to the output at this location, if in + /// bounds. + #[unstable(feature = "slice_index_methods", issue = "none")] + fn get_mut(self, slice: &mut T) -> Option<&mut Self::Output>; + + /// Returns a shared reference to the output at this location, without + /// performing any bounds checking. + /// Calling this method with an out-of-bounds index or a dangling `slice` pointer + /// is *[undefined behavior]* even if the resulting reference is not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[unstable(feature = "slice_index_methods", issue = "none")] + unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output; + + /// Returns a mutable reference to the output at this location, without + /// performing any bounds checking. + /// Calling this method with an out-of-bounds index or a dangling `slice` pointer + /// is *[undefined behavior]* even if the resulting reference is not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[unstable(feature = "slice_index_methods", issue = "none")] + unsafe fn get_unchecked_mut(self, slice: *mut T) -> *mut Self::Output; + + /// Returns a shared reference to the output at this location, panicking + /// if out of bounds. + #[unstable(feature = "slice_index_methods", issue = "none")] + #[track_caller] + fn index(self, slice: &T) -> &Self::Output; + + /// Returns a mutable reference to the output at this location, panicking + /// if out of bounds. + #[unstable(feature = "slice_index_methods", issue = "none")] + #[track_caller] + fn index_mut(self, slice: &mut T) -> &mut Self::Output; +} + +#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] +unsafe impl SliceIndex<[T]> for usize { + type Output = T; + + #[inline] + fn get(self, slice: &[T]) -> Option<&T> { + // SAFETY: `self` is checked to be in bounds. + if self < slice.len() { unsafe { Some(&*self.get_unchecked(slice)) } } else { None } + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut T> { + // SAFETY: `self` is checked to be in bounds. + if self < slice.len() { unsafe { Some(&mut *self.get_unchecked_mut(slice)) } } else { None } + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const [T]) -> *const T { + // SAFETY: the caller guarantees that `slice` is not dangling, so it + // cannot be longer than `isize::MAX`. They also guarantee that + // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, + // so the call to `add` is safe. + unsafe { slice.as_ptr().add(self) } + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T { + // SAFETY: see comments for `get_unchecked` above. + unsafe { slice.as_mut_ptr().add(self) } + } + + #[inline] + fn index(self, slice: &[T]) -> &T { + // N.B., use intrinsic indexing + &(*slice)[self] + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut T { + // N.B., use intrinsic indexing + &mut (*slice)[self] + } +} + +#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] +unsafe impl SliceIndex<[T]> for ops::Range { + type Output = [T]; + + #[inline] + fn get(self, slice: &[T]) -> Option<&[T]> { + if self.start > self.end || self.end > slice.len() { + None + } else { + // SAFETY: `self` is checked to be valid and in bounds above. + unsafe { Some(&*self.get_unchecked(slice)) } + } + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + if self.start > self.end || self.end > slice.len() { + None + } else { + // SAFETY: `self` is checked to be valid and in bounds above. + unsafe { Some(&mut *self.get_unchecked_mut(slice)) } + } + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + // SAFETY: the caller guarantees that `slice` is not dangling, so it + // cannot be longer than `isize::MAX`. They also guarantee that + // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, + // so the call to `add` is safe. + unsafe { ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start) } + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { + // SAFETY: see comments for `get_unchecked` above. + unsafe { + ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start) + } + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + if self.start > self.end { + slice_index_order_fail(self.start, self.end); + } else if self.end > slice.len() { + slice_end_index_len_fail(self.end, slice.len()); + } + // SAFETY: `self` is checked to be valid and in bounds above. + unsafe { &*self.get_unchecked(slice) } + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + if self.start > self.end { + slice_index_order_fail(self.start, self.end); + } else if self.end > slice.len() { + slice_end_index_len_fail(self.end, slice.len()); + } + // SAFETY: `self` is checked to be valid and in bounds above. + unsafe { &mut *self.get_unchecked_mut(slice) } + } +} + +#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] +unsafe impl SliceIndex<[T]> for ops::RangeTo { + type Output = [T]; + + #[inline] + fn get(self, slice: &[T]) -> Option<&[T]> { + (0..self.end).get(slice) + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + (0..self.end).get_mut(slice) + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. + unsafe { (0..self.end).get_unchecked(slice) } + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. + unsafe { (0..self.end).get_unchecked_mut(slice) } + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + (0..self.end).index(slice) + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + (0..self.end).index_mut(slice) + } +} + +#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] +unsafe impl SliceIndex<[T]> for ops::RangeFrom { + type Output = [T]; + + #[inline] + fn get(self, slice: &[T]) -> Option<&[T]> { + (self.start..slice.len()).get(slice) + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + (self.start..slice.len()).get_mut(slice) + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. + unsafe { (self.start..slice.len()).get_unchecked(slice) } + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. + unsafe { (self.start..slice.len()).get_unchecked_mut(slice) } + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + if self.start > slice.len() { + slice_start_index_len_fail(self.start, slice.len()); + } + // SAFETY: `self` is checked to be valid and in bounds above. + unsafe { &*self.get_unchecked(slice) } + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + if self.start > slice.len() { + slice_start_index_len_fail(self.start, slice.len()); + } + // SAFETY: `self` is checked to be valid and in bounds above. + unsafe { &mut *self.get_unchecked_mut(slice) } + } +} + +#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] +unsafe impl SliceIndex<[T]> for ops::RangeFull { + type Output = [T]; + + #[inline] + fn get(self, slice: &[T]) -> Option<&[T]> { + Some(slice) + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + Some(slice) + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + slice + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { + slice + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + slice + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + slice + } +} + +#[stable(feature = "inclusive_range", since = "1.26.0")] +unsafe impl SliceIndex<[T]> for ops::RangeInclusive { + type Output = [T]; + + #[inline] + fn get(self, slice: &[T]) -> Option<&[T]> { + if *self.end() == usize::MAX { None } else { (*self.start()..self.end() + 1).get(slice) } + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + if *self.end() == usize::MAX { + None + } else { + (*self.start()..self.end() + 1).get_mut(slice) + } + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. + unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) } + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. + unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) } + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + if *self.end() == usize::MAX { + slice_end_index_overflow_fail(); + } + (*self.start()..self.end() + 1).index(slice) + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + if *self.end() == usize::MAX { + slice_end_index_overflow_fail(); + } + (*self.start()..self.end() + 1).index_mut(slice) + } +} + +#[stable(feature = "inclusive_range", since = "1.26.0")] +unsafe impl SliceIndex<[T]> for ops::RangeToInclusive { + type Output = [T]; + + #[inline] + fn get(self, slice: &[T]) -> Option<&[T]> { + (0..=self.end).get(slice) + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + (0..=self.end).get_mut(slice) + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. + unsafe { (0..=self.end).get_unchecked(slice) } + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. + unsafe { (0..=self.end).get_unchecked_mut(slice) } + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + (0..=self.end).index(slice) + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + (0..=self.end).index_mut(slice) + } +} diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 87ce4e0e12b72..6447543d0e715 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -20,12 +20,11 @@ // * The `raw` and `bytes` submodules. // * Boilerplate trait implementations. -use crate::cmp; use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::intrinsics::assume; -use crate::marker::{self, Copy, Sized}; +use crate::marker::{self, Copy}; use crate::mem; -use crate::ops::{self, Bound, FnMut, Range, RangeBounds}; +use crate::ops::{Bound, FnMut, Range, RangeBounds}; use crate::option::Option; use crate::option::Option::{None, Some}; use crate::ptr::{self, NonNull}; @@ -40,6 +39,8 @@ use crate::result::Result::{Err, Ok}; /// Pure rust memchr implementation, taken from rust-memchr pub mod memchr; +mod cmp; +mod index; mod iter; mod raw; mod rotate; @@ -79,6 +80,12 @@ pub use raw::{from_mut, from_ref}; #[unstable(feature = "sort_internals", reason = "internal to sort module", issue = "none")] pub use sort::heapsort; +#[stable(feature = "slice_get_slice", since = "1.28.0")] +pub use index::SliceIndex; + +use index::{slice_end_index_len_fail, slice_index_order_fail}; +use index::{slice_end_index_overflow_fail, slice_start_index_overflow_fail}; + // // Extension traits // @@ -428,7 +435,7 @@ impl [T] { /// [10, 40, 30].check_range(1..=usize::MAX); /// ``` /// - /// [`Index::index`]: ops::Index::index + /// [`Index::index`]: crate::ops::Index::index #[track_caller] #[unstable(feature = "slice_check_range", issue = "76393")] pub fn check_range>(&self, range: R) -> Range { @@ -1766,7 +1773,7 @@ impl [T] { where T: PartialEq, { - x.slice_contains(self) + cmp::SliceContains::slice_contains(x, self) } /// Returns `true` if `needle` is a prefix of the slice. @@ -3343,457 +3350,6 @@ fn is_ascii(s: &[u8]) -> bool { !contains_nonascii(last_word) } -#[stable(feature = "rust1", since = "1.0.0")] -impl ops::Index for [T] -where - I: SliceIndex<[T]>, -{ - type Output = I::Output; - - #[inline] - fn index(&self, index: I) -> &I::Output { - index.index(self) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ops::IndexMut for [T] -where - I: SliceIndex<[T]>, -{ - #[inline] - fn index_mut(&mut self, index: I) -> &mut I::Output { - index.index_mut(self) - } -} - -#[inline(never)] -#[cold] -#[track_caller] -fn slice_start_index_len_fail(index: usize, len: usize) -> ! { - panic!("range start index {} out of range for slice of length {}", index, len); -} - -#[inline(never)] -#[cold] -#[track_caller] -fn slice_end_index_len_fail(index: usize, len: usize) -> ! { - panic!("range end index {} out of range for slice of length {}", index, len); -} - -#[inline(never)] -#[cold] -#[track_caller] -fn slice_index_order_fail(index: usize, end: usize) -> ! { - panic!("slice index starts at {} but ends at {}", index, end); -} - -#[inline(never)] -#[cold] -#[track_caller] -fn slice_start_index_overflow_fail() -> ! { - panic!("attempted to index slice from after maximum usize"); -} - -#[inline(never)] -#[cold] -#[track_caller] -fn slice_end_index_overflow_fail() -> ! { - panic!("attempted to index slice up to maximum usize"); -} - -mod private_slice_index { - use super::ops; - #[stable(feature = "slice_get_slice", since = "1.28.0")] - pub trait Sealed {} - - #[stable(feature = "slice_get_slice", since = "1.28.0")] - impl Sealed for usize {} - #[stable(feature = "slice_get_slice", since = "1.28.0")] - impl Sealed for ops::Range {} - #[stable(feature = "slice_get_slice", since = "1.28.0")] - impl Sealed for ops::RangeTo {} - #[stable(feature = "slice_get_slice", since = "1.28.0")] - impl Sealed for ops::RangeFrom {} - #[stable(feature = "slice_get_slice", since = "1.28.0")] - impl Sealed for ops::RangeFull {} - #[stable(feature = "slice_get_slice", since = "1.28.0")] - impl Sealed for ops::RangeInclusive {} - #[stable(feature = "slice_get_slice", since = "1.28.0")] - impl Sealed for ops::RangeToInclusive {} -} - -/// A helper trait used for indexing operations. -/// -/// Implementations of this trait have to promise that if the argument -/// to `get_(mut_)unchecked` is a safe reference, then so is the result. -#[stable(feature = "slice_get_slice", since = "1.28.0")] -#[rustc_on_unimplemented( - on(T = "str", label = "string indices are ranges of `usize`",), - on( - all(any(T = "str", T = "&str", T = "std::string::String"), _Self = "{integer}"), - note = "you can use `.chars().nth()` or `.bytes().nth()`\n\ - for more information, see chapter 8 in The Book: \ - " - ), - message = "the type `{T}` cannot be indexed by `{Self}`", - label = "slice indices are of type `usize` or ranges of `usize`" -)] -pub unsafe trait SliceIndex: private_slice_index::Sealed { - /// The output type returned by methods. - #[stable(feature = "slice_get_slice", since = "1.28.0")] - type Output: ?Sized; - - /// Returns a shared reference to the output at this location, if in - /// bounds. - #[unstable(feature = "slice_index_methods", issue = "none")] - fn get(self, slice: &T) -> Option<&Self::Output>; - - /// Returns a mutable reference to the output at this location, if in - /// bounds. - #[unstable(feature = "slice_index_methods", issue = "none")] - fn get_mut(self, slice: &mut T) -> Option<&mut Self::Output>; - - /// Returns a shared reference to the output at this location, without - /// performing any bounds checking. - /// Calling this method with an out-of-bounds index or a dangling `slice` pointer - /// is *[undefined behavior]* even if the resulting reference is not used. - /// - /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html - #[unstable(feature = "slice_index_methods", issue = "none")] - unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output; - - /// Returns a mutable reference to the output at this location, without - /// performing any bounds checking. - /// Calling this method with an out-of-bounds index or a dangling `slice` pointer - /// is *[undefined behavior]* even if the resulting reference is not used. - /// - /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html - #[unstable(feature = "slice_index_methods", issue = "none")] - unsafe fn get_unchecked_mut(self, slice: *mut T) -> *mut Self::Output; - - /// Returns a shared reference to the output at this location, panicking - /// if out of bounds. - #[unstable(feature = "slice_index_methods", issue = "none")] - #[track_caller] - fn index(self, slice: &T) -> &Self::Output; - - /// Returns a mutable reference to the output at this location, panicking - /// if out of bounds. - #[unstable(feature = "slice_index_methods", issue = "none")] - #[track_caller] - fn index_mut(self, slice: &mut T) -> &mut Self::Output; -} - -#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for usize { - type Output = T; - - #[inline] - fn get(self, slice: &[T]) -> Option<&T> { - // SAFETY: `self` is checked to be in bounds. - if self < slice.len() { unsafe { Some(&*self.get_unchecked(slice)) } } else { None } - } - - #[inline] - fn get_mut(self, slice: &mut [T]) -> Option<&mut T> { - // SAFETY: `self` is checked to be in bounds. - if self < slice.len() { unsafe { Some(&mut *self.get_unchecked_mut(slice)) } } else { None } - } - - #[inline] - unsafe fn get_unchecked(self, slice: *const [T]) -> *const T { - // SAFETY: the caller guarantees that `slice` is not dangling, so it - // cannot be longer than `isize::MAX`. They also guarantee that - // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, - // so the call to `add` is safe. - unsafe { slice.as_ptr().add(self) } - } - - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T { - // SAFETY: see comments for `get_unchecked` above. - unsafe { slice.as_mut_ptr().add(self) } - } - - #[inline] - fn index(self, slice: &[T]) -> &T { - // N.B., use intrinsic indexing - &(*slice)[self] - } - - #[inline] - fn index_mut(self, slice: &mut [T]) -> &mut T { - // N.B., use intrinsic indexing - &mut (*slice)[self] - } -} - -#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::Range { - type Output = [T]; - - #[inline] - fn get(self, slice: &[T]) -> Option<&[T]> { - if self.start > self.end || self.end > slice.len() { - None - } else { - // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { Some(&*self.get_unchecked(slice)) } - } - } - - #[inline] - fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { - if self.start > self.end || self.end > slice.len() { - None - } else { - // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { Some(&mut *self.get_unchecked_mut(slice)) } - } - } - - #[inline] - unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { - // SAFETY: the caller guarantees that `slice` is not dangling, so it - // cannot be longer than `isize::MAX`. They also guarantee that - // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, - // so the call to `add` is safe. - unsafe { ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start) } - } - - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { - // SAFETY: see comments for `get_unchecked` above. - unsafe { - ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start) - } - } - - #[inline] - fn index(self, slice: &[T]) -> &[T] { - if self.start > self.end { - slice_index_order_fail(self.start, self.end); - } else if self.end > slice.len() { - slice_end_index_len_fail(self.end, slice.len()); - } - // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { &*self.get_unchecked(slice) } - } - - #[inline] - fn index_mut(self, slice: &mut [T]) -> &mut [T] { - if self.start > self.end { - slice_index_order_fail(self.start, self.end); - } else if self.end > slice.len() { - slice_end_index_len_fail(self.end, slice.len()); - } - // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { &mut *self.get_unchecked_mut(slice) } - } -} - -#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::RangeTo { - type Output = [T]; - - #[inline] - fn get(self, slice: &[T]) -> Option<&[T]> { - (0..self.end).get(slice) - } - - #[inline] - fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { - (0..self.end).get_mut(slice) - } - - #[inline] - unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { - // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. - unsafe { (0..self.end).get_unchecked(slice) } - } - - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { - // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. - unsafe { (0..self.end).get_unchecked_mut(slice) } - } - - #[inline] - fn index(self, slice: &[T]) -> &[T] { - (0..self.end).index(slice) - } - - #[inline] - fn index_mut(self, slice: &mut [T]) -> &mut [T] { - (0..self.end).index_mut(slice) - } -} - -#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::RangeFrom { - type Output = [T]; - - #[inline] - fn get(self, slice: &[T]) -> Option<&[T]> { - (self.start..slice.len()).get(slice) - } - - #[inline] - fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { - (self.start..slice.len()).get_mut(slice) - } - - #[inline] - unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { - // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. - unsafe { (self.start..slice.len()).get_unchecked(slice) } - } - - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { - // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. - unsafe { (self.start..slice.len()).get_unchecked_mut(slice) } - } - - #[inline] - fn index(self, slice: &[T]) -> &[T] { - if self.start > slice.len() { - slice_start_index_len_fail(self.start, slice.len()); - } - // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { &*self.get_unchecked(slice) } - } - - #[inline] - fn index_mut(self, slice: &mut [T]) -> &mut [T] { - if self.start > slice.len() { - slice_start_index_len_fail(self.start, slice.len()); - } - // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { &mut *self.get_unchecked_mut(slice) } - } -} - -#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::RangeFull { - type Output = [T]; - - #[inline] - fn get(self, slice: &[T]) -> Option<&[T]> { - Some(slice) - } - - #[inline] - fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { - Some(slice) - } - - #[inline] - unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { - slice - } - - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { - slice - } - - #[inline] - fn index(self, slice: &[T]) -> &[T] { - slice - } - - #[inline] - fn index_mut(self, slice: &mut [T]) -> &mut [T] { - slice - } -} - -#[stable(feature = "inclusive_range", since = "1.26.0")] -unsafe impl SliceIndex<[T]> for ops::RangeInclusive { - type Output = [T]; - - #[inline] - fn get(self, slice: &[T]) -> Option<&[T]> { - if *self.end() == usize::MAX { None } else { (*self.start()..self.end() + 1).get(slice) } - } - - #[inline] - fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { - if *self.end() == usize::MAX { - None - } else { - (*self.start()..self.end() + 1).get_mut(slice) - } - } - - #[inline] - unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { - // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. - unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) } - } - - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { - // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. - unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) } - } - - #[inline] - fn index(self, slice: &[T]) -> &[T] { - if *self.end() == usize::MAX { - slice_end_index_overflow_fail(); - } - (*self.start()..self.end() + 1).index(slice) - } - - #[inline] - fn index_mut(self, slice: &mut [T]) -> &mut [T] { - if *self.end() == usize::MAX { - slice_end_index_overflow_fail(); - } - (*self.start()..self.end() + 1).index_mut(slice) - } -} - -#[stable(feature = "inclusive_range", since = "1.26.0")] -unsafe impl SliceIndex<[T]> for ops::RangeToInclusive { - type Output = [T]; - - #[inline] - fn get(self, slice: &[T]) -> Option<&[T]> { - (0..=self.end).get(slice) - } - - #[inline] - fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { - (0..=self.end).get_mut(slice) - } - - #[inline] - unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { - // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. - unsafe { (0..=self.end).get_unchecked(slice) } - } - - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { - // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. - unsafe { (0..=self.end).get_unchecked_mut(slice) } - } - - #[inline] - fn index(self, slice: &[T]) -> &[T] { - (0..=self.end).index(slice) - } - - #[inline] - fn index_mut(self, slice: &mut [T]) -> &mut [T] { - (0..=self.end).index_mut(slice) - } -} - //////////////////////////////////////////////////////////////////////////////// // Common traits //////////////////////////////////////////////////////////////////////////////// @@ -3813,284 +3369,3 @@ impl Default for &mut [T] { &mut [] } } - -// Comparison traits -// - -extern "C" { - /// Calls implementation provided memcmp. - /// - /// Interprets the data as u8. - /// - /// Returns 0 for equal, < 0 for less than and > 0 for greater - /// than. - // FIXME(#32610): Return type should be c_int - fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq<[B]> for [A] -where - A: PartialEq, -{ - fn eq(&self, other: &[B]) -> bool { - SlicePartialEq::equal(self, other) - } - - fn ne(&self, other: &[B]) -> bool { - SlicePartialEq::not_equal(self, other) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for [T] {} - -/// Implements comparison of vectors lexicographically. -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for [T] { - fn cmp(&self, other: &[T]) -> Ordering { - SliceOrd::compare(self, other) - } -} - -/// Implements comparison of vectors lexicographically. -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for [T] { - fn partial_cmp(&self, other: &[T]) -> Option { - SlicePartialOrd::partial_compare(self, other) - } -} - -#[doc(hidden)] -// intermediate trait for specialization of slice's PartialEq -trait SlicePartialEq { - fn equal(&self, other: &[B]) -> bool; - - fn not_equal(&self, other: &[B]) -> bool { - !self.equal(other) - } -} - -// Generic slice equality -impl SlicePartialEq for [A] -where - A: PartialEq, -{ - default fn equal(&self, other: &[B]) -> bool { - if self.len() != other.len() { - return false; - } - - self.iter().zip(other.iter()).all(|(x, y)| x == y) - } -} - -// Use an equal-pointer optimization when types are `Eq` -// We can't make `A` and `B` the same type because `min_specialization` won't -// allow it. -impl SlicePartialEq for [A] -where - A: MarkerEq, -{ - default fn equal(&self, other: &[B]) -> bool { - if self.len() != other.len() { - return false; - } - - // While performance would suffer if `guaranteed_eq` just returned `false` - // for all arguments, correctness and return value of this function are not affected. - if self.as_ptr().guaranteed_eq(other.as_ptr() as *const A) { - return true; - } - - self.iter().zip(other.iter()).all(|(x, y)| x == y) - } -} - -// Use memcmp for bytewise equality when the types allow -impl SlicePartialEq for [A] -where - A: BytewiseEquality, -{ - fn equal(&self, other: &[B]) -> bool { - if self.len() != other.len() { - return false; - } - - // While performance would suffer if `guaranteed_eq` just returned `false` - // for all arguments, correctness and return value of this function are not affected. - if self.as_ptr().guaranteed_eq(other.as_ptr() as *const A) { - return true; - } - // SAFETY: `self` and `other` are references and are thus guaranteed to be valid. - // The two slices have been checked to have the same size above. - unsafe { - let size = mem::size_of_val(self); - memcmp(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0 - } - } -} - -#[doc(hidden)] -// intermediate trait for specialization of slice's PartialOrd -trait SlicePartialOrd: Sized { - fn partial_compare(left: &[Self], right: &[Self]) -> Option; -} - -impl SlicePartialOrd for A { - default fn partial_compare(left: &[A], right: &[A]) -> Option { - let l = cmp::min(left.len(), right.len()); - - // Slice to the loop iteration range to enable bound check - // elimination in the compiler - let lhs = &left[..l]; - let rhs = &right[..l]; - - for i in 0..l { - match lhs[i].partial_cmp(&rhs[i]) { - Some(Ordering::Equal) => (), - non_eq => return non_eq, - } - } - - left.len().partial_cmp(&right.len()) - } -} - -// This is the impl that we would like to have. Unfortunately it's not sound. -// See `partial_ord_slice.rs`. -/* -impl SlicePartialOrd for A -where - A: Ord, -{ - default fn partial_compare(left: &[A], right: &[A]) -> Option { - Some(SliceOrd::compare(left, right)) - } -} -*/ - -impl SlicePartialOrd for A { - fn partial_compare(left: &[A], right: &[A]) -> Option { - Some(SliceOrd::compare(left, right)) - } -} - -#[rustc_specialization_trait] -trait AlwaysApplicableOrd: SliceOrd + Ord {} - -macro_rules! always_applicable_ord { - ($([$($p:tt)*] $t:ty,)*) => { - $(impl<$($p)*> AlwaysApplicableOrd for $t {})* - } -} - -always_applicable_ord! { - [] u8, [] u16, [] u32, [] u64, [] u128, [] usize, - [] i8, [] i16, [] i32, [] i64, [] i128, [] isize, - [] bool, [] char, - [T: ?Sized] *const T, [T: ?Sized] *mut T, - [T: AlwaysApplicableOrd] &T, - [T: AlwaysApplicableOrd] &mut T, - [T: AlwaysApplicableOrd] Option, -} - -#[doc(hidden)] -// intermediate trait for specialization of slice's Ord -trait SliceOrd: Sized { - fn compare(left: &[Self], right: &[Self]) -> Ordering; -} - -impl SliceOrd for A { - default fn compare(left: &[Self], right: &[Self]) -> Ordering { - let l = cmp::min(left.len(), right.len()); - - // Slice to the loop iteration range to enable bound check - // elimination in the compiler - let lhs = &left[..l]; - let rhs = &right[..l]; - - for i in 0..l { - match lhs[i].cmp(&rhs[i]) { - Ordering::Equal => (), - non_eq => return non_eq, - } - } - - left.len().cmp(&right.len()) - } -} - -// memcmp compares a sequence of unsigned bytes lexicographically. -// this matches the order we want for [u8], but no others (not even [i8]). -impl SliceOrd for u8 { - #[inline] - fn compare(left: &[Self], right: &[Self]) -> Ordering { - let order = - // SAFETY: `left` and `right` are references and are thus guaranteed to be valid. - // We use the minimum of both lengths which guarantees that both regions are - // valid for reads in that interval. - unsafe { memcmp(left.as_ptr(), right.as_ptr(), cmp::min(left.len(), right.len())) }; - if order == 0 { - left.len().cmp(&right.len()) - } else if order < 0 { - Less - } else { - Greater - } - } -} - -// Hack to allow specializing on `Eq` even though `Eq` has a method. -#[rustc_unsafe_specialization_marker] -trait MarkerEq: PartialEq {} - -impl MarkerEq for T {} - -#[doc(hidden)] -/// Trait implemented for types that can be compared for equality using -/// their bytewise representation -#[rustc_specialization_trait] -trait BytewiseEquality: MarkerEq + Copy {} - -macro_rules! impl_marker_for { - ($traitname:ident, $($ty:ty)*) => { - $( - impl $traitname<$ty> for $ty { } - )* - } -} - -impl_marker_for!(BytewiseEquality, - u8 i8 u16 i16 u32 i32 u64 i64 u128 i128 usize isize char bool); - -trait SliceContains: Sized { - fn slice_contains(&self, x: &[Self]) -> bool; -} - -impl SliceContains for T -where - T: PartialEq, -{ - default fn slice_contains(&self, x: &[Self]) -> bool { - x.iter().any(|y| *y == *self) - } -} - -impl SliceContains for u8 { - fn slice_contains(&self, x: &[Self]) -> bool { - memchr::memchr(*self, x).is_some() - } -} - -impl SliceContains for i8 { - fn slice_contains(&self, x: &[Self]) -> bool { - let byte = *self as u8; - // SAFETY: `i8` and `u8` have the same memory layout, thus casting `x.as_ptr()` - // as `*const u8` is safe. The `x.as_ptr()` comes from a reference and is thus guaranteed - // to be valid for reads for the length of the slice `x.len()`, which cannot be larger - // than `isize::MAX`. The returned slice is never mutated. - let bytes: &[u8] = unsafe { from_raw_parts(x.as_ptr() as *const u8, x.len()) }; - memchr::memchr(byte, bytes).is_some() - } -} From f2976ab2d69c70b5aa09319a1a9241e3a4f121ab Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 4 Sep 2020 01:45:11 +0000 Subject: [PATCH 0414/1052] Move ascii to new module --- library/core/src/slice/ascii.rs | 156 +++++++++++++++++++++++++++++++ library/core/src/slice/mod.rs | 158 +------------------------------- 2 files changed, 157 insertions(+), 157 deletions(-) create mode 100644 library/core/src/slice/ascii.rs diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs new file mode 100644 index 0000000000000..42032bc9035bc --- /dev/null +++ b/library/core/src/slice/ascii.rs @@ -0,0 +1,156 @@ +//! Operations on ASCII `[u8]`. + +use crate::mem; + +#[lang = "slice_u8"] +#[cfg(not(test))] +impl [u8] { + /// Checks if all bytes in this slice are within the ASCII range. + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn is_ascii(&self) -> bool { + is_ascii(self) + } + + /// Checks that two slices are an ASCII case-insensitive match. + /// + /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, + /// but without allocating and copying temporaries. + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool { + self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a.eq_ignore_ascii_case(b)) + } + + /// Converts this slice to its ASCII upper case equivalent in-place. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new uppercased value without modifying the existing one, use + /// [`to_ascii_uppercase`]. + /// + /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn make_ascii_uppercase(&mut self) { + for byte in self { + byte.make_ascii_uppercase(); + } + } + + /// Converts this slice to its ASCII lower case equivalent in-place. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new lowercased value without modifying the existing one, use + /// [`to_ascii_lowercase`]. + /// + /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn make_ascii_lowercase(&mut self) { + for byte in self { + byte.make_ascii_lowercase(); + } + } +} + +/// Returns `true` if any byte in the word `v` is nonascii (>= 128). Snarfed +/// from `../str/mod.rs`, which does something similar for utf8 validation. +#[inline] +fn contains_nonascii(v: usize) -> bool { + const NONASCII_MASK: usize = 0x80808080_80808080u64 as usize; + (NONASCII_MASK & v) != 0 +} + +/// Optimized ASCII test that will use usize-at-a-time operations instead of +/// byte-at-a-time operations (when possible). +/// +/// The algorithm we use here is pretty simple. If `s` is too short, we just +/// check each byte and be done with it. Otherwise: +/// +/// - Read the first word with an unaligned load. +/// - Align the pointer, read subsequent words until end with aligned loads. +/// - Read the last `usize` from `s` with an unaligned load. +/// +/// If any of these loads produces something for which `contains_nonascii` +/// (above) returns true, then we know the answer is false. +#[inline] +fn is_ascii(s: &[u8]) -> bool { + const USIZE_SIZE: usize = mem::size_of::(); + + let len = s.len(); + let align_offset = s.as_ptr().align_offset(USIZE_SIZE); + + // If we wouldn't gain anything from the word-at-a-time implementation, fall + // back to a scalar loop. + // + // We also do this for architectures where `size_of::()` isn't + // sufficient alignment for `usize`, because it's a weird edge case. + if len < USIZE_SIZE || len < align_offset || USIZE_SIZE < mem::align_of::() { + return s.iter().all(|b| b.is_ascii()); + } + + // We always read the first word unaligned, which means `align_offset` is + // 0, we'd read the same value again for the aligned read. + let offset_to_aligned = if align_offset == 0 { USIZE_SIZE } else { align_offset }; + + let start = s.as_ptr(); + // SAFETY: We verify `len < USIZE_SIZE` above. + let first_word = unsafe { (start as *const usize).read_unaligned() }; + + if contains_nonascii(first_word) { + return false; + } + // We checked this above, somewhat implicitly. Note that `offset_to_aligned` + // is either `align_offset` or `USIZE_SIZE`, both of are explicitly checked + // above. + debug_assert!(offset_to_aligned <= len); + + // SAFETY: word_ptr is the (properly aligned) usize ptr we use to read the + // middle chunk of the slice. + let mut word_ptr = unsafe { start.add(offset_to_aligned) as *const usize }; + + // `byte_pos` is the byte index of `word_ptr`, used for loop end checks. + let mut byte_pos = offset_to_aligned; + + // Paranoia check about alignment, since we're about to do a bunch of + // unaligned loads. In practice this should be impossible barring a bug in + // `align_offset` though. + debug_assert_eq!((word_ptr as usize) % mem::align_of::(), 0); + + // Read subsequent words until the last aligned word, excluding the last + // aligned word by itself to be done in tail check later, to ensure that + // tail is always one `usize` at most to extra branch `byte_pos == len`. + while byte_pos < len - USIZE_SIZE { + debug_assert!( + // Sanity check that the read is in bounds + (word_ptr as usize + USIZE_SIZE) <= (start.wrapping_add(len) as usize) && + // And that our assumptions about `byte_pos` hold. + (word_ptr as usize) - (start as usize) == byte_pos + ); + + // SAFETY: We know `word_ptr` is properly aligned (because of + // `align_offset`), and we know that we have enough bytes between `word_ptr` and the end + let word = unsafe { word_ptr.read() }; + if contains_nonascii(word) { + return false; + } + + byte_pos += USIZE_SIZE; + // SAFETY: We know that `byte_pos <= len - USIZE_SIZE`, which means that + // after this `add`, `word_ptr` will be at most one-past-the-end. + word_ptr = unsafe { word_ptr.add(1) }; + } + + // Sanity check to ensure there really is only one `usize` left. This should + // be guaranteed by our loop condition. + debug_assert!(byte_pos <= len && len - byte_pos <= USIZE_SIZE); + + // SAFETY: This relies on `len >= USIZE_SIZE`, which we check at the start. + let last_word = unsafe { (start.add(len - USIZE_SIZE) as *const usize).read_unaligned() }; + + !contains_nonascii(last_word) +} diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 6447543d0e715..e01374a3f5933 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -39,6 +39,7 @@ use crate::result::Result::{Err, Ok}; /// Pure rust memchr implementation, taken from rust-memchr pub mod memchr; +mod ascii; mod cmp; mod index; mod iter; @@ -3197,163 +3198,6 @@ impl [T] { } } -#[lang = "slice_u8"] -#[cfg(not(test))] -impl [u8] { - /// Checks if all bytes in this slice are within the ASCII range. - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn is_ascii(&self) -> bool { - is_ascii(self) - } - - /// Checks that two slices are an ASCII case-insensitive match. - /// - /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, - /// but without allocating and copying temporaries. - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool { - self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a.eq_ignore_ascii_case(b)) - } - - /// Converts this slice to its ASCII upper case equivalent in-place. - /// - /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', - /// but non-ASCII letters are unchanged. - /// - /// To return a new uppercased value without modifying the existing one, use - /// [`to_ascii_uppercase`]. - /// - /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn make_ascii_uppercase(&mut self) { - for byte in self { - byte.make_ascii_uppercase(); - } - } - - /// Converts this slice to its ASCII lower case equivalent in-place. - /// - /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', - /// but non-ASCII letters are unchanged. - /// - /// To return a new lowercased value without modifying the existing one, use - /// [`to_ascii_lowercase`]. - /// - /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn make_ascii_lowercase(&mut self) { - for byte in self { - byte.make_ascii_lowercase(); - } - } -} - -/// Returns `true` if any byte in the word `v` is nonascii (>= 128). Snarfed -/// from `../str/mod.rs`, which does something similar for utf8 validation. -#[inline] -fn contains_nonascii(v: usize) -> bool { - const NONASCII_MASK: usize = 0x80808080_80808080u64 as usize; - (NONASCII_MASK & v) != 0 -} - -/// Optimized ASCII test that will use usize-at-a-time operations instead of -/// byte-at-a-time operations (when possible). -/// -/// The algorithm we use here is pretty simple. If `s` is too short, we just -/// check each byte and be done with it. Otherwise: -/// -/// - Read the first word with an unaligned load. -/// - Align the pointer, read subsequent words until end with aligned loads. -/// - Read the last `usize` from `s` with an unaligned load. -/// -/// If any of these loads produces something for which `contains_nonascii` -/// (above) returns true, then we know the answer is false. -#[inline] -fn is_ascii(s: &[u8]) -> bool { - const USIZE_SIZE: usize = mem::size_of::(); - - let len = s.len(); - let align_offset = s.as_ptr().align_offset(USIZE_SIZE); - - // If we wouldn't gain anything from the word-at-a-time implementation, fall - // back to a scalar loop. - // - // We also do this for architectures where `size_of::()` isn't - // sufficient alignment for `usize`, because it's a weird edge case. - if len < USIZE_SIZE || len < align_offset || USIZE_SIZE < mem::align_of::() { - return s.iter().all(|b| b.is_ascii()); - } - - // We always read the first word unaligned, which means `align_offset` is - // 0, we'd read the same value again for the aligned read. - let offset_to_aligned = if align_offset == 0 { USIZE_SIZE } else { align_offset }; - - let start = s.as_ptr(); - // SAFETY: We verify `len < USIZE_SIZE` above. - let first_word = unsafe { (start as *const usize).read_unaligned() }; - - if contains_nonascii(first_word) { - return false; - } - // We checked this above, somewhat implicitly. Note that `offset_to_aligned` - // is either `align_offset` or `USIZE_SIZE`, both of are explicitly checked - // above. - debug_assert!(offset_to_aligned <= len); - - // SAFETY: word_ptr is the (properly aligned) usize ptr we use to read the - // middle chunk of the slice. - let mut word_ptr = unsafe { start.add(offset_to_aligned) as *const usize }; - - // `byte_pos` is the byte index of `word_ptr`, used for loop end checks. - let mut byte_pos = offset_to_aligned; - - // Paranoia check about alignment, since we're about to do a bunch of - // unaligned loads. In practice this should be impossible barring a bug in - // `align_offset` though. - debug_assert_eq!((word_ptr as usize) % mem::align_of::(), 0); - - // Read subsequent words until the last aligned word, excluding the last - // aligned word by itself to be done in tail check later, to ensure that - // tail is always one `usize` at most to extra branch `byte_pos == len`. - while byte_pos < len - USIZE_SIZE { - debug_assert!( - // Sanity check that the read is in bounds - (word_ptr as usize + USIZE_SIZE) <= (start.wrapping_add(len) as usize) && - // And that our assumptions about `byte_pos` hold. - (word_ptr as usize) - (start as usize) == byte_pos - ); - - // SAFETY: We know `word_ptr` is properly aligned (because of - // `align_offset`), and we know that we have enough bytes between `word_ptr` and the end - let word = unsafe { word_ptr.read() }; - if contains_nonascii(word) { - return false; - } - - byte_pos += USIZE_SIZE; - // SAFETY: We know that `byte_pos <= len - USIZE_SIZE`, which means that - // after this `add`, `word_ptr` will be at most one-past-the-end. - word_ptr = unsafe { word_ptr.add(1) }; - } - - // Sanity check to ensure there really is only one `usize` left. This should - // be guaranteed by our loop condition. - debug_assert!(byte_pos <= len && len - byte_pos <= USIZE_SIZE); - - // SAFETY: This relies on `len >= USIZE_SIZE`, which we check at the start. - let last_word = unsafe { (start.add(len - USIZE_SIZE) as *const usize).read_unaligned() }; - - !contains_nonascii(last_word) -} - -//////////////////////////////////////////////////////////////////////////////// -// Common traits -//////////////////////////////////////////////////////////////////////////////// - #[stable(feature = "rust1", since = "1.0.0")] impl Default for &[T] { /// Creates an empty slice. From 6655ad7ed85d68e7475c576729cde91c3c921960 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 4 Sep 2020 15:15:18 +0000 Subject: [PATCH 0415/1052] Removed outdated comments --- library/core/src/slice/mod.rs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index e01374a3f5933..64a707c39f076 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -8,18 +8,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -// How this module is organized. -// -// The library infrastructure for slices is fairly messy. There's -// a lot of stuff defined here. Let's keep it clean. -// -// The layout of this file is thus: -// -// * Inherent methods. This is where most of the slice API resides. -// * Implementations of a few common traits with important slice ops. -// * The `raw` and `bytes` submodules. -// * Boilerplate trait implementations. - use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::intrinsics::assume; use crate::marker::{self, Copy}; @@ -87,10 +75,6 @@ pub use index::SliceIndex; use index::{slice_end_index_len_fail, slice_index_order_fail}; use index::{slice_end_index_overflow_fail, slice_start_index_overflow_fail}; -// -// Extension traits -// - #[lang = "slice"] #[cfg(not(test))] impl [T] { From bfb56d82d465c6e24b4ab27c44fbb7e39bb4dd13 Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Mon, 14 Sep 2020 13:14:16 +0200 Subject: [PATCH 0416/1052] Update based on @alex's PR --- src/ci/docker/host-x86_64/dist-various-1/Dockerfile | 6 ------ src/doc/rustc/src/platform-support.md | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile index 4e48d9b543361..431892697d4c9 100644 --- a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile @@ -84,10 +84,6 @@ RUN env \ CXX=arm-linux-gnueabihf-g++ CXXFLAGS="-march=armv7-a" \ bash musl.sh armv7hf && \ env \ - CC=aarch64-linux-gnu-gcc \ - CXX=aarch64-linux-gnu-g++ \ - bash musl.sh aarch64 && \ - env \ CC=mips-openwrt-linux-gcc \ CXX=mips-openwrt-linux-g++ \ bash musl.sh mips && \ @@ -130,7 +126,6 @@ ENV TARGETS=$TARGETS,arm-unknown-linux-musleabihf ENV TARGETS=$TARGETS,armv5te-unknown-linux-gnueabi ENV TARGETS=$TARGETS,armv5te-unknown-linux-musleabi ENV TARGETS=$TARGETS,armv7-unknown-linux-musleabihf -ENV TARGETS=$TARGETS,aarch64-unknown-linux-musl ENV TARGETS=$TARGETS,aarch64-unknown-none ENV TARGETS=$TARGETS,aarch64-unknown-none-softfloat ENV TARGETS=$TARGETS,sparc64-unknown-linux-gnu @@ -185,7 +180,6 @@ ENV RUST_CONFIGURE_ARGS \ --musl-root-arm=/musl-arm \ --musl-root-armhf=/musl-armhf \ --musl-root-armv7hf=/musl-armv7hf \ - --musl-root-aarch64=/musl-aarch64 \ --musl-root-mips=/musl-mips \ --musl-root-mipsel=/musl-mipsel \ --musl-root-mips64=/musl-mips64 \ diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 794eeafbbbff9..56e90e0ac03e1 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -62,7 +62,7 @@ target | std | host | notes `aarch64-linux-android` | ✓ | | ARM64 Android `aarch64-pc-windows-msvc` | ✓ | | ARM64 Windows MSVC `aarch64-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (kernel 4.2, glibc 2.17) -`aarch64-unknown-linux-musl` | ✓ | | ARM64 Linux with MUSL +`aarch64-unknown-linux-musl` | ✓ | ✓ | ARM64 Linux with MUSL `aarch64-unknown-none` | * | | Bare ARM64, hardfloat `aarch64-unknown-none-softfloat` | * | | Bare ARM64, softfloat `arm-linux-androideabi` | ✓ | | ARMv7 Android From b88155160cf4abc07a5b8da98385ac343a5eeca0 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Mon, 14 Sep 2020 21:08:08 +0800 Subject: [PATCH 0417/1052] Simplify iter flatten struct doc --- library/core/src/iter/adapters/flatten.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 4202e52448dcf..4b19c451a993b 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -7,8 +7,8 @@ use super::Map; /// An iterator that maps each element to an iterator, and yields the elements /// of the produced iterators. /// -/// This `struct` is created by the [`flat_map`] method on [`Iterator`]. See its -/// documentation for more. +/// This `struct` is created by [`Iterator::flat_map`]. See its documentation +/// for more. /// /// [`flat_map`]: trait.Iterator.html#method.flat_map /// [`Iterator`]: trait.Iterator.html From 43709f7111b37a473dc779b12c755ed4df5beaf5 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 14 Sep 2020 16:11:06 +0200 Subject: [PATCH 0418/1052] :arrow_up: rust-analyzer --- src/tools/rust-analyzer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer index 0275b08d15216..0d03fe6ef57d3 160000 --- a/src/tools/rust-analyzer +++ b/src/tools/rust-analyzer @@ -1 +1 @@ -Subproject commit 0275b08d1521606fa733f76fe5d5707717456fb4 +Subproject commit 0d03fe6ef57d3956e92382e0e1f1a916015191cb From 5112f879ff3c106dadc9d5699f471b06473cf7e0 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Tue, 15 Sep 2020 00:35:48 +0800 Subject: [PATCH 0419/1052] Remove flatten doc intra-doc links --- library/core/src/iter/adapters/flatten.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 4b19c451a993b..ddb1aaebc1f3e 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -9,9 +9,6 @@ use super::Map; /// /// This `struct` is created by [`Iterator::flat_map`]. See its documentation /// for more. -/// -/// [`flat_map`]: trait.Iterator.html#method.flat_map -/// [`Iterator`]: trait.Iterator.html #[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] pub struct FlatMap { From 1f26a189551ea037e769d27c433b4eaf8c3091b2 Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Mon, 14 Sep 2020 10:32:42 -0700 Subject: [PATCH 0420/1052] Use intra-doc links for `DelaySpanBugEmitted` Also improve the docs for it a bit. --- compiler/rustc_middle/src/ty/context.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index aacf61e5b425a..56746666e2f1f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -66,8 +66,8 @@ use std::mem; use std::ops::{Bound, Deref}; use std::sync::Arc; -/// A type that is not publicly constructable. This prevents people from making `TyKind::Error` -/// except through `tcx.err*()`, which are in this module. +/// A type that is not publicly constructable. This prevents people from making [`TyKind::Error`]s +/// except through the error-reporting functions on a [`tcx`][TyCtxt]. #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] #[derive(TyEncodable, TyDecodable, HashStable)] pub struct DelaySpanBugEmitted(()); From 15349ef5fad7778c872ce0f7d887e581819183f4 Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Mon, 14 Sep 2020 10:39:07 -0700 Subject: [PATCH 0421/1052] Minor improvements to `mir::Constant` docs --- compiler/rustc_middle/src/mir/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index d32a7a4062e27..29daf7e9309aa 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2285,8 +2285,8 @@ impl<'tcx> Debug for Rvalue<'tcx> { /// Constants /// /// Two constants are equal if they are the same constant. Note that -/// this does not necessarily mean that they are "==" in Rust -- in -/// particular one must be wary of `NaN`! +/// this does not necessarily mean that they are `==` in Rust -- in +/// particular, one must be wary of `NaN`! #[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, HashStable)] pub struct Constant<'tcx> { From 5c1043a7507245098d9ba1a90e034487654dd961 Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Mon, 14 Sep 2020 10:42:06 -0700 Subject: [PATCH 0422/1052] Fix diagram for `DebruijnIndex` --- compiler/rustc_middle/src/ty/sty.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 9f5fc5a2d3fbc..1f6c0121ae2eb 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1233,13 +1233,13 @@ rustc_index::newtype_index! { /// particular, imagine a type like this: /// /// for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char) - /// ^ ^ | | | - /// | | | | | - /// | +------------+ 0 | | - /// | | | - /// +--------------------------------+ 1 | - /// | | - /// +------------------------------------------+ 0 + /// ^ ^ | | | + /// | | | | | + /// | +------------+ 0 | | + /// | | | + /// +----------------------------------+ 1 | + /// | | + /// +----------------------------------------------+ 0 /// /// In this type, there are two binders (the outer fn and the inner /// fn). We need to be able to determine, for any given region, which From 62effcbd5bfaf74e99def3e9a660dba9728b0b47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 31 Aug 2020 10:24:37 -0700 Subject: [PATCH 0423/1052] Detect turbofish with multiple type params missing leading `::` Fix #76072. --- .../rustc_parse/src/parser/diagnostics.rs | 46 ++++++++++ compiler/rustc_parse/src/parser/stmt.rs | 26 ++++-- src/test/ui/did_you_mean/issue-40396.rs | 21 +++++ src/test/ui/did_you_mean/issue-40396.stderr | 83 ++++++++++++++++++- 4 files changed, 167 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 12efe391fb964..002d8baf03ff0 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -548,6 +548,52 @@ impl<'a> Parser<'a> { } } + /// When writing a turbofish with multiple type parameters missing the leading `::`, we will + /// encounter a parse error when encountering the first `,`. + pub(super) fn check_mistyped_turbofish_with_multiple_type_params( + &mut self, + mut e: DiagnosticBuilder<'a>, + expr: &mut P, + ) -> PResult<'a, ()> { + if let ExprKind::Binary(binop, _, _) = &expr.kind { + if let ast::BinOpKind::Lt = binop.node { + if self.eat(&token::Comma) { + let x = self.parse_seq_to_before_end( + &token::Gt, + SeqSep::trailing_allowed(token::Comma), + |p| p.parse_ty(), + ); + match x { + Ok((_, _, false)) => { + self.bump(); // `>` + match self.parse_expr() { + Ok(_) => { + e.span_suggestion_verbose( + binop.span.shrink_to_lo(), + "use `::<...>` instead of `<...>` to specify type arguments", + "::".to_string(), + Applicability::MaybeIncorrect, + ); + e.emit(); + *expr = self.mk_expr_err(expr.span.to(self.prev_token.span)); + return Ok(()); + } + Err(mut err) => { + err.cancel(); + } + } + } + Err(mut err) => { + err.cancel(); + } + _ => {} + } + } + } + } + Err(e) + } + /// Check to see if a pair of chained operators looks like an attempt at chained comparison, /// e.g. `1 < x <= 3`. If so, suggest either splitting the comparison into two, or /// parenthesising the leftmost comparison. diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index ac067cb0eab8c..d8a2e106dc086 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -363,7 +363,7 @@ impl<'a> Parser<'a> { let mut eat_semi = true; match stmt.kind { // Expression without semicolon. - StmtKind::Expr(ref expr) + StmtKind::Expr(ref mut expr) if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) => { // Just check for errors and recover; do not eat semicolon yet. @@ -387,15 +387,29 @@ impl<'a> Parser<'a> { ); } } - e.emit(); - self.recover_stmt(); + if let Err(mut e) = + self.check_mistyped_turbofish_with_multiple_type_params(e, expr) + { + e.emit(); + self.recover_stmt(); + } // Don't complain about type errors in body tail after parse error (#57383). let sp = expr.span.to(self.prev_token.span); - stmt.kind = StmtKind::Expr(self.mk_expr_err(sp)); + *expr = self.mk_expr_err(sp); } } - StmtKind::Local(..) => { - self.expect_semi()?; + StmtKind::Local(ref mut local) => { + if let Err(e) = self.expect_semi() { + // We might be at the `,` in `let x = foo;`. Try to recover. + match &mut local.init { + Some(ref mut expr) => { + self.check_mistyped_turbofish_with_multiple_type_params(e, expr)?; + // We found `foo`, have we fully recovered? + self.expect_semi()?; + } + None => return Err(e), + } + } eat_semi = false; } StmtKind::Empty => eat_semi = false, diff --git a/src/test/ui/did_you_mean/issue-40396.rs b/src/test/ui/did_you_mean/issue-40396.rs index e4e94bb949237..5497ba2e11f73 100644 --- a/src/test/ui/did_you_mean/issue-40396.rs +++ b/src/test/ui/did_you_mean/issue-40396.rs @@ -1,8 +1,29 @@ fn main() { (0..13).collect>(); //~^ ERROR comparison operators cannot be chained + //~| HELP use `::<...>` instead Vec::new(); //~^ ERROR comparison operators cannot be chained + //~| HELP use `::<...>` instead (0..13).collect(); //~^ ERROR comparison operators cannot be chained + //~| HELP use `::<...>` instead + let x = std::collections::HashMap::new(); //~ ERROR expected one of + //~^ HELP use `::<...>` instead + let x: () = 42; //~ ERROR mismatched types + let x = { + std::collections::HashMap::new() //~ ERROR expected one of + //~^ HELP use `::<...>` instead + }; + let x: () = 42; //~ ERROR mismatched types + let x = { + std::collections::HashMap::new(); //~ ERROR expected one of + //~^ HELP use `::<...>` instead + let x: () = 42; //~ ERROR mismatched types + }; + { + std::collections::HashMap::new(1, 2); //~ ERROR expected one of + //~^ HELP use `::<...>` instead + let x: () = 32; //~ ERROR mismatched types + }; } diff --git a/src/test/ui/did_you_mean/issue-40396.stderr b/src/test/ui/did_you_mean/issue-40396.stderr index 10972697f9fcd..184bcf0c74b14 100644 --- a/src/test/ui/did_you_mean/issue-40396.stderr +++ b/src/test/ui/did_you_mean/issue-40396.stderr @@ -10,7 +10,7 @@ LL | (0..13).collect::>(); | ^^ error: comparison operators cannot be chained - --> $DIR/issue-40396.rs:4:8 + --> $DIR/issue-40396.rs:5:8 | LL | Vec::new(); | ^ ^ @@ -21,7 +21,7 @@ LL | Vec::::new(); | ^^ error: comparison operators cannot be chained - --> $DIR/issue-40396.rs:6:20 + --> $DIR/issue-40396.rs:8:20 | LL | (0..13).collect(); | ^ ^ @@ -31,5 +31,82 @@ help: use `::<...>` instead of `<...>` to specify type arguments LL | (0..13).collect::(); | ^^ -error: aborting due to 3 previous errors +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, or an operator, found `,` + --> $DIR/issue-40396.rs:11:43 + | +LL | let x = std::collections::HashMap::new(); + | ^ expected one of 7 possible tokens + | +help: use `::<...>` instead of `<...>` to specify type arguments + | +LL | let x = std::collections::HashMap::::new(); + | ^^ + +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `,` + --> $DIR/issue-40396.rs:15:39 + | +LL | std::collections::HashMap::new() + | ^ expected one of 8 possible tokens + | +help: use `::<...>` instead of `<...>` to specify type arguments + | +LL | std::collections::HashMap::::new() + | ^^ + +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `,` + --> $DIR/issue-40396.rs:20:39 + | +LL | std::collections::HashMap::new(); + | ^ expected one of 8 possible tokens + | +help: use `::<...>` instead of `<...>` to specify type arguments + | +LL | std::collections::HashMap::::new(); + | ^^ + +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `,` + --> $DIR/issue-40396.rs:25:39 + | +LL | std::collections::HashMap::new(1, 2); + | ^ expected one of 8 possible tokens + | +help: use `::<...>` instead of `<...>` to specify type arguments + | +LL | std::collections::HashMap::::new(1, 2); + | ^^ + +error[E0308]: mismatched types + --> $DIR/issue-40396.rs:13:17 + | +LL | let x: () = 42; + | -- ^^ expected `()`, found integer + | | + | expected due to this + +error[E0308]: mismatched types + --> $DIR/issue-40396.rs:18:17 + | +LL | let x: () = 42; + | -- ^^ expected `()`, found integer + | | + | expected due to this + +error[E0308]: mismatched types + --> $DIR/issue-40396.rs:22:21 + | +LL | let x: () = 42; + | -- ^^ expected `()`, found integer + | | + | expected due to this + +error[E0308]: mismatched types + --> $DIR/issue-40396.rs:27:21 + | +LL | let x: () = 32; + | -- ^^ expected `()`, found integer + | | + | expected due to this + +error: aborting due to 11 previous errors +For more information about this error, try `rustc --explain E0308`. From c6f2ddf1cb1e328245da59a4fb42f90403389a07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 11 Sep 2020 17:20:56 -0700 Subject: [PATCH 0424/1052] Fix rebase and add comments --- compiler/rustc_typeck/src/check/_match.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs index 08cf178c81390..836a4ff78c79e 100644 --- a/compiler/rustc_typeck/src/check/_match.rs +++ b/compiler/rustc_typeck/src/check/_match.rs @@ -6,7 +6,7 @@ use rustc_infer::traits::Obligation; use rustc_middle::ty::{self, ToPredicate, Ty}; use rustc_span::Span; use rustc_trait_selection::opaque_types::InferCtxtExt as _; -use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, }; @@ -153,12 +153,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); suggest_box &= self.infcx.predicate_must_hold_modulo_regions(&obl); if !suggest_box { + // We've encountered some obligation that didn't hold, so the + // return expression can't just be boxed. We don't need to + // evaluate the rest of the obligations. break; } } _ => {} } } + // If all the obligations hold (or there are no obligations) the tail expression + // we can suggest to return a boxed trait object instead of an opaque type. if suggest_box { self.ret_type_span.clone() } else { None } } _ => None, From e1607c87f0bb96c1c59d84a2789b7f7d2b69e182 Mon Sep 17 00:00:00 2001 From: iximeow Date: Mon, 14 Sep 2020 13:13:02 -0700 Subject: [PATCH 0425/1052] clean up comment text a bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Esteban Küber --- compiler/rustc_middle/src/ty/diagnostics.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 0416ef9e64387..715319747e390 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -204,7 +204,7 @@ pub fn suggest_constraining_type_param( // - insert: `, T: Zar` // // Additionally, there may be no `where` clause whatsoever in the case that this was - // reached becauase the generic parameter has a default: + // reached because the generic parameter has a default: // // Message: // trait Foo {... } @@ -217,8 +217,8 @@ pub fn suggest_constraining_type_param( if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. }) && generics.where_clause.predicates.len() == 0 { - // Suggest a bound, but there are no existing where clauses for this ``, so - // suggest adding one. + // Suggest a bound, but there is no existing `where` clause *and* the type param has a + // default (``), so we suggest adding `where T: Bar`. err.span_suggestion_verbose( generics.where_clause.tail_span_for_suggestion(), &msg_restrict_type_further, From 32efcfca2fece73a69efcedd1c78f45b0bbcb39c Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 14 Sep 2020 14:42:37 -0700 Subject: [PATCH 0426/1052] Include non-JSON output in error display for lint-doc failure. Some errors, like if rustc is broken, or dylib search path is wrong, will only display non-JSON errors. Show those, too, to make it easier to debug a problem. --- src/tools/lint-docs/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index 5323bc357c09d..92b3d186fa141 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -402,9 +402,12 @@ fn generate_lint_output( None => { let rendered: Vec<&str> = msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect(); + let non_json: Vec<&str> = + stderr.lines().filter(|line| !line.starts_with('{')).collect(); Err(format!( - "did not find lint `{}` in output of example, got:\n{}", + "did not find lint `{}` in output of example, got:\n{}\n{}", name, + non_json.join("\n"), rendered.join("\n") ) .into()) From 9dad90814543bdd10b1989020edad70939b0e869 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 14 Sep 2020 14:42:56 -0700 Subject: [PATCH 0427/1052] Fix generating rustc docs with non-default lib directory. --- src/bootstrap/builder.rs | 8 ++++++-- src/bootstrap/doc.rs | 4 ++++ src/bootstrap/test.rs | 8 ++++---- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 0f18660c0e109..53560c9deb6c2 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -710,7 +710,7 @@ impl<'a> Builder<'a> { /// Adds the compiler's directory of dynamic libraries to `cmd`'s dynamic /// library lookup path. - pub fn add_rustc_lib_path(&self, compiler: Compiler, cmd: &mut Cargo) { + pub fn add_rustc_lib_path(&self, compiler: Compiler, cmd: &mut Command) { // Windows doesn't need dylib path munging because the dlls for the // compiler live next to the compiler and the system will find them // automatically. @@ -718,7 +718,7 @@ impl<'a> Builder<'a> { return; } - add_dylib_path(vec![self.rustc_libdir(compiler)], &mut cmd.command); + add_dylib_path(vec![self.rustc_libdir(compiler)], cmd); } /// Gets a path to the compiler specified. @@ -1515,6 +1515,10 @@ impl Cargo { self.command.env(key.as_ref(), value.as_ref()); self } + + pub fn add_rustc_lib_path(&mut self, builder: &Builder<'_>, compiler: Compiler) { + builder.add_rustc_lib_path(compiler, &mut self.command); + } } impl From for Command { diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 98a0119e4df12..f90e76a4f4ea6 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -766,6 +766,10 @@ impl Step for RustcBook { if builder.config.verbose() { cmd.arg("--verbose"); } + // If the lib directories are in an unusual location (changed in + // config.toml), then this needs to explicitly update the dylib search + // path. + builder.add_rustc_lib_path(self.compiler, &mut cmd); builder.run(&mut cmd); // Run rustbook/mdbook to generate the HTML pages. builder.ensure(RustbookSrc { diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 045dda2d4cb4c..ba5f75c49ac77 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -270,7 +270,7 @@ impl Step for Rls { &[], ); - builder.add_rustc_lib_path(compiler, &mut cargo); + cargo.add_rustc_lib_path(builder, compiler); cargo.arg("--").args(builder.config.cmd.test_args()); if try_run(builder, &mut cargo.into()) { @@ -328,7 +328,7 @@ impl Step for Rustfmt { t!(fs::create_dir_all(&dir)); cargo.env("RUSTFMT_TEST_DIR", dir); - builder.add_rustc_lib_path(compiler, &mut cargo); + cargo.add_rustc_lib_path(builder, compiler); if try_run(builder, &mut cargo.into()) { builder.save_toolstate("rustfmt", ToolState::TestPass); @@ -449,7 +449,7 @@ impl Step for Miri { cargo.arg("--").args(builder.config.cmd.test_args()); - builder.add_rustc_lib_path(compiler, &mut cargo); + cargo.add_rustc_lib_path(builder, compiler); if !try_run(builder, &mut cargo.into()) { return; @@ -554,7 +554,7 @@ impl Step for Clippy { cargo.arg("--").args(builder.config.cmd.test_args()); - builder.add_rustc_lib_path(compiler, &mut cargo); + cargo.add_rustc_lib_path(builder, compiler); builder.run(&mut cargo.into()); } From 58310ce94bc9bde54fdbf97ec4fee18201d69221 Mon Sep 17 00:00:00 2001 From: Camelid Date: Mon, 14 Sep 2020 15:14:21 -0700 Subject: [PATCH 0428/1052] Use intra-doc links in `core::mem` --- library/core/src/mem/mod.rs | 57 +++++++++++-------------------------- 1 file changed, 17 insertions(+), 40 deletions(-) diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 6d8ed2f4ffb1a..aa1b5529df222 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -31,10 +31,10 @@ pub use crate::intrinsics::transmute; /// forever in an unreachable state. However, it does not guarantee that pointers /// to this memory will remain valid. /// -/// * If you want to leak memory, see [`Box::leak`][leak]. -/// * If you want to obtain a raw pointer to the memory, see [`Box::into_raw`][into_raw]. +/// * If you want to leak memory, see [`Box::leak`]. +/// * If you want to obtain a raw pointer to the memory, see [`Box::into_raw`]. /// * If you want to dispose of a value properly, running its destructor, see -/// [`mem::drop`][drop]. +/// [`mem::drop`]. /// /// # Safety /// @@ -132,15 +132,11 @@ pub use crate::intrinsics::transmute; /// ownership to `s` — the final step of interacting with `v` to dispose of it without /// running its destructor is entirely avoided. /// -/// [drop]: fn.drop.html -/// [uninit]: fn.uninitialized.html -/// [clone]: ../clone/trait.Clone.html -/// [swap]: fn.swap.html -/// [box]: ../../std/boxed/struct.Box.html -/// [leak]: ../../std/boxed/struct.Box.html#method.leak -/// [into_raw]: ../../std/boxed/struct.Box.html#method.into_raw +/// [`Box`]: ../../std/boxed/struct.Box.html +/// [`Box::leak`]: ../../std/boxed/struct.Box.html#method.leak +/// [`Box::into_raw`]: ../../std/boxed/struct.Box.html#method.into_raw +/// [`mem::drop`]: drop /// [ub]: ../../reference/behavior-considered-undefined.html -/// [`ManuallyDrop`]: struct.ManuallyDrop.html #[inline] #[rustc_const_stable(feature = "const_forget", since = "1.46.0")] #[stable(feature = "rust1", since = "1.0.0")] @@ -152,8 +148,6 @@ pub const fn forget(t: T) { /// /// This function is just a shim intended to be removed when the `unsized_locals` feature gets /// stabilized. -/// -/// [`forget`]: fn.forget.html #[inline] #[unstable(feature = "forget_unsized", issue = "none")] pub fn forget_unsized(t: T) { @@ -301,7 +295,7 @@ pub fn forget_unsized(t: T) { /// assert_eq!(2, mem::size_of::()); /// ``` /// -/// [alignment]: ./fn.align_of.html +/// [alignment]: align_of #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_promotable] @@ -365,7 +359,6 @@ pub const fn size_of_val(val: &T) -> usize { /// [slice]: ../../std/primitive.slice.html /// [trait object]: ../../book/ch17-02-trait-objects.html /// [extern type]: ../../unstable-book/language-features/extern-types.html -/// [`size_of_val`]: ../../core/mem/fn.size_of_val.html /// /// # Examples /// @@ -501,7 +494,6 @@ pub const fn align_of_val(val: &T) -> usize { /// [slice]: ../../std/primitive.slice.html /// [trait object]: ../../book/ch17-02-trait-objects.html /// [extern type]: ../../unstable-book/language-features/extern-types.html -/// [`align_of_val`]: ../../core/mem/fn.align_of_val.html /// /// # Examples /// @@ -540,7 +532,7 @@ pub unsafe fn align_of_val_raw(val: *const T) -> usize { /// `needs_drop` explicitly. Types like [`HashMap`], on the other hand, have to drop /// values one at a time and should use this API. /// -/// [`drop_in_place`]: ../ptr/fn.drop_in_place.html +/// [`drop_in_place`]: crate::ptr::drop_in_place /// [`HashMap`]: ../../std/collections/struct.HashMap.html /// /// # Examples @@ -595,9 +587,9 @@ pub const fn needs_drop() -> bool { /// This has the same effect as [`MaybeUninit::zeroed().assume_init()`][zeroed]. /// It is useful for FFI sometimes, but should generally be avoided. /// -/// [zeroed]: union.MaybeUninit.html#method.zeroed +/// [zeroed]: MaybeUninit::zeroed /// [ub]: ../../reference/behavior-considered-undefined.html -/// [inv]: union.MaybeUninit.html#initialization-invariant +/// [inv]: MaybeUninit#initialization-invariant /// /// # Examples /// @@ -650,10 +642,10 @@ pub unsafe fn zeroed() -> T { /// (Notice that the rules around uninitialized integers are not finalized yet, but /// until they are, it is advisable to avoid them.) /// -/// [`MaybeUninit`]: union.MaybeUninit.html -/// [uninit]: union.MaybeUninit.html#method.uninit -/// [assume_init]: union.MaybeUninit.html#method.assume_init -/// [inv]: union.MaybeUninit.html#initialization-invariant +/// [`MaybeUninit`]: MaybeUninit +/// [uninit]: MaybeUninit::uninit +/// [assume_init]: MaybeUninit::assume_init +/// [inv]: MaybeUninit#initialization-invariant #[inline(always)] #[rustc_deprecated(since = "1.39.0", reason = "use `mem::MaybeUninit` instead")] #[stable(feature = "rust1", since = "1.0.0")] @@ -686,9 +678,6 @@ pub unsafe fn uninitialized() -> T { /// assert_eq!(42, x); /// assert_eq!(5, y); /// ``` -/// -/// [`replace`]: fn.replace.html -/// [`take`]: fn.take.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn swap(x: &mut T, y: &mut T) { @@ -754,10 +743,6 @@ pub fn swap(x: &mut T, y: &mut T) { /// assert_eq!(buffer.get_and_reset(), vec![0, 1]); /// assert_eq!(buffer.buf.len(), 0); /// ``` -/// -/// [`Clone`]: ../../std/clone/trait.Clone.html -/// [`replace`]: fn.replace.html -/// [`swap`]: fn.swap.html #[inline] #[stable(feature = "mem_take", since = "1.40.0")] pub fn take(dest: &mut T) -> T { @@ -822,10 +807,6 @@ pub fn take(dest: &mut T) -> T { /// assert_eq!(buffer.replace_index(0, 2), 0); /// assert_eq!(buffer.buf[0], 2); /// ``` -/// -/// [`Clone`]: ../../std/clone/trait.Clone.html -/// [`swap`]: fn.swap.html -/// [`take`]: fn.take.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "if you don't need the old value, you can just assign the new value directly"] @@ -851,7 +832,7 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// Because `_x` is moved into the function, it is automatically dropped before /// the function returns. /// -/// [drop]: ../ops/trait.Drop.html +/// [drop]: Drop /// /// # Examples /// @@ -894,8 +875,7 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// println!("x: {}, y: {}", x, y.0); // still available /// ``` /// -/// [`RefCell`]: ../../std/cell/struct.RefCell.html -/// [`Copy`]: ../../std/marker/trait.Copy.html +/// [`RefCell`]: crate::cell::RefCell #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn drop(_x: T) {} @@ -914,7 +894,6 @@ pub fn drop(_x: T) {} /// `T`. /// /// [ub]: ../../reference/behavior-considered-undefined.html -/// [size_of]: fn.size_of.html /// /// # Examples /// @@ -960,8 +939,6 @@ pub unsafe fn transmute_copy(src: &T) -> U { /// Opaque type representing the discriminant of an enum. /// /// See the [`discriminant`] function in this module for more information. -/// -/// [`discriminant`]: fn.discriminant.html #[stable(feature = "discriminant_value", since = "1.21.0")] pub struct Discriminant(::Discriminant); From 1b5317f68b2b55803d5051e9945f9a33817fccef Mon Sep 17 00:00:00 2001 From: Robin Schoonover Date: Sun, 13 Sep 2020 21:52:25 -0600 Subject: [PATCH 0429/1052] Add rc_buffer lint for Rc and other buffer types --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/types.rs | 84 ++++++++++++++++++++++++++++++++- clippy_lints/src/utils/paths.rs | 1 + src/lintlist/mod.rs | 7 +++ tests/ui/rc_buffer.rs | 13 +++++ tests/ui/rc_buffer.stderr | 28 +++++++++++ 7 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 tests/ui/rc_buffer.rs create mode 100644 tests/ui/rc_buffer.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 285a2ff8060d2..8922f5e702790 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1775,6 +1775,7 @@ Released 2018-09-13 [`range_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_plus_one [`range_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_step_by_zero [`range_zip_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_zip_with_len +[`rc_buffer`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer [`redundant_allocation`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation [`redundant_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone [`redundant_closure`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c017c5cb5d02c..239eeb10bb421 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -837,6 +837,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &types::LET_UNIT_VALUE, &types::LINKEDLIST, &types::OPTION_OPTION, + &types::RC_BUFFER, &types::REDUNDANT_ALLOCATION, &types::TYPE_COMPLEXITY, &types::UNIT_ARG, @@ -1804,6 +1805,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE), LintId::of(&redundant_pub_crate::REDUNDANT_PUB_CRATE), LintId::of(&transmute::USELESS_TRANSMUTE), + LintId::of(&types::RC_BUFFER), LintId::of(&use_self::USE_SELF), ]); } diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index b6d405cca770d..5f3a2e0b6d42f 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -215,11 +215,41 @@ declare_clippy_lint! { "redundant allocation" } +declare_clippy_lint! { + /// **What it does:** Checks for Rc and Arc when T is a mutable buffer type such as String or Vec + /// + /// **Why is this bad?** Expressions such as Rc have no advantage over Rc, since + /// it is larger and involves an extra level of indirection, and doesn't implement Borrow. + /// + /// While mutating a buffer type would still be possible with Rc::get_mut(), it only + /// works if there are no additional references yet, which defeats the purpose of + /// enclosing it in a shared ownership type. Instead, additionally wrapping the inner + /// type with an interior mutable container (such as RefCell or Mutex) would normally + /// be used. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust,ignore + /// # use std::rc::Rc; + /// fn foo(interned: Rc) { ... } + /// ``` + /// + /// Better: + /// + /// ```rust,ignore + /// fn foo(interned: Rc) { ... } + /// ``` + pub RC_BUFFER, + nursery, + "shared ownership of a buffer type" +} + pub struct Types { vec_box_size_threshold: u64, } -impl_lint_pass!(Types => [BOX_VEC, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, REDUNDANT_ALLOCATION]); +impl_lint_pass!(Types => [BOX_VEC, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, REDUNDANT_ALLOCATION, RC_BUFFER]); impl<'tcx> LateLintPass<'tcx> for Types { fn check_fn(&mut self, cx: &LateContext<'_>, _: FnKind<'_>, decl: &FnDecl<'_>, _: &Body<'_>, _: Span, id: HirId) { @@ -272,6 +302,19 @@ fn match_type_parameter(cx: &LateContext<'_>, qpath: &QPath<'_>, path: &[&str]) None } +fn match_buffer_type(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<&'static str> { + if match_type_parameter(cx, qpath, &paths::STRING).is_some() { + return Some("str"); + } + if match_type_parameter(cx, qpath, &paths::OS_STRING).is_some() { + return Some("std::ffi::OsStr"); + } + if match_type_parameter(cx, qpath, &paths::PATH_BUF).is_some() { + return Some("std::path::Path"); + } + None +} + fn match_borrows_parameter(_cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option { let last = last_path_segment(qpath); if_chain! { @@ -385,6 +428,45 @@ impl Types { ); return; // don't recurse into the type } + if let Some(alternate) = match_buffer_type(cx, qpath) { + span_lint_and_sugg( + cx, + RC_BUFFER, + hir_ty.span, + "usage of `Rc` when T is a buffer type", + "try", + format!("Rc<{}>", alternate), + Applicability::MachineApplicable, + ); + return; // don't recurse into the type + } + if match_type_parameter(cx, qpath, &paths::VEC).is_some() { + let vec_ty = match &last_path_segment(qpath).args.unwrap().args[0] { + GenericArg::Type(ty) => match &ty.kind { + TyKind::Path(qpath) => qpath, + _ => return, + }, + _ => return, + }; + let inner_span = match &last_path_segment(&vec_ty).args.unwrap().args[0] { + GenericArg::Type(ty) => ty.span, + _ => return, + }; + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + RC_BUFFER, + hir_ty.span, + "usage of `Rc` when T is a buffer type", + "try", + format!( + "Rc<[{}]>", + snippet_with_applicability(cx, inner_span, "..", &mut applicability) + ), + Applicability::MachineApplicable, + ); + return; // don't recurse into the type + } if let Some(span) = match_borrows_parameter(cx, qpath) { let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 65320d6a0e0bd..2df11d2efcfbf 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -113,6 +113,7 @@ pub const STD_CONVERT_IDENTITY: [&str; 3] = ["std", "convert", "identity"]; pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"]; pub const STD_MEM_TRANSMUTE: [&str; 3] = ["std", "mem", "transmute"]; pub const STD_PTR_NULL: [&str; 3] = ["std", "ptr", "null"]; +pub const STRING: [&str; 3] = ["alloc", "string", "String"]; 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 SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"]; diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index a7d38c93433d1..d0c6a1d63d97b 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1851,6 +1851,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "ranges", }, + Lint { + name: "rc_buffer", + group: "nursery", + desc: "shared ownership of a buffer type", + deprecation: None, + module: "types", + }, Lint { name: "redundant_allocation", group: "perf", diff --git a/tests/ui/rc_buffer.rs b/tests/ui/rc_buffer.rs new file mode 100644 index 0000000000000..c8c2bec67ee59 --- /dev/null +++ b/tests/ui/rc_buffer.rs @@ -0,0 +1,13 @@ +use std::ffi::OsString; +use std::path::PathBuf; +use std::rc::Rc; + +#[warn(clippy::rc_buffer)] +struct S { + a: Rc, + b: Rc, + c: Rc>, + d: Rc, +} + +fn main() {} diff --git a/tests/ui/rc_buffer.stderr b/tests/ui/rc_buffer.stderr new file mode 100644 index 0000000000000..641a13a225134 --- /dev/null +++ b/tests/ui/rc_buffer.stderr @@ -0,0 +1,28 @@ +error: usage of `Rc` when T is a buffer type + --> $DIR/rc_buffer.rs:7:8 + | +LL | a: Rc, + | ^^^^^^^^^^ help: try: `Rc` + | + = note: `-D clippy::rc-buffer` implied by `-D warnings` + +error: usage of `Rc` when T is a buffer type + --> $DIR/rc_buffer.rs:8:8 + | +LL | b: Rc, + | ^^^^^^^^^^^ help: try: `Rc` + +error: usage of `Rc` when T is a buffer type + --> $DIR/rc_buffer.rs:9:8 + | +LL | c: Rc>, + | ^^^^^^^^^^^ help: try: `Rc<[u8]>` + +error: usage of `Rc` when T is a buffer type + --> $DIR/rc_buffer.rs:10:8 + | +LL | d: Rc, + | ^^^^^^^^^^^^ help: try: `Rc` + +error: aborting due to 4 previous errors + From 2dd7175d60e070c7ee2b4609bdb17eae16e381f0 Mon Sep 17 00:00:00 2001 From: Robin Schoonover Date: Sun, 13 Sep 2020 22:17:10 -0600 Subject: [PATCH 0430/1052] Apply rc_buffer lint to Arc --- clippy_lints/src/types.rs | 40 +++++++++++++++++++++++++++++++++++ tests/ui/rc_buffer_arc.rs | 13 ++++++++++++ tests/ui/rc_buffer_arc.stderr | 28 ++++++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 tests/ui/rc_buffer_arc.rs create mode 100644 tests/ui/rc_buffer_arc.stderr diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 5f3a2e0b6d42f..da04d07885b9f 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -480,6 +480,46 @@ impl Types { ); return; // don't recurse into the type } + } else if cx.tcx.is_diagnostic_item(sym::Arc, def_id) { + if let Some(alternate) = match_buffer_type(cx, qpath) { + span_lint_and_sugg( + cx, + RC_BUFFER, + hir_ty.span, + "usage of `Arc` when T is a buffer type", + "try", + format!("Arc<{}>", alternate), + Applicability::MachineApplicable, + ); + return; // don't recurse into the type + } + if match_type_parameter(cx, qpath, &paths::VEC).is_some() { + let vec_ty = match &last_path_segment(qpath).args.unwrap().args[0] { + GenericArg::Type(ty) => match &ty.kind { + TyKind::Path(qpath) => qpath, + _ => return, + }, + _ => return, + }; + let inner_span = match &last_path_segment(&vec_ty).args.unwrap().args[0] { + GenericArg::Type(ty) => ty.span, + _ => return, + }; + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + RC_BUFFER, + hir_ty.span, + "usage of `Arc` when T is a buffer type", + "try", + format!( + "Arc<[{}]>", + snippet_with_applicability(cx, inner_span, "..", &mut applicability) + ), + Applicability::MachineApplicable, + ); + return; // don't recurse into the type + } } else if cx.tcx.is_diagnostic_item(sym!(vec_type), def_id) { if_chain! { // Get the _ part of Vec<_> diff --git a/tests/ui/rc_buffer_arc.rs b/tests/ui/rc_buffer_arc.rs new file mode 100644 index 0000000000000..a878b0ab3365d --- /dev/null +++ b/tests/ui/rc_buffer_arc.rs @@ -0,0 +1,13 @@ +use std::ffi::OsString; +use std::path::PathBuf; +use std::sync::Arc; + +#[warn(clippy::rc_buffer)] +struct S { + a: Arc, + b: Arc, + c: Arc>, + d: Arc, +} + +fn main() {} diff --git a/tests/ui/rc_buffer_arc.stderr b/tests/ui/rc_buffer_arc.stderr new file mode 100644 index 0000000000000..c4b016210469b --- /dev/null +++ b/tests/ui/rc_buffer_arc.stderr @@ -0,0 +1,28 @@ +error: usage of `Arc` when T is a buffer type + --> $DIR/rc_buffer_arc.rs:7:8 + | +LL | a: Arc, + | ^^^^^^^^^^^ help: try: `Arc` + | + = note: `-D clippy::rc-buffer` implied by `-D warnings` + +error: usage of `Arc` when T is a buffer type + --> $DIR/rc_buffer_arc.rs:8:8 + | +LL | b: Arc, + | ^^^^^^^^^^^^ help: try: `Arc` + +error: usage of `Arc` when T is a buffer type + --> $DIR/rc_buffer_arc.rs:9:8 + | +LL | c: Arc>, + | ^^^^^^^^^^^^ help: try: `Arc<[u8]>` + +error: usage of `Arc` when T is a buffer type + --> $DIR/rc_buffer_arc.rs:10:8 + | +LL | d: Arc, + | ^^^^^^^^^^^^^ help: try: `Arc` + +error: aborting due to 4 previous errors + From 4d73ccaa9419b393b9c94f977ec0e158897feeb3 Mon Sep 17 00:00:00 2001 From: Haraman Johal Date: Tue, 15 Sep 2020 00:20:31 +0100 Subject: [PATCH 0431/1052] clarify margin of error in wording of float comparison operator lint messages --- clippy_lints/src/misc.rs | 6 +++--- tests/ui/float_cmp.stderr | 22 +++++++++++----------- tests/ui/float_cmp_const.stderr | 30 +++++++++++++++--------------- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index d4a50dd9013f0..81e6214f143ec 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -411,16 +411,16 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { if !is_comparing_arrays { diag.span_suggestion( expr.span, - "consider comparing them within some error", + "consider comparing them within some margin of error", format!( - "({}).abs() {} error", + "({}).abs() {} error_margin", lhs - rhs, if op == BinOpKind::Eq { '<' } else { '>' } ), Applicability::HasPlaceholders, // snippet ); } - diag.note("`f32::EPSILON` and `f64::EPSILON` are available for the `error`"); + diag.note("`f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`"); }); } else if op == BinOpKind::Rem && is_integer_const(cx, right, 1) { span_lint(cx, MODULO_ONE, expr.span, "any number modulo 1 will be 0"); diff --git a/tests/ui/float_cmp.stderr b/tests/ui/float_cmp.stderr index 2d454e8e70de5..f7c380fc915c0 100644 --- a/tests/ui/float_cmp.stderr +++ b/tests/ui/float_cmp.stderr @@ -2,34 +2,34 @@ error: strict comparison of `f32` or `f64` --> $DIR/float_cmp.rs:65:5 | LL | ONE as f64 != 2.0; - | ^^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(ONE as f64 - 2.0).abs() > error` + | ^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE as f64 - 2.0).abs() > error_margin` | = note: `-D clippy::float-cmp` implied by `-D warnings` - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error` + = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` --> $DIR/float_cmp.rs:70:5 | LL | x == 1.0; - | ^^^^^^^^ help: consider comparing them within some error: `(x - 1.0).abs() < error` + | ^^^^^^^^ help: consider comparing them within some margin of error: `(x - 1.0).abs() < error_margin` | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error` + = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` --> $DIR/float_cmp.rs:73:5 | LL | twice(x) != twice(ONE as f64); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(twice(x) - twice(ONE as f64)).abs() > error` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(twice(x) - twice(ONE as f64)).abs() > error_margin` | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error` + = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` --> $DIR/float_cmp.rs:93:5 | LL | NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(NON_ZERO_ARRAY[i] - NON_ZERO_ARRAY[j]).abs() < error` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(NON_ZERO_ARRAY[i] - NON_ZERO_ARRAY[j]).abs() < error_margin` | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error` + = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` arrays --> $DIR/float_cmp.rs:98:5 @@ -37,15 +37,15 @@ error: strict comparison of `f32` or `f64` arrays LL | a1 == a2; | ^^^^^^^^ | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error` + = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` --> $DIR/float_cmp.rs:99:5 | LL | a1[0] == a2[0]; - | ^^^^^^^^^^^^^^ help: consider comparing them within some error: `(a1[0] - a2[0]).abs() < error` + | ^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(a1[0] - a2[0]).abs() < error_margin` | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error` + = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: aborting due to 6 previous errors diff --git a/tests/ui/float_cmp_const.stderr b/tests/ui/float_cmp_const.stderr index 19dc4a284b726..5d0455363e8e0 100644 --- a/tests/ui/float_cmp_const.stderr +++ b/tests/ui/float_cmp_const.stderr @@ -2,58 +2,58 @@ error: strict comparison of `f32` or `f64` constant --> $DIR/float_cmp_const.rs:20:5 | LL | 1f32 == ONE; - | ^^^^^^^^^^^ help: consider comparing them within some error: `(1f32 - ONE).abs() < error` + | ^^^^^^^^^^^ help: consider comparing them within some margin of error: `(1f32 - ONE).abs() < error_margin` | = note: `-D clippy::float-cmp-const` implied by `-D warnings` - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error` + = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` constant --> $DIR/float_cmp_const.rs:21:5 | LL | TWO == ONE; - | ^^^^^^^^^^ help: consider comparing them within some error: `(TWO - ONE).abs() < error` + | ^^^^^^^^^^ help: consider comparing them within some margin of error: `(TWO - ONE).abs() < error_margin` | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error` + = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` constant --> $DIR/float_cmp_const.rs:22:5 | LL | TWO != ONE; - | ^^^^^^^^^^ help: consider comparing them within some error: `(TWO - ONE).abs() > error` + | ^^^^^^^^^^ help: consider comparing them within some margin of error: `(TWO - ONE).abs() > error_margin` | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error` + = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` constant --> $DIR/float_cmp_const.rs:23:5 | LL | ONE + ONE == TWO; - | ^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(ONE + ONE - TWO).abs() < error` + | ^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE + ONE - TWO).abs() < error_margin` | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error` + = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` constant --> $DIR/float_cmp_const.rs:25:5 | LL | x as f32 == ONE; - | ^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(x as f32 - ONE).abs() < error` + | ^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(x as f32 - ONE).abs() < error_margin` | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error` + = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` constant --> $DIR/float_cmp_const.rs:28:5 | LL | v == ONE; - | ^^^^^^^^ help: consider comparing them within some error: `(v - ONE).abs() < error` + | ^^^^^^^^ help: consider comparing them within some margin of error: `(v - ONE).abs() < error_margin` | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error` + = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` constant --> $DIR/float_cmp_const.rs:29:5 | LL | v != ONE; - | ^^^^^^^^ help: consider comparing them within some error: `(v - ONE).abs() > error` + | ^^^^^^^^ help: consider comparing them within some margin of error: `(v - ONE).abs() > error_margin` | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error` + = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` constant arrays --> $DIR/float_cmp_const.rs:61:5 @@ -61,7 +61,7 @@ error: strict comparison of `f32` or `f64` constant arrays LL | NON_ZERO_ARRAY == NON_ZERO_ARRAY2; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error` + = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: aborting due to 8 previous errors From fd151f5135def6ffae7530f17ff0c458239f209d Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Tue, 15 Sep 2020 08:51:52 +0900 Subject: [PATCH 0432/1052] Remove an extra blank line in `shadow_same` --- clippy_lints/src/shadow.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 087d50c90e671..ef4a54735a498 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -25,7 +25,6 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// # let x = 1; - /// /// // Bad /// let x = &x; /// From a4183f0e61b68ec5a45deeb5208091dd5ede35b0 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 7 Jul 2020 13:35:55 -0700 Subject: [PATCH 0433/1052] librustc_target: Initial support for riscv32gc_unknown_linux_gnu Signed-off-by: Alistair Francis --- compiler/rustc_target/src/spec/mod.rs | 1 + .../src/spec/riscv32gc_unknown_linux_gnu.rs | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index d6e8b304380ca..f1e8330425e25 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -654,6 +654,7 @@ supported_targets! { ("riscv32i-unknown-none-elf", riscv32i_unknown_none_elf), ("riscv32imc-unknown-none-elf", riscv32imc_unknown_none_elf), ("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf), + ("riscv32gc-unknown-linux-gnu", riscv32gc_unknown_linux_gnu), ("riscv64imac-unknown-none-elf", riscv64imac_unknown_none_elf), ("riscv64gc-unknown-none-elf", riscv64gc_unknown_none_elf), ("riscv64gc-unknown-linux-gnu", riscv64gc_unknown_linux_gnu), diff --git a/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs new file mode 100644 index 0000000000000..53963fbb2fd76 --- /dev/null +++ b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs @@ -0,0 +1,25 @@ +use crate::spec::{CodeModel, LinkerFlavor, Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + Ok(Target { + llvm_target: "riscv32-unknown-linux-gnu".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + target_c_int_width: "32".to_string(), + target_env: "gnu".to_string(), + data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(), + arch: "riscv32".to_string(), + target_os: "linux".to_string(), + target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, + options: TargetOptions { + abi_blacklist: super::riscv_base::abi_blacklist(), + code_model: Some(CodeModel::Medium), + cpu: "generic-rv32".to_string(), + features: "+m,+a,+f,+d,+c".to_string(), + llvm_abiname: "ilp32d".to_string(), + max_atomic_width: Some(32), + ..super::linux_base::opts() + }, + }) +} From 82bd5a3e1da85a3c6ee099fe4a4809e7a6913e0b Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Mon, 14 Sep 2020 17:43:06 -0700 Subject: [PATCH 0434/1052] librustc_target: Address comments Signed-off-by: Alistair Francis --- compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs index 53963fbb2fd76..28710c60175b0 100644 --- a/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs @@ -13,7 +13,7 @@ pub fn target() -> TargetResult { target_vendor: "unknown".to_string(), linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { - abi_blacklist: super::riscv_base::abi_blacklist(), + unsupported_abis: super::riscv_base::unsupported_abis(), code_model: Some(CodeModel::Medium), cpu: "generic-rv32".to_string(), features: "+m,+a,+f,+d,+c".to_string(), From 8e3ce43de9844a869e85eafca531079f8e89b732 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 14 Sep 2020 16:54:53 -0700 Subject: [PATCH 0435/1052] Add `Engine::pass_name` to differentiate dataflow runs --- .../src/dataflow/framework/engine.rs | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir/src/dataflow/framework/engine.rs b/compiler/rustc_mir/src/dataflow/framework/engine.rs index 0b5b437d186aa..757709f90ff8e 100644 --- a/compiler/rustc_mir/src/dataflow/framework/engine.rs +++ b/compiler/rustc_mir/src/dataflow/framework/engine.rs @@ -84,6 +84,7 @@ where def_id: DefId, dead_unwinds: Option<&'a BitSet>, entry_sets: IndexVec, + pass_name: Option<&'static str>, analysis: A, /// Cached, cumulative transfer functions for each block. @@ -174,6 +175,7 @@ where body, def_id, dead_unwinds: None, + pass_name: None, entry_sets, apply_trans_for_block, } @@ -189,6 +191,15 @@ where self } + /// Adds an identifier to the graphviz output for this particular run of a dataflow analysis. + /// + /// Some analyses are run multiple times in the compilation pipeline. Give them a `pass_name` + /// to differentiate them. Otherwise, only the results for the latest run will be saved. + pub fn pass_name(mut self, name: &'static str) -> Self { + self.pass_name = Some(name); + self + } + /// Computes the fixpoint for this dataflow problem and returns it. pub fn iterate_to_fixpoint(self) -> Results<'tcx, A> where @@ -202,6 +213,7 @@ where mut entry_sets, tcx, apply_trans_for_block, + pass_name, .. } = self; @@ -249,7 +261,7 @@ where let results = Results { analysis, entry_sets }; - let res = write_graphviz_results(tcx, def_id, &body, &results); + let res = write_graphviz_results(tcx, def_id, &body, &results, pass_name); if let Err(e) = res { warn!("Failed to write graphviz dataflow results: {}", e); } @@ -267,6 +279,7 @@ fn write_graphviz_results( def_id: DefId, body: &mir::Body<'tcx>, results: &Results<'tcx, A>, + pass_name: Option<&'static str>, ) -> std::io::Result<()> where A: Analysis<'tcx>, @@ -285,12 +298,17 @@ where None if tcx.sess.opts.debugging_opts.dump_mir_dataflow && dump_enabled(tcx, A::NAME, def_id) => { + // FIXME: Use some variant of `pretty::dump_path` for this let mut path = PathBuf::from(&tcx.sess.opts.debugging_opts.dump_mir_dir); + let crate_name = tcx.crate_name(def_id.krate); let item_name = ty::print::with_forced_impl_filename_line(|| { tcx.def_path(def_id).to_filename_friendly_no_crate() }); - path.push(format!("rustc.{}.{}.dot", item_name, A::NAME)); + + let pass_name = pass_name.map(|s| format!(".{}", s)).unwrap_or_default(); + + path.push(format!("{}.{}.{}{}.dot", crate_name, item_name, A::NAME, pass_name)); path } From 0475c365fedb8243219247db1186d590032b550e Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 14 Sep 2020 17:13:47 -0700 Subject: [PATCH 0436/1052] Add pass names to some common dataflow analyses --- compiler/rustc_mir/src/borrow_check/mod.rs | 4 ++++ .../rustc_mir/src/transform/check_consts/validation.rs | 1 + compiler/rustc_mir/src/transform/elaborate_drops.rs | 3 +++ compiler/rustc_mir/src/transform/generator.rs | 7 +++++-- src/tools/clippy/clippy_lints/src/redundant_clone.rs | 1 + 5 files changed, 14 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs index acd9e3dcf3fcd..a6f06fee3b27b 100644 --- a/compiler/rustc_mir/src/borrow_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/mod.rs @@ -205,6 +205,7 @@ fn do_mir_borrowck<'a, 'tcx>( let mut flow_inits = MaybeInitializedPlaces::new(tcx, &body, &mdpe) .into_engine(tcx, &body, def.did.to_def_id()) + .pass_name("borrowck") .iterate_to_fixpoint() .into_results_cursor(&body); @@ -264,12 +265,15 @@ fn do_mir_borrowck<'a, 'tcx>( let flow_borrows = Borrows::new(tcx, &body, regioncx.clone(), &borrow_set) .into_engine(tcx, &body, def.did.to_def_id()) + .pass_name("borrowck") .iterate_to_fixpoint(); let flow_uninits = MaybeUninitializedPlaces::new(tcx, &body, &mdpe) .into_engine(tcx, &body, def.did.to_def_id()) + .pass_name("borrowck") .iterate_to_fixpoint(); let flow_ever_inits = EverInitializedPlaces::new(tcx, &body, &mdpe) .into_engine(tcx, &body, def.did.to_def_id()) + .pass_name("borrowck") .iterate_to_fixpoint(); let movable_generator = match tcx.hir().get(id) { diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index e8411b121e394..ef306813825f5 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -57,6 +57,7 @@ impl Qualifs<'mir, 'tcx> { MaybeMutBorrowedLocals::mut_borrows_only(tcx, &body, param_env) .unsound_ignore_borrow_on_drop() .into_engine(tcx, &body, def_id.to_def_id()) + .pass_name("const_qualification") .iterate_to_fixpoint() .into_results_cursor(&body) }); diff --git a/compiler/rustc_mir/src/transform/elaborate_drops.rs b/compiler/rustc_mir/src/transform/elaborate_drops.rs index 5f1930693568c..a8b2ee5705f1f 100644 --- a/compiler/rustc_mir/src/transform/elaborate_drops.rs +++ b/compiler/rustc_mir/src/transform/elaborate_drops.rs @@ -44,6 +44,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { let inits = MaybeInitializedPlaces::new(tcx, body, &env) .into_engine(tcx, body, def_id) .dead_unwinds(&dead_unwinds) + .pass_name("elaborate_drops") .iterate_to_fixpoint() .into_results_cursor(body); @@ -51,6 +52,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { .mark_inactive_variants_as_uninit() .into_engine(tcx, body, def_id) .dead_unwinds(&dead_unwinds) + .pass_name("elaborate_drops") .iterate_to_fixpoint() .into_results_cursor(body); @@ -83,6 +85,7 @@ fn find_dead_unwinds<'tcx>( let mut dead_unwinds = BitSet::new_empty(body.basic_blocks().len()); let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &env) .into_engine(tcx, body, def_id) + .pass_name("find_dead_unwinds") .iterate_to_fixpoint() .into_results_cursor(body); for (bb, bb_data) in body.basic_blocks().iter_enumerated() { diff --git a/compiler/rustc_mir/src/transform/generator.rs b/compiler/rustc_mir/src/transform/generator.rs index 78cedec502007..1fffcf8151537 100644 --- a/compiler/rustc_mir/src/transform/generator.rs +++ b/compiler/rustc_mir/src/transform/generator.rs @@ -467,8 +467,10 @@ fn locals_live_across_suspend_points( // Calculate the MIR locals which have been previously // borrowed (even if they are still active). - let borrowed_locals_results = - MaybeBorrowedLocals::all_borrows().into_engine(tcx, body_ref, def_id).iterate_to_fixpoint(); + let borrowed_locals_results = MaybeBorrowedLocals::all_borrows() + .into_engine(tcx, body_ref, def_id) + .pass_name("generator") + .iterate_to_fixpoint(); let mut borrowed_locals_cursor = dataflow::ResultsCursor::new(body_ref, &borrowed_locals_results); @@ -484,6 +486,7 @@ fn locals_live_across_suspend_points( // Calculate the liveness of MIR locals ignoring borrows. let mut liveness = MaybeLiveLocals .into_engine(tcx, body_ref, def_id) + .pass_name("generator") .iterate_to_fixpoint() .into_results_cursor(body_ref); diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs index 57a45e628db61..1615f19237096 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs @@ -87,6 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { let maybe_storage_live_result = MaybeStorageLive .into_engine(cx.tcx, mir, def_id.to_def_id()) + .pass_name("redundant_clone") .iterate_to_fixpoint() .into_results_cursor(mir); let mut possible_borrower = { From f7f9a6c1356dbc79394fbf93d485d6d8b44db380 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 14 Sep 2020 22:03:54 -0400 Subject: [PATCH 0437/1052] Add a comment why `extern crate` is necessary for rustdoc --- src/librustdoc/lib.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 73a783d54060c..94e51d91b542a 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -16,6 +16,12 @@ #[macro_use] extern crate lazy_static; +#[macro_use] +extern crate tracing; + +// N.B. these need `extern crate` even in 2018 edition +// because they're loaded implicitly from the sysroot. +// Dependencies listed in Cargo.toml do not need extern crate. extern crate rustc_ast; extern crate rustc_ast_pretty; extern crate rustc_attr; @@ -42,8 +48,6 @@ extern crate rustc_target; extern crate rustc_trait_selection; extern crate rustc_typeck; extern crate test as testing; -#[macro_use] -extern crate tracing; use std::default::Default; use std::env; From 0f1d25e5564b6f497417e00ed417234a0df7a227 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Mon, 24 Aug 2020 13:15:20 -0400 Subject: [PATCH 0438/1052] Test that bounds checks are elided for indexing after .[r]position() --- ...issue-73396-bounds-check-after-position.rs | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 src/test/codegen/issue-73396-bounds-check-after-position.rs diff --git a/src/test/codegen/issue-73396-bounds-check-after-position.rs b/src/test/codegen/issue-73396-bounds-check-after-position.rs new file mode 100644 index 0000000000000..e5f3ae45c07d3 --- /dev/null +++ b/src/test/codegen/issue-73396-bounds-check-after-position.rs @@ -0,0 +1,78 @@ +// min-llvm-version: 11.0.0 +// compile-flags: -O +// ignore-debug: the debug assertions get in the way +#![crate_type = "lib"] + +// Make sure no bounds checks are emitted when slicing or indexing +// with an index from `position()` or `rposition()`. + +// CHECK-LABEL: @position_slice_to_no_bounds_check +#[no_mangle] +pub fn position_slice_to_no_bounds_check(s: &[u8]) -> &[u8] { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().position(|b| *b == b'\\') { + &s[..idx] + } else { + s + } +} + +// CHECK-LABEL: @position_slice_from_no_bounds_check +#[no_mangle] +pub fn position_slice_from_no_bounds_check(s: &[u8]) -> &[u8] { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().position(|b| *b == b'\\') { + &s[idx..] + } else { + s + } +} + +// CHECK-LABEL: @position_index_no_bounds_check +#[no_mangle] +pub fn position_index_no_bounds_check(s: &[u8]) -> u8 { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().position(|b| *b == b'\\') { + s[idx] + } else { + 42 + } +} +// CHECK-LABEL: @rposition_slice_to_no_bounds_check +#[no_mangle] +pub fn rposition_slice_to_no_bounds_check(s: &[u8]) -> &[u8] { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { + &s[..idx] + } else { + s + } +} + +// CHECK-LABEL: @rposition_slice_from_no_bounds_check +#[no_mangle] +pub fn rposition_slice_from_no_bounds_check(s: &[u8]) -> &[u8] { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { + &s[idx..] + } else { + s + } +} + +// CHECK-LABEL: @rposition_index_no_bounds_check +#[no_mangle] +pub fn rposition_index_no_bounds_check(s: &[u8]) -> u8 { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { + s[idx] + } else { + 42 + } +} From fd79ed42254d7483569ccc48ef35a79635ed5881 Mon Sep 17 00:00:00 2001 From: Camelid Date: Mon, 14 Sep 2020 20:05:00 -0700 Subject: [PATCH 0439/1052] Add docs for `BasicBlock` --- compiler/rustc_middle/src/mir/mod.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index d32a7a4062e27..aeaea0d102c0d 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1076,6 +1076,19 @@ pub struct VarDebugInfo<'tcx> { // BasicBlock rustc_index::newtype_index! { + /// The unit of the MIR [control-flow graph][CFG]. + /// + /// There is no branching (e.g., `if`s, function calls, etc.) within a basic block, which makes + /// it easier to do [data-flow analyses] and optimizations. Basic blocks consist of a series of + /// [statements][`Statement`], ending with a [terminator][`Terminator`]. Basic blocks can have + /// multiple predecessors and successors. + /// + /// Read more about basic blocks in the [rustc-dev-guide][guide-mir]. + /// + /// [CFG]: https://rustc-dev-guide.rust-lang.org/appendix/background.html#cfg + /// [data-flow analyses]: + /// https://rustc-dev-guide.rust-lang.org/appendix/background.html#what-is-a-dataflow-analysis + /// [guide-mir]: https://rustc-dev-guide.rust-lang.org/mir/ pub struct BasicBlock { derive [HashStable] DEBUG_FORMAT = "bb{}", @@ -1092,6 +1105,7 @@ impl BasicBlock { /////////////////////////////////////////////////////////////////////////// // BasicBlockData and Terminator +/// See [`BasicBlock`] for documentation on what basic blocks are at a high level. #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)] pub struct BasicBlockData<'tcx> { /// List of statements in this block. From a872ec47145ce3a82c39bedaca21b99e867d9be2 Mon Sep 17 00:00:00 2001 From: Camelid Date: Mon, 14 Sep 2020 20:10:29 -0700 Subject: [PATCH 0440/1052] Clarify how branching works in a CFG --- compiler/rustc_middle/src/mir/mod.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index aeaea0d102c0d..6f6585d383d52 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1079,9 +1079,11 @@ rustc_index::newtype_index! { /// The unit of the MIR [control-flow graph][CFG]. /// /// There is no branching (e.g., `if`s, function calls, etc.) within a basic block, which makes - /// it easier to do [data-flow analyses] and optimizations. Basic blocks consist of a series of - /// [statements][`Statement`], ending with a [terminator][`Terminator`]. Basic blocks can have - /// multiple predecessors and successors. + /// it easier to do [data-flow analyses] and optimizations. Instead, branches are represented + /// as an edge in a graph between basic blocks. + /// + /// Basic blocks consist of a series of [statements][`Statement`], ending with a + /// [terminator][`Terminator`]. Basic blocks can have multiple predecessors and successors. /// /// Read more about basic blocks in the [rustc-dev-guide][guide-mir]. /// From 792b2ea5812a06fe3d362ae36025998af66199ee Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 14 Sep 2020 22:35:41 -0700 Subject: [PATCH 0441/1052] Update src/doc/rustdoc/src/lints.md Co-authored-by: Joshua Nelson --- src/doc/rustdoc/src/lints.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md index 89aeb683682ec..5424a01edb65c 100644 --- a/src/doc/rustdoc/src/lints.md +++ b/src/doc/rustdoc/src/lints.md @@ -25,11 +25,11 @@ pub fn foo() {} You'll get a warning saying: ```text -warning: `[Nonexistent]` cannot be resolved, ignoring it. +warning: unresolved link to `Nonexistent` --> test.rs:1:24 | 1 | /// I want to link to [`Nonexistent`] but it doesn't exist! - | ^^^^^^^^^^^^^ cannot be resolved, ignoring + | ^^^^^^^^^^^^^ no item named `Nonexistent` in `test` ``` It will also warn when there is an ambiguity and suggest how to disambiguate: From 1f572b03492e7d3ce7156d00f9b44ccedf47bb50 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Tue, 15 Sep 2020 14:41:43 +0800 Subject: [PATCH 0442/1052] Vec doc use elision as code rather than comment --- library/alloc/src/vec.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index d39b6b701e6d8..f6807c4c5c3ae 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -171,7 +171,9 @@ use crate::raw_vec::RawVec; /// /// // ... and that's all! /// // you can also do it like this: -/// let u: &[usize] = &v; // or &[_] +/// let u: &[usize] = &v; +/// // or like this: +/// let u: &[_] = &v; /// ``` /// /// In Rust, it's more common to pass slices as arguments rather than vectors From 7d5db239e73067de3d35394d4c194dd4396c90f1 Mon Sep 17 00:00:00 2001 From: Hameer Abbasi Date: Mon, 14 Sep 2020 23:39:43 +0200 Subject: [PATCH 0443/1052] This commit introduces the following changes: * Change error message for type param in a const expression when using min_const_generics * Change ParamInNonTrivialAnonConst to contain an extra bool used for distinguishing whether the passed-in symbol is a type or a value. --- compiler/rustc_resolve/src/diagnostics.rs | 18 ++++++++++++++---- compiler/rustc_resolve/src/lib.rs | 14 +++++++++----- .../issues/issue-64494.min.stderr | 4 ++-- .../issues/issue-67739.min.stderr | 2 +- .../issue-76701-ty-param-in-const.full.stderr | 18 ++++++++++++++++++ .../issue-76701-ty-param-in-const.min.stderr | 18 ++++++++++++++++++ .../issues/issue-76701-ty-param-in-const.rs | 18 ++++++++++++++++++ .../self-ty-in-const-1.stderr | 2 +- ...rams-in-ct-in-ty-param-lazy-norm.min.stderr | 2 +- 9 files changed, 82 insertions(+), 14 deletions(-) create mode 100644 src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.full.stderr create mode 100644 src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr create mode 100644 src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index b80da64149150..5d66d90e2c008 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -466,7 +466,7 @@ impl<'a> Resolver<'a> { ); err } - ResolutionError::ParamInNonTrivialAnonConst(name) => { + ResolutionError::ParamInNonTrivialAnonConst { name, is_type } => { let mut err = self.session.struct_span_err( span, "generic parameters must not be used inside of non trivial constant values", @@ -478,9 +478,19 @@ impl<'a> Resolver<'a> { name ), ); - err.help( - &format!("it is currently only allowed to use either `{0}` or `{{ {0} }}` as generic constants", name) - ); + + if is_type { + err.note(&format!( + "type parameters are currently not permitted in anonymous constants" + )); + } else { + err.help( + &format!("it is currently only allowed to use either `{0}` or `{{ {0} }}` as generic constants", + name + ) + ); + } + err } ResolutionError::SelfInTyParamDefault => { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 00a37d908cd07..85ddc5f55d110 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -221,7 +221,7 @@ enum ResolutionError<'a> { /// generic parameters must not be used inside of non trivial constant values. /// /// This error is only emitted when using `min_const_generics`. - ParamInNonTrivialAnonConst(Symbol), + ParamInNonTrivialAnonConst { name: Symbol, is_type: bool }, /// Error E0735: type parameters with a default cannot use `Self` SelfInTyParamDefault, /// Error E0767: use of unreachable label @@ -2638,9 +2638,10 @@ impl<'a> Resolver<'a> { if record_used { self.report_error( span, - ResolutionError::ParamInNonTrivialAnonConst( - rib_ident.name, - ), + ResolutionError::ParamInNonTrivialAnonConst { + name: rib_ident.name, + is_type: true, + }, ); } return Res::Err; @@ -2718,7 +2719,10 @@ impl<'a> Resolver<'a> { if record_used { self.report_error( span, - ResolutionError::ParamInNonTrivialAnonConst(rib_ident.name), + ResolutionError::ParamInNonTrivialAnonConst { + name: rib_ident.name, + is_type: false, + }, ); } return Res::Err; diff --git a/src/test/ui/const-generics/issues/issue-64494.min.stderr b/src/test/ui/const-generics/issues/issue-64494.min.stderr index 69fe0974a791a..07822f86f524b 100644 --- a/src/test/ui/const-generics/issues/issue-64494.min.stderr +++ b/src/test/ui/const-generics/issues/issue-64494.min.stderr @@ -4,7 +4,7 @@ error: generic parameters must not be used inside of non trivial constant values LL | impl MyTrait for T where Is<{T::VAL == 5}>: True {} | ^^^^^^ non-trivial anonymous constants must not depend on the parameter `T` | - = help: it is currently only allowed to use either `T` or `{ T }` as generic constants + = note: type parameters are currently not permitted in anonymous constants error: generic parameters must not be used inside of non trivial constant values --> $DIR/issue-64494.rs:19:38 @@ -12,7 +12,7 @@ error: generic parameters must not be used inside of non trivial constant values LL | impl MyTrait for T where Is<{T::VAL == 6}>: True {} | ^^^^^^ non-trivial anonymous constants must not depend on the parameter `T` | - = help: it is currently only allowed to use either `T` or `{ T }` as generic constants + = note: type parameters are currently not permitted in anonymous constants error[E0119]: conflicting implementations of trait `MyTrait`: --> $DIR/issue-64494.rs:19:1 diff --git a/src/test/ui/const-generics/issues/issue-67739.min.stderr b/src/test/ui/const-generics/issues/issue-67739.min.stderr index 1254ee7239dc7..68f1733decb93 100644 --- a/src/test/ui/const-generics/issues/issue-67739.min.stderr +++ b/src/test/ui/const-generics/issues/issue-67739.min.stderr @@ -4,7 +4,7 @@ error: generic parameters must not be used inside of non trivial constant values LL | [0u8; mem::size_of::()]; | ^^^^^^^^^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `Self` | - = help: it is currently only allowed to use either `Self` or `{ Self }` as generic constants + = note: type parameters are currently not permitted in anonymous constants error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.full.stderr b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.full.stderr new file mode 100644 index 0000000000000..089937e66ca06 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.full.stderr @@ -0,0 +1,18 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-76701-ty-param-in-const.rs:6:21 + | +LL | fn ty_param() -> [u8; std::mem::size_of::()] { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: constant expression depends on a generic parameter + --> $DIR/issue-76701-ty-param-in-const.rs:12:37 + | +LL | fn const_param() -> [u8; N + 1] { + | ^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr new file mode 100644 index 0000000000000..a39495e0b2db0 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr @@ -0,0 +1,18 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-76701-ty-param-in-const.rs:6:46 + | +LL | fn ty_param() -> [u8; std::mem::size_of::()] { + | ^ non-trivial anonymous constants must not depend on the parameter `T` + | + = note: type parameters are currently not permitted in anonymous constants + +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-76701-ty-param-in-const.rs:12:42 + | +LL | fn const_param() -> [u8; N + 1] { + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs new file mode 100644 index 0000000000000..9252b592360d3 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs @@ -0,0 +1,18 @@ +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] + +fn ty_param() -> [u8; std::mem::size_of::()] { + //[full]~^ ERROR constant expression depends on a generic parameter + //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values + todo!() +} + +fn const_param() -> [u8; N + 1] { + //[full]~^ ERROR constant expression depends on a generic parameter + //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values + todo!() +} + +fn main() {} diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr index 89ce58564e465..edb77a8743061 100644 --- a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr +++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr @@ -4,7 +4,7 @@ error: generic parameters must not be used inside of non trivial constant values LL | fn t1() -> [u8; std::mem::size_of::()]; | ^^^^ non-trivial anonymous constants must not depend on the parameter `Self` | - = help: it is currently only allowed to use either `Self` or `{ Self }` as generic constants + = note: type parameters are currently not permitted in anonymous constants error: generic `Self` types are currently not permitted in anonymous constants --> $DIR/self-ty-in-const-1.rs:14:41 diff --git a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr index 461822a96083b..e545ae8571f67 100644 --- a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr +++ b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr @@ -12,7 +12,7 @@ error: generic parameters must not be used inside of non trivial constant values LL | struct Foo()]>(T, U); | ^ non-trivial anonymous constants must not depend on the parameter `T` | - = help: it is currently only allowed to use either `T` or `{ T }` as generic constants + = note: type parameters are currently not permitted in anonymous constants 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 From 8afa7ed6aec37c5423cffe12dbc854c954799fb3 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Sun, 6 Sep 2020 23:32:48 +0200 Subject: [PATCH 0444/1052] Add internal lint MatchTypeOnDiagItem --- clippy_lints/src/lib.rs | 3 + clippy_lints/src/utils/internal_lints.rs | 115 ++++++++++++++++++++++- clippy_lints/src/utils/mod.rs | 5 + tests/ui/match_type_on_diag_item.rs | 50 ++++++++++ tests/ui/match_type_on_diag_item.stderr | 33 +++++++ 5 files changed, 203 insertions(+), 3 deletions(-) create mode 100644 tests/ui/match_type_on_diag_item.rs create mode 100644 tests/ui/match_type_on_diag_item.stderr diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 44afd7e82fe7c..b60a80e07d708 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -867,6 +867,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &utils::internal_lints::COMPILER_LINT_FUNCTIONS, &utils::internal_lints::DEFAULT_LINT, &utils::internal_lints::LINT_WITHOUT_LINT_PASS, + &utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM, &utils::internal_lints::OUTER_EXPN_EXPN_DATA, &utils::internal_lints::PRODUCE_ICE, &vec::USELESS_VEC, @@ -1112,6 +1113,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box self_assignment::SelfAssignment); store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs); store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync); + store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1240,6 +1242,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&utils::internal_lints::COMPILER_LINT_FUNCTIONS), LintId::of(&utils::internal_lints::DEFAULT_LINT), LintId::of(&utils::internal_lints::LINT_WITHOUT_LINT_PASS), + LintId::of(&utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM), LintId::of(&utils::internal_lints::OUTER_EXPN_EXPN_DATA), LintId::of(&utils::internal_lints::PRODUCE_ICE), ]); diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 8fa5d22210a36..5beb4be5b2924 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -1,6 +1,6 @@ use crate::utils::{ - is_expn_of, match_def_path, match_qpath, match_type, method_calls, paths, run_lints, snippet, span_lint, - span_lint_and_help, span_lint_and_sugg, walk_ptrs_ty, SpanlessEq, + is_expn_of, match_def_path, match_qpath, match_type, method_calls, path_to_res, paths, qpath_res, run_lints, + snippet, span_lint, span_lint_and_help, span_lint_and_sugg, walk_ptrs_ty, SpanlessEq, }; use if_chain::if_chain; use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, NodeId}; @@ -11,7 +11,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_hir::intravisit::{NestedVisitorMap, Visitor}; -use rustc_hir::{Crate, Expr, ExprKind, HirId, Item, MutTy, Mutability, Path, StmtKind, Ty, TyKind}; +use rustc_hir::{Crate, Expr, ExprKind, HirId, Item, MutTy, Mutability, Node, Path, StmtKind, Ty, TyKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; @@ -206,6 +206,29 @@ declare_clippy_lint! { "found collapsible `span_lint_and_then` calls" } +declare_clippy_lint! { + /// **What it does:** Checks for calls to `utils::match_type()` on a type diagnostic item + /// and suggests to use `utils::is_type_diagnostic_item()` instead. + /// + /// **Why is this bad?** `utils::is_type_diagnostic_item()` does not require hardcoded paths. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// Bad: + /// ```rust,ignore + /// utils::match_type(cx, ty, &paths::VEC) + /// ``` + /// + /// Good: + /// ```rust,ignore + /// utils::is_type_diagnostic_item(cx, ty, sym!(vec_type)) + /// ``` + pub MATCH_TYPE_ON_DIAGNOSTIC_ITEM, + internal, + "using `utils::match_type()` instead of `utils::is_type_diagnostic_item()`" +} + declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]); impl EarlyLintPass for ClippyLintsInternal { @@ -652,3 +675,89 @@ fn suggest_note( Applicability::MachineApplicable, ); } + +declare_lint_pass!(MatchTypeOnDiagItem => [MATCH_TYPE_ON_DIAGNOSTIC_ITEM]); + +impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { + if !run_lints(cx, &[MATCH_TYPE_ON_DIAGNOSTIC_ITEM], expr.hir_id) { + return; + } + + if_chain! { + // Check if this is a call to utils::match_type() + if let ExprKind::Call(fn_path, [context, ty, ty_path]) = expr.kind; + if let ExprKind::Path(fn_qpath) = &fn_path.kind; + if match_qpath(&fn_qpath, &["utils", "match_type"]); + // Extract the path to the matched type + if let Some(segments) = path_to_matched_type(cx, ty_path); + let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect(); + if let Some(ty_did) = path_to_res(cx, &segments[..]).and_then(|res| res.opt_def_id()); + // Check if the matched type is a diagnostic item + let diag_items = cx.tcx.diagnostic_items(ty_did.krate); + if let Some(item_name) = diag_items.iter().find_map(|(k, v)| if *v == ty_did { Some(k) } else { None }); + then { + let cx_snippet = snippet(cx, context.span, "_"); + let ty_snippet = snippet(cx, ty.span, "_"); + + span_lint_and_sugg( + cx, + MATCH_TYPE_ON_DIAGNOSTIC_ITEM, + expr.span, + "usage of `utils::match_type() on a type diagnostic item`", + "try", + format!("utils::is_type_diagnostic_item({}, {}, sym!({}))", cx_snippet, ty_snippet, item_name), + Applicability::MaybeIncorrect, + ); + } + } + } +} + +fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option> { + use rustc_hir::ItemKind; + + match &expr.kind { + ExprKind::AddrOf(.., expr) => return path_to_matched_type(cx, expr), + ExprKind::Path(qpath) => match qpath_res(cx, qpath, expr.hir_id) { + Res::Local(hir_id) => { + let parent_id = cx.tcx.hir().get_parent_node(hir_id); + if let Some(Node::Local(local)) = cx.tcx.hir().find(parent_id) { + if let Some(init) = local.init { + return path_to_matched_type(cx, init); + } + } + }, + Res::Def(DefKind::Const | DefKind::Static, def_id) => { + if let Some(Node::Item(item)) = cx.tcx.hir().get_if_local(def_id) { + if let ItemKind::Const(.., body_id) | ItemKind::Static(.., body_id) = item.kind { + let body = cx.tcx.hir().body(body_id); + return path_to_matched_type(cx, &body.value); + } + } + }, + _ => {}, + }, + ExprKind::Array(exprs) => { + let segments: Vec = exprs + .iter() + .filter_map(|expr| { + if let ExprKind::Lit(lit) = &expr.kind { + if let LitKind::Str(sym, _) = lit.node { + return Some(sym.as_str()); + } + } + + None + }) + .collect(); + + if segments.len() == exprs.len() { + return Some(segments); + } + }, + _ => {}, + } + + None +} diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 3ebbfed645627..8db7e693e6261 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -130,6 +130,9 @@ pub fn is_wild<'tcx>(pat: &impl std::ops::Deref>) -> bool { } /// Checks if type is struct, enum or union type with the given def path. +/// +/// If the type is a diagnostic item, use `is_type_diagnostic_item` instead. +/// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem` pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool { match ty.kind() { ty::Adt(adt, _) => match_def_path(cx, adt.did, path), @@ -138,6 +141,8 @@ pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool { } /// Checks if the type is equal to a diagnostic item +/// +/// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem` pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symbol) -> bool { match ty.kind() { ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did), diff --git a/tests/ui/match_type_on_diag_item.rs b/tests/ui/match_type_on_diag_item.rs new file mode 100644 index 0000000000000..fe950b0aa7c70 --- /dev/null +++ b/tests/ui/match_type_on_diag_item.rs @@ -0,0 +1,50 @@ +#![deny(clippy::internal)] +#![feature(rustc_private)] + +extern crate rustc_hir; +extern crate rustc_lint; +extern crate rustc_middle; +#[macro_use] +extern crate rustc_session; +use rustc_hir::Expr; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::Ty; + +mod paths { + pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"]; +} + +mod utils { + use super::*; + + pub fn match_type(_cx: &LateContext<'_>, _ty: Ty<'_>, _path: &[&str]) -> bool { + false + } +} + +use utils::match_type; + +declare_lint! { + pub TEST_LINT, + Warn, + "" +} + +declare_lint_pass!(Pass => [TEST_LINT]); + +static OPTION: [&str; 3] = ["core", "option", "Option"]; + +impl<'tcx> LateLintPass<'tcx> for Pass { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr) { + let ty = cx.typeck_results().expr_ty(expr); + + let _ = match_type(cx, ty, &paths::VEC); + let _ = match_type(cx, ty, &OPTION); + let _ = match_type(cx, ty, &["core", "result", "Result"]); + + let rc_path = &["alloc", "rc", "Rc"]; + let _ = utils::match_type(cx, ty, rc_path); + } +} + +fn main() {} diff --git a/tests/ui/match_type_on_diag_item.stderr b/tests/ui/match_type_on_diag_item.stderr new file mode 100644 index 0000000000000..c89137eb758f0 --- /dev/null +++ b/tests/ui/match_type_on_diag_item.stderr @@ -0,0 +1,33 @@ +error: usage of `utils::match_type() on a type diagnostic item` + --> $DIR/match_type_on_diag_item.rs:41:17 + | +LL | let _ = match_type(cx, ty, &paths::VEC); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym!(vec_type))` + | +note: the lint level is defined here + --> $DIR/match_type_on_diag_item.rs:1:9 + | +LL | #![deny(clippy::internal)] + | ^^^^^^^^^^^^^^^^ + = note: `#[deny(clippy::match_type_on_diagnostic_item)]` implied by `#[deny(clippy::internal)]` + +error: usage of `utils::match_type() on a type diagnostic item` + --> $DIR/match_type_on_diag_item.rs:42:17 + | +LL | let _ = match_type(cx, ty, &OPTION); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym!(option_type))` + +error: usage of `utils::match_type() on a type diagnostic item` + --> $DIR/match_type_on_diag_item.rs:43:17 + | +LL | let _ = match_type(cx, ty, &["core", "result", "Result"]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym!(result_type))` + +error: usage of `utils::match_type() on a type diagnostic item` + --> $DIR/match_type_on_diag_item.rs:46:17 + | +LL | let _ = utils::match_type(cx, ty, rc_path); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym!(Rc))` + +error: aborting due to 4 previous errors + From 332c2dcb4dfe5151d7c8d44cdf96c4abd06db593 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Sun, 6 Sep 2020 23:48:04 +0200 Subject: [PATCH 0445/1052] Fix dogfood after MatchTypeOnDiagItem --- clippy_lints/src/loops.rs | 2 +- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/option_if_let_else.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 6c54c07869ad1..3d2fd0eee85a7 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1114,7 +1114,7 @@ fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(& if let Some(self_expr) = args.get(0); if let Some(pushed_item) = args.get(1); // Check that the method being called is push() on a Vec - if match_type(cx, cx.typeck_results().expr_ty(self_expr), &paths::VEC); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym!(vec_type)); if path.ident.name.as_str() == "push"; then { return Some((self_expr, pushed_item)) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 98e027b6d2290..de966cccd111c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1808,7 +1808,7 @@ fn lint_or_fun_call<'tcx>( _ => (), } - if match_type(cx, ty, &paths::VEC) { + if is_type_diagnostic_item(cx, ty, sym!(vec_type)) { return; } } diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 9494efe736cce..60e5e7bfed398 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -1,6 +1,6 @@ use crate::utils; use crate::utils::sugg::Sugg; -use crate::utils::{match_type, paths, span_lint_and_sugg}; +use crate::utils::{is_type_diagnostic_item, paths, span_lint_and_sugg}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -73,7 +73,7 @@ declare_lint_pass!(OptionIfLetElse => [OPTION_IF_LET_ELSE]); fn is_result_ok(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool { if let ExprKind::MethodCall(ref path, _, &[ref receiver], _) = &expr.kind { path.ident.name.to_ident_string() == "ok" - && match_type(cx, &cx.typeck_results().expr_ty(&receiver), &paths::RESULT) + && is_type_diagnostic_item(cx, &cx.typeck_results().expr_ty(&receiver), sym!(result_type)) } else { false } From c86a7e5f38e54f4404cc71874316eb0b4dba200b Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Sun, 6 Sep 2020 23:57:24 +0200 Subject: [PATCH 0446/1052] Misc doc updates --- clippy_lints/src/utils/diagnostics.rs | 9 +++++++++ doc/common_tools_writing_lints.md | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/utils/diagnostics.rs b/clippy_lints/src/utils/diagnostics.rs index e4e65b5f4d420..0a58231558ede 100644 --- a/clippy_lints/src/utils/diagnostics.rs +++ b/clippy_lints/src/utils/diagnostics.rs @@ -51,6 +51,8 @@ pub fn span_lint(cx: &T, lint: &'static Lint, sp: impl Into( /// The `note` message is presented separately from the main lint message /// and is attached to a specific span: /// +/// If you change the signature, remember to update the internal lint `CollapsibleCalls` +/// /// # Example /// /// ```ignore @@ -126,6 +130,7 @@ pub fn span_lint_and_note<'a, T: LintContext>( /// Like `span_lint` but allows to add notes, help and suggestions using a closure. /// /// If you need to customize your lint output a lot, use this function. +/// If you change the signature, remember to update the internal lint `CollapsibleCalls` pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F) where F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>), @@ -168,6 +173,10 @@ pub fn span_lint_hir_and_then( /// In the example below, `help` is `"try"` and `sugg` is the suggested replacement `".any(|x| x > /// 2)"`. /// +/// If you change the signature, remember to update the internal lint `CollapsibleCalls` +/// +/// # Example +/// /// ```ignore /// error: This `.fold` can be more succinctly expressed as `.any` /// --> $DIR/methods.rs:390:13 diff --git a/doc/common_tools_writing_lints.md b/doc/common_tools_writing_lints.md index 9dd4c8a5f7a70..53c3d084dbc98 100644 --- a/doc/common_tools_writing_lints.md +++ b/doc/common_tools_writing_lints.md @@ -60,7 +60,7 @@ impl LateLintPass<'_> for MyStructLint { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { if_chain! { // Check our expr is calling a method - if let hir::ExprKind::MethodCall(path, _, _args) = &expr.kind; + if let hir::ExprKind::MethodCall(path, _, _args, _) = &expr.kind; // Check the name of this method is `some_method` if path.ident.name == sym!(some_method); then { From d0b5663d30457d1a9ec4f98eb9baff7123b77172 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Tue, 15 Sep 2020 10:31:50 +0200 Subject: [PATCH 0447/1052] Fix usage of backquotes in suggestion --- clippy_lints/src/utils/internal_lints.rs | 2 +- tests/ui/match_type_on_diag_item.stderr | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 5beb4be5b2924..f201494a02466 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -704,7 +704,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem { cx, MATCH_TYPE_ON_DIAGNOSTIC_ITEM, expr.span, - "usage of `utils::match_type() on a type diagnostic item`", + "usage of `utils::match_type()` on a type diagnostic item", "try", format!("utils::is_type_diagnostic_item({}, {}, sym!({}))", cx_snippet, ty_snippet, item_name), Applicability::MaybeIncorrect, diff --git a/tests/ui/match_type_on_diag_item.stderr b/tests/ui/match_type_on_diag_item.stderr index c89137eb758f0..5e5fe9e3a3e73 100644 --- a/tests/ui/match_type_on_diag_item.stderr +++ b/tests/ui/match_type_on_diag_item.stderr @@ -1,4 +1,4 @@ -error: usage of `utils::match_type() on a type diagnostic item` +error: usage of `utils::match_type()` on a type diagnostic item --> $DIR/match_type_on_diag_item.rs:41:17 | LL | let _ = match_type(cx, ty, &paths::VEC); @@ -11,19 +11,19 @@ LL | #![deny(clippy::internal)] | ^^^^^^^^^^^^^^^^ = note: `#[deny(clippy::match_type_on_diagnostic_item)]` implied by `#[deny(clippy::internal)]` -error: usage of `utils::match_type() on a type diagnostic item` +error: usage of `utils::match_type()` on a type diagnostic item --> $DIR/match_type_on_diag_item.rs:42:17 | LL | let _ = match_type(cx, ty, &OPTION); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym!(option_type))` -error: usage of `utils::match_type() on a type diagnostic item` +error: usage of `utils::match_type()` on a type diagnostic item --> $DIR/match_type_on_diag_item.rs:43:17 | LL | let _ = match_type(cx, ty, &["core", "result", "Result"]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym!(result_type))` -error: usage of `utils::match_type() on a type diagnostic item` +error: usage of `utils::match_type()` on a type diagnostic item --> $DIR/match_type_on_diag_item.rs:46:17 | LL | let _ = utils::match_type(cx, ty, rc_path); From 5f0b77539011a5a5297beda420d70f6ab22b2e7e Mon Sep 17 00:00:00 2001 From: Hameer Abbasi Date: Tue, 15 Sep 2020 11:11:18 +0200 Subject: [PATCH 0448/1052] Remove redundant `&format!`. Co-authored-by: Bastian Kauschke --- compiler/rustc_resolve/src/diagnostics.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 5d66d90e2c008..612bc3e74911c 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -480,9 +480,7 @@ impl<'a> Resolver<'a> { ); if is_type { - err.note(&format!( - "type parameters are currently not permitted in anonymous constants" - )); + err.note("type parameters are currently not permitted in anonymous constants"); } else { err.help( &format!("it is currently only allowed to use either `{0}` or `{{ {0} }}` as generic constants", From c65050d537ee48be7dc378203af895f7fad0403b Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Tue, 15 Sep 2020 10:21:40 +0000 Subject: [PATCH 0449/1052] Fix clippy hard-code slice::Iter path --- src/tools/clippy/clippy_lints/src/utils/paths.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/clippy/clippy_lints/src/utils/paths.rs b/src/tools/clippy/clippy_lints/src/utils/paths.rs index 65320d6a0e0bd..3b031a552e5ce 100644 --- a/src/tools/clippy/clippy_lints/src/utils/paths.rs +++ b/src/tools/clippy/clippy_lints/src/utils/paths.rs @@ -106,7 +106,7 @@ pub const RWLOCK_WRITE_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockWrite pub const SERDE_DESERIALIZE: [&str; 2] = ["_serde", "Deserialize"]; pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"]; pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "", "into_vec"]; -pub const SLICE_ITER: [&str; 3] = ["core", "slice", "Iter"]; +pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"]; pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"]; pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"]; pub const STD_CONVERT_IDENTITY: [&str; 3] = ["std", "convert", "identity"]; From 78f9ea543154b6a0d6b5b5a86e92d8cc1938b436 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Tue, 15 Sep 2020 10:21:40 +0000 Subject: [PATCH 0450/1052] Fix clippy hard-code slice::Iter path --- clippy_lints/src/utils/paths.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 65320d6a0e0bd..3b031a552e5ce 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -106,7 +106,7 @@ pub const RWLOCK_WRITE_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockWrite pub const SERDE_DESERIALIZE: [&str; 2] = ["_serde", "Deserialize"]; pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"]; pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "", "into_vec"]; -pub const SLICE_ITER: [&str; 3] = ["core", "slice", "Iter"]; +pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"]; pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"]; pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"]; pub const STD_CONVERT_IDENTITY: [&str; 3] = ["std", "convert", "identity"]; From 176956c115c2b797471a3f59eef3e17789229007 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Tue, 15 Sep 2020 00:02:48 +0200 Subject: [PATCH 0451/1052] Test and fix Sync & Send traits of BTreeMap artefacts --- library/alloc/src/collections/btree/borrow.rs | 3 + .../alloc/src/collections/btree/map/tests.rs | 140 ++++++++++++++++++ 2 files changed, 143 insertions(+) diff --git a/library/alloc/src/collections/btree/borrow.rs b/library/alloc/src/collections/btree/borrow.rs index 5c95acfbe9c20..016f139a501a0 100644 --- a/library/alloc/src/collections/btree/borrow.rs +++ b/library/alloc/src/collections/btree/borrow.rs @@ -16,6 +16,9 @@ pub struct DormantMutRef<'a, T> { _marker: PhantomData<&'a mut T>, } +unsafe impl<'a, T> Sync for DormantMutRef<'a, T> where &'a mut T: Sync {} +unsafe impl<'a, T> Send for DormantMutRef<'a, T> where &'a mut T: Send {} + impl<'a, T> DormantMutRef<'a, T> { /// Capture a unique borrow, and immediately reborrow it. For the compiler, /// the lifetime of the new reference is the same as the lifetime of the diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index af5cf7d7d875c..d2cd6b8e5241a 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -1418,6 +1418,146 @@ fn test_variance() { } } +#[test] +#[allow(dead_code)] +fn test_sync() { + fn map(v: &BTreeMap) -> impl Sync + '_ { + v + } + + fn into_iter(v: BTreeMap) -> impl Sync { + v.into_iter() + } + + fn into_keys(v: BTreeMap) -> impl Sync { + v.into_keys() + } + + fn into_values(v: BTreeMap) -> impl Sync { + v.into_values() + } + + fn drain_filter(v: &mut BTreeMap) -> impl Sync + '_ { + v.drain_filter(|_, _| false) + } + + fn iter(v: &BTreeMap) -> impl Sync + '_ { + v.iter() + } + + fn iter_mut(v: &mut BTreeMap) -> impl Sync + '_ { + v.iter_mut() + } + + fn keys(v: &BTreeMap) -> impl Sync + '_ { + v.keys() + } + + fn values(v: &BTreeMap) -> impl Sync + '_ { + v.values() + } + + fn values_mut(v: &mut BTreeMap) -> impl Sync + '_ { + v.values_mut() + } + + fn range(v: &BTreeMap) -> impl Sync + '_ { + v.range(..) + } + + fn range_mut(v: &mut BTreeMap) -> impl Sync + '_ { + v.range_mut(..) + } + + fn entry(v: &mut BTreeMap) -> impl Sync + '_ { + v.entry(Default::default()) + } + + fn occupied_entry(v: &mut BTreeMap) -> impl Sync + '_ { + match v.entry(Default::default()) { + Occupied(entry) => entry, + _ => unreachable!(), + } + } + + fn vacant_entry(v: &mut BTreeMap) -> impl Sync + '_ { + match v.entry(Default::default()) { + Vacant(entry) => entry, + _ => unreachable!(), + } + } +} + +#[test] +#[allow(dead_code)] +fn test_send() { + fn map(v: BTreeMap) -> impl Send { + v + } + + fn into_iter(v: BTreeMap) -> impl Send { + v.into_iter() + } + + fn into_keys(v: BTreeMap) -> impl Send { + v.into_keys() + } + + fn into_values(v: BTreeMap) -> impl Send { + v.into_values() + } + + fn drain_filter(v: &mut BTreeMap) -> impl Send + '_ { + v.drain_filter(|_, _| false) + } + + fn iter(v: &BTreeMap) -> impl Send + '_ { + v.iter() + } + + fn iter_mut(v: &mut BTreeMap) -> impl Send + '_ { + v.iter_mut() + } + + fn keys(v: &BTreeMap) -> impl Send + '_ { + v.keys() + } + + fn values(v: &BTreeMap) -> impl Send + '_ { + v.values() + } + + fn values_mut(v: &mut BTreeMap) -> impl Send + '_ { + v.values_mut() + } + + fn range(v: &BTreeMap) -> impl Send + '_ { + v.range(..) + } + + fn range_mut(v: &mut BTreeMap) -> impl Send + '_ { + v.range_mut(..) + } + + fn entry(v: &mut BTreeMap) -> impl Send + '_ { + v.entry(Default::default()) + } + + fn occupied_entry(v: &mut BTreeMap) -> impl Send + '_ { + match v.entry(Default::default()) { + Occupied(entry) => entry, + _ => unreachable!(), + } + } + + fn vacant_entry(v: &mut BTreeMap) -> impl Send + '_ { + match v.entry(Default::default()) { + Vacant(entry) => entry, + _ => unreachable!(), + } + } +} + #[test] fn test_occupied_entry_key() { let mut a = BTreeMap::new(); From b93a8315f2fcff479a99e0694309fe12dbe095d5 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 15 Sep 2020 08:40:10 -0400 Subject: [PATCH 0452/1052] Add a comment why rustdoc loads crates from the sysroot --- src/librustdoc/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 94e51d91b542a..7762e8f8d4fb1 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -21,7 +21,11 @@ extern crate tracing; // N.B. these need `extern crate` even in 2018 edition // because they're loaded implicitly from the sysroot. -// Dependencies listed in Cargo.toml do not need extern crate. +// The reason they're loaded from the sysroot is because +// the rustdoc artifacts aren't stored in rustc's cargo target directory. +// So if `rustc` was specified in Cargo.toml, this would spuriously rebuild crates. +// +// Dependencies listed in Cargo.toml do not need `extern crate`. extern crate rustc_ast; extern crate rustc_ast_pretty; extern crate rustc_attr; From 5f3145febd4e0e8ff28bfeec0418ece7f832428a Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 15 Sep 2020 08:59:34 -0400 Subject: [PATCH 0453/1052] Avoid printing dry run timings --- src/bootstrap/builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 0f18660c0e109..dc027661c8320 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -1421,7 +1421,7 @@ impl<'a> Builder<'a> { (out, dur - deps) }; - if self.config.print_step_timings { + if self.config.print_step_timings && !self.config.dry_run { println!("[TIMING] {:?} -- {}.{:03}", step, dur.as_secs(), dur.subsec_millis()); } From 5a4098ed0fb0b8aea373a7af8ace57da98b09fec Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 20 Aug 2020 10:45:18 -0700 Subject: [PATCH 0454/1052] Consolidate byte-identical modules. --- library/std/src/sys/sgx/fs.rs | 308 ------------------------ library/std/src/sys/sgx/io.rs | 47 ---- library/std/src/sys/sgx/mod.rs | 4 + library/std/src/sys/sgx/pipe.rs | 38 --- library/std/src/sys/sgx/process.rs | 149 ------------ library/std/src/sys/unsupported/mod.rs | 1 + library/std/src/sys/unsupported/path.rs | 19 -- library/std/src/sys/wasi/mod.rs | 2 + library/std/src/sys/wasi/path.rs | 19 -- library/std/src/sys/wasi/pipe.rs | 40 --- library/std/src/sys/wasm/mod.rs | 2 +- 11 files changed, 8 insertions(+), 621 deletions(-) delete mode 100644 library/std/src/sys/sgx/fs.rs delete mode 100644 library/std/src/sys/sgx/io.rs delete mode 100644 library/std/src/sys/sgx/pipe.rs delete mode 100644 library/std/src/sys/sgx/process.rs delete mode 100644 library/std/src/sys/unsupported/path.rs delete mode 100644 library/std/src/sys/wasi/path.rs delete mode 100644 library/std/src/sys/wasi/pipe.rs diff --git a/library/std/src/sys/sgx/fs.rs b/library/std/src/sys/sgx/fs.rs deleted file mode 100644 index ecb5b51cccdcd..0000000000000 --- a/library/std/src/sys/sgx/fs.rs +++ /dev/null @@ -1,308 +0,0 @@ -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 { - match self.0 {} - } - - pub fn accessed(&self) -> io::Result { - match self.0 {} - } - - pub fn created(&self) -> io::Result { - 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(&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; - - fn next(&mut self) -> Option> { - 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 { - match self.0 {} - } - - pub fn file_type(&self) -> io::Result { - 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 { - unsupported() - } - - pub fn file_attr(&self) -> io::Result { - 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 { - match self.0 {} - } - - pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_read_vectored(&self) -> bool { - match self.0 {} - } - - pub fn write(&self, _buf: &[u8]) -> io::Result { - match self.0 {} - } - - pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { - 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 { - match self.0 {} - } - - pub fn duplicate(&self) -> io::Result { - 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 { - 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 { - 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 { - unsupported() -} - -pub fn lstat(_p: &Path) -> io::Result { - unsupported() -} - -pub fn canonicalize(_p: &Path) -> io::Result { - unsupported() -} - -pub fn copy(_from: &Path, _to: &Path) -> io::Result { - unsupported() -} diff --git a/library/std/src/sys/sgx/io.rs b/library/std/src/sys/sgx/io.rs deleted file mode 100644 index d5f475b4310fd..0000000000000 --- a/library/std/src/sys/sgx/io.rs +++ /dev/null @@ -1,47 +0,0 @@ -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 - } -} diff --git a/library/std/src/sys/sgx/mod.rs b/library/std/src/sys/sgx/mod.rs index 1d32eb2542434..1abd91e75e8c4 100644 --- a/library/std/src/sys/sgx/mod.rs +++ b/library/std/src/sys/sgx/mod.rs @@ -17,14 +17,18 @@ pub mod condvar; pub mod env; pub mod ext; pub mod fd; +#[path = "../unsupported/fs.rs"] pub mod fs; +#[path = "../unsupported/io.rs"] pub mod io; pub mod memchr; pub mod mutex; pub mod net; pub mod os; pub mod path; +#[path = "../unsupported/pipe.rs"] pub mod pipe; +#[path = "../unsupported/process.rs"] pub mod process; pub mod rwlock; pub mod stack_overflow; diff --git a/library/std/src/sys/sgx/pipe.rs b/library/std/src/sys/sgx/pipe.rs deleted file mode 100644 index 10d0925823eb9..0000000000000 --- a/library/std/src/sys/sgx/pipe.rs +++ /dev/null @@ -1,38 +0,0 @@ -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 { - match self.0 {} - } - - pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_read_vectored(&self) -> bool { - match self.0 {} - } - - pub fn write(&self, _buf: &[u8]) -> io::Result { - match self.0 {} - } - - pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { - 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, _p2: AnonPipe, _v2: &mut Vec) -> io::Result<()> { - match p1.0 {} -} diff --git a/library/std/src/sys/sgx/process.rs b/library/std/src/sys/sgx/process.rs deleted file mode 100644 index 4702e5c549228..0000000000000 --- a/library/std/src/sys/sgx/process.rs +++ /dev/null @@ -1,149 +0,0 @@ -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, - pub stdout: Option, - pub stderr: Option, -} - -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 for Stdio { - fn from(pipe: AnonPipe) -> Stdio { - pipe.diverge() - } -} - -impl From 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 { - 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 { - match self.0 {} - } - - pub fn try_wait(&mut self) -> io::Result> { - match self.0 {} - } -} diff --git a/library/std/src/sys/unsupported/mod.rs b/library/std/src/sys/unsupported/mod.rs index 87f655eecd54e..8ba870c5dbc14 100644 --- a/library/std/src/sys/unsupported/mod.rs +++ b/library/std/src/sys/unsupported/mod.rs @@ -8,6 +8,7 @@ pub mod io; pub mod mutex; pub mod net; pub mod os; +#[path = "../unix/path.rs"] pub mod path; pub mod pipe; pub mod process; diff --git a/library/std/src/sys/unsupported/path.rs b/library/std/src/sys/unsupported/path.rs deleted file mode 100644 index 840a7ae042625..0000000000000 --- a/library/std/src/sys/unsupported/path.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::ffi::OsStr; -use crate::path::Prefix; - -#[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'/' -} - -#[inline] -pub fn is_verbatim_sep(b: u8) -> bool { - b == b'/' -} - -pub fn parse_prefix(_: &OsStr) -> Option> { - None -} - -pub const MAIN_SEP_STR: &str = "/"; -pub const MAIN_SEP: char = '/'; diff --git a/library/std/src/sys/wasi/mod.rs b/library/std/src/sys/wasi/mod.rs index 2704ff484f991..e1aa596503b4d 100644 --- a/library/std/src/sys/wasi/mod.rs +++ b/library/std/src/sys/wasi/mod.rs @@ -33,7 +33,9 @@ pub mod net; pub mod os; pub use crate::sys_common::os_str_bytes as os_str; pub mod ext; +#[path = "../unix/path.rs"] pub mod path; +#[path = "../unsupported/pipe.rs"] pub mod pipe; pub mod process; #[path = "../unsupported/rwlock.rs"] diff --git a/library/std/src/sys/wasi/path.rs b/library/std/src/sys/wasi/path.rs deleted file mode 100644 index 840a7ae042625..0000000000000 --- a/library/std/src/sys/wasi/path.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::ffi::OsStr; -use crate::path::Prefix; - -#[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'/' -} - -#[inline] -pub fn is_verbatim_sep(b: u8) -> bool { - b == b'/' -} - -pub fn parse_prefix(_: &OsStr) -> Option> { - None -} - -pub const MAIN_SEP_STR: &str = "/"; -pub const MAIN_SEP: char = '/'; diff --git a/library/std/src/sys/wasi/pipe.rs b/library/std/src/sys/wasi/pipe.rs deleted file mode 100644 index 180fc114d86db..0000000000000 --- a/library/std/src/sys/wasi/pipe.rs +++ /dev/null @@ -1,40 +0,0 @@ -#![deny(unsafe_op_in_unsafe_fn)] - -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 { - match self.0 {} - } - - pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_read_vectored(&self) -> bool { - match self.0 {} - } - - pub fn write(&self, _buf: &[u8]) -> io::Result { - match self.0 {} - } - - pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { - 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, _p2: AnonPipe, _v2: &mut Vec) -> io::Result<()> { - match p1.0 {} -} diff --git a/library/std/src/sys/wasm/mod.rs b/library/std/src/sys/wasm/mod.rs index 3de5890404357..2934ea59ab5ff 100644 --- a/library/std/src/sys/wasm/mod.rs +++ b/library/std/src/sys/wasm/mod.rs @@ -27,7 +27,7 @@ pub mod io; pub mod net; #[path = "../unsupported/os.rs"] pub mod os; -#[path = "../unsupported/path.rs"] +#[path = "../unix/path.rs"] pub mod path; #[path = "../unsupported/pipe.rs"] pub mod pipe; From cfb955da6f67b4d11d266f0d2957c8ddab26b66f Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 20 Aug 2020 11:00:41 -0700 Subject: [PATCH 0455/1052] Consolidate wasi alloc with unix alloc. --- library/std/src/sys/unix/alloc.rs | 86 ++++++++++++++++--------------- library/std/src/sys/wasi/alloc.rs | 69 ------------------------- library/std/src/sys/wasi/mod.rs | 1 + 3 files changed, 45 insertions(+), 111 deletions(-) delete mode 100644 library/std/src/sys/wasi/alloc.rs diff --git a/library/std/src/sys/unix/alloc.rs b/library/std/src/sys/unix/alloc.rs index 8e193935460eb..964abe8b8c9ea 100644 --- a/library/std/src/sys/unix/alloc.rs +++ b/library/std/src/sys/unix/alloc.rs @@ -52,46 +52,48 @@ unsafe impl GlobalAlloc for System { } } -#[cfg(any( - target_os = "android", - target_os = "illumos", - target_os = "redox", - target_os = "solaris" -))] -#[inline] -unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { - // On android we currently target API level 9 which unfortunately - // doesn't have the `posix_memalign` API used below. Instead we use - // `memalign`, but this unfortunately has the property on some systems - // where the memory returned cannot be deallocated by `free`! - // - // Upon closer inspection, however, this appears to work just fine with - // Android, so for this platform we should be fine to call `memalign` - // (which is present in API level 9). Some helpful references could - // possibly be chromium using memalign [1], attempts at documenting that - // memalign + free is ok [2] [3], or the current source of chromium - // which still uses memalign on android [4]. - // - // [1]: https://codereview.chromium.org/10796020/ - // [2]: https://code.google.com/p/android/issues/detail?id=35391 - // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579 - // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/ - // /memory/aligned_memory.cc - libc::memalign(layout.align(), layout.size()) as *mut u8 -} - -#[cfg(not(any( - target_os = "android", - target_os = "illumos", - target_os = "redox", - target_os = "solaris" -)))] -#[inline] -unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { - let mut out = ptr::null_mut(); - // posix_memalign requires that the alignment be a multiple of `sizeof(void*)`. - // Since these are all powers of 2, we can just use max. - let align = layout.align().max(crate::mem::size_of::()); - let ret = libc::posix_memalign(&mut out, align, layout.size()); - if ret != 0 { ptr::null_mut() } else { out as *mut u8 } +cfg_if::cfg_if! { + if #[cfg(any( + target_os = "android", + target_os = "illumos", + target_os = "redox", + target_os = "solaris" + ))] { + #[inline] + unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { + // On android we currently target API level 9 which unfortunately + // doesn't have the `posix_memalign` API used below. Instead we use + // `memalign`, but this unfortunately has the property on some systems + // where the memory returned cannot be deallocated by `free`! + // + // Upon closer inspection, however, this appears to work just fine with + // Android, so for this platform we should be fine to call `memalign` + // (which is present in API level 9). Some helpful references could + // possibly be chromium using memalign [1], attempts at documenting that + // memalign + free is ok [2] [3], or the current source of chromium + // which still uses memalign on android [4]. + // + // [1]: https://codereview.chromium.org/10796020/ + // [2]: https://code.google.com/p/android/issues/detail?id=35391 + // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579 + // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/ + // /memory/aligned_memory.cc + libc::memalign(layout.align(), layout.size()) as *mut u8 + } + } else if #[cfg(target_os = "wasi")] { + #[inline] + unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { + libc::aligned_alloc(layout.align(), layout.size()) as *mut u8 + } + } else { + #[inline] + unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { + let mut out = ptr::null_mut(); + // posix_memalign requires that the alignment be a multiple of `sizeof(void*)`. + // Since these are all powers of 2, we can just use max. + let align = layout.align().max(crate::mem::size_of::()); + let ret = libc::posix_memalign(&mut out, align, layout.size()); + if ret != 0 { ptr::null_mut() } else { out as *mut u8 } + } + } } diff --git a/library/std/src/sys/wasi/alloc.rs b/library/std/src/sys/wasi/alloc.rs deleted file mode 100644 index 4d0afe27bb8b2..0000000000000 --- a/library/std/src/sys/wasi/alloc.rs +++ /dev/null @@ -1,69 +0,0 @@ -#![deny(unsafe_op_in_unsafe_fn)] - -use crate::alloc::{GlobalAlloc, Layout, System}; -use crate::ptr; -use crate::sys_common::alloc::{realloc_fallback, MIN_ALIGN}; - -// SAFETY: All methods implemented follow the contract rules defined -// in `GlobalAlloc`. -#[stable(feature = "alloc_system_type", since = "1.28.0")] -unsafe impl GlobalAlloc for System { - #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - // SAFETY: `libc::malloc` is guaranteed to be safe, it will allocate - // `layout.size()` bytes of memory and return a pointer to it - unsafe { libc::malloc(layout.size()) as *mut u8 } - } else { - // SAFETY: `libc::aligned_alloc` is guaranteed to be safe if - // `layout.size()` is a multiple of `layout.align()`. This - // constraint can be satisfied if `pad_to_align` is called, - // which creates a layout by rounding the size of this layout up - // to a multiple of the layout's alignment - let aligned_layout = layout.pad_to_align(); - unsafe { libc::aligned_alloc(aligned_layout.align(), aligned_layout.size()) as *mut u8 } - } - } - - #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { - if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - // SAFETY: `libc::calloc` is safe as long that `layout.size() * 1` - // would not result in integer overflow which cannot happen, - // multiplying by one never overflows - unsafe { libc::calloc(layout.size(), 1) as *mut u8 } - } else { - // SAFETY: The safety contract for `alloc` must be upheld by the caller - let ptr = unsafe { self.alloc(layout.clone()) }; - if !ptr.is_null() { - // SAFETY: in the case of the `ptr` being not null - // it will be properly aligned and a valid ptr - // which satisfies `ptr::write_bytes` safety constrains - unsafe { ptr::write_bytes(ptr, 0, layout.size()) }; - } - ptr - } - } - - #[inline] - unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { - // SAFETY: `libc::free` is guaranteed to be safe if `ptr` is allocated - // by this allocator or if `ptr` is NULL - unsafe { libc::free(ptr as *mut libc::c_void) } - } - - #[inline] - unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { - if layout.align() <= MIN_ALIGN && layout.align() <= new_size { - // SAFETY: `libc::realloc` is safe if `ptr` is allocated by this - // allocator or NULL - // - If `new_size` is 0 and `ptr` is not NULL, it will act as `libc::free` - // - If `new_size` is not 0 and `ptr` is NULL, it will act as `libc::malloc` - // - Else, it will resize the block accordingly - unsafe { libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 } - } else { - // SAFETY: The safety contract for `realloc_fallback` must be upheld by the caller - unsafe { realloc_fallback(self, ptr, layout, new_size) } - } - } -} diff --git a/library/std/src/sys/wasi/mod.rs b/library/std/src/sys/wasi/mod.rs index e1aa596503b4d..a379fc891a857 100644 --- a/library/std/src/sys/wasi/mod.rs +++ b/library/std/src/sys/wasi/mod.rs @@ -17,6 +17,7 @@ use crate::io as std_io; use crate::mem; +#[path = "../unix/alloc.rs"] pub mod alloc; pub mod args; #[path = "../unsupported/cmath.rs"] From 25cca07ea04d02a1a2d68cea63ee656b5194af03 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 20 Aug 2020 11:22:46 -0700 Subject: [PATCH 0456/1052] Consolidate wasi::process and unsupported::process --- library/std/src/sys/unsupported/fs.rs | 4 - library/std/src/sys/unsupported/process.rs | 4 +- library/std/src/sys/wasi/mod.rs | 1 + library/std/src/sys/wasi/process.rs | 151 --------------------- 4 files changed, 3 insertions(+), 157 deletions(-) delete mode 100644 library/std/src/sys/wasi/process.rs diff --git a/library/std/src/sys/unsupported/fs.rs b/library/std/src/sys/unsupported/fs.rs index ecb5b51cccdcd..faa53b6a74422 100644 --- a/library/std/src/sys/unsupported/fs.rs +++ b/library/std/src/sys/unsupported/fs.rs @@ -233,10 +233,6 @@ impl File { pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { match self.0 {} } - - pub fn diverge(&self) -> ! { - match self.0 {} - } } impl DirBuilder { diff --git a/library/std/src/sys/unsupported/process.rs b/library/std/src/sys/unsupported/process.rs index 4702e5c549228..7156c9ab92f2b 100644 --- a/library/std/src/sys/unsupported/process.rs +++ b/library/std/src/sys/unsupported/process.rs @@ -65,8 +65,8 @@ impl From for Stdio { } impl From for Stdio { - fn from(file: File) -> Stdio { - file.diverge() + fn from(_file: File) -> Stdio { + panic!("unsupported") } } diff --git a/library/std/src/sys/wasi/mod.rs b/library/std/src/sys/wasi/mod.rs index a379fc891a857..a7a4407ac38e2 100644 --- a/library/std/src/sys/wasi/mod.rs +++ b/library/std/src/sys/wasi/mod.rs @@ -38,6 +38,7 @@ pub mod ext; pub mod path; #[path = "../unsupported/pipe.rs"] pub mod pipe; +#[path = "../unsupported/process.rs"] pub mod process; #[path = "../unsupported/rwlock.rs"] pub mod rwlock; diff --git a/library/std/src/sys/wasi/process.rs b/library/std/src/sys/wasi/process.rs deleted file mode 100644 index c69d6376b0138..0000000000000 --- a/library/std/src/sys/wasi/process.rs +++ /dev/null @@ -1,151 +0,0 @@ -#![deny(unsafe_op_in_unsafe_fn)] - -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, - pub stdout: Option, - pub stderr: Option, -} - -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 for Stdio { - fn from(pipe: AnonPipe) -> Stdio { - pipe.diverge() - } -} - -impl From for Stdio { - fn from(_file: File) -> Stdio { - panic!("unsupported") - } -} - -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 { - 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 { - match self.0 {} - } - - pub fn try_wait(&mut self) -> io::Result> { - match self.0 {} - } -} From f001a0c8dd074ae46276ce84c3de6a6072e77015 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 14 Sep 2020 16:22:56 -0400 Subject: [PATCH 0457/1052] Enable shared linking to LLVM on non-Windows Windows doesn't quite support dynamic linking to LLVM yet, but on other platforms we do. In #76708, it was discovered that we dynamically link to LLVM from the LLVM tools (e.g., rust-lld), so we need the shared LLVM library to link against. That means that if we do not have a shared link to LLVM, and want LLVM tools to work, we'd be shipping two copies of LLVM on all of these platforms: one in librustc_driver and one in libLLVM. Also introduce an error into rustbuild if we do end up configured for shared linking on Windows. --- src/bootstrap/native.rs | 4 ++++ src/ci/run.sh | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 6cd850bc0bfaa..3829d47da335f 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -129,6 +129,10 @@ impl Step for Llvm { Err(m) => m, }; + if builder.config.llvm_link_shared && target.contains("windows") { + panic!("shared linking to LLVM is not currently supported on Windows"); + } + builder.info(&format!("Building LLVM for {}", target)); t!(stamp.remove()); let _time = util::timeit(&builder); diff --git a/src/ci/run.sh b/src/ci/run.sh index 5231aa2e76619..c8faf1ec83179 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -75,6 +75,13 @@ if [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.remap-debuginfo" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --debuginfo-level-std=1" + # If we're distributing binaries, we want a shared LLVM link. We're already + # going to link LLVM to the LLVM tools dynamically, so we need to ship a + # libLLVM library anyway. + if !isWindows; then + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set llvm.link-shared=true" + fi + if [ "$NO_LLVM_ASSERTIONS" = "1" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-assertions" elif [ "$DEPLOY_ALT" != "" ]; then From 4de9a53d98533868dfa209bfb3604bba92d5e7b1 Mon Sep 17 00:00:00 2001 From: SNCPlay42 Date: Sun, 21 Jun 2020 21:37:17 +0100 Subject: [PATCH 0458/1052] improve diagnostics for lifetime after `&mut` --- compiler/rustc_parse/src/parser/ty.rs | 28 +++++++++- .../parser/issue-73568-lifetime-after-mut.rs | 21 ++++++++ .../issue-73568-lifetime-after-mut.stderr | 53 +++++++++++++++++++ 3 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/parser/issue-73568-lifetime-after-mut.rs create mode 100644 src/test/ui/parser/issue-73568-lifetime-after-mut.stderr diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 259764a317df8..fc4c62ccbd90e 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -276,8 +276,34 @@ impl<'a> Parser<'a> { } fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { - let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None }; + let and_span = self.prev_token.span; + let mut opt_lifetime = + if self.check_lifetime() { Some(self.expect_lifetime()) } else { None }; let mutbl = self.parse_mutability(); + if self.token.is_lifetime() && mutbl == Mutability::Mut && opt_lifetime.is_none() { + // A lifetime is invalid here: it would be part of a bare trait bound, which requires + // it to be followed by a plus, but we disallow plus in the pointee type. + // So we can handle this case as an error here, and suggest `'a mut`. + // If there *is* a plus next though, handling the error later provides better suggestions + // (like adding parentheses) + if !self.look_ahead(1, |t| t.is_like_plus()) { + let lifetime_span = self.token.span; + let span = and_span.to(lifetime_span); + + let mut err = self.struct_span_err(span, "lifetime must precede `mut`"); + if let Ok(lifetime_src) = self.span_to_snippet(lifetime_span) { + err.span_suggestion( + span, + "place the lifetime before `mut`", + format!("&{} mut", lifetime_src), + Applicability::MaybeIncorrect, + ); + } + err.emit(); + + opt_lifetime = Some(self.expect_lifetime()); + } + } let ty = self.parse_ty_no_plus()?; Ok(TyKind::Rptr(opt_lifetime, MutTy { ty, mutbl })) } diff --git a/src/test/ui/parser/issue-73568-lifetime-after-mut.rs b/src/test/ui/parser/issue-73568-lifetime-after-mut.rs new file mode 100644 index 0000000000000..0b10a5f6f4e41 --- /dev/null +++ b/src/test/ui/parser/issue-73568-lifetime-after-mut.rs @@ -0,0 +1,21 @@ +#![crate_type="lib"] +fn x<'a>(x: &mut 'a i32){} //~ ERROR lifetime must precede `mut` + +macro_rules! mac { + ($lt:lifetime) => { + fn w<$lt>(w: &mut $lt i32) {} + //~^ ERROR lifetime must precede `mut` + } +} + +mac!('a); + +// avoid false positives +fn y<'a>(y: &mut 'a + Send) { + //~^ ERROR expected a path on the left-hand side of `+`, not `&mut 'a` + //~| WARNING trait objects without an explicit `dyn` are deprecated + //~| ERROR at least one trait is required for an object type + let z = y as &mut 'a + Send; + //~^ ERROR expected value, found trait `Send` + //~| WARNING trait objects without an explicit `dyn` are deprecated +} diff --git a/src/test/ui/parser/issue-73568-lifetime-after-mut.stderr b/src/test/ui/parser/issue-73568-lifetime-after-mut.stderr new file mode 100644 index 0000000000000..abb64f7e490df --- /dev/null +++ b/src/test/ui/parser/issue-73568-lifetime-after-mut.stderr @@ -0,0 +1,53 @@ +error: lifetime must precede `mut` + --> $DIR/issue-73568-lifetime-after-mut.rs:2:13 + | +LL | fn x<'a>(x: &mut 'a i32){} + | ^^^^^^^ help: place the lifetime before `mut`: `&'a mut` + +error[E0178]: expected a path on the left-hand side of `+`, not `&mut 'a` + --> $DIR/issue-73568-lifetime-after-mut.rs:14:13 + | +LL | fn y<'a>(y: &mut 'a + Send) { + | ^^^^^^^^^^^^^^ help: try adding parentheses: `&mut ('a + Send)` + +error: lifetime must precede `mut` + --> $DIR/issue-73568-lifetime-after-mut.rs:6:22 + | +LL | fn w<$lt>(w: &mut $lt i32) {} + | ^^^^^^^^ help: place the lifetime before `mut`: `&$lt mut` +... +LL | mac!('a); + | --------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0423]: expected value, found trait `Send` + --> $DIR/issue-73568-lifetime-after-mut.rs:18:28 + | +LL | let z = y as &mut 'a + Send; + | ^^^^ not a value + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/issue-73568-lifetime-after-mut.rs:14:18 + | +LL | fn y<'a>(y: &mut 'a + Send) { + | ^^ help: use `dyn`: `dyn 'a` + | + = note: `#[warn(bare_trait_objects)]` on by default + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/issue-73568-lifetime-after-mut.rs:18:23 + | +LL | let z = y as &mut 'a + Send; + | ^^ help: use `dyn`: `dyn 'a` + +error[E0224]: at least one trait is required for an object type + --> $DIR/issue-73568-lifetime-after-mut.rs:14:18 + | +LL | fn y<'a>(y: &mut 'a + Send) { + | ^^ + +error: aborting due to 5 previous errors; 2 warnings emitted + +Some errors have detailed explanations: E0178, E0224, E0423. +For more information about an error, try `rustc --explain E0178`. From cbda1546b1d2464fc7c012f9274874bc62b25e24 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 15 Sep 2020 07:58:33 -0700 Subject: [PATCH 0459/1052] doc: platform-support.md: Document port Signed-off-by: Alistair Francis --- src/doc/rustc/src/platform-support.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 794eeafbbbff9..aa152bdbf8df9 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -101,6 +101,7 @@ target | std | host | notes `powerpc-unknown-linux-gnu` | ✓ | ✓ | PowerPC Linux (kernel 2.6.32, glibc 2.11) `powerpc64-unknown-linux-gnu` | ✓ | ✓ | PPC64 Linux (kernel 2.6.32, glibc 2.11) `powerpc64le-unknown-linux-gnu` | ✓ | ✓ | PPC64LE Linux (kernel 3.10, glibc 2.17) +`riscv32gc-unknown-linux-gnu` | ✓ | ✓ | RISC-V Linux (kernel 5.4, glibc 2.33) `riscv32i-unknown-none-elf` | * | | Bare RISC-V (RV32I ISA) `riscv32imac-unknown-none-elf` | * | | Bare RISC-V (RV32IMAC ISA) `riscv32imc-unknown-none-elf` | * | | Bare RISC-V (RV32IMC ISA) From e968f86f7162304e9a59bd89bd0fe40e8db1ac6d Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 15 Sep 2020 08:13:01 -0700 Subject: [PATCH 0460/1052] doc: platform-support.md: Move to tier 3 Signed-off-by: Alistair Francis --- src/doc/rustc/src/platform-support.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index aa152bdbf8df9..da27d2fbf99a3 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -101,7 +101,6 @@ target | std | host | notes `powerpc-unknown-linux-gnu` | ✓ | ✓ | PowerPC Linux (kernel 2.6.32, glibc 2.11) `powerpc64-unknown-linux-gnu` | ✓ | ✓ | PPC64 Linux (kernel 2.6.32, glibc 2.11) `powerpc64le-unknown-linux-gnu` | ✓ | ✓ | PPC64LE Linux (kernel 3.10, glibc 2.17) -`riscv32gc-unknown-linux-gnu` | ✓ | ✓ | RISC-V Linux (kernel 5.4, glibc 2.33) `riscv32i-unknown-none-elf` | * | | Bare RISC-V (RV32I ISA) `riscv32imac-unknown-none-elf` | * | | Bare RISC-V (RV32IMAC ISA) `riscv32imc-unknown-none-elf` | * | | Bare RISC-V (RV32IMC ISA) @@ -196,6 +195,7 @@ target | std | host | notes `powerpc64-unknown-linux-musl` | ? | | `powerpc64-wrs-vxworks` | ? | | `powerpc64le-unknown-linux-musl` | ? | | +`riscv32gc-unknown-linux-gnu` | | | RISC-V Linux (kernel 5.4, glibc 2.33) `sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux `sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64 `sparc64-unknown-openbsd` | ? | | From 328c61c15711ae8a741b2aa56af1c450f54d1796 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 11 Sep 2020 22:17:16 -0400 Subject: [PATCH 0461/1052] Make the default stage for x.py configurable This allows configuring the default stage for each sub-command individually. - Normalize the stage as early as possible, so there's no confusion about which to use. - Don't add an explicit `stage` option in config.toml This offers no more flexibility than `*_stage` and makes it confusing which takes precedence. - Always give `--stage N` precedence over config.toml - Fix bootstrap tests This changes the tests to go through `Config::parse` so that they test the actual defaults, not the dummy ones provided by `default_opts`. To make this workable (and independent of the environment), it does not read `config.toml` for tests. --- config.toml.example | 17 ++++++++++ src/bootstrap/builder.rs | 31 ++---------------- src/bootstrap/builder/tests.rs | 14 ++++---- src/bootstrap/config.rs | 59 ++++++++++++++++++++++++++++++---- 4 files changed, 79 insertions(+), 42 deletions(-) diff --git a/config.toml.example b/config.toml.example index 2d5b3136450b9..f10d1a7b44e5e 100644 --- a/config.toml.example +++ b/config.toml.example @@ -111,6 +111,23 @@ # General build configuration options # ============================================================================= [build] +# The default stage to use for the `doc` subcommand +#doc-stage = 0 + +# The default stage to use for the `build` subcommand +#build-stage = 1 + +# The default stage to use for the `test` subcommand +#test-stage = 1 + +# The default stage to use for the `dist` subcommand +#dist-stage = 2 + +# The default stage to use for the `install` subcommand +#install-stage = 2 + +# The default stage to use for the `bench` subcommand +#bench-stage = 2 # Build triple for the original snapshot compiler. This must be a compiler that # nightlies are already produced for. The current platform must be able to run diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 31d4f1f28a86d..034b01a502cc5 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -526,23 +526,9 @@ impl<'a> Builder<'a> { } fn new_internal(build: &Build, kind: Kind, paths: Vec) -> Builder<'_> { - let top_stage = if let Some(explicit_stage) = build.config.stage { - explicit_stage - } else { - // See https://github.com/rust-lang/compiler-team/issues/326 - match kind { - Kind::Doc => 0, - Kind::Build | Kind::Test => 1, - Kind::Bench | Kind::Dist | Kind::Install => 2, - // These are all bootstrap tools, which don't depend on the compiler. - // The stage we pass shouldn't matter, but use 0 just in case. - Kind::Check | Kind::Clippy | Kind::Fix | Kind::Run | Kind::Format => 0, - } - }; - Builder { build, - top_stage, + top_stage: build.config.stage, kind, cache: Cache::new(), stack: RefCell::new(Vec::new()), @@ -566,20 +552,7 @@ impl<'a> Builder<'a> { Subcommand::Format { .. } | Subcommand::Clean { .. } => panic!(), }; - let this = Self::new_internal(build, kind, paths.to_owned()); - - // CI should always run stage 2 builds, unless it specifically states otherwise - #[cfg(not(test))] - if build.config.stage.is_none() && build.ci_env != crate::CiEnv::None { - match kind { - Kind::Test | Kind::Doc | Kind::Build | Kind::Bench | Kind::Dist | Kind::Install => { - assert_eq!(this.top_stage, 2) - } - Kind::Check | Kind::Clippy | Kind::Fix | Kind::Run | Kind::Format => {} - } - } - - this + Self::new_internal(build, kind, paths.to_owned()) } pub fn execute_cli(&self) { diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index c6eac95c34507..f96925f927086 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -2,8 +2,8 @@ use super::*; use crate::config::{Config, TargetSelection}; use std::thread; -fn configure(host: &[&str], target: &[&str]) -> Config { - let mut config = Config::default_opts(); +fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config { + let mut config = Config::parse(&[cmd.to_owned()]); // don't save toolstates config.save_toolstates = None; config.skip_only_host_steps = false; @@ -42,7 +42,7 @@ mod defaults { #[test] fn build_default() { - let build = Build::new(configure(&[], &[])); + let build = Build::new(configure("build", &[], &[])); let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); @@ -70,7 +70,7 @@ mod defaults { #[test] fn build_stage_0() { - let config = Config { stage: Some(0), ..configure(&[], &[]) }; + let config = Config { stage: 0, ..configure("build", &[], &[]) }; let build = Build::new(config); let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); @@ -92,7 +92,7 @@ mod defaults { #[test] fn doc_default() { - let mut config = configure(&[], &[]); + let mut config = configure("doc", &[], &[]); config.compiler_docs = true; config.cmd = Subcommand::Doc { paths: Vec::new(), open: false }; let build = Build::new(config); @@ -126,7 +126,7 @@ mod dist { use pretty_assertions::assert_eq; fn configure(host: &[&str], target: &[&str]) -> Config { - Config { stage: Some(2), ..super::configure(host, target) } + Config { stage: 2, ..super::configure("dist", host, target) } } #[test] @@ -455,7 +455,7 @@ mod dist { #[test] fn test_with_no_doc_stage0() { let mut config = configure(&[], &[]); - config.stage = Some(0); + config.stage = 0; config.cmd = Subcommand::Test { paths: vec!["library/std".into()], test_args: vec![], diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 5a79d3db5c905..cc0a534314a52 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -10,7 +10,6 @@ use std::ffi::OsString; use std::fmt; use std::fs; use std::path::{Path, PathBuf}; -use std::process; use crate::cache::{Interned, INTERNER}; use crate::flags::Flags; @@ -57,7 +56,7 @@ pub struct Config { pub skip_only_host_steps: bool, pub on_fail: Option, - pub stage: Option, + pub stage: u32, pub keep_stage: Vec, pub src: PathBuf, pub jobs: Option, @@ -300,6 +299,12 @@ struct Build { configure_args: Option>, local_rebuild: Option, print_step_timings: Option, + doc_stage: Option, + build_stage: Option, + test_stage: Option, + install_stage: Option, + dist_stage: Option, + bench_stage: Option, } /// TOML representation of various global install decisions. @@ -480,13 +485,11 @@ impl Config { pub fn parse(args: &[String]) -> Config { let flags = Flags::parse(&args); - let file = flags.config.clone(); let mut config = Config::default_opts(); config.exclude = flags.exclude; config.rustc_error_format = flags.rustc_error_format; config.json_output = flags.json_output; config.on_fail = flags.on_fail; - config.stage = flags.stage; config.jobs = flags.jobs.map(threads_from_config); config.cmd = flags.cmd; config.incremental = flags.incremental; @@ -503,8 +506,14 @@ impl Config { config.out = dir; } - let toml = file + #[cfg(test)] + let toml = TomlConfig::default(); + #[cfg(not(test))] + let toml = flags + .config .map(|file| { + use std::process; + let contents = t!(fs::read_to_string(&file)); match toml::from_str(&contents) { Ok(table) => table, @@ -520,7 +529,7 @@ impl Config { }) .unwrap_or_else(TomlConfig::default); - let build = toml.build.clone().unwrap_or_default(); + let build = toml.build.unwrap_or_default(); // If --target was specified but --host wasn't specified, don't run any host-only tests. let has_hosts = build.host.is_some() || flags.host.is_some(); @@ -564,6 +573,44 @@ impl Config { set(&mut config.configure_args, build.configure_args); set(&mut config.local_rebuild, build.local_rebuild); set(&mut config.print_step_timings, build.print_step_timings); + + // See https://github.com/rust-lang/compiler-team/issues/326 + config.stage = match config.cmd { + Subcommand::Doc { .. } => flags.stage.or(build.doc_stage).unwrap_or(0), + Subcommand::Build { .. } => flags.stage.or(build.build_stage).unwrap_or(1), + Subcommand::Test { .. } => flags.stage.or(build.test_stage).unwrap_or(1), + Subcommand::Bench { .. } => flags.stage.or(build.bench_stage).unwrap_or(2), + Subcommand::Dist { .. } => flags.stage.or(build.dist_stage).unwrap_or(2), + Subcommand::Install { .. } => flags.stage.or(build.install_stage).unwrap_or(2), + // These are all bootstrap tools, which don't depend on the compiler. + // The stage we pass shouldn't matter, but use 0 just in case. + Subcommand::Clean { .. } + | Subcommand::Check { .. } + | Subcommand::Clippy { .. } + | Subcommand::Fix { .. } + | Subcommand::Run { .. } + | Subcommand::Format { .. } => flags.stage.unwrap_or(0), + }; + + // CI should always run stage 2 builds, unless it specifically states otherwise + #[cfg(not(test))] + if flags.stage.is_none() && crate::CiEnv::current() != crate::CiEnv::None { + match config.cmd { + Subcommand::Test { .. } + | Subcommand::Doc { .. } + | Subcommand::Build { .. } + | Subcommand::Bench { .. } + | Subcommand::Dist { .. } + | Subcommand::Install { .. } => assert_eq!(config.stage, 2), + Subcommand::Clean { .. } + | Subcommand::Check { .. } + | Subcommand::Clippy { .. } + | Subcommand::Fix { .. } + | Subcommand::Run { .. } + | Subcommand::Format { .. } => {} + } + } + config.verbose = cmp::max(config.verbose, flags.verbose); if let Some(ref install) = toml.install { From 0122e08dae79c2320ce0a9ce60a48ec35f970aff Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Tue, 8 Sep 2020 14:17:15 +0200 Subject: [PATCH 0462/1052] Update stdarch --- library/stdarch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/stdarch b/library/stdarch index 78891cdf292c2..718175b34a39e 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit 78891cdf292c23278ca8723bd543100249159604 +Subproject commit 718175b34a39e4e3d59b40e35930326edc515b87 From 44eb66d947191be51f0a7b7d35c05936a4142a97 Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Wed, 16 Sep 2020 00:25:00 +0900 Subject: [PATCH 0463/1052] Add note to `shadow_unrelated` This lint can be disabled at function level. --- clippy_lints/src/shadow.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index ef4a54735a498..225fe58906f73 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -74,7 +74,9 @@ declare_clippy_lint! { /// names to bindings or introducing more scopes to contain the bindings. /// /// **Known problems:** This lint, as the other shadowing related lints, - /// currently only catches very simple patterns. + /// currently only catches very simple patterns. Note that + /// `allow`/`warn`/`deny`/`forbid` attributes only work on the function level + /// for this lint. /// /// **Example:** /// ```rust From 81161bed41124a7a62bdaf5a349df0e8f2ff09bf Mon Sep 17 00:00:00 2001 From: Niclas Schwarzlose <15schnic@gmail.com> Date: Tue, 15 Sep 2020 18:10:41 +0200 Subject: [PATCH 0464/1052] Adjust spelling Co-authored-by: Joshua Nelson --- compiler/rustc_error_codes/src/error_codes/E0118.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0118.md b/compiler/rustc_error_codes/src/error_codes/E0118.md index ddd4f498f0c34..345ec341c3f40 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0118.md +++ b/compiler/rustc_error_codes/src/error_codes/E0118.md @@ -1,5 +1,5 @@ -An inherent implementation was defined for something which isn't a struct, an -enum, a union or a trait object. +An inherent implementation was defined for something which isn't a struct, +enum, union, or trait object. Erroneous code example: From 2a5a6b42ecf99b198eae89e13053b00bd1582a27 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 15 Sep 2020 18:18:04 +0200 Subject: [PATCH 0465/1052] Add missing code examples in libcore --- library/core/src/num/dec2flt/mod.rs | 10 ++++++++++ library/core/src/num/mod.rs | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/dec2flt/mod.rs index ed6202bb82f0f..6f3a3a867450d 100644 --- a/library/core/src/num/dec2flt/mod.rs +++ b/library/core/src/num/dec2flt/mod.rs @@ -166,6 +166,16 @@ from_str_float_impl!(f64); /// /// This error is used as the error type for the [`FromStr`] implementation /// for [`f32`] and [`f64`]. +/// +/// # Example +/// +/// ``` +/// use std::str::FromStr; +/// +/// if let Err(e) = f64::from_str("a.12") { +/// println!("Failed conversion to f64: {}", e); +/// } +/// ``` #[derive(Debug, Clone, PartialEq, Eq)] #[stable(feature = "rust1", since = "1.0.0")] pub struct ParseFloatError { diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 2a936c1867da0..050c187e55576 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -5286,6 +5286,14 @@ fn from_str_radix(src: &str, radix: u32) -> Result Date: Tue, 15 Sep 2020 21:25:03 +0200 Subject: [PATCH 0469/1052] manual-strip: Fix formatting --- clippy_lints/src/manual_strip.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 127938aecd63c..4afb0ab3badb0 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -124,8 +124,7 @@ fn len_arg<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx E if match_def_path(cx, method_def_id, &paths::STR_LEN); then { Some(arg) - } - else { + } else { None } } From 9bf1f27f5895295cdbbbb457b957a3e3ec2b7a2e Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Tue, 15 Sep 2020 21:56:07 +0200 Subject: [PATCH 0470/1052] ci: gate macOS on GHA too --- .github/workflows/ci.yml | 98 +++++++++++++++++---------- src/ci/github-actions/ci.yml | 124 +++++++++++++++++++++-------------- 2 files changed, 135 insertions(+), 87 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8b6828fd49d27..50ae8c313d6fc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -76,7 +76,7 @@ jobs: uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master with: github_token: "${{ secrets.github_token }}" - if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && !env.RUST_CI_TEMP_SKIP_CANCEL_OUTDATED" + if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'" - name: collect CPU statistics run: src/ci/scripts/collect-cpu-stats.sh if: success() && !env.SKIP_JOB @@ -180,7 +180,7 @@ jobs: uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master with: github_token: "${{ secrets.github_token }}" - if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && !env.RUST_CI_TEMP_SKIP_CANCEL_OUTDATED" + if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'" - name: collect CPU statistics run: src/ci/scripts/collect-cpu-stats.sh if: success() && !env.SKIP_JOB @@ -375,6 +375,64 @@ jobs: env: DEPLOY_TOOLSTATES_JSON: toolstates-linux.json os: ubuntu-latest-xl + - name: dist-x86_64-apple + env: + SCRIPT: "./x.py dist" + RUST_CONFIGURE_ARGS: "--host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false" + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + DIST_REQUIRE_ALL_TOOLS: 1 + os: macos-latest + - name: dist-x86_64-apple-alt + env: + SCRIPT: "./x.py dist" + RUST_CONFIGURE_ARGS: "--enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false" + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + os: macos-latest + - name: x86_64-apple + env: + SCRIPT: "./x.py --stage 2 test" + RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false" + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.8 + MACOSX_STD_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + os: macos-latest + - name: dist-x86_64-apple + env: + SCRIPT: "./x.py dist" + RUST_CONFIGURE_ARGS: "--host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false" + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + DIST_REQUIRE_ALL_TOOLS: 1 + os: macos-latest + - name: dist-x86_64-apple-alt + env: + SCRIPT: "./x.py dist" + RUST_CONFIGURE_ARGS: "--enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false" + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + os: macos-latest + - name: x86_64-apple + env: + SCRIPT: "./x.py --stage 2 test" + RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false" + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.8 + MACOSX_STD_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + os: macos-latest - name: x86_64-msvc-1 env: RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler" @@ -499,7 +557,7 @@ jobs: uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master with: github_token: "${{ secrets.github_token }}" - if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && !env.RUST_CI_TEMP_SKIP_CANCEL_OUTDATED" + if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'" - name: collect CPU statistics run: src/ci/scripts/collect-cpu-stats.sh if: success() && !env.SKIP_JOB @@ -580,38 +638,6 @@ jobs: - self-hosted - ARM64 - linux - - name: dist-x86_64-apple - env: - SCRIPT: "./x.py dist" - RUST_CONFIGURE_ARGS: "--host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false" - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - RUST_CI_TEMP_SKIP_CANCEL_OUTDATED: 1 - os: macos-latest - - name: dist-x86_64-apple-alt - env: - SCRIPT: "./x.py dist" - RUST_CONFIGURE_ARGS: "--enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false" - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - RUST_CI_TEMP_SKIP_CANCEL_OUTDATED: 1 - os: macos-latest - - name: x86_64-apple - env: - SCRIPT: "./x.py --stage 2 test" - RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false" - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.8 - MACOSX_STD_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - RUST_CI_TEMP_SKIP_CANCEL_OUTDATED: 1 - os: macos-latest timeout-minutes: 600 runs-on: "${{ matrix.os }}" steps: @@ -638,7 +664,7 @@ jobs: uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master with: github_token: "${{ secrets.github_token }}" - if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && !env.RUST_CI_TEMP_SKIP_CANCEL_OUTDATED" + if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'" - name: collect CPU statistics run: src/ci/scripts/collect-cpu-stats.sh if: success() && !env.SKIP_JOB diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 2109cdf4e86b7..f8d3bc8e8e588 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -130,9 +130,7 @@ x--expand-yaml-anchors--remove: uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master with: github_token: "${{ secrets.github_token }}" - # TODO: remove the condition on RUST_CI_TEMP_SKIP_CANCEL_OUTDATED once - # we remove the `auto-fallible` job. - if: success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && !env.RUST_CI_TEMP_SKIP_CANCEL_OUTDATED + if: success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' <<: *step - name: collect CPU statistics @@ -434,6 +432,78 @@ jobs: DEPLOY_TOOLSTATES_JSON: toolstates-linux.json <<: *job-linux-xl + #################### + # macOS Builders # + #################### + + - name: dist-x86_64-apple + env: + SCRIPT: ./x.py dist + RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + DIST_REQUIRE_ALL_TOOLS: 1 + <<: *job-macos-xl + + - name: dist-x86_64-apple-alt + env: + SCRIPT: ./x.py dist + RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + <<: *job-macos-xl + + - name: x86_64-apple + env: + SCRIPT: ./x.py --stage 2 test + RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.8 + MACOSX_STD_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + <<: *job-macos-xl + + #################### + # macOS Builders # + #################### + + - name: dist-x86_64-apple + env: + SCRIPT: ./x.py dist + RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + DIST_REQUIRE_ALL_TOOLS: 1 + <<: *job-macos-xl + + - name: dist-x86_64-apple-alt + env: + SCRIPT: ./x.py dist + RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + <<: *job-macos-xl + + - name: x86_64-apple + env: + SCRIPT: ./x.py --stage 2 test + RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.8 + MACOSX_STD_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + <<: *job-macos-xl + ###################### # Windows Builders # ###################### @@ -600,54 +670,6 @@ jobs: - name: aarch64-gnu <<: *job-aarch64-linux - #################### - # macOS Builders # - #################### - - - name: dist-x86_64-apple - env: - SCRIPT: ./x.py dist - RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - - # TODO: remove once we move this job away from auto-fallible. - # Also, remove the variable from the cancel-outdated-builds step - RUST_CI_TEMP_SKIP_CANCEL_OUTDATED: 1 - <<: *job-macos-xl - - - name: dist-x86_64-apple-alt - env: - SCRIPT: ./x.py dist - RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - - # TODO: remove once we move this job away from auto-fallible. - # Also, remove the variable from the cancel-outdated-builds step - RUST_CI_TEMP_SKIP_CANCEL_OUTDATED: 1 - <<: *job-macos-xl - - - name: x86_64-apple - env: - SCRIPT: ./x.py --stage 2 test - RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.8 - MACOSX_STD_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - - # TODO: remove once we move this job away from auto-fallible. - # Also, remove the variable from the cancel-outdated-builds step - RUST_CI_TEMP_SKIP_CANCEL_OUTDATED: 1 - <<: *job-macos-xl - master: name: master runs-on: ubuntu-latest From 73d4171ea6cb07b9426b386041b19376606db079 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Tue, 15 Sep 2020 22:36:43 +0200 Subject: [PATCH 0471/1052] fix a couple of stylistic clippy warnings namely: clippy::redundant_pattern_matching clippy::redundant_pattern clippy::search_is_some clippy::filter_next clippy::into_iter_on_ref clippy::clone_on_copy clippy::needless_return --- .../error_reporting/nice_region_error/named_anon_conflict.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 4 ++-- .../rustc_mir/src/borrow_check/diagnostics/region_errors.rs | 2 +- compiler/rustc_mir/src/transform/instcombine.rs | 2 +- compiler/rustc_resolve/src/late/diagnostics.rs | 2 +- compiler/rustc_trait_selection/src/traits/coherence.rs | 2 +- compiler/rustc_typeck/src/check/_match.rs | 2 +- compiler/rustc_typeck/src/check/expr.rs | 3 +-- compiler/rustc_typeck/src/check/pat.rs | 3 +-- 9 files changed, 10 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs index 89142edb2dc61..e3c613b1d6a12 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -85,7 +85,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { debug!("try_report_named_anon_conflict: ret ty {:?}", ty); if sub == &ty::ReStatic - && v.0.into_iter().find(|t| t.span.desugaring_kind().is_none()).is_some() + && v.0.into_iter().any(|t| t.span.desugaring_kind().is_none()) { // If the failure is due to a `'static` requirement coming from a `dyn` or // `impl` Trait that *isn't* caused by `async fn` desugaring, handle this case diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 9562d43791493..4b2e9a16d4a07 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -273,10 +273,10 @@ pub trait PrettyPrinter<'tcx>: } match self.tcx().trimmed_def_paths(LOCAL_CRATE).get(&def_id) { - None => return Ok((self, false)), + None => Ok((self, false)), Some(symbol) => { self.write_str(&symbol.as_str())?; - return Ok((self, true)); + Ok((self, true)) } } } diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs index 639428ff07d9d..eb1f70099fc89 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs @@ -387,7 +387,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if let ReturnConstraint::ClosureUpvar(upvar) = kind { let def_id = match self.regioncx.universal_regions().defining_ty { DefiningTy::Closure(def_id, _) => def_id, - ty @ _ => bug!("unexpected DefiningTy {:?}", ty), + ty => bug!("unexpected DefiningTy {:?}", ty), }; let upvar_def_span = self.infcx.tcx.hir().span(upvar); diff --git a/compiler/rustc_mir/src/transform/instcombine.rs b/compiler/rustc_mir/src/transform/instcombine.rs index c4924cf16ab64..b224df92e9da0 100644 --- a/compiler/rustc_mir/src/transform/instcombine.rs +++ b/compiler/rustc_mir/src/transform/instcombine.rs @@ -126,7 +126,7 @@ impl OptimizationFinder<'b, 'tcx> { } } - return None; + None } } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 9b5650c260c22..2cc87dc637566 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1534,7 +1534,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { } }; - let lifetime_names: Vec<_> = lifetime_names.into_iter().collect(); + let lifetime_names: Vec<_> = lifetime_names.iter().collect(); match (&lifetime_names[..], snippet.as_deref()) { ([name], Some("&")) => { suggest_existing(err, &name.as_str()[..], &|name| format!("&{} ", name)); diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index c27d2fcc14998..c53c65c00b769 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -182,7 +182,7 @@ fn overlap_within_probe( } if !skip_leak_check.is_yes() { - if let Err(_) = infcx.leak_check(true, snapshot) { + if infcx.leak_check(true, snapshot).is_err() { debug!("overlap: leak check failed"); return None; } diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs index 836a4ff78c79e..7cb23dc053795 100644 --- a/compiler/rustc_typeck/src/check/_match.rs +++ b/compiler/rustc_typeck/src/check/_match.rs @@ -164,7 +164,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // If all the obligations hold (or there are no obligations) the tail expression // we can suggest to return a boxed trait object instead of an opaque type. - if suggest_box { self.ret_type_span.clone() } else { None } + if suggest_box { self.ret_type_span } else { None } } _ => None, }; diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index dba46f35dca92..d5563cdac02de 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1243,10 +1243,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else if check_completeness && !error_happened && !remaining_fields.is_empty() { let no_accessible_remaining_fields = remaining_fields .iter() - .filter(|(_, (_, field))| { + .find(|(_, (_, field))| { field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx) }) - .next() .is_none(); if no_accessible_remaining_fields { diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 6be2fdf9f1904..54b0671fab5a7 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -1141,10 +1141,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else if !etc && !unmentioned_fields.is_empty() { let no_accessible_unmentioned_fields = unmentioned_fields .iter() - .filter(|(field, _)| { + .find(|(field, _)| { field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx) }) - .next() .is_none(); if no_accessible_unmentioned_fields { From f567287f9f35e4d4781213bddc5770e270f48d0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Tue, 15 Sep 2020 22:44:43 +0200 Subject: [PATCH 0472/1052] don't convert types to the same type with try_into (clippy::useless_conversion) --- compiler/rustc_mir/src/dataflow/move_paths/builder.rs | 5 +---- compiler/rustc_mir/src/interpret/place.rs | 6 ++---- compiler/rustc_mir_build/src/build/matches/util.rs | 2 +- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_mir/src/dataflow/move_paths/builder.rs b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs index b083044a9c6d9..eb92461672259 100644 --- a/compiler/rustc_mir/src/dataflow/move_paths/builder.rs +++ b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs @@ -4,7 +4,6 @@ use rustc_middle::mir::*; use rustc_middle::ty::{self, TyCtxt}; use smallvec::{smallvec, SmallVec}; -use std::convert::TryInto; use std::mem; use super::abs_domain::Lift; @@ -482,10 +481,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { let base_ty = base_place.ty(self.builder.body, self.builder.tcx).ty; let len: u64 = match base_ty.kind() { ty::Array(_, size) => { - let length = size.eval_usize(self.builder.tcx, self.builder.param_env); + let length: u64 = size.eval_usize(self.builder.tcx, self.builder.param_env); length - .try_into() - .expect("slice pattern of array with more than u32::MAX elements") } _ => bug!("from_end: false slice pattern of non-array type"), }; diff --git a/compiler/rustc_mir/src/interpret/place.rs b/compiler/rustc_mir/src/interpret/place.rs index 9e16063bd21af..3b22eb5d98719 100644 --- a/compiler/rustc_mir/src/interpret/place.rs +++ b/compiler/rustc_mir/src/interpret/place.rs @@ -551,7 +551,7 @@ where let n = base.len(self)?; if n < min_length { // This can only be reached in ConstProp and non-rustc-MIR. - throw_ub!(BoundsCheckFailed { len: min_length.into(), index: n }); + throw_ub!(BoundsCheckFailed { len: min_length, index: n }); } let index = if from_end { @@ -565,9 +565,7 @@ where self.mplace_index(base, index)? } - Subslice { from, to, from_end } => { - self.mplace_subslice(base, u64::from(from), u64::from(to), from_end)? - } + Subslice { from, to, from_end } => self.mplace_subslice(base, from, to, from_end)?, }) } diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index d6e828c966a95..4ef88c25cadf3 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -33,7 +33,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let tcx = self.hir.tcx(); let (min_length, exact_size) = match place.ty(&self.local_decls, tcx).ty.kind() { ty::Array(_, length) => { - (length.eval_usize(tcx, self.hir.param_env).try_into().unwrap(), true) + (length.eval_usize(tcx, self.hir.param_env), true) } _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false), }; From fafb2e9de717c40b95e52889bb641b32c1dc6a1e Mon Sep 17 00:00:00 2001 From: Adam Lesinski Date: Tue, 15 Sep 2020 13:54:46 -0700 Subject: [PATCH 0473/1052] [fuchsia] Propagate the userspace UTC clock On Fuchsia, spawning a subprocess does not automatically clone all of the parent process' capabilities. UTC time on Fuchsia is managed by a top-level userspace clock capability that is cloned and passed to subprocesses. This change ensures that any Rust subprocess gets access to the UTC clock, if the parent had access to it. This is critical for tests, which on Fuchsia, use panic=abort and spawn subprocesses per test. --- library/std/src/sys/unix/process/process_fuchsia.rs | 3 ++- library/std/src/sys/unix/process/zircon.rs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/process/process_fuchsia.rs b/library/std/src/sys/unix/process/process_fuchsia.rs index 6daf2885baed0..fab27cd9f7085 100644 --- a/library/std/src/sys/unix/process/process_fuchsia.rs +++ b/library/std/src/sys/unix/process/process_fuchsia.rs @@ -118,7 +118,8 @@ impl Command { FDIO_SPAWN_CLONE_JOB | FDIO_SPAWN_CLONE_LDSVC | FDIO_SPAWN_CLONE_NAMESPACE - | FDIO_SPAWN_CLONE_ENVIRON, // this is ignored when envp is non-null + | FDIO_SPAWN_CLONE_ENVIRON // this is ignored when envp is non-null + | FDIO_SPAWN_CLONE_UTC_CLOCK, self.get_program().as_ptr(), self.get_argv().as_ptr(), envp, diff --git a/library/std/src/sys/unix/process/zircon.rs b/library/std/src/sys/unix/process/zircon.rs index 750b8f0762ae5..69ec275c2b318 100644 --- a/library/std/src/sys/unix/process/zircon.rs +++ b/library/std/src/sys/unix/process/zircon.rs @@ -138,6 +138,7 @@ pub const FDIO_SPAWN_CLONE_LDSVC: u32 = 0x0002; pub const FDIO_SPAWN_CLONE_NAMESPACE: u32 = 0x0004; pub const FDIO_SPAWN_CLONE_STDIO: u32 = 0x0008; pub const FDIO_SPAWN_CLONE_ENVIRON: u32 = 0x0010; +pub const FDIO_SPAWN_CLONE_UTC_CLOCK: u32 = 0x0020; pub const FDIO_SPAWN_CLONE_ALL: u32 = 0xFFFF; // fdio_spawn_etc actions From d888725fba70af4139629da0f7a17910aa66d951 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 13 Sep 2020 11:27:21 +0200 Subject: [PATCH 0474/1052] reduce size of test_from_iter_specialization_with_iterator_adapters test in Miri --- library/alloc/tests/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 608a3c9bdf762..5fdbef7171025 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -894,7 +894,7 @@ fn test_from_iter_partially_drained_in_place_specialization() { #[test] fn test_from_iter_specialization_with_iterator_adapters() { fn assert_in_place_trait(_: &T) {}; - let src: Vec = vec![0usize; 65535]; + let src: Vec = vec![0usize; if cfg!(miri) { 256 } else { 65535 }]; let srcptr = src.as_ptr(); let iter = src .into_iter() From 143e4e975b1465f0380985d3e5597c22a6c5ee58 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Tue, 15 Sep 2020 23:12:08 +0200 Subject: [PATCH 0475/1052] Fix stabilization marker for future_readiness_fns Moved it from 1.47.0 -> 1.48.0, which is the correct release for this to stabilize in --- library/core/src/future/mod.rs | 4 ++-- library/core/src/future/pending.rs | 12 ++++++------ library/core/src/future/ready.rs | 8 ++++---- library/std/src/future.rs | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs index ec343f75f34ce..bec3adfa98422 100644 --- a/library/core/src/future/mod.rs +++ b/library/core/src/future/mod.rs @@ -21,9 +21,9 @@ pub use self::future::Future; #[unstable(feature = "into_future", issue = "67644")] pub use into_future::IntoFuture; -#[stable(feature = "future_readiness_fns", since = "1.47.0")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] pub use pending::{pending, Pending}; -#[stable(feature = "future_readiness_fns", since = "1.47.0")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] pub use ready::{ready, Ready}; #[unstable(feature = "future_poll_fn", issue = "72302")] diff --git a/library/core/src/future/pending.rs b/library/core/src/future/pending.rs index c1a4e0cda0320..4fec219ede2bc 100644 --- a/library/core/src/future/pending.rs +++ b/library/core/src/future/pending.rs @@ -11,7 +11,7 @@ use crate::task::{Context, Poll}; /// documentation for more. /// /// [`pending`]: fn.pending.html -#[stable(feature = "future_readiness_fns", since = "1.47.0")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct Pending { _data: marker::PhantomData, @@ -31,12 +31,12 @@ pub struct Pending { /// unreachable!(); /// # } /// ``` -#[stable(feature = "future_readiness_fns", since = "1.47.0")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] pub fn pending() -> Pending { Pending { _data: marker::PhantomData } } -#[stable(feature = "future_readiness_fns", since = "1.47.0")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] impl Future for Pending { type Output = T; @@ -45,17 +45,17 @@ impl Future for Pending { } } -#[stable(feature = "future_readiness_fns", since = "1.47.0")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] impl Unpin for Pending {} -#[stable(feature = "future_readiness_fns", since = "1.47.0")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] impl Debug for Pending { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Pending").finish() } } -#[stable(feature = "future_readiness_fns", since = "1.47.0")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] impl Clone for Pending { fn clone(&self) -> Self { pending() diff --git a/library/core/src/future/ready.rs b/library/core/src/future/ready.rs index ddae6cfed4bdb..fcfd8779b0ad2 100644 --- a/library/core/src/future/ready.rs +++ b/library/core/src/future/ready.rs @@ -8,15 +8,15 @@ use crate::task::{Context, Poll}; /// documentation for more. /// /// [`ready`]: fn.ready.html -#[stable(feature = "future_readiness_fns", since = "1.47.0")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] #[derive(Debug, Clone)] #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct Ready(Option); -#[stable(feature = "future_readiness_fns", since = "1.47.0")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] impl Unpin for Ready {} -#[stable(feature = "future_readiness_fns", since = "1.47.0")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] impl Future for Ready { type Output = T; @@ -42,7 +42,7 @@ impl Future for Ready { /// assert_eq!(a.await, 1); /// # } /// ``` -#[stable(feature = "future_readiness_fns", since = "1.47.0")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] pub fn ready(t: T) -> Ready { Ready(Some(t)) } diff --git a/library/std/src/future.rs b/library/std/src/future.rs index 5ff74e557547c..9d9c36e9afb0f 100644 --- a/library/std/src/future.rs +++ b/library/std/src/future.rs @@ -9,7 +9,7 @@ pub use core::future::Future; pub use core::future::{from_generator, get_context, ResumeTy}; #[doc(inline)] -#[stable(feature = "future_readiness_fns", since = "1.47.0")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] pub use core::future::{pending, ready, Pending, Ready}; #[doc(inline)] From c528d2419672bd4ace322ddbc000813a12c1d4c7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 13 Sep 2020 12:14:59 +0200 Subject: [PATCH 0476/1052] fix slice::check_range aliasing problems --- library/alloc/src/collections/vec_deque.rs | 6 +- library/alloc/src/slice.rs | 2 + library/alloc/src/string.rs | 3 +- library/alloc/src/vec.rs | 2 +- library/alloc/tests/vec.rs | 2 +- library/core/src/slice/index.rs | 75 +++++++++++++++++++- library/core/src/slice/mod.rs | 81 ++-------------------- 7 files changed, 85 insertions(+), 86 deletions(-) diff --git a/library/alloc/src/collections/vec_deque.rs b/library/alloc/src/collections/vec_deque.rs index 253a3e9f2bea9..65cfe9a9b4996 100644 --- a/library/alloc/src/collections/vec_deque.rs +++ b/library/alloc/src/collections/vec_deque.rs @@ -1089,11 +1089,7 @@ impl VecDeque { where R: RangeBounds, { - // SAFETY: This buffer is only used to check the range. It might be partially - // uninitialized, but `check_range` needs a contiguous slice. - // https://github.com/rust-lang/rust/pull/75207#discussion_r471193682 - let buffer = unsafe { slice::from_raw_parts(self.ptr(), self.len()) }; - let Range { start, end } = buffer.check_range(range); + let Range { start, end } = slice::check_range(self.len(), range); let tail = self.wrap_add(self.tail, start); let head = self.wrap_add(self.tail, end); (tail, head) diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 677bfdd2349ec..55afdd94f4468 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -91,6 +91,8 @@ use crate::borrow::ToOwned; use crate::boxed::Box; use crate::vec::Vec; +#[unstable(feature = "slice_check_range", issue = "76393")] +pub use core::slice::check_range; #[unstable(feature = "array_chunks", issue = "74985")] pub use core::slice::ArrayChunks; #[unstable(feature = "array_chunks", issue = "74985")] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index e1724bf3c9a90..2b0ce5ede5630 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -49,6 +49,7 @@ use core::iter::{FromIterator, FusedIterator}; use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{self, Add, AddAssign, Index, IndexMut, Range, RangeBounds}; use core::ptr; +use core::slice; use core::str::{lossy, pattern::Pattern}; use crate::borrow::{Cow, ToOwned}; @@ -1506,7 +1507,7 @@ impl String { // of the vector version. The data is just plain bytes. // Because the range removal happens in Drop, if the Drain iterator is leaked, // the removal will not happen. - let Range { start, end } = self.as_bytes().check_range(range); + let Range { start, end } = slice::check_range(self.len(), range); assert!(self.is_char_boundary(start)); assert!(self.is_char_boundary(end)); diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index cb4c1c20abcf6..fdd71a3211afa 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -1310,7 +1310,7 @@ impl Vec { // the hole, and the vector length is restored to the new length. // let len = self.len(); - let Range { start, end } = self.check_range(range); + let Range { start, end } = slice::check_range(len, range); unsafe { // set self.vec length's to start, to be safe in case Drain is leaked diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 5fdbef7171025..9ef5df01565c6 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -894,7 +894,7 @@ fn test_from_iter_partially_drained_in_place_specialization() { #[test] fn test_from_iter_specialization_with_iterator_adapters() { fn assert_in_place_trait(_: &T) {}; - let src: Vec = vec![0usize; if cfg!(miri) { 256 } else { 65535 }]; + let src: Vec = vec![0usize; 256]; let srcptr = src.as_ptr(); let iter = src .into_iter() diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index d67e0ae536d9f..a662d9682c51b 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -1,6 +1,6 @@ //! Indexing implementations for `[T]`. -use crate::ops; +use crate::ops::{self, Bound, Range, RangeBounds}; use crate::ptr; #[stable(feature = "rust1", since = "1.0.0")] @@ -62,6 +62,79 @@ pub(super) fn slice_end_index_overflow_fail() -> ! { panic!("attempted to index slice up to maximum usize"); } +/// Performs bounds-checking of the given range. +/// The returned [`Range`] is safe to pass to [`get_unchecked`] and [`get_unchecked_mut`] +/// for slices of the given length. +/// +/// [`get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked +/// [`get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut +/// +/// # Panics +/// +/// Panics if the range is out of bounds. +/// +/// # Examples +/// +/// ``` +/// #![feature(slice_check_range)] +/// use std::slice; +/// +/// let v = [10, 40, 30]; +/// assert_eq!(1..2, slice::check_range(v.len(), 1..2)); +/// assert_eq!(0..2, slice::check_range(v.len(), ..2)); +/// assert_eq!(1..3, slice::check_range(v.len(), 1..)); +/// ``` +/// +/// Panics when [`Index::index`] would panic: +/// +/// ```should_panic +/// #![feature(slice_check_range)] +/// +/// std::slice::check_range(3, 2..1); +/// ``` +/// +/// ```should_panic +/// #![feature(slice_check_range)] +/// +/// std::slice::check_range(3, 1..4); +/// ``` +/// +/// ```should_panic +/// #![feature(slice_check_range)] +/// +/// std::slice::check_range(3, 1..=usize::MAX); +/// ``` +/// +/// [`Index::index`]: crate::ops::Index::index +#[track_caller] +#[unstable(feature = "slice_check_range", issue = "76393")] +pub fn check_range>(len: usize, range: R) -> Range { + let start = match range.start_bound() { + Bound::Included(&start) => start, + Bound::Excluded(start) => { + start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) + } + Bound::Unbounded => 0, + }; + + let end = match range.end_bound() { + Bound::Included(end) => { + end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) + } + Bound::Excluded(&end) => end, + Bound::Unbounded => len, + }; + + if start > end { + slice_index_order_fail(start, end); + } + if end > len { + slice_end_index_len_fail(end, len); + } + + Range { start, end } +} + mod private_slice_index { use super::ops; #[stable(feature = "slice_get_slice", since = "1.28.0")] diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 64a707c39f076..ba3185433c8d8 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -12,7 +12,7 @@ use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::intrinsics::assume; use crate::marker::{self, Copy}; use crate::mem; -use crate::ops::{Bound, FnMut, Range, RangeBounds}; +use crate::ops::{FnMut, Range, RangeBounds}; use crate::option::Option; use crate::option::Option::{None, Some}; use crate::ptr::{self, NonNull}; @@ -72,8 +72,8 @@ pub use sort::heapsort; #[stable(feature = "slice_get_slice", since = "1.28.0")] pub use index::SliceIndex; -use index::{slice_end_index_len_fail, slice_index_order_fail}; -use index::{slice_end_index_overflow_fail, slice_start_index_overflow_fail}; +#[unstable(feature = "slice_check_range", issue = "76393")] +pub use index::check_range; #[lang = "slice"] #[cfg(not(test))] @@ -378,79 +378,6 @@ impl [T] { unsafe { &mut *index.get_unchecked_mut(self) } } - /// Converts a range over this slice to [`Range`]. - /// - /// The returned range is safe to pass to [`get_unchecked`] and [`get_unchecked_mut`]. - /// - /// [`get_unchecked`]: #method.get_unchecked - /// [`get_unchecked_mut`]: #method.get_unchecked_mut - /// - /// # Panics - /// - /// Panics if the range is out of bounds. - /// - /// # Examples - /// - /// ``` - /// #![feature(slice_check_range)] - /// - /// let v = [10, 40, 30]; - /// assert_eq!(1..2, v.check_range(1..2)); - /// assert_eq!(0..2, v.check_range(..2)); - /// assert_eq!(1..3, v.check_range(1..)); - /// ``` - /// - /// Panics when [`Index::index`] would panic: - /// - /// ```should_panic - /// #![feature(slice_check_range)] - /// - /// [10, 40, 30].check_range(2..1); - /// ``` - /// - /// ```should_panic - /// #![feature(slice_check_range)] - /// - /// [10, 40, 30].check_range(1..4); - /// ``` - /// - /// ```should_panic - /// #![feature(slice_check_range)] - /// - /// [10, 40, 30].check_range(1..=usize::MAX); - /// ``` - /// - /// [`Index::index`]: crate::ops::Index::index - #[track_caller] - #[unstable(feature = "slice_check_range", issue = "76393")] - pub fn check_range>(&self, range: R) -> Range { - let start = match range.start_bound() { - Bound::Included(&start) => start, - Bound::Excluded(start) => { - start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) - } - Bound::Unbounded => 0, - }; - - let len = self.len(); - let end = match range.end_bound() { - Bound::Included(end) => { - end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) - } - Bound::Excluded(&end) => end, - Bound::Unbounded => len, - }; - - if start > end { - slice_index_order_fail(start, end); - } - if end > len { - slice_end_index_len_fail(end, len); - } - - Range { start, end } - } - /// Returns a raw pointer to the slice's buffer. /// /// The caller must ensure that the slice outlives the pointer this @@ -2794,7 +2721,7 @@ impl [T] { where T: Copy, { - let Range { start: src_start, end: src_end } = self.check_range(src); + let Range { start: src_start, end: src_end } = check_range(self.len(), src); let count = src_end - src_start; assert!(dest <= self.len() - count, "dest is out of bounds"); // SAFETY: the conditions for `ptr::copy` have all been checked above, From fd9be8f7aadb729e6c37c71419b43fc4d3c188f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Tue, 15 Sep 2020 23:10:24 +0200 Subject: [PATCH 0477/1052] don't lazily evaulate some trivial values for Option::None replacements (clippy::unnecessary_lazy_evaluations) --- compiler/rustc_lint/src/builtin.rs | 2 +- compiler/rustc_metadata/src/native_libs.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index efdb7489ba5b0..5b5dbcf192ca1 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -961,7 +961,7 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: & continue; } - let span = sugared_span.take().unwrap_or_else(|| attr.span); + let span = sugared_span.take().unwrap_or(attr.span); if attr.is_doc_comment() || cx.sess().check_name(attr, sym::doc) { cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| { diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 3976475cb063e..e76c2cb356f3f 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -170,7 +170,7 @@ impl Collector<'tcx> { feature_err( &self.tcx.sess.parse_sess, sym::static_nobundle, - span.unwrap_or_else(|| rustc_span::DUMMY_SP), + span.unwrap_or(rustc_span::DUMMY_SP), "kind=\"static-nobundle\" is unstable", ) .emit(); @@ -179,7 +179,7 @@ impl Collector<'tcx> { feature_err( &self.tcx.sess.parse_sess, sym::raw_dylib, - span.unwrap_or_else(|| rustc_span::DUMMY_SP), + span.unwrap_or(rustc_span::DUMMY_SP), "kind=\"raw-dylib\" is unstable", ) .emit(); From 21b0c1286a1f01cb8a21bda0973833ca11889364 Mon Sep 17 00:00:00 2001 From: khyperia Date: Tue, 15 Sep 2020 23:35:31 +0200 Subject: [PATCH 0478/1052] Extract some intrinsics out of rustc_codegen_llvm A significant amount of intrinsics do not actually need backend-specific behaviors to be implemented, instead relying on methods already in rustc_codegen_ssa. So, extract those methods out to rustc_codegen_ssa, so that each backend doesn't need to reimplement the same code. --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 527 +--------------- compiler/rustc_codegen_ssa/src/mir/block.rs | 3 +- .../rustc_codegen_ssa/src/mir/intrinsic.rs | 596 ++++++++++++++++++ compiler/rustc_codegen_ssa/src/mir/mod.rs | 1 + 4 files changed, 606 insertions(+), 521 deletions(-) create mode 100644 compiler/rustc_codegen_ssa/src/mir/intrinsic.rs diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 2208ceca00c83..7f5b09eac4f9e 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -7,15 +7,12 @@ use crate::type_of::LayoutLlvmExt; use crate::va_arg::emit_va_arg; use crate::value::Value; -use rustc_ast as ast; use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh}; use rustc_codegen_ssa::common::span_invalid_monomorphization_error; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; -use rustc_codegen_ssa::glue; -use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; +use rustc_codegen_ssa::mir::operand::OperandRef; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::*; -use rustc_codegen_ssa::MemFlags; use rustc_hir as hir; use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt}; use rustc_middle::ty::{self, Ty}; @@ -71,8 +68,6 @@ fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: Symbol) -> Option<&'ll Va sym::nearbyintf64 => "llvm.nearbyint.f64", sym::roundf32 => "llvm.round.f32", sym::roundf64 => "llvm.round.f64", - sym::assume => "llvm.assume", - sym::abort => "llvm.trap", _ => return None, }; Some(cx.get_intrinsic(&llvm_name)) @@ -112,9 +107,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { &args.iter().map(|arg| arg.immediate()).collect::>(), None, ), - sym::unreachable => { - return; - } sym::likely => { let expect = self.get_intrinsic(&("llvm.expect.i1")); self.call(expect, &[args[0].immediate(), self.const_bool(true)], None) @@ -137,8 +129,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { let llfn = self.get_intrinsic(&("llvm.debugtrap")); self.call(llfn, &[], None) } - sym::va_start => self.va_start(args[0].immediate()), - sym::va_end => self.va_end(args[0].immediate()), sym::va_copy => { let intrinsic = self.cx().get_intrinsic(&("llvm.va_copy")); self.call(intrinsic, &[args[0].immediate(), args[1].immediate()], None) @@ -169,123 +159,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { _ => bug!("the va_arg intrinsic does not work with non-scalar types"), } } - sym::size_of_val => { - let tp_ty = substs.type_at(0); - if let OperandValue::Pair(_, meta) = args[0].val { - let (llsize, _) = glue::size_and_align_of_dst(self, tp_ty, Some(meta)); - llsize - } else { - self.const_usize(self.size_of(tp_ty).bytes()) - } - } - sym::min_align_of_val => { - let tp_ty = substs.type_at(0); - if let OperandValue::Pair(_, meta) = args[0].val { - let (_, llalign) = glue::size_and_align_of_dst(self, tp_ty, Some(meta)); - llalign - } else { - self.const_usize(self.align_of(tp_ty).bytes()) - } - } - sym::size_of - | sym::pref_align_of - | sym::min_align_of - | sym::needs_drop - | sym::type_id - | sym::type_name - | sym::variant_count => { - let value = self - .tcx - .const_eval_instance(ty::ParamEnv::reveal_all(), instance, None) - .unwrap(); - OperandRef::from_const(self, value, ret_ty).immediate_or_packed_pair(self) - } - // Effectively no-op - sym::forget => { - return; - } - sym::offset => { - let ptr = args[0].immediate(); - let offset = args[1].immediate(); - self.inbounds_gep(ptr, &[offset]) - } - sym::arith_offset => { - let ptr = args[0].immediate(); - let offset = args[1].immediate(); - self.gep(ptr, &[offset]) - } - - sym::copy_nonoverlapping => { - copy_intrinsic( - self, - false, - false, - substs.type_at(0), - args[1].immediate(), - args[0].immediate(), - args[2].immediate(), - ); - return; - } - sym::copy => { - copy_intrinsic( - self, - true, - false, - substs.type_at(0), - args[1].immediate(), - args[0].immediate(), - args[2].immediate(), - ); - return; - } - sym::write_bytes => { - memset_intrinsic( - self, - false, - substs.type_at(0), - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - ); - return; - } - sym::volatile_copy_nonoverlapping_memory => { - copy_intrinsic( - self, - false, - true, - substs.type_at(0), - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - ); - return; - } - sym::volatile_copy_memory => { - copy_intrinsic( - self, - true, - true, - substs.type_at(0), - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - ); - return; - } - sym::volatile_set_memory => { - memset_intrinsic( - self, - true, - substs.type_at(0), - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - ); - return; - } sym::volatile_load | sym::unaligned_volatile_load => { let tp_ty = substs.type_at(0); let mut ptr = args[0].immediate(); @@ -343,20 +217,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { | sym::ctpop | sym::bswap | sym::bitreverse - | sym::add_with_overflow - | sym::sub_with_overflow - | sym::mul_with_overflow - | sym::wrapping_add - | sym::wrapping_sub - | sym::wrapping_mul - | sym::unchecked_div - | sym::unchecked_rem - | sym::unchecked_shl - | sym::unchecked_shr - | sym::unchecked_add - | sym::unchecked_sub - | sym::unchecked_mul - | sym::exact_div | sym::rotate_left | sym::rotate_right | sym::saturating_add @@ -396,84 +256,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { &[args[0].immediate()], None, ), - sym::add_with_overflow - | sym::sub_with_overflow - | sym::mul_with_overflow => { - let intrinsic = format!( - "llvm.{}{}.with.overflow.i{}", - if signed { 's' } else { 'u' }, - &name_str[..3], - width - ); - let llfn = self.get_intrinsic(&intrinsic); - - // Convert `i1` to a `bool`, and write it to the out parameter - let pair = - self.call(llfn, &[args[0].immediate(), args[1].immediate()], None); - let val = self.extract_value(pair, 0); - let overflow = self.extract_value(pair, 1); - let overflow = self.zext(overflow, self.type_bool()); - - let dest = result.project_field(self, 0); - self.store(val, dest.llval, dest.align); - let dest = result.project_field(self, 1); - self.store(overflow, dest.llval, dest.align); - - return; - } - sym::wrapping_add => self.add(args[0].immediate(), args[1].immediate()), - sym::wrapping_sub => self.sub(args[0].immediate(), args[1].immediate()), - sym::wrapping_mul => self.mul(args[0].immediate(), args[1].immediate()), - sym::exact_div => { - if signed { - self.exactsdiv(args[0].immediate(), args[1].immediate()) - } else { - self.exactudiv(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_div => { - if signed { - self.sdiv(args[0].immediate(), args[1].immediate()) - } else { - self.udiv(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_rem => { - if signed { - self.srem(args[0].immediate(), args[1].immediate()) - } else { - self.urem(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_shl => self.shl(args[0].immediate(), args[1].immediate()), - sym::unchecked_shr => { - if signed { - self.ashr(args[0].immediate(), args[1].immediate()) - } else { - self.lshr(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_add => { - if signed { - self.unchecked_sadd(args[0].immediate(), args[1].immediate()) - } else { - self.unchecked_uadd(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_sub => { - if signed { - self.unchecked_ssub(args[0].immediate(), args[1].immediate()) - } else { - self.unchecked_usub(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_mul => { - if signed { - self.unchecked_smul(args[0].immediate(), args[1].immediate()) - } else { - self.unchecked_umul(args[0].immediate(), args[1].immediate()) - } - } sym::rotate_left | sym::rotate_right => { let is_left = name == sym::rotate_left; let val = args[0].immediate(); @@ -513,75 +295,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { } } } - sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => { - match float_type_width(arg_tys[0]) { - Some(_width) => match name { - sym::fadd_fast => self.fadd_fast(args[0].immediate(), args[1].immediate()), - sym::fsub_fast => self.fsub_fast(args[0].immediate(), args[1].immediate()), - sym::fmul_fast => self.fmul_fast(args[0].immediate(), args[1].immediate()), - sym::fdiv_fast => self.fdiv_fast(args[0].immediate(), args[1].immediate()), - sym::frem_fast => self.frem_fast(args[0].immediate(), args[1].immediate()), - _ => bug!(), - }, - None => { - span_invalid_monomorphization_error( - tcx.sess, - span, - &format!( - "invalid monomorphization of `{}` intrinsic: \ - expected basic float type, found `{}`", - name, arg_tys[0] - ), - ); - return; - } - } - } - - sym::float_to_int_unchecked => { - if float_type_width(arg_tys[0]).is_none() { - span_invalid_monomorphization_error( - tcx.sess, - span, - &format!( - "invalid monomorphization of `float_to_int_unchecked` \ - intrinsic: expected basic float type, \ - found `{}`", - arg_tys[0] - ), - ); - return; - } - let (width, signed) = match int_type_width_signed(ret_ty, self.cx) { - Some(pair) => pair, - None => { - span_invalid_monomorphization_error( - tcx.sess, - span, - &format!( - "invalid monomorphization of `float_to_int_unchecked` \ - intrinsic: expected basic integer type, \ - found `{}`", - ret_ty - ), - ); - return; - } - }; - if signed { - self.fptosi(args[0].immediate(), self.cx.type_ix(width)) - } else { - self.fptoui(args[0].immediate(), self.cx.type_ix(width)) - } - } - - sym::discriminant_value => { - if ret_ty.is_integral() { - args[0].deref(self.cx()).codegen_get_discr(self, ret_ty) - } else { - span_bug!(span, "Invalid discriminant type for `{:?}`", arg_tys[0]) - } - } _ if name_str.starts_with("simd_") => { match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) { @@ -589,174 +302,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { Err(()) => return, } } - // This requires that atomic intrinsics follow a specific naming pattern: - // "atomic_[_]", and no ordering means SeqCst - name if name_str.starts_with("atomic_") => { - use rustc_codegen_ssa::common::AtomicOrdering::*; - use rustc_codegen_ssa::common::{AtomicRmwBinOp, SynchronizationScope}; - - let split: Vec<&str> = name_str.split('_').collect(); - - let is_cxchg = split[1] == "cxchg" || split[1] == "cxchgweak"; - let (order, failorder) = match split.len() { - 2 => (SequentiallyConsistent, SequentiallyConsistent), - 3 => match split[2] { - "unordered" => (Unordered, Unordered), - "relaxed" => (Monotonic, Monotonic), - "acq" => (Acquire, Acquire), - "rel" => (Release, Monotonic), - "acqrel" => (AcquireRelease, Acquire), - "failrelaxed" if is_cxchg => (SequentiallyConsistent, Monotonic), - "failacq" if is_cxchg => (SequentiallyConsistent, Acquire), - _ => self.sess().fatal("unknown ordering in atomic intrinsic"), - }, - 4 => match (split[2], split[3]) { - ("acq", "failrelaxed") if is_cxchg => (Acquire, Monotonic), - ("acqrel", "failrelaxed") if is_cxchg => (AcquireRelease, Monotonic), - _ => self.sess().fatal("unknown ordering in atomic intrinsic"), - }, - _ => self.sess().fatal("Atomic intrinsic not in correct format"), - }; - - let invalid_monomorphization = |ty| { - span_invalid_monomorphization_error( - tcx.sess, - span, - &format!( - "invalid monomorphization of `{}` intrinsic: \ - expected basic integer type, found `{}`", - name, ty - ), - ); - }; - - match split[1] { - "cxchg" | "cxchgweak" => { - let ty = substs.type_at(0); - if int_type_width_signed(ty, self).is_some() { - let weak = split[1] == "cxchgweak"; - let pair = self.atomic_cmpxchg( - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - order, - failorder, - weak, - ); - let val = self.extract_value(pair, 0); - let success = self.extract_value(pair, 1); - let success = self.zext(success, self.type_bool()); - - let dest = result.project_field(self, 0); - self.store(val, dest.llval, dest.align); - let dest = result.project_field(self, 1); - self.store(success, dest.llval, dest.align); - return; - } else { - return invalid_monomorphization(ty); - } - } - - "load" => { - let ty = substs.type_at(0); - if int_type_width_signed(ty, self).is_some() { - let size = self.size_of(ty); - self.atomic_load(args[0].immediate(), order, size) - } else { - return invalid_monomorphization(ty); - } - } - - "store" => { - let ty = substs.type_at(0); - if int_type_width_signed(ty, self).is_some() { - let size = self.size_of(ty); - self.atomic_store( - args[1].immediate(), - args[0].immediate(), - order, - size, - ); - return; - } else { - return invalid_monomorphization(ty); - } - } - - "fence" => { - self.atomic_fence(order, SynchronizationScope::CrossThread); - return; - } - - "singlethreadfence" => { - self.atomic_fence(order, SynchronizationScope::SingleThread); - return; - } - - // These are all AtomicRMW ops - op => { - let atom_op = match op { - "xchg" => AtomicRmwBinOp::AtomicXchg, - "xadd" => AtomicRmwBinOp::AtomicAdd, - "xsub" => AtomicRmwBinOp::AtomicSub, - "and" => AtomicRmwBinOp::AtomicAnd, - "nand" => AtomicRmwBinOp::AtomicNand, - "or" => AtomicRmwBinOp::AtomicOr, - "xor" => AtomicRmwBinOp::AtomicXor, - "max" => AtomicRmwBinOp::AtomicMax, - "min" => AtomicRmwBinOp::AtomicMin, - "umax" => AtomicRmwBinOp::AtomicUMax, - "umin" => AtomicRmwBinOp::AtomicUMin, - _ => self.sess().fatal("unknown atomic operation"), - }; - - let ty = substs.type_at(0); - if int_type_width_signed(ty, self).is_some() { - self.atomic_rmw( - atom_op, - args[0].immediate(), - args[1].immediate(), - order, - ) - } else { - return invalid_monomorphization(ty); - } - } - } - } - - sym::nontemporal_store => { - let dst = args[0].deref(self.cx()); - args[1].val.nontemporal_store(self, dst); - return; - } - - sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => { - let a = args[0].immediate(); - let b = args[1].immediate(); - if name == sym::ptr_guaranteed_eq { - self.icmp(IntPredicate::IntEQ, a, b) - } else { - self.icmp(IntPredicate::IntNE, a, b) - } - } - - sym::ptr_offset_from => { - let ty = substs.type_at(0); - let pointee_size = self.size_of(ty); - - // This is the same sequence that Clang emits for pointer subtraction. - // It can be neither `nsw` nor `nuw` because the input is treated as - // unsigned but then the output is treated as signed, so neither works. - let a = args[0].immediate(); - let b = args[1].immediate(); - let a = self.ptrtoint(a, self.type_isize()); - let b = self.ptrtoint(b, self.type_isize()); - let d = self.sub(a, b); - let pointee_size = self.const_usize(pointee_size.bytes()); - // this is where the signed magic happens (notice the `s` in `exactsdiv`) - self.exactsdiv(d, pointee_size) - } _ => bug!("unknown intrinsic '{}'", name), }; @@ -807,39 +352,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { } } -fn copy_intrinsic( - bx: &mut Builder<'a, 'll, 'tcx>, - allow_overlap: bool, - volatile: bool, - ty: Ty<'tcx>, - dst: &'ll Value, - src: &'ll Value, - count: &'ll Value, -) { - let (size, align) = bx.size_and_align_of(ty); - let size = bx.mul(bx.const_usize(size.bytes()), count); - let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() }; - if allow_overlap { - bx.memmove(dst, align, src, align, size, flags); - } else { - bx.memcpy(dst, align, src, align, size, flags); - } -} - -fn memset_intrinsic( - bx: &mut Builder<'a, 'll, 'tcx>, - volatile: bool, - ty: Ty<'tcx>, - dst: &'ll Value, - val: &'ll Value, - count: &'ll Value, -) { - let (size, align) = bx.size_and_align_of(ty); - let size = bx.mul(bx.const_usize(size.bytes()), count); - let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() }; - bx.memset(dst, val, size, align, flags); -} - fn try_intrinsic( bx: &mut Builder<'a, 'll, 'tcx>, try_func: &'ll Value, @@ -2205,37 +1717,12 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, // stuffs. fn int_type_width_signed(ty: Ty<'_>, cx: &CodegenCx<'_, '_>) -> Option<(u64, bool)> { match ty.kind() { - ty::Int(t) => Some(( - match t { - ast::IntTy::Isize => u64::from(cx.tcx.sess.target.ptr_width), - ast::IntTy::I8 => 8, - ast::IntTy::I16 => 16, - ast::IntTy::I32 => 32, - ast::IntTy::I64 => 64, - ast::IntTy::I128 => 128, - }, - true, - )), - ty::Uint(t) => Some(( - match t { - ast::UintTy::Usize => u64::from(cx.tcx.sess.target.ptr_width), - ast::UintTy::U8 => 8, - ast::UintTy::U16 => 16, - ast::UintTy::U32 => 32, - ast::UintTy::U64 => 64, - ast::UintTy::U128 => 128, - }, - false, - )), - _ => None, - } -} - -// Returns the width of a float Ty -// Returns None if the type is not a float -fn float_type_width(ty: Ty<'_>) -> Option { - match ty.kind() { - ty::Float(t) => Some(t.bit_width()), + ty::Int(t) => { + Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.ptr_width)), true)) + } + ty::Uint(t) => { + Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.ptr_width)), false)) + } _ => None, } } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 4639ce4a5ab5b..4f85d232caa68 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -687,7 +687,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }) .collect(); - bx.codegen_intrinsic_call( + Self::codegen_intrinsic_call( + &mut bx, *instance.as_ref().unwrap(), &fn_abi, &args, diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs new file mode 100644 index 0000000000000..14f1ed59a67c5 --- /dev/null +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -0,0 +1,596 @@ +use super::operand::{OperandRef, OperandValue}; +use super::place::PlaceRef; +use super::FunctionCx; +use crate::common::{span_invalid_monomorphization_error, IntPredicate}; +use crate::glue; +use crate::traits::*; +use crate::MemFlags; + +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::{sym, Span}; +use rustc_target::abi::call::{FnAbi, PassMode}; + +fn copy_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + bx: &mut Bx, + allow_overlap: bool, + volatile: bool, + ty: Ty<'tcx>, + dst: Bx::Value, + src: Bx::Value, + count: Bx::Value, +) { + let layout = bx.layout_of(ty); + let size = layout.size; + let align = layout.align.abi; + let size = bx.mul(bx.const_usize(size.bytes()), count); + let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() }; + if allow_overlap { + bx.memmove(dst, align, src, align, size, flags); + } else { + bx.memcpy(dst, align, src, align, size, flags); + } +} + +fn memset_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + bx: &mut Bx, + volatile: bool, + ty: Ty<'tcx>, + dst: Bx::Value, + val: Bx::Value, + count: Bx::Value, +) { + let layout = bx.layout_of(ty); + let size = layout.size; + let align = layout.align.abi; + let size = bx.mul(bx.const_usize(size.bytes()), count); + let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() }; + bx.memset(dst, val, size, align, flags); +} + +impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { + pub fn codegen_intrinsic_call( + bx: &mut Bx, + instance: ty::Instance<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + args: &[OperandRef<'tcx, Bx::Value>], + llresult: Bx::Value, + span: Span, + ) { + let callee_ty = instance.ty(bx.tcx(), ty::ParamEnv::reveal_all()); + + let (def_id, substs) = match *callee_ty.kind() { + ty::FnDef(def_id, substs) => (def_id, substs), + _ => bug!("expected fn item type, found {}", callee_ty), + }; + + let sig = callee_ty.fn_sig(bx.tcx()); + let sig = bx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); + let arg_tys = sig.inputs(); + let ret_ty = sig.output(); + let name = bx.tcx().item_name(def_id); + let name_str = &*name.as_str(); + + let llret_ty = bx.backend_type(bx.layout_of(ret_ty)); + let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout); + + let llval = match name { + sym::assume => { + bx.assume(args[0].immediate()); + return; + } + sym::abort => { + bx.abort(); + return; + } + + sym::unreachable => { + return; + } + sym::va_start => bx.va_start(args[0].immediate()), + sym::va_end => bx.va_end(args[0].immediate()), + sym::size_of_val => { + let tp_ty = substs.type_at(0); + if let OperandValue::Pair(_, meta) = args[0].val { + let (llsize, _) = glue::size_and_align_of_dst(bx, tp_ty, Some(meta)); + llsize + } else { + bx.const_usize(bx.layout_of(tp_ty).size.bytes()) + } + } + sym::min_align_of_val => { + let tp_ty = substs.type_at(0); + if let OperandValue::Pair(_, meta) = args[0].val { + let (_, llalign) = glue::size_and_align_of_dst(bx, tp_ty, Some(meta)); + llalign + } else { + bx.const_usize(bx.layout_of(tp_ty).align.abi.bytes()) + } + } + sym::size_of + | sym::pref_align_of + | sym::min_align_of + | sym::needs_drop + | sym::type_id + | sym::type_name + | sym::variant_count => { + let value = bx + .tcx() + .const_eval_instance(ty::ParamEnv::reveal_all(), instance, None) + .unwrap(); + OperandRef::from_const(bx, value, ret_ty).immediate_or_packed_pair(bx) + } + // Effectively no-op + sym::forget => { + return; + } + sym::offset => { + let ptr = args[0].immediate(); + let offset = args[1].immediate(); + bx.inbounds_gep(ptr, &[offset]) + } + sym::arith_offset => { + let ptr = args[0].immediate(); + let offset = args[1].immediate(); + bx.gep(ptr, &[offset]) + } + + sym::copy_nonoverlapping => { + copy_intrinsic( + bx, + false, + false, + substs.type_at(0), + args[1].immediate(), + args[0].immediate(), + args[2].immediate(), + ); + return; + } + sym::copy => { + copy_intrinsic( + bx, + true, + false, + substs.type_at(0), + args[1].immediate(), + args[0].immediate(), + args[2].immediate(), + ); + return; + } + sym::write_bytes => { + memset_intrinsic( + bx, + false, + substs.type_at(0), + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + ); + return; + } + + sym::volatile_copy_nonoverlapping_memory => { + copy_intrinsic( + bx, + false, + true, + substs.type_at(0), + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + ); + return; + } + sym::volatile_copy_memory => { + copy_intrinsic( + bx, + true, + true, + substs.type_at(0), + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + ); + return; + } + sym::volatile_set_memory => { + memset_intrinsic( + bx, + true, + substs.type_at(0), + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + ); + return; + } + sym::volatile_store => { + let dst = args[0].deref(bx.cx()); + args[1].val.volatile_store(bx, dst); + return; + } + sym::unaligned_volatile_store => { + let dst = args[0].deref(bx.cx()); + args[1].val.unaligned_volatile_store(bx, dst); + return; + } + sym::add_with_overflow + | sym::sub_with_overflow + | sym::mul_with_overflow + | sym::wrapping_add + | sym::wrapping_sub + | sym::wrapping_mul + | sym::unchecked_div + | sym::unchecked_rem + | sym::unchecked_shl + | sym::unchecked_shr + | sym::unchecked_add + | sym::unchecked_sub + | sym::unchecked_mul + | sym::exact_div => { + let ty = arg_tys[0]; + match int_type_width_signed(ty, bx.tcx()) { + Some((_width, signed)) => match name { + sym::add_with_overflow + | sym::sub_with_overflow + | sym::mul_with_overflow => { + let op = match name { + sym::add_with_overflow => OverflowOp::Add, + sym::sub_with_overflow => OverflowOp::Sub, + sym::mul_with_overflow => OverflowOp::Mul, + _ => bug!(), + }; + let (val, overflow) = + bx.checked_binop(op, ty, args[0].immediate(), args[1].immediate()); + // Convert `i1` to a `bool`, and write it to the out parameter + let val = bx.from_immediate(val); + let overflow = bx.from_immediate(overflow); + + let dest = result.project_field(bx, 0); + bx.store(val, dest.llval, dest.align); + let dest = result.project_field(bx, 1); + bx.store(overflow, dest.llval, dest.align); + + return; + } + sym::wrapping_add => bx.add(args[0].immediate(), args[1].immediate()), + sym::wrapping_sub => bx.sub(args[0].immediate(), args[1].immediate()), + sym::wrapping_mul => bx.mul(args[0].immediate(), args[1].immediate()), + sym::exact_div => { + if signed { + bx.exactsdiv(args[0].immediate(), args[1].immediate()) + } else { + bx.exactudiv(args[0].immediate(), args[1].immediate()) + } + } + sym::unchecked_div => { + if signed { + bx.sdiv(args[0].immediate(), args[1].immediate()) + } else { + bx.udiv(args[0].immediate(), args[1].immediate()) + } + } + sym::unchecked_rem => { + if signed { + bx.srem(args[0].immediate(), args[1].immediate()) + } else { + bx.urem(args[0].immediate(), args[1].immediate()) + } + } + sym::unchecked_shl => bx.shl(args[0].immediate(), args[1].immediate()), + sym::unchecked_shr => { + if signed { + bx.ashr(args[0].immediate(), args[1].immediate()) + } else { + bx.lshr(args[0].immediate(), args[1].immediate()) + } + } + sym::unchecked_add => { + if signed { + bx.unchecked_sadd(args[0].immediate(), args[1].immediate()) + } else { + bx.unchecked_uadd(args[0].immediate(), args[1].immediate()) + } + } + sym::unchecked_sub => { + if signed { + bx.unchecked_ssub(args[0].immediate(), args[1].immediate()) + } else { + bx.unchecked_usub(args[0].immediate(), args[1].immediate()) + } + } + sym::unchecked_mul => { + if signed { + bx.unchecked_smul(args[0].immediate(), args[1].immediate()) + } else { + bx.unchecked_umul(args[0].immediate(), args[1].immediate()) + } + } + _ => bug!(), + }, + None => { + span_invalid_monomorphization_error( + bx.tcx().sess, + span, + &format!( + "invalid monomorphization of `{}` intrinsic: \ + expected basic integer type, found `{}`", + name, ty + ), + ); + return; + } + } + } + sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => { + match float_type_width(arg_tys[0]) { + Some(_width) => match name { + sym::fadd_fast => bx.fadd_fast(args[0].immediate(), args[1].immediate()), + sym::fsub_fast => bx.fsub_fast(args[0].immediate(), args[1].immediate()), + sym::fmul_fast => bx.fmul_fast(args[0].immediate(), args[1].immediate()), + sym::fdiv_fast => bx.fdiv_fast(args[0].immediate(), args[1].immediate()), + sym::frem_fast => bx.frem_fast(args[0].immediate(), args[1].immediate()), + _ => bug!(), + }, + None => { + span_invalid_monomorphization_error( + bx.tcx().sess, + span, + &format!( + "invalid monomorphization of `{}` intrinsic: \ + expected basic float type, found `{}`", + name, arg_tys[0] + ), + ); + return; + } + } + } + + sym::float_to_int_unchecked => { + if float_type_width(arg_tys[0]).is_none() { + span_invalid_monomorphization_error( + bx.tcx().sess, + span, + &format!( + "invalid monomorphization of `float_to_int_unchecked` \ + intrinsic: expected basic float type, \ + found `{}`", + arg_tys[0] + ), + ); + return; + } + let (_width, signed) = match int_type_width_signed(ret_ty, bx.tcx()) { + Some(pair) => pair, + None => { + span_invalid_monomorphization_error( + bx.tcx().sess, + span, + &format!( + "invalid monomorphization of `float_to_int_unchecked` \ + intrinsic: expected basic integer type, \ + found `{}`", + ret_ty + ), + ); + return; + } + }; + if signed { + bx.fptosi(args[0].immediate(), llret_ty) + } else { + bx.fptoui(args[0].immediate(), llret_ty) + } + } + + sym::discriminant_value => { + if ret_ty.is_integral() { + args[0].deref(bx.cx()).codegen_get_discr(bx, ret_ty) + } else { + span_bug!(span, "Invalid discriminant type for `{:?}`", arg_tys[0]) + } + } + + // This requires that atomic intrinsics follow a specific naming pattern: + // "atomic_[_]", and no ordering means SeqCst + name if name_str.starts_with("atomic_") => { + use crate::common::AtomicOrdering::*; + use crate::common::{AtomicRmwBinOp, SynchronizationScope}; + + let split: Vec<&str> = name_str.split('_').collect(); + + let is_cxchg = split[1] == "cxchg" || split[1] == "cxchgweak"; + let (order, failorder) = match split.len() { + 2 => (SequentiallyConsistent, SequentiallyConsistent), + 3 => match split[2] { + "unordered" => (Unordered, Unordered), + "relaxed" => (Monotonic, Monotonic), + "acq" => (Acquire, Acquire), + "rel" => (Release, Monotonic), + "acqrel" => (AcquireRelease, Acquire), + "failrelaxed" if is_cxchg => (SequentiallyConsistent, Monotonic), + "failacq" if is_cxchg => (SequentiallyConsistent, Acquire), + _ => bx.sess().fatal("unknown ordering in atomic intrinsic"), + }, + 4 => match (split[2], split[3]) { + ("acq", "failrelaxed") if is_cxchg => (Acquire, Monotonic), + ("acqrel", "failrelaxed") if is_cxchg => (AcquireRelease, Monotonic), + _ => bx.sess().fatal("unknown ordering in atomic intrinsic"), + }, + _ => bx.sess().fatal("Atomic intrinsic not in correct format"), + }; + + let invalid_monomorphization = |ty| { + span_invalid_monomorphization_error( + bx.tcx().sess, + span, + &format!( + "invalid monomorphization of `{}` intrinsic: \ + expected basic integer type, found `{}`", + name, ty + ), + ); + }; + + match split[1] { + "cxchg" | "cxchgweak" => { + let ty = substs.type_at(0); + if int_type_width_signed(ty, bx.tcx()).is_some() { + let weak = split[1] == "cxchgweak"; + let pair = bx.atomic_cmpxchg( + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + order, + failorder, + weak, + ); + let val = bx.extract_value(pair, 0); + let success = bx.extract_value(pair, 1); + let val = bx.from_immediate(val); + let success = bx.from_immediate(success); + + let dest = result.project_field(bx, 0); + bx.store(val, dest.llval, dest.align); + let dest = result.project_field(bx, 1); + bx.store(success, dest.llval, dest.align); + return; + } else { + return invalid_monomorphization(ty); + } + } + + "load" => { + let ty = substs.type_at(0); + if int_type_width_signed(ty, bx.tcx()).is_some() { + let size = bx.layout_of(ty).size; + bx.atomic_load(args[0].immediate(), order, size) + } else { + return invalid_monomorphization(ty); + } + } + + "store" => { + let ty = substs.type_at(0); + if int_type_width_signed(ty, bx.tcx()).is_some() { + let size = bx.layout_of(ty).size; + bx.atomic_store(args[1].immediate(), args[0].immediate(), order, size); + return; + } else { + return invalid_monomorphization(ty); + } + } + + "fence" => { + bx.atomic_fence(order, SynchronizationScope::CrossThread); + return; + } + + "singlethreadfence" => { + bx.atomic_fence(order, SynchronizationScope::SingleThread); + return; + } + + // These are all AtomicRMW ops + op => { + let atom_op = match op { + "xchg" => AtomicRmwBinOp::AtomicXchg, + "xadd" => AtomicRmwBinOp::AtomicAdd, + "xsub" => AtomicRmwBinOp::AtomicSub, + "and" => AtomicRmwBinOp::AtomicAnd, + "nand" => AtomicRmwBinOp::AtomicNand, + "or" => AtomicRmwBinOp::AtomicOr, + "xor" => AtomicRmwBinOp::AtomicXor, + "max" => AtomicRmwBinOp::AtomicMax, + "min" => AtomicRmwBinOp::AtomicMin, + "umax" => AtomicRmwBinOp::AtomicUMax, + "umin" => AtomicRmwBinOp::AtomicUMin, + _ => bx.sess().fatal("unknown atomic operation"), + }; + + let ty = substs.type_at(0); + if int_type_width_signed(ty, bx.tcx()).is_some() { + bx.atomic_rmw(atom_op, args[0].immediate(), args[1].immediate(), order) + } else { + return invalid_monomorphization(ty); + } + } + } + } + + sym::nontemporal_store => { + let dst = args[0].deref(bx.cx()); + args[1].val.nontemporal_store(bx, dst); + return; + } + + sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => { + let a = args[0].immediate(); + let b = args[1].immediate(); + if name == sym::ptr_guaranteed_eq { + bx.icmp(IntPredicate::IntEQ, a, b) + } else { + bx.icmp(IntPredicate::IntNE, a, b) + } + } + + sym::ptr_offset_from => { + let ty = substs.type_at(0); + let pointee_size = bx.layout_of(ty).size; + + // This is the same sequence that Clang emits for pointer subtraction. + // It can be neither `nsw` nor `nuw` because the input is treated as + // unsigned but then the output is treated as signed, so neither works. + let a = args[0].immediate(); + let b = args[1].immediate(); + let a = bx.ptrtoint(a, bx.type_isize()); + let b = bx.ptrtoint(b, bx.type_isize()); + let d = bx.sub(a, b); + let pointee_size = bx.const_usize(pointee_size.bytes()); + // this is where the signed magic happens (notice the `s` in `exactsdiv`) + bx.exactsdiv(d, pointee_size) + } + + _ => { + // Need to use backend-specific things in the implementation. + bx.codegen_intrinsic_call(instance, fn_abi, args, llresult, span); + return; + } + }; + + if !fn_abi.ret.is_ignore() { + if let PassMode::Cast(ty) = fn_abi.ret.mode { + let ptr_llty = bx.type_ptr_to(bx.cast_backend_type(&ty)); + let ptr = bx.pointercast(result.llval, ptr_llty); + bx.store(llval, ptr, result.align); + } else { + OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout) + .val + .store(bx, result); + } + } + } +} + +// Returns the width of an int Ty, and if it's signed or not +// Returns None if the type is not an integer +// FIXME: there’s multiple of this functions, investigate using some of the already existing +// stuffs. +fn int_type_width_signed(ty: Ty<'_>, tcx: TyCtxt<'_>) -> Option<(u64, bool)> { + match ty.kind() { + ty::Int(t) => Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.ptr_width)), true)), + ty::Uint(t) => Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.ptr_width)), false)), + _ => None, + } +} + +// Returns the width of a float Ty +// Returns None if the type is not a float +fn float_type_width(ty: Ty<'_>) -> Option { + match ty.kind() { + ty::Float(t) => Some(t.bit_width()), + _ => None, + } +} diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index c1e7cfd80ef10..64d456fb7aa67 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -486,6 +486,7 @@ mod block; pub mod constant; pub mod coverageinfo; pub mod debuginfo; +mod intrinsic; pub mod operand; pub mod place; mod rvalue; From 7d67546a6ade5c1ade4b8e66266411f7aa4fae69 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 15 Sep 2020 23:46:26 +0200 Subject: [PATCH 0479/1052] hopefully fix rustdoc links --- library/core/src/slice/index.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index a662d9682c51b..16fcb6231dc09 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -105,7 +105,7 @@ pub(super) fn slice_end_index_overflow_fail() -> ! { /// std::slice::check_range(3, 1..=usize::MAX); /// ``` /// -/// [`Index::index`]: crate::ops::Index::index +/// [`Index::index`]: ops::Index::index #[track_caller] #[unstable(feature = "slice_check_range", issue = "76393")] pub fn check_range>(len: usize, range: R) -> Range { From f95d7ba7d38a9ffc8d7caf6809f4b44178ab3916 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 15 Sep 2020 14:52:18 -0700 Subject: [PATCH 0480/1052] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 875e0123259b0..8777a6b1e8834 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 875e0123259b0b6299903fe4aea0a12ecde9324f +Subproject commit 8777a6b1e8834899f51b7e09cc9b8d85b2417110 From e0c1621a3f687f30a372be5308cda4c8e261c768 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 15 Sep 2020 14:55:50 -0700 Subject: [PATCH 0481/1052] Update books --- src/doc/book | 2 +- src/doc/nomicon | 2 +- src/doc/reference | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/book b/src/doc/book index e5ed97128302d..cb28dee95e5e5 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit e5ed97128302d5fa45dbac0e64426bc7649a558c +Subproject commit cb28dee95e5e50b793e6ba9291c5d1568d3ad72e diff --git a/src/doc/nomicon b/src/doc/nomicon index 25854752549d4..6e57e64501f61 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 25854752549d44d76fbd7650e17cb4f167a0b8fb +Subproject commit 6e57e64501f61873ab80cb78a07180a22751a5d6 diff --git a/src/doc/reference b/src/doc/reference index 25391dba46262..56a13c082ee90 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 25391dba46262f882fa846beefaff54a966a8fa5 +Subproject commit 56a13c082ee90736c08d6abdcd90462517b703d3 From 378b64392f5bdbcffbdc6506b00b6bfcfcd46d73 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Tue, 15 Sep 2020 22:11:46 +0200 Subject: [PATCH 0482/1052] BTreeMap: avoid slices even more --- library/alloc/src/collections/btree/node.rs | 45 +++++++++++++-------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 6c343b1726440..8776a5efbe4f5 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -465,6 +465,22 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { unsafe { &mut (*self.node.as_ptr()) } } + /// Borrows a mutable reference to one of the keys stored in the node. + /// + /// # Safety + /// The node has more than `idx` initialized elements. + pub unsafe fn key_mut_at(&mut self, idx: usize) -> &mut K { + unsafe { self.reborrow_mut().into_key_mut_at(idx) } + } + + /// Borrows a mutable reference to one of the values stored in the node. + /// + /// # Safety + /// The node has more than `idx` initialized elements. + pub unsafe fn val_mut_at(&mut self, idx: usize) -> &mut V { + unsafe { self.reborrow_mut().into_val_mut_at(idx) } + } + fn keys_mut(&mut self) -> &mut [K] { // SAFETY: the caller will not be able to call further methods on self // until the key slice reference is dropped, as we have unique access @@ -555,15 +571,14 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Leaf> { /// Adds a key/value pair to the end of the node. pub fn push(&mut self, key: K, val: V) { - assert!(self.len() < CAPACITY); - - let idx = self.len(); - + let len = &mut self.as_leaf_mut().len; + let idx = *len as usize; + assert!(idx < CAPACITY); + *len += 1; unsafe { - ptr::write(self.keys_mut().get_unchecked_mut(idx), key); - ptr::write(self.vals_mut().get_unchecked_mut(idx), val); + ptr::write(self.key_mut_at(idx), key); + ptr::write(self.val_mut_at(idx), val); } - self.as_leaf_mut().len += 1; } /// Adds a key/value pair to the beginning of the node. @@ -600,17 +615,15 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { /// the end of the node. pub fn push(&mut self, key: K, val: V, edge: Root) { assert!(edge.height == self.height - 1); - assert!(self.len() < CAPACITY); - - let idx = self.len(); + let len = &mut self.as_leaf_mut().len; + let idx = *len as usize; + assert!(idx < CAPACITY); + *len += 1; unsafe { - ptr::write(self.keys_mut().get_unchecked_mut(idx), key); - ptr::write(self.vals_mut().get_unchecked_mut(idx), val); + ptr::write(self.key_mut_at(idx), key); + ptr::write(self.val_mut_at(idx), val); self.as_internal_mut().edges.get_unchecked_mut(idx + 1).write(edge.node); - - self.as_leaf_mut().len += 1; - Handle::new_edge(self.reborrow_mut(), idx + 1).correct_parent_link(); } } @@ -903,7 +916,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, mark /// The returned pointer points to the inserted value. fn insert_fit(&mut self, key: K, val: V) -> *mut V { self.leafy_insert_fit(key, val); - unsafe { self.node.vals_mut().get_unchecked_mut(self.idx) } + unsafe { self.node.val_mut_at(self.idx) } } } From 6ba36bcfd3802d9520d0ac48dabfe6dc06d8dc82 Mon Sep 17 00:00:00 2001 From: Tim Nielens Date: Sat, 22 Aug 2020 00:43:04 +0200 Subject: [PATCH 0483/1052] option_if_let_else - distinguish pure from impure else expressions --- .../src/methods/bind_instead_of_map.rs | 21 ++- clippy_lints/src/methods/mod.rs | 66 +++------ .../src/methods/unnecessary_lazy_eval.rs | 76 ++--------- clippy_lints/src/option_if_let_else.rs | 33 ++--- clippy_lints/src/utils/eager_or_lazy.rs | 128 ++++++++++++++++++ clippy_lints/src/utils/mod.rs | 1 + clippy_lints/src/utils/sugg.rs | 2 +- clippy_lints/src/utils/usage.rs | 66 +++++++++ tests/ui/option_if_let_else.fixed | 10 ++ tests/ui/option_if_let_else.rs | 15 ++ tests/ui/option_if_let_else.stderr | 36 +++-- tests/ui/unnecessary_lazy_eval.fixed | 42 +++--- tests/ui/unnecessary_lazy_eval.rs | 26 ++-- tests/ui/unnecessary_lazy_eval.stderr | 112 ++++++++++----- 14 files changed, 420 insertions(+), 214 deletions(-) create mode 100644 clippy_lints/src/utils/eager_or_lazy.rs diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 498f12518f8a3..ae37942e55a1b 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -12,6 +12,7 @@ use rustc_middle::hir::map::Map; use rustc_span::Span; pub(crate) struct OptionAndThenSome; + impl BindInsteadOfMap for OptionAndThenSome { const TYPE_NAME: &'static str = "Option"; const TYPE_QPATH: &'static [&'static str] = &paths::OPTION; @@ -24,6 +25,7 @@ impl BindInsteadOfMap for OptionAndThenSome { } pub(crate) struct ResultAndThenOk; + impl BindInsteadOfMap for ResultAndThenOk { const TYPE_NAME: &'static str = "Result"; const TYPE_QPATH: &'static [&'static str] = &paths::RESULT; @@ -36,6 +38,7 @@ impl BindInsteadOfMap for ResultAndThenOk { } pub(crate) struct ResultOrElseErrInfo; + impl BindInsteadOfMap for ResultOrElseErrInfo { const TYPE_NAME: &'static str = "Result"; const TYPE_QPATH: &'static [&'static str] = &paths::RESULT; @@ -120,9 +123,9 @@ pub(crate) trait BindInsteadOfMap { } } - fn lint_closure(cx: &LateContext<'_>, expr: &hir::Expr<'_>, closure_expr: &hir::Expr<'_>) { + fn lint_closure(cx: &LateContext<'_>, expr: &hir::Expr<'_>, closure_expr: &hir::Expr<'_>) -> bool { let mut suggs = Vec::new(); - let can_sugg = find_all_ret_expressions(cx, closure_expr, |ret_expr| { + let can_sugg: bool = find_all_ret_expressions(cx, closure_expr, |ret_expr| { if_chain! { if !in_macro(ret_expr.span); if let hir::ExprKind::Call(ref func_path, ref args) = ret_expr.kind; @@ -153,12 +156,13 @@ pub(crate) trait BindInsteadOfMap { ) }); } + can_sugg } /// Lint use of `_.and_then(|x| Some(y))` for `Option`s - fn lint(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { + fn lint(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) -> bool { if !match_type(cx, cx.typeck_results().expr_ty(&args[0]), Self::TYPE_QPATH) { - return; + return false; } match args[1].kind { @@ -166,8 +170,10 @@ pub(crate) trait BindInsteadOfMap { let closure_body = cx.tcx.hir().body(body_id); let closure_expr = remove_blocks(&closure_body.value); - if !Self::lint_closure_autofixable(cx, expr, args, closure_expr, closure_args_span) { - Self::lint_closure(cx, expr, closure_expr); + if Self::lint_closure_autofixable(cx, expr, args, closure_expr, closure_args_span) { + true + } else { + Self::lint_closure(cx, expr, closure_expr) } }, // `_.and_then(Some)` case, which is no-op. @@ -181,8 +187,9 @@ pub(crate) trait BindInsteadOfMap { snippet(cx, args[0].span, "..").into(), Applicability::MachineApplicable, ); + true }, - _ => {}, + _ => false, } } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 98e027b6d2290..914f9f94e776a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -25,14 +25,15 @@ use rustc_span::source_map::Span; use rustc_span::symbol::{sym, SymbolStr}; use crate::consts::{constant, Constant}; +use crate::utils::eager_or_lazy::is_lazyness_candidate; use crate::utils::usage::mutated_variables; use crate::utils::{ contains_ty, get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro, - is_copy, is_ctor_or_promotable_const_function, is_expn_of, is_type_diagnostic_item, iter_input_pats, - last_path_segment, match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls, - method_chain_args, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, - snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, - span_lint_and_then, sugg, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq, + is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, + match_trait_method, match_type, match_var, method_calls, method_chain_args, paths, remove_blocks, return_ty, + single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, + span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty, + walk_ptrs_ty_depth, SpanlessEq, }; declare_clippy_lint! { @@ -1454,18 +1455,21 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["unwrap_or", "map"] => option_map_unwrap_or::lint(cx, expr, arg_lists[1], arg_lists[0], method_spans[1]), ["unwrap_or_else", "map"] => { if !lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0]) { - unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "unwrap_or"); + unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "unwrap_or"); } }, ["map_or", ..] => lint_map_or_none(cx, expr, arg_lists[0]), ["and_then", ..] => { - unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], false, "and"); - bind_instead_of_map::OptionAndThenSome::lint(cx, expr, arg_lists[0]); - bind_instead_of_map::ResultAndThenOk::lint(cx, expr, arg_lists[0]); + let biom_option_linted = bind_instead_of_map::OptionAndThenSome::lint(cx, expr, arg_lists[0]); + let biom_result_linted = bind_instead_of_map::ResultAndThenOk::lint(cx, expr, arg_lists[0]); + if !biom_option_linted && !biom_result_linted { + unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "and"); + } }, ["or_else", ..] => { - unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], false, "or"); - bind_instead_of_map::ResultOrElseErrInfo::lint(cx, expr, arg_lists[0]); + if !bind_instead_of_map::ResultOrElseErrInfo::lint(cx, expr, arg_lists[0]) { + unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "or"); + } }, ["next", "filter"] => lint_filter_next(cx, expr, arg_lists[1]), ["next", "skip_while"] => lint_skip_while_next(cx, expr, arg_lists[1]), @@ -1508,9 +1512,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["is_file", ..] => lint_filetype_is_file(cx, expr, arg_lists[0]), ["map", "as_ref"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], false), ["map", "as_mut"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true), - ["unwrap_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "unwrap_or"), - ["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "get_or_insert"), - ["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "ok_or"), + ["unwrap_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "unwrap_or"), + ["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "get_or_insert"), + ["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "ok_or"), _ => {}, } @@ -1714,37 +1718,6 @@ fn lint_or_fun_call<'tcx>( name: &str, args: &'tcx [hir::Expr<'_>], ) { - // Searches an expression for method calls or function calls that aren't ctors - struct FunCallFinder<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - found: bool, - } - - impl<'a, 'tcx> intravisit::Visitor<'tcx> for FunCallFinder<'a, 'tcx> { - type Map = Map<'tcx>; - - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { - let call_found = match &expr.kind { - // ignore enum and struct constructors - hir::ExprKind::Call(..) => !is_ctor_or_promotable_const_function(self.cx, expr), - hir::ExprKind::MethodCall(..) => true, - _ => false, - }; - - if call_found { - self.found |= true; - } - - if !self.found { - intravisit::walk_expr(self, expr); - } - } - - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { - intravisit::NestedVisitorMap::None - } - } - /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`. fn check_unwrap_or_default( cx: &LateContext<'_>, @@ -1825,8 +1798,7 @@ fn lint_or_fun_call<'tcx>( if_chain! { if know_types.iter().any(|k| k.2.contains(&name)); - let mut finder = FunCallFinder { cx: &cx, found: false }; - if { finder.visit_expr(&arg); finder.found }; + if is_lazyness_candidate(cx, arg); if !contains_return(&arg); let self_ty = cx.typeck_results().expr_ty(self_expr); diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 31517659c34dc..08b3eab9b7cdf 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -1,78 +1,17 @@ -use crate::utils::{is_type_diagnostic_item, match_qpath, snippet, span_lint_and_sugg}; -use if_chain::if_chain; +use crate::utils::{eager_or_lazy, usage}; +use crate::utils::{is_type_diagnostic_item, snippet, span_lint_and_sugg}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use super::UNNECESSARY_LAZY_EVALUATIONS; -// Return true if the expression is an accessor of any of the arguments -fn expr_uses_argument(expr: &hir::Expr<'_>, params: &[hir::Param<'_>]) -> bool { - params.iter().any(|arg| { - if_chain! { - if let hir::PatKind::Binding(_, _, ident, _) = arg.pat.kind; - if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = expr.kind; - if let [p, ..] = path.segments; - then { - ident.name == p.ident.name - } else { - false - } - } - }) -} - -fn match_any_qpath(path: &hir::QPath<'_>, paths: &[&[&str]]) -> bool { - paths.iter().any(|candidate| match_qpath(path, candidate)) -} - -fn can_simplify(expr: &hir::Expr<'_>, params: &[hir::Param<'_>], variant_calls: bool) -> bool { - match expr.kind { - // Closures returning literals can be unconditionally simplified - hir::ExprKind::Lit(_) => true, - - hir::ExprKind::Index(ref object, ref index) => { - // arguments are not being indexed into - if expr_uses_argument(object, params) { - false - } else { - // arguments are not used as index - !expr_uses_argument(index, params) - } - }, - - // Reading fields can be simplified if the object is not an argument of the closure - hir::ExprKind::Field(ref object, _) => !expr_uses_argument(object, params), - - // Paths can be simplified if the root is not the argument, this also covers None - hir::ExprKind::Path(_) => !expr_uses_argument(expr, params), - - // Calls to Some, Ok, Err can be considered literals if they don't derive an argument - hir::ExprKind::Call(ref func, ref args) => if_chain! { - if variant_calls; // Disable lint when rules conflict with bind_instead_of_map - if let hir::ExprKind::Path(ref path) = func.kind; - if match_any_qpath(path, &[&["Some"], &["Ok"], &["Err"]]); - then { - // Recursively check all arguments - args.iter().all(|arg| can_simplify(arg, params, variant_calls)) - } else { - false - } - }, - - // For anything more complex than the above, a closure is probably the right solution, - // or the case is handled by an other lint - _ => false, - } -} - /// lint use of `_else(simple closure)` for `Option`s and `Result`s that can be /// replaced with `(return value of simple closure)` pub(super) fn lint<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, args: &'tcx [hir::Expr<'_>], - allow_variant_calls: bool, simplify_using: &str, ) { let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym!(option_type)); @@ -81,10 +20,13 @@ pub(super) fn lint<'tcx>( if is_option || is_result { if let hir::ExprKind::Closure(_, _, eid, _, _) = args[1].kind { let body = cx.tcx.hir().body(eid); - let ex = &body.value; - let params = &body.params; + let body_expr = &body.value; + + if usage::BindingUsageFinder::are_params_used(cx, body) { + return; + } - if can_simplify(ex, params, allow_variant_calls) { + if eager_or_lazy::is_eagerness_candidate(cx, body_expr) { let msg = if is_option { "unnecessary closure used to substitute value for `Option::None`" } else { @@ -101,7 +43,7 @@ pub(super) fn lint<'tcx>( "{0}.{1}({2})", snippet(cx, args[0].span, ".."), simplify_using, - snippet(cx, ex.span, ".."), + snippet(cx, body_expr.span, ".."), ), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 9494efe736cce..5e2652b48cb2a 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -1,4 +1,5 @@ use crate::utils; +use crate::utils::eager_or_lazy; use crate::utils::sugg::Sugg; use crate::utils::{match_type, paths, span_lint_and_sugg}; use if_chain::if_chain; @@ -13,22 +14,16 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { /// **What it does:** /// Lints usage of `if let Some(v) = ... { y } else { x }` which is more - /// idiomatically done with `Option::map_or` (if the else bit is a simple - /// expression) or `Option::map_or_else` (if the else bit is a longer - /// block). + /// idiomatically done with `Option::map_or` (if the else bit is a pure + /// expression) or `Option::map_or_else` (if the else bit is an impure + /// expresion). /// /// **Why is this bad?** /// Using the dedicated functions of the Option type is clearer and /// more concise than an if let expression. /// /// **Known problems:** - /// This lint uses whether the block is just an expression or if it has - /// more statements to decide whether to use `Option::map_or` or - /// `Option::map_or_else`. If you have a single expression which calls - /// an expensive function, then it would be more efficient to use - /// `Option::map_or_else`, but this lint would suggest `Option::map_or`. - /// - /// Also, this lint uses a deliberately conservative metric for checking + /// This lint uses a deliberately conservative metric for checking /// if the inside of either body contains breaks or continues which will /// cause it to not suggest a fix if either block contains a loop with /// continues or breaks contained within the loop. @@ -92,6 +87,7 @@ struct OptionIfLetElseOccurence { struct ReturnBreakContinueMacroVisitor { seen_return_break_continue: bool, } + impl ReturnBreakContinueMacroVisitor { fn new() -> ReturnBreakContinueMacroVisitor { ReturnBreakContinueMacroVisitor { @@ -99,6 +95,7 @@ impl ReturnBreakContinueMacroVisitor { } } } + impl<'tcx> Visitor<'tcx> for ReturnBreakContinueMacroVisitor { type Map = Map<'tcx>; fn nested_visit_map(&mut self) -> NestedVisitorMap { @@ -157,7 +154,7 @@ fn extract_body_from_arm<'a>(arm: &'a Arm<'a>) -> Option<&'a Expr<'a>> { } /// If this is the else body of an if/else expression, then we need to wrap -/// it in curcly braces. Otherwise, we don't. +/// it in curly braces. Otherwise, we don't. fn should_wrap_in_braces(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { utils::get_enclosing_block(cx, expr.hir_id).map_or(false, |parent| { if let Some(Expr { @@ -199,7 +196,10 @@ fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: boo /// If this expression is the option if let/else construct we're detecting, then /// this function returns an `OptionIfLetElseOccurence` struct with details if /// this construct is found, or None if this construct is not found. -fn detect_option_if_let_else(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { +fn detect_option_if_let_else<'tcx>( + cx: &'_ LateContext<'tcx>, + expr: &'_ Expr<'tcx>, +) -> Option { if_chain! { if !utils::in_macro(expr.span); // Don't lint macros, because it behaves weirdly if let ExprKind::Match(cond_expr, arms, MatchSource::IfLetDesugar{contains_else_clause: true}) = &expr.kind; @@ -214,10 +214,7 @@ fn detect_option_if_let_else(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option "map_or_else", - _ => "map_or", - }; + let method_sugg = if eager_or_lazy::is_eagerness_candidate(cx, none_body) { "map_or" } else { "map_or_else" }; let capture_name = id.name.to_ident_string(); let wrap_braces = should_wrap_in_braces(cx, expr); let (as_ref, as_mut) = match &cond_expr.kind { @@ -243,8 +240,8 @@ fn detect_option_if_let_else(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option LateLintPass<'a> for OptionIfLetElse { - fn check_expr(&mut self, cx: &LateContext<'a>, expr: &Expr<'_>) { +impl<'tcx> LateLintPass<'tcx> for OptionIfLetElse { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { if let Some(detection) = detect_option_if_let_else(cx, expr) { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/utils/eager_or_lazy.rs b/clippy_lints/src/utils/eager_or_lazy.rs new file mode 100644 index 0000000000000..6938d9971d96d --- /dev/null +++ b/clippy_lints/src/utils/eager_or_lazy.rs @@ -0,0 +1,128 @@ +//! Utilities for evaluating whether eagerly evaluated expressions can be made lazy and vice versa. +//! +//! Things to consider: +//! - has the expression side-effects? +//! - is the expression computationally expensive? +//! +//! See lints: +//! - unnecessary-lazy-evaluations +//! - or-fun-call +//! - option-if-let-else + +use crate::utils::is_ctor_or_promotable_const_function; +use rustc_hir::def::{DefKind, Res}; + +use rustc_hir::intravisit; +use rustc_hir::intravisit::{NestedVisitorMap, Visitor}; + +use rustc_hir::{Block, Expr, ExprKind, Path, QPath}; +use rustc_lint::LateContext; +use rustc_middle::hir::map::Map; + +/// Is the expr pure (is it free from side-effects)? +/// This function is named so to stress that it isn't exhaustive and returns FNs. +fn identify_some_pure_patterns(expr: &Expr<'_>) -> bool { + match expr.kind { + ExprKind::Lit(..) | ExprKind::Path(..) | ExprKind::Field(..) => true, + ExprKind::AddrOf(_, _, addr_of_expr) => identify_some_pure_patterns(addr_of_expr), + ExprKind::Tup(tup_exprs) => tup_exprs.iter().all(|expr| identify_some_pure_patterns(expr)), + ExprKind::Struct(_, fields, expr) => { + fields.iter().all(|f| identify_some_pure_patterns(f.expr)) + && expr.map_or(true, |e| identify_some_pure_patterns(e)) + }, + ExprKind::Call( + &Expr { + kind: + ExprKind::Path(QPath::Resolved( + _, + Path { + res: Res::Def(DefKind::Ctor(..) | DefKind::Variant, ..), + .. + }, + )), + .. + }, + args, + ) => args.iter().all(|expr| identify_some_pure_patterns(expr)), + ExprKind::Block( + &Block { + stmts, + expr: Some(expr), + .. + }, + _, + ) => stmts.is_empty() && identify_some_pure_patterns(expr), + ExprKind::Box(..) + | ExprKind::Array(..) + | ExprKind::Call(..) + | ExprKind::MethodCall(..) + | ExprKind::Binary(..) + | ExprKind::Unary(..) + | ExprKind::Cast(..) + | ExprKind::Type(..) + | ExprKind::DropTemps(..) + | ExprKind::Loop(..) + | ExprKind::Match(..) + | ExprKind::Closure(..) + | ExprKind::Block(..) + | ExprKind::Assign(..) + | ExprKind::AssignOp(..) + | ExprKind::Index(..) + | ExprKind::Break(..) + | ExprKind::Continue(..) + | ExprKind::Ret(..) + | ExprKind::InlineAsm(..) + | ExprKind::LlvmInlineAsm(..) + | ExprKind::Repeat(..) + | ExprKind::Yield(..) + | ExprKind::Err => false, + } +} + +/// Identify some potentially computationally expensive patterns. +/// This function is named so to stress that its implementation is non-exhaustive. +/// It returns FNs and FPs. +fn identify_some_potentially_expensive_patterns<'a, 'tcx>(cx: &'a LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { + // Searches an expression for method calls or function calls that aren't ctors + struct FunCallFinder<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + found: bool, + } + + impl<'a, 'tcx> intravisit::Visitor<'tcx> for FunCallFinder<'a, 'tcx> { + type Map = Map<'tcx>; + + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + let call_found = match &expr.kind { + // ignore enum and struct constructors + ExprKind::Call(..) => !is_ctor_or_promotable_const_function(self.cx, expr), + ExprKind::MethodCall(..) => true, + _ => false, + }; + + if call_found { + self.found |= true; + } + + if !self.found { + intravisit::walk_expr(self, expr); + } + } + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } + } + + let mut finder = FunCallFinder { cx, found: false }; + finder.visit_expr(expr); + finder.found +} + +pub fn is_eagerness_candidate<'a, 'tcx>(cx: &'a LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { + !identify_some_potentially_expensive_patterns(cx, expr) && identify_some_pure_patterns(expr) +} + +pub fn is_lazyness_candidate<'a, 'tcx>(cx: &'a LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { + identify_some_potentially_expensive_patterns(cx, expr) +} diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 3ebbfed645627..7efeef6269041 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -10,6 +10,7 @@ pub mod comparisons; pub mod conf; pub mod constants; mod diagnostics; +pub mod eager_or_lazy; pub mod higher; mod hir_utils; pub mod inspector; diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 811fde388d15a..ec8b7e59b5976 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -49,7 +49,7 @@ impl<'a> Sugg<'a> { /// Convenience function around `hir_opt` for suggestions with a default /// text. pub fn hir(cx: &LateContext<'_>, expr: &hir::Expr<'_>, default: &'a str) -> Self { - Self::hir_opt(cx, expr).unwrap_or_else(|| Sugg::NonParen(Cow::Borrowed(default))) + Self::hir_opt(cx, expr).unwrap_or(Sugg::NonParen(Cow::Borrowed(default))) } /// Same as `hir`, but it adapts the applicability level by following rules: diff --git a/clippy_lints/src/utils/usage.rs b/clippy_lints/src/utils/usage.rs index 4a64b935ac9b4..ea1dc3be29ba0 100644 --- a/clippy_lints/src/utils/usage.rs +++ b/clippy_lints/src/utils/usage.rs @@ -1,6 +1,8 @@ use crate::utils::match_var; use rustc_data_structures::fx::FxHashSet; +use rustc_hir as hir; use rustc_hir::def::Res; +use rustc_hir::intravisit; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{Expr, HirId, Path}; use rustc_infer::infer::TyCtxtInferExt; @@ -108,3 +110,67 @@ pub fn is_unused<'tcx>(ident: &'tcx Ident, body: &'tcx Expr<'_>) -> bool { walk_expr(&mut visitor, body); !visitor.used } + +pub struct ParamBindingIdCollector { + binding_hir_ids: Vec, +} +impl<'tcx> ParamBindingIdCollector { + fn collect_binding_hir_ids(body: &'tcx hir::Body<'tcx>) -> Vec { + let mut finder = ParamBindingIdCollector { + binding_hir_ids: Vec::new(), + }; + finder.visit_body(body); + finder.binding_hir_ids + } +} +impl<'tcx> intravisit::Visitor<'tcx> for ParamBindingIdCollector { + type Map = Map<'tcx>; + + fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { + if let hir::PatKind::Binding(_, hir_id, ..) = param.pat.kind { + self.binding_hir_ids.push(hir_id); + } + } + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::None + } +} + +pub struct BindingUsageFinder<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + binding_ids: Vec, + usage_found: bool, +} +impl<'a, 'tcx> BindingUsageFinder<'a, 'tcx> { + pub fn are_params_used(cx: &'a LateContext<'tcx>, body: &'tcx hir::Body<'tcx>) -> bool { + let mut finder = BindingUsageFinder { + cx, + binding_ids: ParamBindingIdCollector::collect_binding_hir_ids(body), + usage_found: false, + }; + finder.visit_body(body); + finder.usage_found + } +} +impl<'a, 'tcx> intravisit::Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> { + type Map = Map<'tcx>; + + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + if !self.usage_found { + intravisit::walk_expr(self, expr); + } + } + + fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) { + if let hir::def::Res::Local(id) = path.res { + if self.binding_ids.contains(&id) { + self.usage_found = true; + } + } + } + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::OnlyBodies(self.cx.tcx.hir()) + } +} diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed index 695a460cc4edf..a7fb00a270577 100644 --- a/tests/ui/option_if_let_else.fixed +++ b/tests/ui/option_if_let_else.fixed @@ -1,5 +1,6 @@ // run-rustfix #![warn(clippy::option_if_let_else)] +#![allow(clippy::redundant_closure)] fn bad1(string: Option<&str>) -> (bool, &str) { string.map_or((false, "hello"), |x| (true, x)) @@ -36,6 +37,14 @@ fn longer_body(arg: Option) -> u32 { }) } +fn impure_else(arg: Option) { + let side_effect = || { + println!("return 1"); + 1 + }; + let _ = arg.map_or_else(|| side_effect(), |x| x); +} + fn test_map_or_else(arg: Option) { let _ = arg.map_or_else(|| { let mut y = 1; @@ -71,4 +80,5 @@ fn main() { let _ = longer_body(None); test_map_or_else(None); let _ = negative_tests(None); + let _ = impure_else(None); } diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs index dee80d26bd976..895fd86321faf 100644 --- a/tests/ui/option_if_let_else.rs +++ b/tests/ui/option_if_let_else.rs @@ -1,5 +1,6 @@ // run-rustfix #![warn(clippy::option_if_let_else)] +#![allow(clippy::redundant_closure)] fn bad1(string: Option<&str>) -> (bool, &str) { if let Some(x) = string { @@ -52,6 +53,19 @@ fn longer_body(arg: Option) -> u32 { } } +fn impure_else(arg: Option) { + let side_effect = || { + println!("return 1"); + 1 + }; + let _ = if let Some(x) = arg { + x + } else { + // map_or_else must be suggested + side_effect() + }; +} + fn test_map_or_else(arg: Option) { let _ = if let Some(x) = arg { x * x * x * x @@ -89,4 +103,5 @@ fn main() { let _ = longer_body(None); test_map_or_else(None); let _ = negative_tests(None); + let _ = impure_else(None); } diff --git a/tests/ui/option_if_let_else.stderr b/tests/ui/option_if_let_else.stderr index 7005850efaf83..b69fe76768270 100644 --- a/tests/ui/option_if_let_else.stderr +++ b/tests/ui/option_if_let_else.stderr @@ -1,5 +1,5 @@ error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:5:5 + --> $DIR/option_if_let_else.rs:6:5 | LL | / if let Some(x) = string { LL | | (true, x) @@ -11,7 +11,7 @@ LL | | } = note: `-D clippy::option-if-let-else` implied by `-D warnings` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:15:12 + --> $DIR/option_if_let_else.rs:16:12 | LL | } else if let Some(x) = string { | ____________^ @@ -22,19 +22,19 @@ LL | | } | |_____^ help: try: `{ string.map_or(Some((false, "")), |x| Some((true, x))) }` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:23:13 + --> $DIR/option_if_let_else.rs:24:13 | LL | let _ = if let Some(s) = *string { s.len() } else { 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:24:13 + --> $DIR/option_if_let_else.rs:25:13 | LL | let _ = if let Some(s) = &num { s } else { &0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:25:13 + --> $DIR/option_if_let_else.rs:26:13 | LL | let _ = if let Some(s) = &mut num { | _____________^ @@ -54,13 +54,13 @@ LL | }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:31:13 + --> $DIR/option_if_let_else.rs:32:13 | LL | let _ = if let Some(ref s) = num { s } else { &0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:32:13 + --> $DIR/option_if_let_else.rs:33:13 | LL | let _ = if let Some(mut s) = num { | _____________^ @@ -80,7 +80,7 @@ LL | }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:38:13 + --> $DIR/option_if_let_else.rs:39:13 | LL | let _ = if let Some(ref mut s) = num { | _____________^ @@ -100,7 +100,7 @@ LL | }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:47:5 + --> $DIR/option_if_let_else.rs:48:5 | LL | / if let Some(x) = arg { LL | | let y = x * x; @@ -119,7 +119,19 @@ LL | }) | error: use Option::map_or_else instead of an if let/else - --> $DIR/option_if_let_else.rs:56:13 + --> $DIR/option_if_let_else.rs:61:13 + | +LL | let _ = if let Some(x) = arg { + | _____________^ +LL | | x +LL | | } else { +LL | | // map_or_else must be suggested +LL | | side_effect() +LL | | }; + | |_____^ help: try: `arg.map_or_else(|| side_effect(), |x| x)` + +error: use Option::map_or_else instead of an if let/else + --> $DIR/option_if_let_else.rs:70:13 | LL | let _ = if let Some(x) = arg { | _____________^ @@ -142,10 +154,10 @@ LL | }, |x| x * x * x * x); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:85:13 + --> $DIR/option_if_let_else.rs:99:13 | LL | let _ = if let Some(x) = optional { x + 2 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)` -error: aborting due to 11 previous errors +error: aborting due to 12 previous errors diff --git a/tests/ui/unnecessary_lazy_eval.fixed b/tests/ui/unnecessary_lazy_eval.fixed index fa66e68794e4b..4980c1114999c 100644 --- a/tests/ui/unnecessary_lazy_eval.fixed +++ b/tests/ui/unnecessary_lazy_eval.fixed @@ -2,6 +2,7 @@ #![warn(clippy::unnecessary_lazy_evaluations)] #![allow(clippy::redundant_closure)] #![allow(clippy::bind_instead_of_map)] +#![allow(clippy::map_identity)] struct Deep(Option); @@ -34,13 +35,13 @@ fn main() { let _ = opt.unwrap_or(2); let _ = opt.unwrap_or(astronomers_pi); let _ = opt.unwrap_or(ext_str.some_field); - let _ = opt.unwrap_or(ext_arr[0]); + let _ = opt.unwrap_or_else(|| ext_arr[0]); let _ = opt.and(ext_opt); let _ = opt.or(ext_opt); let _ = opt.or(None); let _ = opt.get_or_insert(2); let _ = opt.ok_or(2); - let _ = opt.ok_or(ext_arr[0]); + let _ = nested_tuple_opt.unwrap_or(Some((1, 2))); // Cases when unwrap is not called on a simple variable let _ = Some(10).unwrap_or(2); @@ -60,7 +61,6 @@ fn main() { // Should not lint - Option let _ = opt.unwrap_or_else(|| ext_str.return_some_field()); let _ = nested_opt.unwrap_or_else(|| Some(some_call())); - let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); let _ = nested_tuple_opt.unwrap_or_else(|| Some((some_call(), some_call()))); let _ = opt.or_else(some_call); let _ = opt.or_else(|| some_call()); @@ -69,13 +69,16 @@ fn main() { let _ = deep.0.get_or_insert_with(|| some_call()); let _ = deep.0.or_else(some_call); let _ = deep.0.or_else(|| some_call()); + let _ = opt.ok_or_else(|| ext_arr[0]); - // These are handled by bind_instead_of_map + // should not lint, bind_instead_of_map takes priority let _ = Some(10).and_then(|idx| Some(ext_arr[idx])); let _ = Some(10).and_then(|idx| Some(idx)); - let _: Option = None.or_else(|| Some(3)); - let _ = deep.0.or_else(|| Some(3)); - let _ = opt.or_else(|| Some(3)); + + // should lint, bind_instead_of_map doesn't apply + let _: Option = None.or(Some(3)); + let _ = deep.0.or(Some(3)); + let _ = opt.or(Some(3)); // Should lint - Result let res: Result = Err(5); @@ -92,26 +95,27 @@ fn main() { let _ = res2.unwrap_or_else(|err| err.return_some_field()); let _ = res2.unwrap_or_else(|_| ext_str.return_some_field()); + // should not lint, bind_instead_of_map takes priority let _: Result = res.and_then(|x| Ok(x)); - let _: Result = res.and_then(|x| Err(x)); - - let _: Result = res.or_else(|err| Ok(err)); let _: Result = res.or_else(|err| Err(err)); - // These are handled by bind_instead_of_map let _: Result = res.and_then(|_| Ok(2)); let _: Result = res.and_then(|_| Ok(astronomers_pi)); let _: Result = res.and_then(|_| Ok(ext_str.some_field)); - let _: Result = res.and_then(|_| Err(2)); - let _: Result = res.and_then(|_| Err(astronomers_pi)); - let _: Result = res.and_then(|_| Err(ext_str.some_field)); - - let _: Result = res.or_else(|_| Ok(2)); - let _: Result = res.or_else(|_| Ok(astronomers_pi)); - let _: Result = res.or_else(|_| Ok(ext_str.some_field)); - let _: Result = res.or_else(|_| Err(2)); let _: Result = res.or_else(|_| Err(astronomers_pi)); let _: Result = res.or_else(|_| Err(ext_str.some_field)); + + // should lint, bind_instead_of_map doesn't apply + let _: Result = res.and_then(|x| Err(x)); + let _: Result = res.or_else(|err| Ok(err)); + + let _: Result = res.and(Err(2)); + let _: Result = res.and(Err(astronomers_pi)); + let _: Result = res.and(Err(ext_str.some_field)); + + let _: Result = res.or(Ok(2)); + let _: Result = res.or(Ok(astronomers_pi)); + let _: Result = res.or(Ok(ext_str.some_field)); } diff --git a/tests/ui/unnecessary_lazy_eval.rs b/tests/ui/unnecessary_lazy_eval.rs index 04f47d1aa2978..0b270939ec20a 100644 --- a/tests/ui/unnecessary_lazy_eval.rs +++ b/tests/ui/unnecessary_lazy_eval.rs @@ -2,6 +2,7 @@ #![warn(clippy::unnecessary_lazy_evaluations)] #![allow(clippy::redundant_closure)] #![allow(clippy::bind_instead_of_map)] +#![allow(clippy::map_identity)] struct Deep(Option); @@ -40,7 +41,7 @@ fn main() { let _ = opt.or_else(|| None); let _ = opt.get_or_insert_with(|| 2); let _ = opt.ok_or_else(|| 2); - let _ = opt.ok_or_else(|| ext_arr[0]); + let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); // Cases when unwrap is not called on a simple variable let _ = Some(10).unwrap_or_else(|| 2); @@ -60,7 +61,6 @@ fn main() { // Should not lint - Option let _ = opt.unwrap_or_else(|| ext_str.return_some_field()); let _ = nested_opt.unwrap_or_else(|| Some(some_call())); - let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); let _ = nested_tuple_opt.unwrap_or_else(|| Some((some_call(), some_call()))); let _ = opt.or_else(some_call); let _ = opt.or_else(|| some_call()); @@ -69,10 +69,13 @@ fn main() { let _ = deep.0.get_or_insert_with(|| some_call()); let _ = deep.0.or_else(some_call); let _ = deep.0.or_else(|| some_call()); + let _ = opt.ok_or_else(|| ext_arr[0]); - // These are handled by bind_instead_of_map + // should not lint, bind_instead_of_map takes priority let _ = Some(10).and_then(|idx| Some(ext_arr[idx])); let _ = Some(10).and_then(|idx| Some(idx)); + + // should lint, bind_instead_of_map doesn't apply let _: Option = None.or_else(|| Some(3)); let _ = deep.0.or_else(|| Some(3)); let _ = opt.or_else(|| Some(3)); @@ -92,17 +95,22 @@ fn main() { let _ = res2.unwrap_or_else(|err| err.return_some_field()); let _ = res2.unwrap_or_else(|_| ext_str.return_some_field()); + // should not lint, bind_instead_of_map takes priority let _: Result = res.and_then(|x| Ok(x)); - let _: Result = res.and_then(|x| Err(x)); - - let _: Result = res.or_else(|err| Ok(err)); let _: Result = res.or_else(|err| Err(err)); - // These are handled by bind_instead_of_map let _: Result = res.and_then(|_| Ok(2)); let _: Result = res.and_then(|_| Ok(astronomers_pi)); let _: Result = res.and_then(|_| Ok(ext_str.some_field)); + let _: Result = res.or_else(|_| Err(2)); + let _: Result = res.or_else(|_| Err(astronomers_pi)); + let _: Result = res.or_else(|_| Err(ext_str.some_field)); + + // should lint, bind_instead_of_map doesn't apply + let _: Result = res.and_then(|x| Err(x)); + let _: Result = res.or_else(|err| Ok(err)); + let _: Result = res.and_then(|_| Err(2)); let _: Result = res.and_then(|_| Err(astronomers_pi)); let _: Result = res.and_then(|_| Err(ext_str.some_field)); @@ -110,8 +118,4 @@ fn main() { let _: Result = res.or_else(|_| Ok(2)); let _: Result = res.or_else(|_| Ok(astronomers_pi)); let _: Result = res.or_else(|_| Ok(ext_str.some_field)); - - let _: Result = res.or_else(|_| Err(2)); - let _: Result = res.or_else(|_| Err(astronomers_pi)); - let _: Result = res.or_else(|_| Err(ext_str.some_field)); } diff --git a/tests/ui/unnecessary_lazy_eval.stderr b/tests/ui/unnecessary_lazy_eval.stderr index 5c1b2eb1f14e8..1cf7ac46346db 100644 --- a/tests/ui/unnecessary_lazy_eval.stderr +++ b/tests/ui/unnecessary_lazy_eval.stderr @@ -1,5 +1,5 @@ error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:34:13 + --> $DIR/unnecessary_lazy_eval.rs:35:13 | LL | let _ = opt.unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(2)` @@ -7,142 +7,190 @@ LL | let _ = opt.unwrap_or_else(|| 2); = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:35:13 + --> $DIR/unnecessary_lazy_eval.rs:36:13 | LL | let _ = opt.unwrap_or_else(|| astronomers_pi); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:36:13 + --> $DIR/unnecessary_lazy_eval.rs:37:13 | LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:37:13 - | -LL | let _ = opt.unwrap_or_else(|| ext_arr[0]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(ext_arr[0])` - -error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:38:13 + --> $DIR/unnecessary_lazy_eval.rs:39:13 | LL | let _ = opt.and_then(|_| ext_opt); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `opt.and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:39:13 + --> $DIR/unnecessary_lazy_eval.rs:40:13 | LL | let _ = opt.or_else(|| ext_opt); | ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:40:13 + --> $DIR/unnecessary_lazy_eval.rs:41:13 | LL | let _ = opt.or_else(|| None); | ^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:41:13 + --> $DIR/unnecessary_lazy_eval.rs:42:13 | LL | let _ = opt.get_or_insert_with(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `opt.get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:42:13 + --> $DIR/unnecessary_lazy_eval.rs:43:13 | LL | let _ = opt.ok_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `opt.ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:43:13 + --> $DIR/unnecessary_lazy_eval.rs:44:13 | -LL | let _ = opt.ok_or_else(|| ext_arr[0]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `opt.ok_or(ext_arr[0])` +LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `nested_tuple_opt.unwrap_or(Some((1, 2)))` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:46:13 + --> $DIR/unnecessary_lazy_eval.rs:47:13 | LL | let _ = Some(10).unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Some(10).unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:47:13 + --> $DIR/unnecessary_lazy_eval.rs:48:13 | LL | let _ = Some(10).and_then(|_| ext_opt); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `Some(10).and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:48:28 + --> $DIR/unnecessary_lazy_eval.rs:49:28 | LL | let _: Option = None.or_else(|| ext_opt); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:49:13 + --> $DIR/unnecessary_lazy_eval.rs:50:13 | LL | let _ = None.get_or_insert_with(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `None.get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:50:35 + --> $DIR/unnecessary_lazy_eval.rs:51:35 | LL | let _: Result = None.ok_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `None.ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:51:28 + --> $DIR/unnecessary_lazy_eval.rs:52:28 | LL | let _: Option = None.or_else(|| None); | ^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:54:13 + --> $DIR/unnecessary_lazy_eval.rs:55:13 | LL | let _ = deep.0.unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `deep.0.unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:55:13 + --> $DIR/unnecessary_lazy_eval.rs:56:13 | LL | let _ = deep.0.and_then(|_| ext_opt); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `deep.0.and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:56:13 + --> $DIR/unnecessary_lazy_eval.rs:57:13 | LL | let _ = deep.0.or_else(|| None); | ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `deep.0.or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:57:13 + --> $DIR/unnecessary_lazy_eval.rs:58:13 | LL | let _ = deep.0.get_or_insert_with(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `deep.0.get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:58:13 + --> $DIR/unnecessary_lazy_eval.rs:59:13 | LL | let _ = deep.0.ok_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `deep.0.ok_or(2)` +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:79:28 + | +LL | let _: Option = None.or_else(|| Some(3)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(Some(3))` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:80:13 + | +LL | let _ = deep.0.or_else(|| Some(3)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `deep.0.or(Some(3))` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:81:13 + | +LL | let _ = opt.or_else(|| Some(3)); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(Some(3))` + error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:84:13 + --> $DIR/unnecessary_lazy_eval.rs:87:13 | LL | let _ = res2.unwrap_or_else(|_| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(2)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:85:13 + --> $DIR/unnecessary_lazy_eval.rs:88:13 | LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:86:13 + --> $DIR/unnecessary_lazy_eval.rs:89:13 | LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(ext_str.some_field)` -error: aborting due to 24 previous errors +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval.rs:114:35 + | +LL | let _: Result = res.and_then(|_| Err(2)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `res.and(Err(2))` + +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval.rs:115:35 + | +LL | let _: Result = res.and_then(|_| Err(astronomers_pi)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `res.and(Err(astronomers_pi))` + +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval.rs:116:35 + | +LL | let _: Result = res.and_then(|_| Err(ext_str.some_field)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `res.and(Err(ext_str.some_field))` + +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval.rs:118:35 + | +LL | let _: Result = res.or_else(|_| Ok(2)); + | ^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `res.or(Ok(2))` + +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval.rs:119:35 + | +LL | let _: Result = res.or_else(|_| Ok(astronomers_pi)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `res.or(Ok(astronomers_pi))` + +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval.rs:120:35 + | +LL | let _: Result = res.or_else(|_| Ok(ext_str.some_field)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `res.or(Ok(ext_str.some_field))` + +error: aborting due to 32 previous errors From ff1a9e406bfccefedb6c4f2cabc0c4d59ac947d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Wed, 16 Sep 2020 00:00:00 +0000 Subject: [PATCH 0484/1052] Fix underflow when calculating the number of no-op jumps folded When removing unwinds to no-op blocks and folding jumps to no-op blocks, remove the unwind target first. Otherwise we cannot determine if target has been already folded or not. Previous implementation incorrectly assumed that all resume targets had been folded already, occasionally resulting in an underflow: remove_noop_landing_pads: removed 18446744073709551613 jumps and 3 landing pads --- .../src/transform/remove_noop_landing_pads.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs b/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs index 0bad1e5037a0b..4079f0110e2c0 100644 --- a/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs @@ -102,6 +102,16 @@ impl RemoveNoopLandingPads { let postorder: Vec<_> = traversal::postorder(body).map(|(bb, _)| bb).collect(); for bb in postorder { debug!(" processing {:?}", bb); + if let Some(unwind) = body[bb].terminator_mut().unwind_mut() { + if let Some(unwind_bb) = *unwind { + if nop_landing_pads.contains(unwind_bb) { + debug!(" removing noop landing pad"); + landing_pads_removed += 1; + *unwind = None; + } + } + } + for target in body[bb].terminator_mut().successors_mut() { if *target != resume_block && nop_landing_pads.contains(*target) { debug!(" folding noop jump to {:?} to resume block", target); @@ -110,15 +120,6 @@ impl RemoveNoopLandingPads { } } - if let Some(unwind) = body[bb].terminator_mut().unwind_mut() { - if *unwind == Some(resume_block) { - debug!(" removing noop landing pad"); - jumps_folded -= 1; - landing_pads_removed += 1; - *unwind = None; - } - } - let is_nop_landing_pad = self.is_nop_landing_pad(bb, body, &nop_landing_pads); if is_nop_landing_pad { nop_landing_pads.insert(bb); From c910e038e844628b5a1fcf0e892eb88dd819ce47 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Tue, 15 Sep 2020 18:32:12 -0700 Subject: [PATCH 0485/1052] Strip a single leading tab when rendering dataflow diffs --- compiler/rustc_mir/src/dataflow/framework/graphviz.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/dataflow/framework/graphviz.rs b/compiler/rustc_mir/src/dataflow/framework/graphviz.rs index 179c471cf4829..94151fbd0903a 100644 --- a/compiler/rustc_mir/src/dataflow/framework/graphviz.rs +++ b/compiler/rustc_mir/src/dataflow/framework/graphviz.rs @@ -578,7 +578,7 @@ where return String::new(); } - let re = Regex::new("\u{001f}([+-])").unwrap(); + let re = Regex::new("\t?\u{001f}([+-])").unwrap(); let raw_diff = format!("{:#?}", DebugDiffWithAdapter { new, old, ctxt }); From e82be710e47a38dc303ae8f2df02d9a8c682b1b6 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Mon, 14 Sep 2020 04:59:55 +0000 Subject: [PATCH 0486/1052] document how to use memory addresses as operands Co-authored-by: Amanieu --- .../unstable-book/src/library-features/asm.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md index 28a5fe31fc4b5..df113f0f1613c 100644 --- a/src/doc/unstable-book/src/library-features/asm.md +++ b/src/doc/unstable-book/src/library-features/asm.md @@ -345,6 +345,25 @@ The `h` modifier will emit the register name for the high byte of that register If you use a smaller data type (e.g. `u16`) with an operand and forget the use template modifiers, the compiler will emit a warning and suggest the correct modifier to use. +## Memory address operands + +Sometimes assembly instructions require operands passed via memory addresses/memory locations. +You have to manually use the memory address syntax specified by the respectively architectures. +For example, in x86/x86_64 and intel assembly syntax, you should wrap inputs/outputs in `[]` +to indicate they are memory operands: + +```rust,allow_fail +# #![feature(asm, llvm_asm)] +# fn load_fpu_control_word(control: u16) { +unsafe { + asm!("fldcw [{}]", in(reg) &control, options(nostack)); + + // Previously this would have been written with the deprecated `llvm_asm!` like this + llvm_asm!("fldcw $0" :: "m" (control) :: "volatile"); +} +# } +``` + ## Options By default, an inline assembly block is treated the same way as an external FFI function call with a custom calling convention: it may read/write memory, have observable side effects, etc. However in many cases, it is desirable to give the compiler more information about what the assembly code is actually doing so that it can optimize better. From d0ddbb9d0d0d6b9b6adb51b259819ec270421642 Mon Sep 17 00:00:00 2001 From: Robin Schoonover Date: Tue, 15 Sep 2020 21:10:50 -0600 Subject: [PATCH 0487/1052] Extend testing of rc_buffer lint --- tests/ui/rc_buffer.rs | 23 +++++++--- tests/ui/rc_buffer.stderr | 50 ++++++++++++++++------ tests/ui/rc_buffer_arc.rs | 24 ++++++++--- tests/ui/rc_buffer_arc.stderr | 50 ++++++++++++++++------ tests/ui/rc_buffer_redefined_string.rs | 12 ++++++ tests/ui/rc_buffer_redefined_string.stderr | 0 6 files changed, 122 insertions(+), 37 deletions(-) create mode 100644 tests/ui/rc_buffer_redefined_string.rs create mode 100644 tests/ui/rc_buffer_redefined_string.stderr diff --git a/tests/ui/rc_buffer.rs b/tests/ui/rc_buffer.rs index c8c2bec67ee59..1fa9864393687 100644 --- a/tests/ui/rc_buffer.rs +++ b/tests/ui/rc_buffer.rs @@ -1,13 +1,26 @@ +#![warn(clippy::rc_buffer)] + +use std::cell::RefCell; use std::ffi::OsString; use std::path::PathBuf; use std::rc::Rc; -#[warn(clippy::rc_buffer)] struct S { - a: Rc, - b: Rc, - c: Rc>, - d: Rc, + // triggers lint + bad1: Rc, + bad2: Rc, + bad3: Rc>, + bad4: Rc, + // does not trigger lint + good1: Rc>, } +// triggers lint +fn func_bad1(_: Rc) {} +fn func_bad2(_: Rc) {} +fn func_bad3(_: Rc>) {} +fn func_bad4(_: Rc) {} +// does not trigger lint +fn func_good1(_: Rc>) {} + fn main() {} diff --git a/tests/ui/rc_buffer.stderr b/tests/ui/rc_buffer.stderr index 641a13a225134..e4cc169af07b9 100644 --- a/tests/ui/rc_buffer.stderr +++ b/tests/ui/rc_buffer.stderr @@ -1,28 +1,52 @@ error: usage of `Rc` when T is a buffer type - --> $DIR/rc_buffer.rs:7:8 + --> $DIR/rc_buffer.rs:10:11 | -LL | a: Rc, - | ^^^^^^^^^^ help: try: `Rc` +LL | bad1: Rc, + | ^^^^^^^^^^ help: try: `Rc` | = note: `-D clippy::rc-buffer` implied by `-D warnings` error: usage of `Rc` when T is a buffer type - --> $DIR/rc_buffer.rs:8:8 + --> $DIR/rc_buffer.rs:11:11 | -LL | b: Rc, - | ^^^^^^^^^^^ help: try: `Rc` +LL | bad2: Rc, + | ^^^^^^^^^^^ help: try: `Rc` error: usage of `Rc` when T is a buffer type - --> $DIR/rc_buffer.rs:9:8 + --> $DIR/rc_buffer.rs:12:11 | -LL | c: Rc>, - | ^^^^^^^^^^^ help: try: `Rc<[u8]>` +LL | bad3: Rc>, + | ^^^^^^^^^^^ help: try: `Rc<[u8]>` error: usage of `Rc` when T is a buffer type - --> $DIR/rc_buffer.rs:10:8 + --> $DIR/rc_buffer.rs:13:11 | -LL | d: Rc, - | ^^^^^^^^^^^^ help: try: `Rc` +LL | bad4: Rc, + | ^^^^^^^^^^^^ help: try: `Rc` -error: aborting due to 4 previous errors +error: usage of `Rc` when T is a buffer type + --> $DIR/rc_buffer.rs:19:17 + | +LL | fn func_bad1(_: Rc) {} + | ^^^^^^^^^^ help: try: `Rc` + +error: usage of `Rc` when T is a buffer type + --> $DIR/rc_buffer.rs:20:17 + | +LL | fn func_bad2(_: Rc) {} + | ^^^^^^^^^^^ help: try: `Rc` + +error: usage of `Rc` when T is a buffer type + --> $DIR/rc_buffer.rs:21:17 + | +LL | fn func_bad3(_: Rc>) {} + | ^^^^^^^^^^^ help: try: `Rc<[u8]>` + +error: usage of `Rc` when T is a buffer type + --> $DIR/rc_buffer.rs:22:17 + | +LL | fn func_bad4(_: Rc) {} + | ^^^^^^^^^^^^ help: try: `Rc` + +error: aborting due to 8 previous errors diff --git a/tests/ui/rc_buffer_arc.rs b/tests/ui/rc_buffer_arc.rs index a878b0ab3365d..5d586584817bd 100644 --- a/tests/ui/rc_buffer_arc.rs +++ b/tests/ui/rc_buffer_arc.rs @@ -1,13 +1,25 @@ +#![warn(clippy::rc_buffer)] + use std::ffi::OsString; use std::path::PathBuf; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; -#[warn(clippy::rc_buffer)] struct S { - a: Arc, - b: Arc, - c: Arc>, - d: Arc, + // triggers lint + bad1: Arc, + bad2: Arc, + bad3: Arc>, + bad4: Arc, + // does not trigger lint + good1: Arc>, } +// triggers lint +fn func_bad1(_: Arc) {} +fn func_bad2(_: Arc) {} +fn func_bad3(_: Arc>) {} +fn func_bad4(_: Arc) {} +// does not trigger lint +fn func_good1(_: Arc>) {} + fn main() {} diff --git a/tests/ui/rc_buffer_arc.stderr b/tests/ui/rc_buffer_arc.stderr index c4b016210469b..8252270d2ac74 100644 --- a/tests/ui/rc_buffer_arc.stderr +++ b/tests/ui/rc_buffer_arc.stderr @@ -1,28 +1,52 @@ error: usage of `Arc` when T is a buffer type - --> $DIR/rc_buffer_arc.rs:7:8 + --> $DIR/rc_buffer_arc.rs:9:11 | -LL | a: Arc, - | ^^^^^^^^^^^ help: try: `Arc` +LL | bad1: Arc, + | ^^^^^^^^^^^ help: try: `Arc` | = note: `-D clippy::rc-buffer` implied by `-D warnings` error: usage of `Arc` when T is a buffer type - --> $DIR/rc_buffer_arc.rs:8:8 + --> $DIR/rc_buffer_arc.rs:10:11 | -LL | b: Arc, - | ^^^^^^^^^^^^ help: try: `Arc` +LL | bad2: Arc, + | ^^^^^^^^^^^^ help: try: `Arc` error: usage of `Arc` when T is a buffer type - --> $DIR/rc_buffer_arc.rs:9:8 + --> $DIR/rc_buffer_arc.rs:11:11 | -LL | c: Arc>, - | ^^^^^^^^^^^^ help: try: `Arc<[u8]>` +LL | bad3: Arc>, + | ^^^^^^^^^^^^ help: try: `Arc<[u8]>` error: usage of `Arc` when T is a buffer type - --> $DIR/rc_buffer_arc.rs:10:8 + --> $DIR/rc_buffer_arc.rs:12:11 | -LL | d: Arc, - | ^^^^^^^^^^^^^ help: try: `Arc` +LL | bad4: Arc, + | ^^^^^^^^^^^^^ help: try: `Arc` -error: aborting due to 4 previous errors +error: usage of `Arc` when T is a buffer type + --> $DIR/rc_buffer_arc.rs:18:17 + | +LL | fn func_bad1(_: Arc) {} + | ^^^^^^^^^^^ help: try: `Arc` + +error: usage of `Arc` when T is a buffer type + --> $DIR/rc_buffer_arc.rs:19:17 + | +LL | fn func_bad2(_: Arc) {} + | ^^^^^^^^^^^^ help: try: `Arc` + +error: usage of `Arc` when T is a buffer type + --> $DIR/rc_buffer_arc.rs:20:17 + | +LL | fn func_bad3(_: Arc>) {} + | ^^^^^^^^^^^^ help: try: `Arc<[u8]>` + +error: usage of `Arc` when T is a buffer type + --> $DIR/rc_buffer_arc.rs:21:17 + | +LL | fn func_bad4(_: Arc) {} + | ^^^^^^^^^^^^^ help: try: `Arc` + +error: aborting due to 8 previous errors diff --git a/tests/ui/rc_buffer_redefined_string.rs b/tests/ui/rc_buffer_redefined_string.rs new file mode 100644 index 0000000000000..5d31a848cf72c --- /dev/null +++ b/tests/ui/rc_buffer_redefined_string.rs @@ -0,0 +1,12 @@ +#![warn(clippy::rc_buffer)] + +use std::rc::Rc; + +struct String; + +struct S { + // does not trigger lint + good1: Rc, +} + +fn main() {} diff --git a/tests/ui/rc_buffer_redefined_string.stderr b/tests/ui/rc_buffer_redefined_string.stderr new file mode 100644 index 0000000000000..e69de29bb2d1d From 1dc4f8560f70500dc07c548094d8b5abd88c6130 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Wed, 16 Sep 2020 11:45:15 +0800 Subject: [PATCH 0488/1052] Simplify iter fuse struct doc --- library/core/src/iter/adapters/fuse.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index 409f202780ba6..c5b3bd5cf11f2 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -9,11 +9,8 @@ use crate::ops::Try; /// An iterator that yields `None` forever after the underlying iterator /// yields `None` once. /// -/// This `struct` is created by the [`fuse`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`fuse`]: trait.Iterator.html#method.fuse -/// [`Iterator`]: trait.Iterator.html +/// This `struct` is created by [`Iterator::fuse`]. See its documentation +/// for more. #[derive(Clone, Debug)] #[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] From 87666e5bce23c8ef420dfb0e5d86668ddf1acbf2 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Wed, 16 Sep 2020 04:46:23 +0000 Subject: [PATCH 0489/1052] Prefer asm! over llvm_asm! in core --- library/core/src/hint.rs | 5 +++-- library/core/src/num/dec2flt/algorithm.rs | 20 +++++++++++++++++--- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index d40a380286762..929c22e4538f1 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -111,7 +111,7 @@ pub fn spin_loop() { #[inline] #[unstable(feature = "test", issue = "50297")] #[allow(unreachable_code)] // this makes #[cfg] a bit easier below. -pub fn black_box(dummy: T) -> T { +pub fn black_box(mut dummy: T) -> T { // We need to "use" the argument in some way LLVM can't introspect, and on // targets that support it we can typically leverage inline assembly to do // this. LLVM's interpretation of inline assembly is that it's, well, a black @@ -121,7 +121,8 @@ pub fn black_box(dummy: T) -> T { #[cfg(not(miri))] // This is just a hint, so it is fine to skip in Miri. // SAFETY: the inline assembly is a no-op. unsafe { - llvm_asm!("" : : "r"(&dummy)); + // FIXME: Cannot use `asm!` because it doesn't support MIPS and other architectures. + llvm_asm!("" : : "r"(&mut dummy)); } dummy diff --git a/library/core/src/num/dec2flt/algorithm.rs b/library/core/src/num/dec2flt/algorithm.rs index aaeb4d8a22c29..a5fbdc6ee2d48 100644 --- a/library/core/src/num/dec2flt/algorithm.rs +++ b/library/core/src/num/dec2flt/algorithm.rs @@ -60,12 +60,19 @@ mod fpu_precision { fn set_cw(cw: u16) { // SAFETY: the `fldcw` instruction has been audited to be able to work correctly with // any `u16` - unsafe { llvm_asm!("fldcw $0" :: "m" (cw) :: "volatile") } + unsafe { + asm!( + "fldcw ({})", + in(reg) &cw, + // FIXME: We are using ATT syntax to support LLVM 8 and LLVM 9. + options(att_syntax, nostack), + ) + } } /// Sets the precision field of the FPU to `T` and returns a `FPUControlWord`. pub fn set_precision() -> FPUControlWord { - let cw = 0u16; + let mut cw = 0_u16; // Compute the value for the Precision Control field that is appropriate for `T`. let cw_precision = match size_of::() { @@ -78,7 +85,14 @@ mod fpu_precision { // `FPUControlWord` structure is dropped // SAFETY: the `fnstcw` instruction has been audited to be able to work correctly with // any `u16` - unsafe { llvm_asm!("fnstcw $0" : "=*m" (&cw) ::: "volatile") } + unsafe { + asm!( + "fnstcw ({})", + in(reg) &mut cw, + // FIXME: We are using ATT syntax to support LLVM 8 and LLVM 9. + options(att_syntax, nostack), + ) + } // Set the control word to the desired precision. This is achieved by masking away the old // precision (bits 8 and 9, 0x300) and replacing it with the precision flag computed above. From ad6f8c6354f4f1bba8101886646929a4985dec77 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Wed, 16 Sep 2020 12:09:57 +0700 Subject: [PATCH 0490/1052] bump pulldown-cmark v0.8 --- clippy_lints/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index cc7d3a04f003e..341d9e601ee6f 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -21,7 +21,7 @@ cargo_metadata = "0.11.1" if_chain = "1.0.0" itertools = "0.9" lazy_static = "1.0.2" -pulldown-cmark = { version = "0.7.1", default-features = false } +pulldown-cmark = { version = "0.8", default-features = false } quine-mc_cluskey = "0.2.2" regex-syntax = "0.6" serde = { version = "1.0", features = ["derive"] } From eede953c283c7bbe903a0e8abb44c923baf5cfac Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Thu, 10 Sep 2020 03:10:36 +0000 Subject: [PATCH 0491/1052] Only get ImplKind::Impl once --- src/librustdoc/clean/inline.rs | 41 ++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index f8987c6beca33..931355b82f503 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -350,14 +350,22 @@ pub fn build_impl( } } - let for_ = if let Some(did) = did.as_local() { - let hir_id = tcx.hir().local_def_id_to_hir_id(did); - match tcx.hir().expect_item(hir_id).kind { - hir::ItemKind::Impl { self_ty, .. } => self_ty.clean(cx), - _ => panic!("did given to build_impl was not an impl"), + let impl_item = match did.as_local() { + Some(did) => { + let hir_id = tcx.hir().local_def_id_to_hir_id(did); + match tcx.hir().expect_item(hir_id).kind { + hir::ItemKind::Impl { self_ty, ref generics, ref items, .. } => { + Some((self_ty, generics, items)) + } + _ => panic!("`DefID` passed to `build_impl` is not an `impl"), + } } - } else { - tcx.type_of(did).clean(cx) + None => None, + }; + + let for_ = match impl_item { + Some((self_ty, _, _)) => self_ty.clean(cx), + None => tcx.type_of(did).clean(cx), }; // Only inline impl if the implementing type is @@ -377,17 +385,12 @@ pub fn build_impl( } let predicates = tcx.explicit_predicates_of(did); - let (trait_items, generics) = if let Some(did) = did.as_local() { - let hir_id = tcx.hir().local_def_id_to_hir_id(did); - match tcx.hir().expect_item(hir_id).kind { - hir::ItemKind::Impl { ref generics, ref items, .. } => ( - items.iter().map(|item| tcx.hir().impl_item(item.id).clean(cx)).collect::>(), - generics.clean(cx), - ), - _ => panic!("did given to build_impl was not an impl"), - } - } else { - ( + let (trait_items, generics) = match impl_item { + Some((_, generics, items)) => ( + items.iter().map(|item| tcx.hir().impl_item(item.id).clean(cx)).collect::>(), + generics.clean(cx), + ), + None => ( tcx.associated_items(did) .in_definition_order() .filter_map(|item| { @@ -399,7 +402,7 @@ pub fn build_impl( }) .collect::>(), clean::enter_impl_trait(cx, || (tcx.generics_of(did), predicates).clean(cx)), - ) + ), }; let polarity = tcx.impl_polarity(did); let trait_ = associated_trait.clean(cx).map(|bound| match bound { From 4dc4e9f671a36026cf59894622fdf4f6b979bf76 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Wed, 16 Sep 2020 09:25:54 +0000 Subject: [PATCH 0492/1052] Fix black_box bug detected by Amanieu Co-authored-by: Amanieu --- library/core/src/hint.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 929c22e4538f1..1192b9e164a14 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -122,7 +122,7 @@ pub fn black_box(mut dummy: T) -> T { // SAFETY: the inline assembly is a no-op. unsafe { // FIXME: Cannot use `asm!` because it doesn't support MIPS and other architectures. - llvm_asm!("" : : "r"(&mut dummy)); + llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile"); } dummy From d04ca008e1c8ade73ec22976ff6a2a6a13ceabec Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 15 Sep 2020 00:08:37 -0400 Subject: [PATCH 0493/1052] Remove unnecessary `clone()`s in bootstrap The performance difference is negligible, but it makes me feel better. Note that this does not remove some clones in `config`, because it would require changing the logic around (and performance doesn't matter for bootstrap). --- src/bootstrap/builder.rs | 2 +- src/bootstrap/config.rs | 65 ++++++++++++++++++++-------------------- src/bootstrap/format.rs | 8 ++--- src/bootstrap/sanity.rs | 4 +-- 4 files changed, 39 insertions(+), 40 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 34756af21e4fc..319f81c4ebb04 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -1209,7 +1209,7 @@ impl<'a> Builder<'a> { cargo.env(format!("CC_{}", target.triple), &cc); let cflags = self.cflags(target, GitRepo::Rustc).join(" "); - cargo.env(format!("CFLAGS_{}", target.triple), cflags.clone()); + cargo.env(format!("CFLAGS_{}", target.triple), &cflags); if let Some(ar) = self.ar(target) { let ranlib = format!("{} s", ar.display()); diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 30c9e012cd6f5..7e2cb7721865e 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -500,6 +500,7 @@ impl Config { pub fn parse(args: &[String]) -> Config { let flags = Flags::parse(&args); + let mut config = Config::default_opts(); config.exclude = flags.exclude; config.rustc_error_format = flags.rustc_error_format; @@ -551,14 +552,14 @@ impl Config { let has_targets = build.target.is_some() || flags.target.is_some(); config.skip_only_host_steps = !has_hosts && has_targets; - config.hosts = if let Some(arg_host) = flags.host.clone() { + config.hosts = if let Some(arg_host) = flags.host { arg_host } else if let Some(file_host) = build.host { file_host.iter().map(|h| TargetSelection::from_user(h)).collect() } else { vec![config.build] }; - config.targets = if let Some(arg_target) = flags.target.clone() { + config.targets = if let Some(arg_target) = flags.target { arg_target } else if let Some(file_target) = build.target { file_target.iter().map(|h| TargetSelection::from_user(h)).collect() @@ -628,14 +629,14 @@ impl Config { config.verbose = cmp::max(config.verbose, flags.verbose); - if let Some(ref install) = toml.install { - config.prefix = install.prefix.clone().map(PathBuf::from); - config.sysconfdir = install.sysconfdir.clone().map(PathBuf::from); - config.datadir = install.datadir.clone().map(PathBuf::from); - config.docdir = install.docdir.clone().map(PathBuf::from); - set(&mut config.bindir, install.bindir.clone().map(PathBuf::from)); - config.libdir = install.libdir.clone().map(PathBuf::from); - config.mandir = install.mandir.clone().map(PathBuf::from); + if let Some(install) = toml.install { + config.prefix = install.prefix.map(PathBuf::from); + config.sysconfdir = install.sysconfdir.map(PathBuf::from); + config.datadir = install.datadir.map(PathBuf::from); + config.docdir = install.docdir.map(PathBuf::from); + set(&mut config.bindir, install.bindir.map(PathBuf::from)); + config.libdir = install.libdir.map(PathBuf::from); + config.mandir = install.mandir.map(PathBuf::from); } // We want the llvm-skip-rebuild flag to take precedence over the @@ -658,7 +659,7 @@ impl Config { let mut optimize = None; let mut ignore_git = None; - if let Some(ref llvm) = toml.llvm { + if let Some(llvm) = toml.llvm { match llvm.ccache { Some(StringOrBool::String(ref s)) => config.ccache = Some(s.to_string()), Some(StringOrBool::Bool(true)) => { @@ -726,7 +727,7 @@ impl Config { } } - if let Some(ref rust) = toml.rust { + if let Some(rust) = toml.rust { debug = rust.debug; debug_assertions = rust.debug_assertions; debug_assertions_std = rust.debug_assertions_std; @@ -746,7 +747,7 @@ impl Config { set(&mut config.test_compare_mode, rust.test_compare_mode); set(&mut config.llvm_libunwind, rust.llvm_libunwind); set(&mut config.backtrace, rust.backtrace); - set(&mut config.channel, rust.channel.clone()); + set(&mut config.channel, rust.channel); 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 @@ -757,9 +758,9 @@ impl Config { set(&mut config.lld_enabled, rust.lld); set(&mut config.llvm_tools_enabled, rust.llvm_tools); config.rustc_parallel = rust.parallel_compiler.unwrap_or(false); - config.rustc_default_linker = rust.default_linker.clone(); - config.musl_root = rust.musl_root.clone().map(PathBuf::from); - config.save_toolstates = rust.save_toolstates.clone().map(PathBuf::from); + config.rustc_default_linker = rust.default_linker; + config.musl_root = rust.musl_root.map(PathBuf::from); + config.save_toolstates = rust.save_toolstates.map(PathBuf::from); set(&mut config.deny_warnings, flags.deny_warnings.or(rust.deny_warnings)); set(&mut config.backtrace_on_ice, rust.backtrace_on_ice); set(&mut config.rust_verify_llvm_ir, rust.verify_llvm_ir); @@ -776,9 +777,9 @@ impl Config { config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config); } - if let Some(ref t) = toml.target { + if let Some(t) = toml.target { for (triple, cfg) in t { - let mut target = Target::from_triple(triple); + let mut target = Target::from_triple(&triple); if let Some(ref s) = cfg.llvm_config { target.llvm_config = Some(config.src.join(s)); @@ -792,18 +793,18 @@ impl Config { if let Some(s) = cfg.no_std { target.no_std = s; } - target.cc = cfg.cc.clone().map(PathBuf::from); - target.cxx = cfg.cxx.clone().map(PathBuf::from); - target.ar = cfg.ar.clone().map(PathBuf::from); - target.ranlib = cfg.ranlib.clone().map(PathBuf::from); - target.linker = cfg.linker.clone().map(PathBuf::from); + target.cc = cfg.cc.map(PathBuf::from); + target.cxx = cfg.cxx.map(PathBuf::from); + target.ar = cfg.ar.map(PathBuf::from); + target.ranlib = cfg.ranlib.map(PathBuf::from); + target.linker = cfg.linker.map(PathBuf::from); target.crt_static = cfg.crt_static; - target.musl_root = cfg.musl_root.clone().map(PathBuf::from); - target.musl_libdir = cfg.musl_libdir.clone().map(PathBuf::from); - target.wasi_root = cfg.wasi_root.clone().map(PathBuf::from); - target.qemu_rootfs = cfg.qemu_rootfs.clone().map(PathBuf::from); + target.musl_root = cfg.musl_root.map(PathBuf::from); + 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); - config.target_config.insert(TargetSelection::from_user(triple), target); + config.target_config.insert(TargetSelection::from_user(&triple), target); } } @@ -821,10 +822,10 @@ impl Config { build_target.llvm_filecheck = Some(ci_llvm_bin.join(exe("FileCheck", config.build))); } - if let Some(ref t) = toml.dist { - config.dist_sign_folder = t.sign_folder.clone().map(PathBuf::from); - config.dist_gpg_password_file = t.gpg_password_file.clone().map(PathBuf::from); - config.dist_upload_addr = t.upload_addr.clone(); + if let Some(t) = toml.dist { + config.dist_sign_folder = t.sign_folder.map(PathBuf::from); + config.dist_gpg_password_file = t.gpg_password_file.map(PathBuf::from); + config.dist_upload_addr = t.upload_addr; set(&mut config.rust_dist_src, t.src_tarball); set(&mut config.missing_tools, t.missing_tools); } diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs index 6f93082e6752f..0ae9f9712d569 100644 --- a/src/bootstrap/format.rs +++ b/src/bootstrap/format.rs @@ -105,15 +105,13 @@ pub fn format(build: &Build, check: bool) { eprintln!("./x.py fmt is not supported on this channel"); std::process::exit(1); }); - let src = build.src.clone(); - let walker = WalkBuilder::new(&build.src).types(matcher).overrides(ignore_fmt).build_parallel(); + let src = &build.src; + let walker = WalkBuilder::new(src).types(matcher).overrides(ignore_fmt).build_parallel(); walker.run(|| { - let src = src.clone(); - let rustfmt_path = rustfmt_path.clone(); Box::new(move |entry| { let entry = t!(entry); if entry.file_type().map_or(false, |t| t.is_file()) { - rustfmt(&src, &rustfmt_path, &entry.path(), check); + rustfmt(src, &rustfmt_path, &entry.path(), check); } ignore::WalkState::Continue }) diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 4d6612a376a34..6826d177a4ade 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -30,8 +30,8 @@ impl Finder { Self { cache: HashMap::new(), path: env::var_os("PATH").unwrap_or_default() } } - pub fn maybe_have>(&mut self, cmd: S) -> Option { - let cmd: OsString = cmd.as_ref().into(); + pub fn maybe_have>(&mut self, cmd: S) -> Option { + let cmd: OsString = cmd.into(); let path = &self.path; self.cache .entry(cmd.clone()) From 9c546b51d52673372f9e956c8e8c07f6d9d94f51 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Wed, 16 Sep 2020 16:38:58 +0200 Subject: [PATCH 0494/1052] Add S-* label modifier to triagebot --- triagebot.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 411229935c36a..ed3c83af616d7 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1,6 +1,6 @@ [relabel] allow-unauthenticated = [ - "C-*", "A-*", "E-*", "L-*", "M-*", "O-*", + "C-*", "A-*", "E-*", "L-*", "M-*", "O-*", "S-*", "good first issue", "needs test" ] From f240abc1dc9e59bfabfb5ea765fa9eae0aad3122 Mon Sep 17 00:00:00 2001 From: kadmin Date: Thu, 13 Aug 2020 19:09:14 +0000 Subject: [PATCH 0495/1052] Add array window fn Updated issue to #75027 Update to rm oob access And hopefully fix docs as well Fixed naming conflict in test Fix test which used 1-indexing Nth starts from 0, woops Fix a bunch of off by 1 errors See https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=757b311987e3fae1ca47122969acda5a Add even more off by 1 errors And also write `next` and `next_back` in terms of `nth` and `nth_back`. Run fmt Fix forgetting to change fn name in test add nth_back test & document unsafe Remove as_ref().unwrap() Documented occurrences of unsafe, noting what invariants are maintained --- library/alloc/src/lib.rs | 1 + library/alloc/src/slice.rs | 2 + library/core/src/slice/iter.rs | 100 ++++++++++++++++++ library/core/src/slice/mod.rs | 37 +++++++ library/core/tests/lib.rs | 1 + library/core/tests/slice.rs | 49 +++++++++ .../type-dependent/issue-61936.rs | 12 +-- 7 files changed, 196 insertions(+), 6 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 5774ebb9b195a..7881c101f9f60 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -76,6 +76,7 @@ #![cfg_attr(test, feature(test))] #![feature(allocator_api)] #![feature(array_chunks)] +#![feature(array_windows)] #![feature(allow_internal_unstable)] #![feature(arbitrary_self_types)] #![feature(box_patterns)] diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 677bfdd2349ec..93501ef40852a 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -95,6 +95,8 @@ use crate::vec::Vec; pub use core::slice::ArrayChunks; #[unstable(feature = "array_chunks", issue = "74985")] pub use core::slice::ArrayChunksMut; +#[unstable(feature = "array_windows", issue = "75027")] +pub use core::slice::ArrayWindows; #[stable(feature = "slice_get_slice", since = "1.28.0")] pub use core::slice::SliceIndex; #[stable(feature = "from_ref", since = "1.28.0")] diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 2e8c3cd43e999..84fa34c75e3a2 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -1687,6 +1687,106 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> { } } +/// A windowed iterator over a slice in overlapping chunks (`N` elements at a +/// time), starting at the beginning of the slice +/// +/// This struct is created by the [`array_windows`] method on [slices]. +/// +/// [`array_windows`]: ../../std/primitive.slice.html#method.array_windows +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug, Clone, Copy)] +#[unstable(feature = "array_windows", issue = "75027")] +pub struct ArrayWindows<'a, T: 'a, const N: usize> { + pub(crate) slice_head: *const T, + pub(crate) num: usize, + pub(crate) marker: marker::PhantomData<&'a [T; N]>, +} + +#[unstable(feature = "array_windows", issue = "75027")] +impl<'a, T, const N: usize> Iterator for ArrayWindows<'a, T, N> { + type Item = &'a [T; N]; + + #[inline] + fn next(&mut self) -> Option { + if self.num == 0 { + return None; + } + // SAFETY: + // This is safe because it's indexing into a slice guaranteed to be length > N. + let ret = unsafe { &*self.slice_head.cast::<[T; N]>() }; + // SAFETY: Guaranteed that there are at least 1 item remaining otherwise + // earlier branch would've been hit + self.slice_head = unsafe { self.slice_head.add(1) }; + + self.num -= 1; + Some(ret) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (self.num, Some(self.num)) + } + + #[inline] + fn count(self) -> usize { + self.num + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + if self.num <= n { + self.num = 0; + return None; + } + // SAFETY: + // This is safe because it's indexing into a slice guaranteed to be length > N. + let ret = unsafe { &*self.slice_head.add(n).cast::<[T; N]>() }; + // SAFETY: Guaranteed that there are at least n items remaining + self.slice_head = unsafe { self.slice_head.add(n + 1) }; + + self.num -= n + 1; + Some(ret) + } + + #[inline] + fn last(mut self) -> Option { + self.nth(self.num.checked_sub(1)?) + } +} + +#[unstable(feature = "array_windows", issue = "75027")] +impl<'a, T, const N: usize> DoubleEndedIterator for ArrayWindows<'a, T, N> { + #[inline] + fn next_back(&mut self) -> Option<&'a [T; N]> { + if self.num == 0 { + return None; + } + // SAFETY: Guaranteed that there are n items remaining, n-1 for 0-indexing. + let ret = unsafe { &*self.slice_head.add(self.num - 1).cast::<[T; N]>() }; + self.num -= 1; + Some(ret) + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option<&'a [T; N]> { + if self.num <= n { + self.num = 0; + return None; + } + // SAFETY: Guaranteed that there are n items remaining, n-1 for 0-indexing. + let ret = unsafe { &*self.slice_head.add(self.num - (n + 1)).cast::<[T; N]>() }; + self.num -= n + 1; + Some(ret) + } +} + +#[unstable(feature = "array_windows", issue = "75027")] +impl ExactSizeIterator for ArrayWindows<'_, T, N> { + fn is_empty(&self) -> bool { + self.num == 0 + } +} + /// An iterator over a slice in (non-overlapping) chunks (`N` elements at a /// time), starting at the beginning of the slice. /// diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 64a707c39f076..771540b0877be 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -56,6 +56,9 @@ pub use iter::{RChunks, RChunksExact, RChunksExactMut, RChunksMut}; #[unstable(feature = "array_chunks", issue = "74985")] pub use iter::{ArrayChunks, ArrayChunksMut}; +#[unstable(feature = "array_windows", issue = "75027")] +pub use iter::ArrayWindows; + #[unstable(feature = "split_inclusive", issue = "72360")] pub use iter::{SplitInclusive, SplitInclusiveMut}; @@ -1099,6 +1102,40 @@ impl [T] { } } + /// Returns an iterator over overlapping windows of `N` elements of a slice, + /// starting at the beginning of the slice. + /// + /// This is the const generic equivalent of [`windows`]. + /// + /// If `N` is smaller than the size of the array, it will return no windows. + /// + /// # Panics + /// + /// Panics if `N` is 0. This check will most probably get changed to a compile time + /// error before this method gets stabilized. + /// + /// # Examples + /// + /// ``` + /// #![feature(array_windows)] + /// let slice = [0, 1, 2, 3]; + /// let mut iter = slice.array_windows(); + /// assert_eq!(iter.next().unwrap(), &[0, 1]); + /// assert_eq!(iter.next().unwrap(), &[1, 2]); + /// assert_eq!(iter.next().unwrap(), &[2, 3]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// [`windows`]: #method.windows + #[unstable(feature = "array_windows", issue = "75027")] + #[inline] + pub fn array_windows(&self) -> ArrayWindows<'_, T, N> { + assert_ne!(N, 0); + + let num_windows = self.len().saturating_sub(N - 1); + ArrayWindows { slice_head: self.as_ptr(), num: num_windows, marker: marker::PhantomData } + } + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end /// of the slice. /// diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index a2e294ace1860..4a204adb33674 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -2,6 +2,7 @@ #![feature(array_chunks)] #![feature(array_methods)] #![feature(array_map)] +#![feature(array_windows)] #![feature(bool_to_option)] #![feature(bound_cloned)] #![feature(box_syntax)] diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index 9b31e532a6a9f..9556d43f9d78b 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -657,6 +657,55 @@ fn test_array_chunks_mut_zip() { assert_eq!(v1, [13, 14, 19, 20, 4]); } +#[test] +fn test_array_windows_infer() { + let v: &[i32] = &[0, 1, 0, 1]; + assert_eq!(v.array_windows::<2>().count(), 3); + let c = v.array_windows(); + for &[a, b] in c { + assert_eq!(a + b, 1); + } + + let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6]; + let total = v2.array_windows().map(|&[a, b, c]| a + b + c).sum::(); + assert_eq!(total, 3 + 6 + 9 + 12 + 15); +} + +#[test] +fn test_array_windows_count() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let c = v.array_windows::<3>(); + assert_eq!(c.count(), 4); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let c2 = v2.array_windows::<6>(); + assert_eq!(c2.count(), 0); + + let v3: &[i32] = &[]; + let c3 = v3.array_windows::<2>(); + assert_eq!(c3.count(), 0); +} + +#[test] +fn test_array_windows_nth() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let snd = v.array_windows::<4>().nth(1); + assert_eq!(snd, Some(&[1, 2, 3, 4])); + let mut arr_windows = v.array_windows::<2>(); + assert_ne!(arr_windows.nth(0), arr_windows.nth(0)); + let last = v.array_windows::<3>().last(); + assert_eq!(last, Some(&[3, 4, 5])); +} + +#[test] +fn test_array_windows_nth_back() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let snd = v.array_windows::<4>().nth_back(1); + assert_eq!(snd, Some(&[1, 2, 3, 4])); + let mut arr_windows = v.array_windows::<2>(); + assert_ne!(arr_windows.nth_back(0), arr_windows.nth_back(0)); +} + #[test] fn test_rchunks_count() { let v: &[i32] = &[0, 1, 2, 3, 4, 5]; diff --git a/src/test/ui/const-generics/type-dependent/issue-61936.rs b/src/test/ui/const-generics/type-dependent/issue-61936.rs index 1d42afa3f8461..f3b19109a7c80 100644 --- a/src/test/ui/const-generics/type-dependent/issue-61936.rs +++ b/src/test/ui/const-generics/type-dependent/issue-61936.rs @@ -5,21 +5,21 @@ #![cfg_attr(min, feature(min_const_generics))] trait SliceExt { - fn array_windows<'a, const N: usize>(&'a self) -> ArrayWindows<'a, T, N>; + fn array_windows_example<'a, const N: usize>(&'a self) -> ArrayWindowsExample<'a, T, N>; } impl SliceExt for [T] { - fn array_windows<'a, const N: usize>(&'a self) -> ArrayWindows<'a, T, N> { - ArrayWindows{ idx: 0, slice: &self } + fn array_windows_example<'a, const N: usize>(&'a self) -> ArrayWindowsExample<'a, T, N> { + ArrayWindowsExample{ idx: 0, slice: &self } } } -struct ArrayWindows<'a, T, const N: usize> { +struct ArrayWindowsExample<'a, T, const N: usize> { slice: &'a [T], idx: usize, } -impl <'a, T: Clone, const N: usize> Iterator for ArrayWindows<'a, T, N> { +impl <'a, T: Clone, const N: usize> Iterator for ArrayWindowsExample<'a, T, N> { type Item = [T; N]; fn next(&mut self) -> Option { // Note: this is unsound for some `T` and not meant as an example @@ -45,7 +45,7 @@ const FOUR: usize = 4; fn main() { let v: Vec = vec![0; 100]; - for array in v.as_slice().array_windows::() { + for array in v.as_slice().array_windows_example::() { assert_eq!(array, [0, 0, 0, 0]) } } From 5c29332ace48d8c34ad415ffcdce2641526938b8 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Wed, 16 Sep 2020 08:10:06 -0700 Subject: [PATCH 0496/1052] Make graphviz font configurable Alternative to PR ##76776. To change the graphviz output to use an alternative `fontname` value, add a command line option like: `rustc --graphviz-font=monospace`. --- compiler/rustc_graphviz/src/lib.rs | 17 ++++++++++------- .../rustc_mir/src/dataflow/framework/engine.rs | 3 ++- compiler/rustc_mir/src/util/graphviz.rs | 6 +++--- compiler/rustc_session/src/options.rs | 2 ++ 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs index 29ec3572016d7..58db81bc1dc61 100644 --- a/compiler/rustc_graphviz/src/lib.rs +++ b/compiler/rustc_graphviz/src/lib.rs @@ -591,14 +591,14 @@ pub trait GraphWalk<'a> { fn target(&'a self, edge: &Self::Edge) -> Self::Node; } -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug)] pub enum RenderOption { NoEdgeLabels, NoNodeLabels, NoEdgeStyles, NoNodeStyles, - Monospace, + Fontname(String), DarkTheme, } @@ -633,11 +633,14 @@ where // Global graph properties let mut graph_attrs = Vec::new(); let mut content_attrs = Vec::new(); - if options.contains(&RenderOption::Monospace) { - let font = r#"fontname="Courier, monospace""#; - graph_attrs.push(font); - content_attrs.push(font); - }; + let font; + if let Some(fontname) = options.iter().find_map(|option| { + if let RenderOption::Fontname(fontname) = option { Some(fontname) } else { None } + }) { + font = format!(r#"fontname="{}""#, fontname); + graph_attrs.push(&font[..]); + content_attrs.push(&font[..]); + } if options.contains(&RenderOption::DarkTheme) { graph_attrs.push(r#"bgcolor="black""#); content_attrs.push(r#"color="white""#); diff --git a/compiler/rustc_mir/src/dataflow/framework/engine.rs b/compiler/rustc_mir/src/dataflow/framework/engine.rs index 0b5b437d186aa..4084083bd9956 100644 --- a/compiler/rustc_mir/src/dataflow/framework/engine.rs +++ b/compiler/rustc_mir/src/dataflow/framework/engine.rs @@ -306,7 +306,8 @@ where let mut buf = Vec::new(); let graphviz = graphviz::Formatter::new(body, def_id, results, style); - let mut render_opts = vec![dot::RenderOption::Monospace]; + let mut render_opts = + vec![dot::RenderOption::Fontname(tcx.sess.opts.debugging_opts.graphviz_font.clone())]; if tcx.sess.opts.debugging_opts.graphviz_dark_mode { render_opts.push(dot::RenderOption::DarkTheme); } diff --git a/compiler/rustc_mir/src/util/graphviz.rs b/compiler/rustc_mir/src/util/graphviz.rs index e89c943770638..4511962d68f03 100644 --- a/compiler/rustc_mir/src/util/graphviz.rs +++ b/compiler/rustc_mir/src/util/graphviz.rs @@ -55,9 +55,9 @@ where writeln!(w, "{} {}Mir_{} {{", kind, cluster, def_name)?; // Global graph properties - let font = r#"fontname="Courier, monospace""#; - let mut graph_attrs = vec![font]; - let mut content_attrs = vec![font]; + let font = format!(r#"fontname="{}""#, tcx.sess.opts.debugging_opts.graphviz_font); + let mut graph_attrs = vec![&font[..]]; + let mut content_attrs = vec![&font[..]]; let dark_mode = tcx.sess.opts.debugging_opts.graphviz_dark_mode; if dark_mode { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index f31e0431d0da7..60bd557b880eb 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -909,6 +909,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "set the optimization fuel quota for a crate"), graphviz_dark_mode: bool = (false, parse_bool, [UNTRACKED], "use dark-themed colors in graphviz output (default: no)"), + graphviz_font: String = ("Courier, monospace".to_string(), parse_string, [UNTRACKED], + "use the given `fontname` in graphviz output (default: `Courier, monospace`)"), hir_stats: bool = (false, parse_bool, [UNTRACKED], "print some statistics about AST and HIR (default: no)"), human_readable_cgu_names: bool = (false, parse_bool, [TRACKED], From b37e3cdd46e715cacf96522e753829a7991e6fdf Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Thu, 17 Sep 2020 00:06:43 +0900 Subject: [PATCH 0497/1052] Update documentation about moving from Discord to Zulip --- CONTRIBUTING.md | 6 +++--- doc/adding_lints.md | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 54777810abbdf..100c9edb36724 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,7 +8,7 @@ something. We appreciate any sort of contributions, and don't want a wall of rul Clippy welcomes contributions from everyone. There are many ways to contribute to Clippy and the following document explains how you can contribute and how to get started. If you have any questions about contributing or need help with -anything, feel free to ask questions on issues or visit the `#clippy` on [Discord]. +anything, feel free to ask questions on issues or visit the `#clippy` on [Zulip]. All contributors are expected to follow the [Rust Code of Conduct]. @@ -23,7 +23,7 @@ All contributors are expected to follow the [Rust Code of Conduct]. - [Bors and Homu](#bors-and-homu) - [Contributions](#contributions) -[Discord]: https://discord.gg/rust-lang +[Zulip]: https://rust-lang.zulipchat.com/#narrow/stream/clippy [Rust Code of Conduct]: https://www.rust-lang.org/policies/code-of-conduct ## Getting started @@ -242,7 +242,7 @@ to be run inside the `rust` directory): ``` 3. Open a PR to `rust-lang/rust-clippy` and wait for it to get merged (to accelerate the process ping the `@rust-lang/clippy` team in your PR and/or - ~~annoy~~ ask them in the [Discord] channel.) + ~~annoy~~ ask them in the [Zulip] stream.) ### Syncing back changes in Clippy to [`rust-lang/rust`] diff --git a/doc/adding_lints.md b/doc/adding_lints.md index 3c782e9b17ff1..21e0f6f4fc766 100644 --- a/doc/adding_lints.md +++ b/doc/adding_lints.md @@ -488,7 +488,7 @@ For `LateLintPass` lints: While most of Clippy's lint utils are documented, most of rustc's internals lack documentation currently. This is unfortunate, but in most cases you can probably get away with copying things from existing similar lints. If you are stuck, -don't hesitate to ask on [Discord] or in the issue/PR. +don't hesitate to ask on [Zulip] or in the issue/PR. [utils]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/mod.rs [if_chain]: https://docs.rs/if_chain/*/if_chain/ @@ -500,4 +500,4 @@ don't hesitate to ask on [Discord] or in the issue/PR. [nightly_docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ [ast]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/index.html [ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/sty/index.html -[Discord]: https://discord.gg/rust-lang +[Zulip]: https://rust-lang.zulipchat.com/#narrow/stream/clippy From 0261e341fd435f0b42954510fb436cb0b289cdac Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Mon, 14 Sep 2020 14:58:39 -0400 Subject: [PATCH 0498/1052] {print,write}-with-newline: do not suggest empty format string --- clippy_lints/src/write.rs | 6 +++++- tests/ui/print_with_newline.rs | 1 + tests/ui/print_with_newline.stderr | 23 +++++++++++++++++------ tests/ui/write_with_newline.rs | 1 + tests/ui/write_with_newline.stderr | 23 +++++++++++++++++------ 5 files changed, 41 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index e653240d04917..fac63bcb99378 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -322,11 +322,15 @@ impl EarlyLintPass for Write { } /// Given a format string that ends in a newline and its span, calculates the span of the -/// newline. +/// newline, or the format string itself if the format string consists solely of a newline. fn newline_span(fmtstr: &StrLit) -> Span { let sp = fmtstr.span; let contents = &fmtstr.symbol.as_str(); + if *contents == r"\n" { + return sp; + } + let newline_sp_hi = sp.hi() - match fmtstr.style { StrStyle::Cooked => BytePos(1), diff --git a/tests/ui/print_with_newline.rs b/tests/ui/print_with_newline.rs index 3f710540e9038..a43a1fc4f5241 100644 --- a/tests/ui/print_with_newline.rs +++ b/tests/ui/print_with_newline.rs @@ -9,6 +9,7 @@ fn main() { print!("Hello {}\n", "world"); print!("Hello {} {}\n", "world", "#2"); print!("{}\n", 1265); + print!("\n"); // these are all fine print!(""); diff --git a/tests/ui/print_with_newline.stderr b/tests/ui/print_with_newline.stderr index 05fe88915d6ef..54b3ad75b31e8 100644 --- a/tests/ui/print_with_newline.stderr +++ b/tests/ui/print_with_newline.stderr @@ -44,7 +44,18 @@ LL | println!("{}", 1265); | ^^^^^^^ -- error: using `print!()` with a format string that ends in a single newline - --> $DIR/print_with_newline.rs:30:5 + --> $DIR/print_with_newline.rs:12:5 + | +LL | print!("/n"); + | ^^^^^^^^^^^^ + | +help: use `println!` instead + | +LL | println!(); + | ^^^^^^^ -- + +error: using `print!()` with a format string that ends in a single newline + --> $DIR/print_with_newline.rs:31:5 | LL | print!("//n"); // should fail | ^^^^^^^^^^^^^^ @@ -55,7 +66,7 @@ LL | println!("/"); // should fail | ^^^^^^^ -- error: using `print!()` with a format string that ends in a single newline - --> $DIR/print_with_newline.rs:37:5 + --> $DIR/print_with_newline.rs:38:5 | LL | / print!( LL | | " @@ -70,7 +81,7 @@ LL | "" | error: using `print!()` with a format string that ends in a single newline - --> $DIR/print_with_newline.rs:41:5 + --> $DIR/print_with_newline.rs:42:5 | LL | / print!( LL | | r" @@ -85,7 +96,7 @@ LL | r"" | error: using `print!()` with a format string that ends in a single newline - --> $DIR/print_with_newline.rs:49:5 + --> $DIR/print_with_newline.rs:50:5 | LL | print!("/r/n"); //~ ERROR | ^^^^^^^^^^^^^^^ @@ -96,7 +107,7 @@ LL | println!("/r"); //~ ERROR | ^^^^^^^ -- error: using `print!()` with a format string that ends in a single newline - --> $DIR/print_with_newline.rs:50:5 + --> $DIR/print_with_newline.rs:51:5 | LL | print!("foo/rbar/n") // ~ ERROR | ^^^^^^^^^^^^^^^^^^^^ @@ -106,5 +117,5 @@ help: use `println!` instead LL | println!("foo/rbar") // ~ ERROR | ^^^^^^^ -- -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors diff --git a/tests/ui/write_with_newline.rs b/tests/ui/write_with_newline.rs index 93afd73d1114d..1c1b1b58402e8 100644 --- a/tests/ui/write_with_newline.rs +++ b/tests/ui/write_with_newline.rs @@ -14,6 +14,7 @@ fn main() { write!(&mut v, "Hello {}\n", "world"); write!(&mut v, "Hello {} {}\n", "world", "#2"); write!(&mut v, "{}\n", 1265); + write!(&mut v, "\n"); // These should be fine write!(&mut v, ""); diff --git a/tests/ui/write_with_newline.stderr b/tests/ui/write_with_newline.stderr index 2473329ca7276..a14e86122ee5d 100644 --- a/tests/ui/write_with_newline.stderr +++ b/tests/ui/write_with_newline.stderr @@ -44,7 +44,18 @@ LL | writeln!(&mut v, "{}", 1265); | ^^^^^^^ -- error: using `write!()` with a format string that ends in a single newline - --> $DIR/write_with_newline.rs:35:5 + --> $DIR/write_with_newline.rs:17:5 + | +LL | write!(&mut v, "/n"); + | ^^^^^^^^^^^^^^^^^^^^ + | +help: use `writeln!()` instead + | +LL | writeln!(&mut v, ); + | ^^^^^^^ -- + +error: using `write!()` with a format string that ends in a single newline + --> $DIR/write_with_newline.rs:36:5 | LL | write!(&mut v, "//n"); // should fail | ^^^^^^^^^^^^^^^^^^^^^^ @@ -55,7 +66,7 @@ LL | writeln!(&mut v, "/"); // should fail | ^^^^^^^ -- error: using `write!()` with a format string that ends in a single newline - --> $DIR/write_with_newline.rs:42:5 + --> $DIR/write_with_newline.rs:43:5 | LL | / write!( LL | | &mut v, @@ -72,7 +83,7 @@ LL | "" | error: using `write!()` with a format string that ends in a single newline - --> $DIR/write_with_newline.rs:47:5 + --> $DIR/write_with_newline.rs:48:5 | LL | / write!( LL | | &mut v, @@ -89,7 +100,7 @@ LL | r"" | error: using `write!()` with a format string that ends in a single newline - --> $DIR/write_with_newline.rs:56:5 + --> $DIR/write_with_newline.rs:57:5 | LL | write!(&mut v, "/r/n"); //~ ERROR | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -100,7 +111,7 @@ LL | writeln!(&mut v, "/r"); //~ ERROR | ^^^^^^^ -- error: using `write!()` with a format string that ends in a single newline - --> $DIR/write_with_newline.rs:57:5 + --> $DIR/write_with_newline.rs:58:5 | LL | write!(&mut v, "foo/rbar/n"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -110,5 +121,5 @@ help: use `writeln!()` instead LL | writeln!(&mut v, "foo/rbar"); | ^^^^^^^ -- -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors From de0d55cb3c197b13d90922c8998bf90399f3b8a2 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 16 Sep 2020 08:42:39 -0700 Subject: [PATCH 0499/1052] library/panic_unwind: Add UNWIND_DATA_REG for RISC-V 32-bit Signed-off-by: Alistair Francis --- library/panic_unwind/src/gcc.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/panic_unwind/src/gcc.rs b/library/panic_unwind/src/gcc.rs index 85a2a18947db2..81b7b556eb4f0 100644 --- a/library/panic_unwind/src/gcc.rs +++ b/library/panic_unwind/src/gcc.rs @@ -123,6 +123,9 @@ const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 #[cfg(target_arch = "riscv64")] const UNWIND_DATA_REG: (i32, i32) = (10, 11); // x10, x11 +#[cfg(target_arch = "riscv32")] +const UNWIND_DATA_REG: (i32, i32) = (10, 11); // x10, x11 + // The following code is based on GCC's C and C++ personality routines. For reference, see: // https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc // https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c From 84fe26c4d33924d2195af4324f036b64709baba2 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 16 Sep 2020 08:43:54 -0700 Subject: [PATCH 0500/1052] library/std: linux: Add support for RISC-V 32-bit Signed-off-by: Alistair Francis --- library/std/src/os/linux/raw.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/std/src/os/linux/raw.rs b/library/std/src/os/linux/raw.rs index a007fd2b6be04..4ff3a6e578984 100644 --- a/library/std/src/os/linux/raw.rs +++ b/library/std/src/os/linux/raw.rs @@ -234,7 +234,8 @@ mod arch { target_arch = "mips64", target_arch = "s390x", target_arch = "sparc64", - target_arch = "riscv64" + target_arch = "riscv64", + target_arch = "riscv32" ))] mod arch { pub use libc::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t}; From cd066c9debeace035d02867a5b5b2d72197f1831 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 16 Sep 2020 08:44:35 -0700 Subject: [PATCH 0501/1052] library/std: raw: Add support for RISC-V 32-bit Signed-off-by: Alistair Francis --- library/std/src/os/raw/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/std/src/os/raw/mod.rs b/library/std/src/os/raw/mod.rs index 83e8853fe7923..16272aa05712f 100644 --- a/library/std/src/os/raw/mod.rs +++ b/library/std/src/os/raw/mod.rs @@ -22,7 +22,8 @@ mod tests; target_arch = "powerpc", target_arch = "powerpc64", target_arch = "s390x", - target_arch = "riscv64" + target_arch = "riscv64", + target_arch = "riscv32" ) ), all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), @@ -65,7 +66,8 @@ pub type c_char = u8; target_arch = "powerpc", target_arch = "powerpc64", target_arch = "s390x", - target_arch = "riscv64" + target_arch = "riscv64", + target_arch = "riscv32" ) ), all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), From cf075355da15c9fb0b1c975649dd13759a78a2bd Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 16 Sep 2020 08:45:08 -0700 Subject: [PATCH 0502/1052] library/std: sys_common: Add support for RISC-V 32-bit Signed-off-by: Alistair Francis --- library/std/src/sys_common/alloc.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys_common/alloc.rs b/library/std/src/sys_common/alloc.rs index c669410078592..f22476be32560 100644 --- a/library/std/src/sys_common/alloc.rs +++ b/library/std/src/sys_common/alloc.rs @@ -14,7 +14,8 @@ use crate::ptr; target_arch = "powerpc64", target_arch = "asmjs", target_arch = "wasm32", - target_arch = "hexagon" + target_arch = "hexagon", + target_arch = "riscv32" )))] pub const MIN_ALIGN: usize = 8; #[cfg(all(any( From 0f3ccbd662977d9434f8478a379f292c5bb72a8c Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 16 Sep 2020 08:45:49 -0700 Subject: [PATCH 0503/1052] library/unwind: Add support for RISC-V 32-bit Signed-off-by: Alistair Francis --- library/unwind/src/libunwind.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index 0c57861f70a82..2d65ded390916 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -57,6 +57,9 @@ pub const unwinder_private_data_size: usize = 2; #[cfg(target_arch = "riscv64")] pub const unwinder_private_data_size: usize = 2; +#[cfg(target_arch = "riscv32")] +pub const unwinder_private_data_size: usize = 2; + #[cfg(target_os = "emscripten")] pub const unwinder_private_data_size: usize = 20; From be372657089da3b7e88c2baaa44b0b833f3a31d3 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Wed, 16 Sep 2020 12:00:56 -0400 Subject: [PATCH 0504/1052] Give a better error message when x.py uses the wrong stage for CI --- src/bootstrap/config.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 30c9e012cd6f5..913104ff9e3dc 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -616,7 +616,13 @@ impl Config { | Subcommand::Build { .. } | Subcommand::Bench { .. } | Subcommand::Dist { .. } - | Subcommand::Install { .. } => assert_eq!(config.stage, 2), + | Subcommand::Install { .. } => { + assert_eq!( + config.stage, 2, + "x.py should be run with `--stage 2` on CI, but was run with `--stage {}`", + config.stage, + ); + } Subcommand::Clean { .. } | Subcommand::Check { .. } | Subcommand::Clippy { .. } From 3e942958536aad794cec08a2d2b8d6f125e36bb4 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 16 Sep 2020 09:37:00 -0700 Subject: [PATCH 0505/1052] tools/build-manifest: Add support for RISC-V 32-bit Signed-off-by: Alistair Francis --- src/tools/build-manifest/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 58022484fa6cc..1e86f7a4737cc 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -110,6 +110,7 @@ static TARGETS: &[&str] = &[ "riscv32i-unknown-none-elf", "riscv32imc-unknown-none-elf", "riscv32imac-unknown-none-elf", + "riscv32gc-unknown-linux-gnu", "riscv64imac-unknown-none-elf", "riscv64gc-unknown-none-elf", "riscv64gc-unknown-linux-gnu", From 1d930483247bac3dd7df3470abd5432d198fe755 Mon Sep 17 00:00:00 2001 From: Gus Wynn Date: Tue, 15 Sep 2020 09:56:17 -0700 Subject: [PATCH 0506/1052] give better suggestion when matching a const range --- compiler/rustc_typeck/src/check/pat.rs | 53 +++++++++++++++++++++----- src/test/ui/issues/issue-76191.rs | 5 +++ src/test/ui/issues/issue-76191.stderr | 26 ++++++++++++- 3 files changed, 73 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 6be2fdf9f1904..3b1559dfcf5ef 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -772,12 +772,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } _ => { - let const_def_id = match pat_ty.kind() { + let (type_def_id, item_def_id) = match pat_ty.kind() { Adt(def, _) => match res { - Res::Def(DefKind::Const, _) => Some(def.did), - _ => None, + Res::Def(DefKind::Const, def_id) => (Some(def.did), Some(def_id)), + _ => (None, None), }, - _ => None, + _ => (None, None), }; let ranges = &[ @@ -788,11 +788,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.lang_items().range_inclusive_struct(), self.tcx.lang_items().range_to_inclusive_struct(), ]; - if const_def_id != None && ranges.contains(&const_def_id) { - let msg = "constants only support matching by type, \ - if you meant to match against a range of values, \ - consider using a range pattern like `min ..= max` in the match block"; - e.note(msg); + if type_def_id != None && ranges.contains(&type_def_id) { + let generic_message = match item_def_id { + Some(def_id) => match self.tcx.hir().get_if_local(def_id) { + Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Const(_, body_id), + .. + })) => match self.tcx.hir().get(body_id.hir_id) { + hir::Node::Expr(expr) => { + if hir::is_range_literal(expr) { + let span = self.tcx.hir().span(body_id.hir_id); + if let Ok(snip) = + self.tcx.sess.source_map().span_to_snippet(span) + { + e.span_suggestion_verbose( + span, + "you may want to move the range into the match block", + snip, + Applicability::MachineApplicable + ); + false + } else { + true + } + } else { + true + } + } + _ => true, + }, + _ => true, + }, + _ => true, + }; + + if generic_message { + let msg = "constants only support matching by type, \ + if you meant to match against a range of values, \ + consider using a range pattern like `min ..= max` in the match block"; + e.note(msg); + } } else { let msg = "introduce a new binding instead"; let sugg = format!("other_{}", ident.as_str().to_lowercase()); diff --git a/src/test/ui/issues/issue-76191.rs b/src/test/ui/issues/issue-76191.rs index bc327123c6fe9..d9790d2b56e28 100644 --- a/src/test/ui/issues/issue-76191.rs +++ b/src/test/ui/issues/issue-76191.rs @@ -2,13 +2,18 @@ #![allow(non_snake_case)] use std::ops::RangeInclusive; + const RANGE: RangeInclusive = 0..=255; +const RANGE2: RangeInclusive = panic!(); + fn main() { let n: i32 = 1; match n { RANGE => {} //~^ ERROR mismatched types + RANGE2 => {} + //~^ ERROR mismatched types _ => {} } } diff --git a/src/test/ui/issues/issue-76191.stderr b/src/test/ui/issues/issue-76191.stderr index a5544d9e9da40..61f4be81f43a4 100644 --- a/src/test/ui/issues/issue-76191.stderr +++ b/src/test/ui/issues/issue-76191.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-76191.rs:10:9 + --> $DIR/issue-76191.rs:13:9 | LL | const RANGE: RangeInclusive = 0..=255; | ------------------------------------------- constant defined here @@ -14,8 +14,30 @@ LL | RANGE => {} | = note: expected type `i32` found struct `RangeInclusive` +help: you may want to move the range into the match block + | +LL | const RANGE: RangeInclusive = 0..=255; + | ^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/issue-76191.rs:15:9 + | +LL | const RANGE2: RangeInclusive = panic!(); + | --------------------------------------------- constant defined here +... +LL | match n { + | - this expression has type `i32` +... +LL | RANGE2 => {} + | ^^^^^^ + | | + | expected `i32`, found struct `RangeInclusive` + | `RANGE2` is interpreted as a constant, not a new binding + | + = note: expected type `i32` + found struct `RangeInclusive` = note: constants only support matching by type, if you meant to match against a range of values, consider using a range pattern like `min ..= max` in the match block -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. From c35ce3ff170333d11ccf89e75dc87c49f44a570a Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Wed, 16 Sep 2020 13:31:20 -0400 Subject: [PATCH 0507/1052] Don't generate bootstrap usage unless it's needed Previously, `x.py` would unconditionally run `x.py build` to get the help message. After https://github.com/rust-lang/rust/issues/76165, when checking the CI stage was moved into `Config`, that would cause an assertion failure (but only only in CI!): ``` thread 'main' panicked at 'assertion failed: `(left == right)` left: `1`, right: `2`', src/bootstrap/config.rs:619:49 ``` This changes bootstrap to only generate a help message when it needs to (when someone passes `--help`). --- src/bootstrap/flags.rs | 62 ++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index ff8468574469e..842c84a3e5cd6 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -98,7 +98,6 @@ impl Default for Subcommand { impl Flags { pub fn parse(args: &[String]) -> Flags { - let mut extra_help = String::new(); let mut subcommand_help = String::from( "\ Usage: x.py [options] [...] @@ -170,16 +169,6 @@ To learn more about a subcommand, run `./x.py -h`", "VALUE", ); - // fn usage() - let usage = - |exit_code: i32, opts: &Options, subcommand_help: &str, extra_help: &str| -> ! { - println!("{}", opts.usage(subcommand_help)); - if !extra_help.is_empty() { - println!("{}", extra_help); - } - process::exit(exit_code); - }; - // We can't use getopt to parse the options until we have completed specifying which // options are valid, but under the current implementation, some options are conditional on // the subcommand. Therefore we must manually identify the subcommand first, so that we can @@ -263,12 +252,38 @@ To learn more about a subcommand, run `./x.py -h`", _ => {} }; + // fn usage() + let usage = |exit_code: i32, opts: &Options, verbose: bool, subcommand_help: &str| -> ! { + let mut extra_help = String::new(); + + // All subcommands except `clean` can have an optional "Available paths" section + if verbose { + let config = Config::parse(&["build".to_string()]); + let build = Build::new(config); + + let maybe_rules_help = Builder::get_help(&build, subcommand.as_str()); + extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str()); + } else if !(subcommand.as_str() == "clean" || subcommand.as_str() == "fmt") { + extra_help.push_str( + format!("Run `./x.py {} -h -v` to see a list of available paths.", subcommand) + .as_str(), + ); + } + + println!("{}", opts.usage(subcommand_help)); + if !extra_help.is_empty() { + println!("{}", extra_help); + } + process::exit(exit_code); + }; + // Done specifying what options are possible, so do the getopts parsing let matches = opts.parse(&args[..]).unwrap_or_else(|e| { // Invalid argument/option format println!("\n{}\n", e); - usage(1, &opts, &subcommand_help, &extra_help); + usage(1, &opts, false, &subcommand_help); }); + // Extra sanity check to make sure we didn't hit this crazy corner case: // // ./x.py --frobulate clean build @@ -436,24 +451,11 @@ Arguments: let paths = matches.free[1..].iter().map(|p| p.into()).collect::>(); let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from); - - // All subcommands except `clean` can have an optional "Available paths" section - if matches.opt_present("verbose") { - let config = Config::parse(&["build".to_string()]); - let build = Build::new(config); - - let maybe_rules_help = Builder::get_help(&build, subcommand.as_str()); - extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str()); - } else if !(subcommand.as_str() == "clean" || subcommand.as_str() == "fmt") { - extra_help.push_str( - format!("Run `./x.py {} -h -v` to see a list of available paths.", subcommand) - .as_str(), - ); - } + let verbose = matches.opt_present("verbose"); // User passed in -h/--help? if matches.opt_present("help") { - usage(0, &opts, &subcommand_help, &extra_help); + usage(0, &opts, verbose, &subcommand_help); } let cmd = match subcommand.as_str() { @@ -483,7 +485,7 @@ Arguments: "clean" => { if !paths.is_empty() { println!("\nclean does not take a path argument\n"); - usage(1, &opts, &subcommand_help, &extra_help); + usage(1, &opts, verbose, &subcommand_help); } Subcommand::Clean { all: matches.opt_present("all") } @@ -494,12 +496,12 @@ Arguments: "run" | "r" => { if paths.is_empty() { println!("\nrun requires at least a path!\n"); - usage(1, &opts, &subcommand_help, &extra_help); + usage(1, &opts, verbose, &subcommand_help); } Subcommand::Run { paths } } _ => { - usage(1, &opts, &subcommand_help, &extra_help); + usage(1, &opts, verbose, &subcommand_help); } }; From 70292d45060ee2b8829e2af0be54d5a76696cd1d Mon Sep 17 00:00:00 2001 From: Federico Ponzi Date: Wed, 16 Sep 2020 19:40:44 +0200 Subject: [PATCH 0508/1052] Sets as_flags as unstable --- library/std/src/sys/unix/ext/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/ext/fs.rs b/library/std/src/sys/unix/ext/fs.rs index 16fe316110d94..afcd80abb9d27 100644 --- a/library/std/src/sys/unix/ext/fs.rs +++ b/library/std/src/sys/unix/ext/fs.rs @@ -367,7 +367,7 @@ pub trait OpenOptionsExt { /// let file_name = CString::new("foo.txt").unwrap(); /// let file = unsafe { libc::open(file_name.as_c_str().as_ptr(), options.as_flags().unwrap()) }; /// ``` - #[stable(feature = "open_options_ext_as_flags", since = "1.47.0")] + #[unstable(feature = "open_options_ext_as_flags", issue = "76801")] fn as_flags(&self) -> io::Result; } From 79da7474b160e2230467f84ff0df3a23658eb4a6 Mon Sep 17 00:00:00 2001 From: Tim Nielens Date: Wed, 16 Sep 2020 19:59:51 +0200 Subject: [PATCH 0509/1052] option_if_let_else - change misleading test file section --- tests/ui/unnecessary_lazy_eval.fixed | 7 ++++--- tests/ui/unnecessary_lazy_eval.rs | 7 ++++--- tests/ui/unnecessary_lazy_eval.stderr | 12 ++++++------ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/tests/ui/unnecessary_lazy_eval.fixed b/tests/ui/unnecessary_lazy_eval.fixed index 4980c1114999c..4ba2a0a5dbcc1 100644 --- a/tests/ui/unnecessary_lazy_eval.fixed +++ b/tests/ui/unnecessary_lazy_eval.fixed @@ -108,9 +108,6 @@ fn main() { let _: Result = res.or_else(|_| Err(ext_str.some_field)); // should lint, bind_instead_of_map doesn't apply - let _: Result = res.and_then(|x| Err(x)); - let _: Result = res.or_else(|err| Ok(err)); - let _: Result = res.and(Err(2)); let _: Result = res.and(Err(astronomers_pi)); let _: Result = res.and(Err(ext_str.some_field)); @@ -118,4 +115,8 @@ fn main() { let _: Result = res.or(Ok(2)); let _: Result = res.or(Ok(astronomers_pi)); let _: Result = res.or(Ok(ext_str.some_field)); + + // neither bind_instead_of_map nor unnecessary_lazy_eval applies here + let _: Result = res.and_then(|x| Err(x)); + let _: Result = res.or_else(|err| Ok(err)); } diff --git a/tests/ui/unnecessary_lazy_eval.rs b/tests/ui/unnecessary_lazy_eval.rs index 0b270939ec20a..466915217e42e 100644 --- a/tests/ui/unnecessary_lazy_eval.rs +++ b/tests/ui/unnecessary_lazy_eval.rs @@ -108,9 +108,6 @@ fn main() { let _: Result = res.or_else(|_| Err(ext_str.some_field)); // should lint, bind_instead_of_map doesn't apply - let _: Result = res.and_then(|x| Err(x)); - let _: Result = res.or_else(|err| Ok(err)); - let _: Result = res.and_then(|_| Err(2)); let _: Result = res.and_then(|_| Err(astronomers_pi)); let _: Result = res.and_then(|_| Err(ext_str.some_field)); @@ -118,4 +115,8 @@ fn main() { let _: Result = res.or_else(|_| Ok(2)); let _: Result = res.or_else(|_| Ok(astronomers_pi)); let _: Result = res.or_else(|_| Ok(ext_str.some_field)); + + // neither bind_instead_of_map nor unnecessary_lazy_eval applies here + let _: Result = res.and_then(|x| Err(x)); + let _: Result = res.or_else(|err| Ok(err)); } diff --git a/tests/ui/unnecessary_lazy_eval.stderr b/tests/ui/unnecessary_lazy_eval.stderr index 1cf7ac46346db..44dcd0cafbb6e 100644 --- a/tests/ui/unnecessary_lazy_eval.stderr +++ b/tests/ui/unnecessary_lazy_eval.stderr @@ -157,37 +157,37 @@ LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:114:35 + --> $DIR/unnecessary_lazy_eval.rs:111:35 | LL | let _: Result = res.and_then(|_| Err(2)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `res.and(Err(2))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:115:35 + --> $DIR/unnecessary_lazy_eval.rs:112:35 | LL | let _: Result = res.and_then(|_| Err(astronomers_pi)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `res.and(Err(astronomers_pi))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:116:35 + --> $DIR/unnecessary_lazy_eval.rs:113:35 | LL | let _: Result = res.and_then(|_| Err(ext_str.some_field)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `res.and(Err(ext_str.some_field))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:118:35 + --> $DIR/unnecessary_lazy_eval.rs:115:35 | LL | let _: Result = res.or_else(|_| Ok(2)); | ^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `res.or(Ok(2))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:119:35 + --> $DIR/unnecessary_lazy_eval.rs:116:35 | LL | let _: Result = res.or_else(|_| Ok(astronomers_pi)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `res.or(Ok(astronomers_pi))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:120:35 + --> $DIR/unnecessary_lazy_eval.rs:117:35 | LL | let _: Result = res.or_else(|_| Ok(ext_str.some_field)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `res.or(Ok(ext_str.some_field))` From 3875abe32f6b98449bf2ec99ed210b7b77953703 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Wed, 16 Sep 2020 10:47:56 -0700 Subject: [PATCH 0510/1052] Added RUSTC_GRAPHVIZ_FONT environment variable Overrides the debugging_opts.graphviz_font setting. --- compiler/rustc_session/src/config.rs | 4 ++++ compiler/rustc_session/src/options.rs | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 19cd238599210..b0d39b95313cc 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1762,6 +1762,10 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { debugging_opts.symbol_mangling_version = SymbolManglingVersion::V0; } + if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") { + debugging_opts.graphviz_font = graphviz_font; + } + if !cg.embed_bitcode { match cg.lto { LtoCli::No | LtoCli::Unspecified => {} diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 60bd557b880eb..4d35ec2e5d97b 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -910,7 +910,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, graphviz_dark_mode: bool = (false, parse_bool, [UNTRACKED], "use dark-themed colors in graphviz output (default: no)"), graphviz_font: String = ("Courier, monospace".to_string(), parse_string, [UNTRACKED], - "use the given `fontname` in graphviz output (default: `Courier, monospace`)"), + "use the given `fontname` in graphviz output; can be overridden by setting \ + environment variable `RUSTC_GRAPHVIZ_FONT` (default: `Courier, monospace`)"), hir_stats: bool = (false, parse_bool, [UNTRACKED], "print some statistics about AST and HIR (default: no)"), human_readable_cgu_names: bool = (false, parse_bool, [TRACKED], From 3fadc603ab3fba157dfa7001fd9122692f40746a Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 16 Sep 2020 21:09:53 +0200 Subject: [PATCH 0511/1052] Don't use `mut` in Windows Mutex. --- library/std/src/sys/windows/mutex.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/library/std/src/sys/windows/mutex.rs b/library/std/src/sys/windows/mutex.rs index f2c57025a55ba..518f8e0f711f0 100644 --- a/library/std/src/sys/windows/mutex.rs +++ b/library/std/src/sys/windows/mutex.rs @@ -64,7 +64,7 @@ impl Mutex { match kind() { Kind::SRWLock => c::AcquireSRWLockExclusive(raw(self)), Kind::CriticalSection => { - let inner = &mut *self.inner(); + let inner = &*self.inner(); inner.remutex.lock(); if inner.held.replace(true) { // It was already locked, so we got a recursive lock which we do not want. @@ -78,7 +78,7 @@ impl Mutex { match kind() { Kind::SRWLock => c::TryAcquireSRWLockExclusive(raw(self)) != 0, Kind::CriticalSection => { - let inner = &mut *self.inner(); + let inner = &*self.inner(); if !inner.remutex.try_lock() { false } else if inner.held.replace(true) { @@ -95,7 +95,7 @@ impl Mutex { match kind() { Kind::SRWLock => c::ReleaseSRWLockExclusive(raw(self)), Kind::CriticalSection => { - let inner = &mut *(self.lock.load(Ordering::SeqCst) as *mut Inner); + let inner = &*(self.lock.load(Ordering::SeqCst) as *const Inner); inner.held.set(false); inner.remutex.unlock(); } @@ -106,17 +106,15 @@ impl Mutex { Kind::SRWLock => {} Kind::CriticalSection => match self.lock.load(Ordering::SeqCst) { 0 => {} - n => { - Box::from_raw(n as *mut Inner).remutex.destroy(); - } + n => Box::from_raw(n as *mut Inner).remutex.destroy(), }, } } - unsafe fn inner(&self) -> *mut Inner { + unsafe fn inner(&self) -> *const Inner { match self.lock.load(Ordering::SeqCst) { 0 => {} - n => return n as *mut _, + n => return n as *const _, } let inner = box Inner { remutex: ReentrantMutex::uninitialized(), held: Cell::new(false) }; inner.remutex.init(); @@ -125,7 +123,7 @@ impl Mutex { 0 => inner, n => { Box::from_raw(inner).remutex.destroy(); - n as *mut _ + n as *const _ } } } From 0bb96e7490299977abf2d3af16dd752d67ca43a9 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 16 Sep 2020 21:16:32 +0200 Subject: [PATCH 0512/1052] Avoid creating `&mut`s in Windows ReentrantMutex. --- library/std/src/lib.rs | 1 + library/std/src/sys/windows/mutex.rs | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 307e222f713b7..9ffe0d68c3aeb 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -315,6 +315,7 @@ #![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(unsafe_block_in_unsafe_fn)] +#![feature(unsafe_cell_raw_get)] #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(vec_into_raw_parts)] diff --git a/library/std/src/sys/windows/mutex.rs b/library/std/src/sys/windows/mutex.rs index 518f8e0f711f0..1e09b95c87285 100644 --- a/library/std/src/sys/windows/mutex.rs +++ b/library/std/src/sys/windows/mutex.rs @@ -148,7 +148,7 @@ fn kind() -> Kind { } pub struct ReentrantMutex { - inner: UnsafeCell>, + inner: MaybeUninit>, } unsafe impl Send for ReentrantMutex {} @@ -156,27 +156,27 @@ unsafe impl Sync for ReentrantMutex {} impl ReentrantMutex { pub const fn uninitialized() -> ReentrantMutex { - ReentrantMutex { inner: UnsafeCell::new(MaybeUninit::uninit()) } + ReentrantMutex { inner: MaybeUninit::uninit() } } pub unsafe fn init(&self) { - c::InitializeCriticalSection((&mut *self.inner.get()).as_mut_ptr()); + c::InitializeCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr())); } pub unsafe fn lock(&self) { - c::EnterCriticalSection((&mut *self.inner.get()).as_mut_ptr()); + c::EnterCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr())); } #[inline] pub unsafe fn try_lock(&self) -> bool { - c::TryEnterCriticalSection((&mut *self.inner.get()).as_mut_ptr()) != 0 + c::TryEnterCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr())) != 0 } pub unsafe fn unlock(&self) { - c::LeaveCriticalSection((&mut *self.inner.get()).as_mut_ptr()); + c::LeaveCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr())); } pub unsafe fn destroy(&self) { - c::DeleteCriticalSection((&mut *self.inner.get()).as_mut_ptr()); + c::DeleteCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr())); } } From 230355f25f10306211a80040bec1561545715383 Mon Sep 17 00:00:00 2001 From: Gus Wynn Date: Wed, 16 Sep 2020 12:32:10 -0700 Subject: [PATCH 0513/1052] comments and factor to own method --- compiler/rustc_typeck/src/check/pat.rs | 70 +++++++++++++------------- src/test/ui/issues/issue-76191.stderr | 4 +- 2 files changed, 38 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 3b1559dfcf5ef..713717cfe1a54 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -1,5 +1,6 @@ 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}; @@ -740,6 +741,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat_ty } + fn maybe_suggest_range_literal( + &self, + e: &mut DiagnosticBuilder<'_>, + opt_def_id: Option, + ident: Ident, + ) -> bool { + match opt_def_id { + Some(def_id) => match self.tcx.hir().get_if_local(def_id) { + Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Const(_, body_id), .. + })) => match self.tcx.hir().get(body_id.hir_id) { + hir::Node::Expr(expr) => { + if hir::is_range_literal(expr) { + let span = self.tcx.hir().span(body_id.hir_id); + if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span) { + e.span_suggestion_verbose( + ident.span, + "you may want to move the range into the match block", + snip, + Applicability::MachineApplicable, + ); + return true; + } + } + } + _ => (), + }, + _ => (), + }, + _ => (), + } + false + } + fn emit_bad_pat_path( &self, mut e: DiagnosticBuilder<'_>, @@ -789,40 +824,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.lang_items().range_to_inclusive_struct(), ]; if type_def_id != None && ranges.contains(&type_def_id) { - let generic_message = match item_def_id { - Some(def_id) => match self.tcx.hir().get_if_local(def_id) { - Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Const(_, body_id), - .. - })) => match self.tcx.hir().get(body_id.hir_id) { - hir::Node::Expr(expr) => { - if hir::is_range_literal(expr) { - let span = self.tcx.hir().span(body_id.hir_id); - if let Ok(snip) = - self.tcx.sess.source_map().span_to_snippet(span) - { - e.span_suggestion_verbose( - span, - "you may want to move the range into the match block", - snip, - Applicability::MachineApplicable - ); - false - } else { - true - } - } else { - true - } - } - _ => true, - }, - _ => true, - }, - _ => true, - }; - - if generic_message { + if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) { let msg = "constants only support matching by type, \ if you meant to match against a range of values, \ consider using a range pattern like `min ..= max` in the match block"; diff --git a/src/test/ui/issues/issue-76191.stderr b/src/test/ui/issues/issue-76191.stderr index 61f4be81f43a4..bdcd2fe1adc5a 100644 --- a/src/test/ui/issues/issue-76191.stderr +++ b/src/test/ui/issues/issue-76191.stderr @@ -16,8 +16,8 @@ LL | RANGE => {} found struct `RangeInclusive` help: you may want to move the range into the match block | -LL | const RANGE: RangeInclusive = 0..=255; - | ^^^^^^^ +LL | 0..=255 => {} + | ^^^^^^^ error[E0308]: mismatched types --> $DIR/issue-76191.rs:15:9 From 1d2290ffb0f8f85c8de56c17e6be748d84dcfb04 Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Wed, 16 Sep 2020 22:20:23 +0200 Subject: [PATCH 0514/1052] Update LLVM --- src/llvm-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm-project b/src/llvm-project index 833dd1e3d4fd3..a78defc24c739 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 833dd1e3d4fd350c7c9f6fb2ce0c5f16af7a1e21 +Subproject commit a78defc24c73930246db65fcabbca86a3df684c4 From 94dae6004035c356b00dac8764c1b4808d740928 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Wed, 16 Sep 2020 23:09:57 +0200 Subject: [PATCH 0515/1052] simplfy condition in ItemLowerer::with_trait_impl_ref() --- compiler/rustc_ast_lowering/src/item.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 6d41b7836b121..617cacee0e7f1 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -27,7 +27,7 @@ pub(super) struct ItemLowerer<'a, 'lowering, 'hir> { impl ItemLowerer<'_, '_, '_> { fn with_trait_impl_ref(&mut self, impl_ref: &Option, f: impl FnOnce(&mut Self)) { let old = self.lctx.is_in_trait_impl; - self.lctx.is_in_trait_impl = if let &None = impl_ref { false } else { true }; + self.lctx.is_in_trait_impl = impl_ref.is_some(); f(self); self.lctx.is_in_trait_impl = old; } From ed6c7efd87f17a7d9282f4bc7341cb5cbda8db4d Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 2 Sep 2020 13:25:19 -0700 Subject: [PATCH 0516/1052] Use enum for status of non-const ops --- .../src/transform/check_consts/ops.rs | 112 ++++++++++-------- 1 file changed, 61 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index ea025f208e49d..ff27d0c3a9211 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -14,35 +14,32 @@ use super::ConstCx; pub fn non_const(ccx: &ConstCx<'_, '_>, op: O, span: Span) { debug!("illegal_op: op={:?}", op); - if op.is_allowed_in_item(ccx) { - return; - } + let gate = match op.status_in_item(ccx) { + Status::Allowed => return, + Status::Unstable(gate) if ccx.tcx.features().enabled(gate) => return, + Status::Unstable(gate) => Some(gate), + Status::Forbidden => None, + }; if ccx.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you { - ccx.tcx.sess.miri_unleashed_feature(span, O::feature_gate()); + ccx.tcx.sess.miri_unleashed_feature(span, gate); return; } op.emit_error(ccx, span); } +pub enum Status { + Allowed, + Unstable(Symbol), + Forbidden, +} + /// An operation that is not *always* allowed in a const context. pub trait NonConstOp: std::fmt::Debug { - /// Returns the `Symbol` corresponding to the feature gate that would enable this operation, - /// or `None` if such a feature gate does not exist. - fn feature_gate() -> Option { - None - } - - /// Returns `true` if this operation is allowed in the given item. - /// - /// This check should assume that we are not in a non-const `fn`, where all operations are - /// legal. - /// - /// By default, it returns `true` if and only if this operation has a corresponding feature - /// gate and that gate is enabled. - fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool { - Self::feature_gate().map_or(false, |gate| ccx.tcx.features().enabled(gate)) + /// Returns an enum indicating whether this operation is allowed within the given item. + fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status { + Status::Forbidden } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { @@ -53,9 +50,13 @@ pub trait NonConstOp: std::fmt::Debug { "{} contains unimplemented expression type", ccx.const_kind() ); - if let Some(feat) = Self::feature_gate() { - err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feat)); + + if let Status::Unstable(gate) = self.status_in_item(ccx) { + if !ccx.tcx.features().enabled(gate) && nightly_options::is_nightly_build() { + err.help(&format!("add `#![feature({})]` to the crate attributes to enable", gate)); + } } + if ccx.tcx.sess.teach(&err.get_code().unwrap()) { err.note( "A function call isn't allowed in the const's initialization expression \ @@ -182,14 +183,13 @@ impl NonConstOp for CellBorrow { #[derive(Debug)] pub struct MutBorrow; impl NonConstOp for MutBorrow { - fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool { - // Forbid everywhere except in const fn - ccx.const_kind() == hir::ConstContext::ConstFn - && ccx.tcx.features().enabled(Self::feature_gate().unwrap()) - } - - fn feature_gate() -> Option { - Some(sym::const_mut_refs) + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + // Forbid everywhere except in const fn with a feature gate + if ccx.const_kind() == hir::ConstContext::ConstFn { + Status::Unstable(sym::const_mut_refs) + } else { + Status::Forbidden + } } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { @@ -201,15 +201,16 @@ impl NonConstOp for MutBorrow { &format!("mutable references are not allowed in {}s", ccx.const_kind()), ) } else { - struct_span_err!( + let mut err = struct_span_err!( ccx.tcx.sess, span, E0764, "mutable references are not allowed in {}s", ccx.const_kind(), - ) + ); + err.span_label(span, format!("`&mut` is only allowed in `const fn`")); + err }; - err.span_label(span, "`&mut` is only allowed in `const fn`".to_string()); if ccx.tcx.sess.teach(&err.get_code().unwrap()) { err.note( "References in statics and constants may only refer \ @@ -226,11 +227,17 @@ impl NonConstOp for MutBorrow { } } +// FIXME(ecstaticmorse): Unify this with `MutBorrow`. It has basically the same issues. #[derive(Debug)] pub struct MutAddressOf; impl NonConstOp for MutAddressOf { - fn feature_gate() -> Option { - Some(sym::const_mut_refs) + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + // Forbid everywhere except in const fn with a feature gate + if ccx.const_kind() == hir::ConstContext::ConstFn { + Status::Unstable(sym::const_mut_refs) + } else { + Status::Forbidden + } } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { @@ -247,16 +254,16 @@ impl NonConstOp for MutAddressOf { #[derive(Debug)] pub struct MutDeref; impl NonConstOp for MutDeref { - fn feature_gate() -> Option { - Some(sym::const_mut_refs) + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_mut_refs) } } #[derive(Debug)] pub struct Panic; impl NonConstOp for Panic { - fn feature_gate() -> Option { - Some(sym::const_panic) + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_panic) } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { @@ -289,8 +296,8 @@ impl NonConstOp for RawPtrComparison { #[derive(Debug)] pub struct RawPtrDeref; impl NonConstOp for RawPtrDeref { - fn feature_gate() -> Option { - Some(sym::const_raw_ptr_deref) + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_raw_ptr_deref) } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { @@ -307,8 +314,8 @@ impl NonConstOp for RawPtrDeref { #[derive(Debug)] pub struct RawPtrToIntCast; impl NonConstOp for RawPtrToIntCast { - fn feature_gate() -> Option { - Some(sym::const_raw_ptr_to_usize_cast) + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_raw_ptr_to_usize_cast) } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { @@ -326,8 +333,12 @@ impl NonConstOp for RawPtrToIntCast { #[derive(Debug)] pub struct StaticAccess; impl NonConstOp for StaticAccess { - fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool { - matches!(ccx.const_kind(), hir::ConstContext::Static(_)) + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + if let hir::ConstContext::Static(_) = ccx.const_kind() { + Status::Allowed + } else { + Status::Forbidden + } } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { @@ -371,14 +382,13 @@ impl NonConstOp for ThreadLocalAccess { #[derive(Debug)] pub struct UnionAccess; impl NonConstOp for UnionAccess { - fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool { + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { // Union accesses are stable in all contexts except `const fn`. - ccx.const_kind() != hir::ConstContext::ConstFn - || ccx.tcx.features().enabled(Self::feature_gate().unwrap()) - } - - fn feature_gate() -> Option { - Some(sym::const_fn_union) + if ccx.const_kind() != hir::ConstContext::ConstFn { + Status::Allowed + } else { + Status::Unstable(sym::const_fn_union) + } } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { From c3607bd7dd323a898b8cc9d2c603dfd14172c73c Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 2 Sep 2020 14:35:02 -0700 Subject: [PATCH 0517/1052] Use helper function for searching `allow_internal_unstable` --- compiler/rustc_mir/src/transform/check_consts/mod.rs | 8 ++++++++ compiler/rustc_mir/src/transform/qualify_min_const_fn.rs | 7 ++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/mod.rs b/compiler/rustc_mir/src/transform/check_consts/mod.rs index 81c1b0b5bd49f..c1b4cb5f1a8d5 100644 --- a/compiler/rustc_mir/src/transform/check_consts/mod.rs +++ b/compiler/rustc_mir/src/transform/check_consts/mod.rs @@ -4,10 +4,12 @@ //! has interior mutability or needs to be dropped, as well as the visitor that emits errors when //! it finds operations that are invalid in a certain context. +use rustc_attr as attr; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::mir; use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::Symbol; pub use self::qualifs::Qualif; @@ -55,3 +57,9 @@ impl ConstCx<'mir, 'tcx> { pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { Some(def_id) == tcx.lang_items().panic_fn() || Some(def_id) == tcx.lang_items().begin_panic_fn() } + +pub fn allow_internal_unstable(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool { + let attrs = tcx.get_attrs(def_id); + attr::allow_internal_unstable(&tcx.sess, attrs) + .map_or(false, |mut features| features.any(|name| name == feature_gate)) +} diff --git a/compiler/rustc_mir/src/transform/qualify_min_const_fn.rs b/compiler/rustc_mir/src/transform/qualify_min_const_fn.rs index 5e102f5151d0c..f15a7f7c2c889 100644 --- a/compiler/rustc_mir/src/transform/qualify_min_const_fn.rs +++ b/compiler/rustc_mir/src/transform/qualify_min_const_fn.rs @@ -1,4 +1,3 @@ -use rustc_attr as attr; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::mir::*; @@ -344,8 +343,7 @@ fn feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bo // However, we cannot allow stable `const fn`s to use unstable features without an explicit // opt-in via `allow_internal_unstable`. - attr::allow_internal_unstable(&tcx.sess, &tcx.get_attrs(def_id)) - .map_or(false, |mut features| features.any(|name| name == feature_gate)) + super::check_consts::allow_internal_unstable(tcx, def_id, feature_gate) } /// Returns `true` if the given library feature gate is allowed within the function with the given `DefId`. @@ -364,8 +362,7 @@ pub fn lib_feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbo // However, we cannot allow stable `const fn`s to use unstable features without an explicit // opt-in via `allow_internal_unstable`. - attr::allow_internal_unstable(&tcx.sess, &tcx.get_attrs(def_id)) - .map_or(false, |mut features| features.any(|name| name == feature_gate)) + super::check_consts::allow_internal_unstable(tcx, def_id, feature_gate) } fn check_terminator( From e4edc161f20ccbc77fffb7ceb60ebb6102cbd747 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 2 Sep 2020 14:54:55 -0700 Subject: [PATCH 0518/1052] Give name to extra `Span` in `LiveDrop` error --- compiler/rustc_mir/src/transform/check_consts/ops.rs | 6 ++++-- .../src/transform/check_consts/post_drop_elaboration.rs | 2 +- compiler/rustc_mir/src/transform/check_consts/validation.rs | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index ff27d0c3a9211..4af355310ae25 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -148,7 +148,9 @@ pub struct InlineAsm; impl NonConstOp for InlineAsm {} #[derive(Debug)] -pub struct LiveDrop(pub Option); +pub struct LiveDrop { + pub dropped_at: Option, +} impl NonConstOp for LiveDrop { fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { let mut diagnostic = struct_span_err!( @@ -158,7 +160,7 @@ impl NonConstOp for LiveDrop { "destructors cannot be evaluated at compile-time" ); diagnostic.span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind())); - if let Some(span) = self.0 { + if let Some(span) = self.dropped_at { diagnostic.span_label(span, "value is dropped here"); } diagnostic.emit(); diff --git a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs index 55075b3ab5e99..a2e5c905612aa 100644 --- a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs +++ b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs @@ -52,7 +52,7 @@ impl std::ops::Deref for CheckLiveDrops<'mir, 'tcx> { impl CheckLiveDrops<'mir, 'tcx> { fn check_live_drop(&self, span: Span) { - ops::non_const(self.ccx, ops::LiveDrop(None), span); + ops::non_const(self.ccx, ops::LiveDrop { dropped_at: None }, span); } } diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index e8411b121e394..ebba7f29663ed 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -576,7 +576,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { if needs_drop { self.check_op_spanned( - ops::LiveDrop(Some(terminator.source_info.span)), + ops::LiveDrop { dropped_at: Some(terminator.source_info.span) }, err_span, ); } From 81b3b66487c7001a0dbadf7f9af41ad714702533 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 2 Sep 2020 17:11:55 -0700 Subject: [PATCH 0519/1052] Error if an unstable const eval feature is used in a stable const fn --- .../src/transform/check_consts/ops.rs | 26 +++++++++++++++++-- .../check_consts/post_drop_elaboration.rs | 11 +++++--- .../src/transform/check_consts/validation.rs | 2 +- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index 4af355310ae25..032cbc23a3f52 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -1,6 +1,6 @@ //! Concrete error types for all operations which may be invalid in a certain const context. -use rustc_errors::struct_span_err; +use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_session::config::nightly_options; @@ -16,7 +16,29 @@ pub fn non_const(ccx: &ConstCx<'_, '_>, op: O, span: Span) { let gate = match op.status_in_item(ccx) { Status::Allowed => return, - Status::Unstable(gate) if ccx.tcx.features().enabled(gate) => return, + + Status::Unstable(gate) if ccx.tcx.features().enabled(gate) => { + let unstable_in_stable = ccx.const_kind() == hir::ConstContext::ConstFn + && ccx.tcx.features().enabled(sym::staged_api) + && !ccx.tcx.has_attr(ccx.def_id.to_def_id(), sym::rustc_const_unstable) + && !super::allow_internal_unstable(ccx.tcx, ccx.def_id.to_def_id(), gate); + + if unstable_in_stable { + ccx.tcx.sess + .struct_span_err(span, &format!("`#[feature({})]` cannot be depended on in a const-stable function", gate.as_str())) + .span_suggestion( + ccx.body.span, + "if it is not part of the public API, make this function unstably const", + concat!(r#"#[rustc_const_unstable(feature = "...", issue = "...")]"#, '\n').to_owned(), + Applicability::HasPlaceholders, + ) + .help("otherwise `#[allow_internal_unstable]` can be used to bypass stability checks") + .emit(); + } + + return; + } + Status::Unstable(gate) => Some(gate), Status::Forbidden => None, }; diff --git a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs index a2e5c905612aa..0228f2d7de023 100644 --- a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs +++ b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs @@ -2,7 +2,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::{self, BasicBlock, Location}; use rustc_middle::ty::TyCtxt; -use rustc_span::Span; +use rustc_span::{sym, Span}; use super::ops; use super::qualifs::{NeedsDrop, Qualif}; @@ -11,7 +11,12 @@ use super::ConstCx; /// Returns `true` if we should use the more precise live drop checker that runs after drop /// elaboration. -pub fn checking_enabled(tcx: TyCtxt<'tcx>) -> bool { +pub fn checking_enabled(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool { + // Const-stable functions must always use the stable live drop checker. + if tcx.features().staged_api && !tcx.has_attr(def_id.to_def_id(), sym::rustc_const_unstable) { + return false; + } + tcx.features().const_precise_live_drops } @@ -25,7 +30,7 @@ pub fn check_live_drops(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &mir::Body< return; } - if !checking_enabled(tcx) { + if !checking_enabled(tcx, def_id) { return; } diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index ebba7f29663ed..0501302b7610a 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -551,7 +551,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { | TerminatorKind::DropAndReplace { place: dropped_place, .. } => { // If we are checking live drops after drop-elaboration, don't emit duplicate // errors here. - if super::post_drop_elaboration::checking_enabled(self.tcx) { + if super::post_drop_elaboration::checking_enabled(self.tcx, self.def_id) { return; } From 1e1257b8f87d1e3073020df27765dc57fcf2c0cd Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 16 Sep 2020 13:09:46 -0700 Subject: [PATCH 0520/1052] Bless `miri-unleashed` tests `const_mut_refs` doesn't actually work in a `const` or `static` --- src/test/ui/consts/miri_unleashed/box.stderr | 2 +- .../ui/consts/miri_unleashed/mutable_references.stderr | 8 ++++---- .../consts/miri_unleashed/mutable_references_err.stderr | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/ui/consts/miri_unleashed/box.stderr b/src/test/ui/consts/miri_unleashed/box.stderr index 768b795ca5b39..66ea9d5924dfb 100644 --- a/src/test/ui/consts/miri_unleashed/box.stderr +++ b/src/test/ui/consts/miri_unleashed/box.stderr @@ -21,7 +21,7 @@ help: skipping check for `const_mut_refs` feature | LL | &mut *(box 0) | ^^^^^^^^^^^^^ -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/box.rs:10:5 | LL | &mut *(box 0) diff --git a/src/test/ui/consts/miri_unleashed/mutable_references.stderr b/src/test/ui/consts/miri_unleashed/mutable_references.stderr index 7109ffd8b61d7..c6180c1e0041c 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references.stderr @@ -6,17 +6,17 @@ LL | *OH_YES = 99; warning: skipping const checks | -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/mutable_references.rs:9:26 | LL | static FOO: &&mut u32 = &&mut 42; | ^^^^^^^ -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/mutable_references.rs:13:23 | LL | static BAR: &mut () = &mut (); | ^^^^^^^ -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/mutable_references.rs:18:28 | LL | static BOO: &mut Foo<()> = &mut Foo(()); @@ -26,7 +26,7 @@ help: skipping check that does not even have a feature gate | LL | x: &UnsafeCell::new(42), | ^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/mutable_references.rs:30:27 | LL | static OH_YES: &mut i32 = &mut 42; diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr b/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr index 45e7d5a2cc3b3..7647a9ff4f6e4 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr @@ -30,7 +30,7 @@ help: skipping check that does not even have a feature gate | LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/mutable_references_err.rs:30:25 | LL | const BLUNT: &mut i32 = &mut 42; From abc71677da866fd36c70790e768f36d2f809c493 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 16 Sep 2020 13:19:45 -0700 Subject: [PATCH 0521/1052] Test that `const_precise_live_drops` can't be depended upon stably --- .../stable-precise-live-drops-in-libcore.rs | 22 ++++++++++++++++++ ...table-precise-live-drops-in-libcore.stderr | 12 ++++++++++ .../unstable-precise-live-drops-in-libcore.rs | 23 +++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 src/test/ui/consts/stable-precise-live-drops-in-libcore.rs create mode 100644 src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr create mode 100644 src/test/ui/consts/unstable-precise-live-drops-in-libcore.rs diff --git a/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs b/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs new file mode 100644 index 0000000000000..651462d7ef19c --- /dev/null +++ b/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs @@ -0,0 +1,22 @@ +#![stable(feature = "core", since = "1.6.0")] +#![feature(staged_api)] +#![feature(const_precise_live_drops, const_fn)] + +enum Either { + Left(T), + Right(S), +} + +impl Either { + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "foo", since = "1.0.0")] + pub const fn unwrap(self) -> T { + //~^ ERROR destructors cannot be evaluated at compile-time + match self { + Self::Left(t) => t, + Self::Right(t) => t, + } + } +} + +fn main() {} diff --git a/src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr b/src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr new file mode 100644 index 0000000000000..a3f513541dd6a --- /dev/null +++ b/src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr @@ -0,0 +1,12 @@ +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/stable-precise-live-drops-in-libcore.rs:13:25 + | +LL | pub const fn unwrap(self) -> T { + | ^^^^ constant functions cannot evaluate destructors +... +LL | } + | - value is dropped here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0493`. diff --git a/src/test/ui/consts/unstable-precise-live-drops-in-libcore.rs b/src/test/ui/consts/unstable-precise-live-drops-in-libcore.rs new file mode 100644 index 0000000000000..619084eaa517a --- /dev/null +++ b/src/test/ui/consts/unstable-precise-live-drops-in-libcore.rs @@ -0,0 +1,23 @@ +// check-pass + +#![stable(feature = "core", since = "1.6.0")] +#![feature(staged_api)] +#![feature(const_precise_live_drops)] + +enum Either { + Left(T), + Right(S), +} + +impl Either { + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "foo", issue = "none")] + pub const fn unwrap(self) -> T { + match self { + Self::Left(t) => t, + Self::Right(t) => t, + } + } +} + +fn main() {} From 7e24136996fd412ba2890952d5f0ddffb3cb7370 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Wed, 16 Sep 2020 10:29:31 -0400 Subject: [PATCH 0522/1052] Pass --target to lint docs Otherwise, we may not have a standard library built for the native "host" target of the rustc being run. --- src/bootstrap/doc.rs | 4 +++- src/tools/lint-docs/src/groups.rs | 8 ++++---- src/tools/lint-docs/src/lib.rs | 25 ++++++++++++++++--------- src/tools/lint-docs/src/main.rs | 15 ++++++++++++++- 4 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index f90e76a4f4ea6..cf9211bc7ea86 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -752,6 +752,7 @@ impl Step for RustcBook { let out_listing = out_base.join("src/lints"); builder.cp_r(&builder.src.join("src/doc/rustc"), &out_base); builder.info(&format!("Generating lint docs ({})", self.target)); + let rustc = builder.rustc(self.compiler); // The tool runs `rustc` for extracting output examples, so it needs a // functional sysroot. @@ -762,7 +763,8 @@ impl Step for RustcBook { cmd.arg("--out"); cmd.arg(&out_listing); cmd.arg("--rustc"); - cmd.arg(rustc); + cmd.arg(&rustc); + cmd.arg("--rustc-target").arg(&self.target.rustc_target_arg()); if builder.config.verbose() { cmd.arg("--verbose"); } diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index a212459bb4dc6..6b32ebdc284f4 100644 --- a/src/tools/lint-docs/src/groups.rs +++ b/src/tools/lint-docs/src/groups.rs @@ -18,10 +18,10 @@ static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[ /// Updates the documentation of lint groups. pub(crate) fn generate_group_docs( lints: &[Lint], - rustc_path: &Path, + rustc: crate::Rustc<'_>, out_path: &Path, ) -> Result<(), Box> { - let groups = collect_groups(rustc_path)?; + let groups = collect_groups(rustc)?; let groups_path = out_path.join("groups.md"); let contents = fs::read_to_string(&groups_path) .map_err(|e| format!("could not read {}: {}", groups_path.display(), e))?; @@ -36,9 +36,9 @@ pub(crate) fn generate_group_docs( type LintGroups = BTreeMap>; /// Collects the group names from rustc. -fn collect_groups(rustc: &Path) -> Result> { +fn collect_groups(rustc: crate::Rustc<'_>) -> Result> { let mut result = BTreeMap::new(); - let mut cmd = Command::new(rustc); + let mut cmd = Command::new(rustc.path); cmd.arg("-Whelp"); let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?; if !output.status.success() { diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index 92b3d186fa141..6ca71dcaf3cd0 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -45,16 +45,22 @@ impl Level { } } +#[derive(Copy, Clone)] +pub struct Rustc<'a> { + pub path: &'a Path, + pub target: &'a str, +} + /// Collects all lints, and writes the markdown documentation at the given directory. pub fn extract_lint_docs( src_path: &Path, out_path: &Path, - rustc_path: &Path, + rustc: Rustc<'_>, verbose: bool, ) -> Result<(), Box> { let mut lints = gather_lints(src_path)?; for lint in &mut lints { - generate_output_example(lint, rustc_path, verbose).map_err(|e| { + generate_output_example(lint, rustc, verbose).map_err(|e| { format!( "failed to test example in lint docs for `{}` in {}:{}: {}", lint.name, @@ -65,7 +71,7 @@ pub fn extract_lint_docs( })?; } save_lints_markdown(&lints, &out_path.join("listing"))?; - groups::generate_group_docs(&lints, rustc_path, out_path)?; + groups::generate_group_docs(&lints, rustc, out_path)?; Ok(()) } @@ -208,7 +214,7 @@ fn lint_name(line: &str) -> Result { /// actual output from the compiler. fn generate_output_example( lint: &mut Lint, - rustc_path: &Path, + rustc: Rustc<'_>, verbose: bool, ) -> Result<(), Box> { // Explicit list of lints that are allowed to not have an example. Please @@ -230,7 +236,7 @@ fn generate_output_example( // separate test suite, and use an include mechanism such as mdbook's // `{{#rustdoc_include}}`. if !lint.is_ignored() { - replace_produces(lint, rustc_path, verbose)?; + replace_produces(lint, rustc, verbose)?; } Ok(()) } @@ -261,7 +267,7 @@ fn check_style(lint: &Lint) -> Result<(), Box> { /// output from the compiler. fn replace_produces( lint: &mut Lint, - rustc_path: &Path, + rustc: Rustc<'_>, verbose: bool, ) -> Result<(), Box> { let mut lines = lint.doc.iter_mut(); @@ -302,7 +308,7 @@ fn replace_produces( Some(line) if line.is_empty() => {} Some(line) if line == "{{produces}}" => { let output = - generate_lint_output(&lint.name, &example, &options, rustc_path, verbose)?; + generate_lint_output(&lint.name, &example, &options, rustc, verbose)?; line.replace_range( .., &format!( @@ -329,7 +335,7 @@ fn generate_lint_output( name: &str, example: &[&mut String], options: &[&str], - rustc_path: &Path, + rustc: Rustc<'_>, verbose: bool, ) -> Result> { if verbose { @@ -364,13 +370,14 @@ fn generate_lint_output( } fs::write(&tempfile, source) .map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?; - let mut cmd = Command::new(rustc_path); + let mut cmd = Command::new(rustc.path); if options.contains(&"edition2015") { cmd.arg("--edition=2015"); } else { cmd.arg("--edition=2018"); } cmd.arg("--error-format=json"); + cmd.arg("--target").arg(rustc.target); if options.contains(&"test") { cmd.arg("--test"); } diff --git a/src/tools/lint-docs/src/main.rs b/src/tools/lint-docs/src/main.rs index 45d97bd431791..5db49007d375c 100644 --- a/src/tools/lint-docs/src/main.rs +++ b/src/tools/lint-docs/src/main.rs @@ -13,6 +13,7 @@ fn doit() -> Result<(), Box> { let mut src_path = None; let mut out_path = None; let mut rustc_path = None; + let mut rustc_target = None; let mut verbose = false; while let Some(arg) = args.next() { match arg.as_str() { @@ -34,6 +35,12 @@ fn doit() -> Result<(), Box> { None => return Err("--rustc requires a value".into()), }; } + "--rustc-target" => { + rustc_target = match args.next() { + Some(s) => Some(s), + None => return Err("--rustc-target requires a value".into()), + }; + } "-v" | "--verbose" => verbose = true, s => return Err(format!("unexpected argument `{}`", s).into()), } @@ -47,10 +54,16 @@ fn doit() -> Result<(), Box> { if rustc_path.is_none() { return Err("--rustc must be specified to the path of rustc".into()); } + if rustc_target.is_none() { + return Err("--rustc-target must be specified to the rustc target".into()); + } lint_docs::extract_lint_docs( &src_path.unwrap(), &out_path.unwrap(), - &rustc_path.unwrap(), + lint_docs::Rustc { + path: rustc_path.as_deref().unwrap(), + target: rustc_target.as_deref().unwrap(), + }, verbose, ) } From bd4e0af0b54afc91903c282740e25ee6135224c8 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Wed, 16 Sep 2020 12:47:26 -0400 Subject: [PATCH 0523/1052] Build rustdoc for cross-compiled targets This isn't an issue for most folks who use x.py dist, which will directly depend on this. But for x.py build, if we don't properly set target here rustdoc will not be built. Currently, there is not a default-on step for generating a rustc for a given target either, so we will fail to build a rustc as well. --- src/bootstrap/tool.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 99e33e3b006fe..d2346e40e51d2 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -471,7 +471,11 @@ impl Step for Rustdoc { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Rustdoc { - compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), + // Note: this is somewhat unique in that we actually want a *target* + // compiler here, because rustdoc *is* a compiler. We won't be using + // this as the compiler to build with, but rather this is "what + // compiler are we producing"? + compiler: run.builder.compiler(run.builder.top_stage, run.target), }); } From fd762681666d7fe229acf82a1b7b23476fd96148 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 16 Sep 2020 14:31:42 -0700 Subject: [PATCH 0524/1052] library/panic_unwind: Consolidate RV32 and RV64 Signed-off-by: Alistair Francis --- library/panic_unwind/src/gcc.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/library/panic_unwind/src/gcc.rs b/library/panic_unwind/src/gcc.rs index 81b7b556eb4f0..1cfd527b5841a 100644 --- a/library/panic_unwind/src/gcc.rs +++ b/library/panic_unwind/src/gcc.rs @@ -120,10 +120,7 @@ const UNWIND_DATA_REG: (i32, i32) = (24, 25); // I0, I1 #[cfg(target_arch = "hexagon")] const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 -#[cfg(target_arch = "riscv64")] -const UNWIND_DATA_REG: (i32, i32) = (10, 11); // x10, x11 - -#[cfg(target_arch = "riscv32")] +#[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))] const UNWIND_DATA_REG: (i32, i32) = (10, 11); // x10, x11 // The following code is based on GCC's C and C++ personality routines. For reference, see: From 2ce2d6b40e85bf543b3a9e38cd08c7065b357807 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Fri, 11 Sep 2020 14:41:54 +1200 Subject: [PATCH 0525/1052] fix a FP in `indexing_slicing` treat refs to arrays the same as arrays in `indexing_slicing` and `out_of_bounds_indexing` --- clippy_lints/src/indexing_slicing.rs | 2 +- tests/ui/indexing_slicing_index.rs | 3 ++- tests/ui/indexing_slicing_index.stderr | 20 ++++++-------------- tests/ui/indexing_slicing_slice.stderr | 26 +++++++------------------- 4 files changed, 16 insertions(+), 35 deletions(-) diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index a28eda8be15a4..741195f3b10d5 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -88,7 +88,7 @@ declare_lint_pass!(IndexingSlicing => [INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING] impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::Index(ref array, ref index) = &expr.kind { - let ty = cx.typeck_results().expr_ty(array); + let ty = cx.typeck_results().expr_ty(array).peel_refs(); if let Some(range) = higher::range(index) { // Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..] if let ty::Array(_, s) = ty.kind() { diff --git a/tests/ui/indexing_slicing_index.rs b/tests/ui/indexing_slicing_index.rs index 000d5269930ba..ca8ca53c80c3f 100644 --- a/tests/ui/indexing_slicing_index.rs +++ b/tests/ui/indexing_slicing_index.rs @@ -15,7 +15,8 @@ fn main() { x[3]; // Ok, should not produce stderr. let y = &x; - y[0]; + y[0]; // Ok, referencing shouldn't affect this lint. See the issue 6021 + y[4]; // Ok, rustc will handle references too. let v = vec![0; 5]; v[0]; diff --git a/tests/ui/indexing_slicing_index.stderr b/tests/ui/indexing_slicing_index.stderr index 2b3f9be2dfb9b..2f6c9e2f4e5a0 100644 --- a/tests/ui/indexing_slicing_index.stderr +++ b/tests/ui/indexing_slicing_index.stderr @@ -8,15 +8,7 @@ LL | x[index]; = help: Consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic. - --> $DIR/indexing_slicing_index.rs:18:5 - | -LL | y[0]; - | ^^^^ - | - = help: Consider using `.get(n)` or `.get_mut(n)` instead - -error: indexing may panic. - --> $DIR/indexing_slicing_index.rs:21:5 + --> $DIR/indexing_slicing_index.rs:22:5 | LL | v[0]; | ^^^^ @@ -24,7 +16,7 @@ LL | v[0]; = help: Consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic. - --> $DIR/indexing_slicing_index.rs:22:5 + --> $DIR/indexing_slicing_index.rs:23:5 | LL | v[10]; | ^^^^^ @@ -32,7 +24,7 @@ LL | v[10]; = help: Consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic. - --> $DIR/indexing_slicing_index.rs:23:5 + --> $DIR/indexing_slicing_index.rs:24:5 | LL | v[1 << 3]; | ^^^^^^^^^ @@ -40,7 +32,7 @@ LL | v[1 << 3]; = help: Consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic. - --> $DIR/indexing_slicing_index.rs:29:5 + --> $DIR/indexing_slicing_index.rs:30:5 | LL | v[N]; | ^^^^ @@ -48,12 +40,12 @@ LL | v[N]; = help: Consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic. - --> $DIR/indexing_slicing_index.rs:30:5 + --> $DIR/indexing_slicing_index.rs:31:5 | LL | v[M]; | ^^^^ | = help: Consider using `.get(n)` or `.get_mut(n)` instead -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors diff --git a/tests/ui/indexing_slicing_slice.stderr b/tests/ui/indexing_slicing_slice.stderr index ec6c157ac1a26..2231deee833ee 100644 --- a/tests/ui/indexing_slicing_slice.stderr +++ b/tests/ui/indexing_slicing_slice.stderr @@ -71,29 +71,17 @@ LL | &x[1..][..5]; | = help: Consider using `.get(..n)`or `.get_mut(..n)` instead -error: slicing may panic. - --> $DIR/indexing_slicing_slice.rs:24:6 - | -LL | &y[1..2]; - | ^^^^^^^ - | - = help: Consider using `.get(n..m)` or `.get_mut(n..m)` instead - -error: slicing may panic. - --> $DIR/indexing_slicing_slice.rs:25:6 +error: range is out of bounds + --> $DIR/indexing_slicing_slice.rs:25:12 | LL | &y[0..=4]; - | ^^^^^^^^ - | - = help: Consider using `.get(n..m)` or `.get_mut(n..m)` instead + | ^ -error: slicing may panic. - --> $DIR/indexing_slicing_slice.rs:26:6 +error: range is out of bounds + --> $DIR/indexing_slicing_slice.rs:26:11 | LL | &y[..=4]; - | ^^^^^^^ - | - = help: Consider using `.get(..n)`or `.get_mut(..n)` instead + | ^ error: slicing may panic. --> $DIR/indexing_slicing_slice.rs:31:6 @@ -133,5 +121,5 @@ LL | &v[..100]; | = help: Consider using `.get(..n)`or `.get_mut(..n)` instead -error: aborting due to 17 previous errors +error: aborting due to 16 previous errors From ce064722469672a504d8a1720ab4d2f681c21610 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Fri, 11 Sep 2020 15:06:49 +1200 Subject: [PATCH 0526/1052] replace `walk_ptrs_ty` with `peel_refs` --- clippy_lints/src/bytecount.rs | 7 +++---- clippy_lints/src/duration_subsec.rs | 4 ++-- clippy_lints/src/entry.rs | 4 ++-- clippy_lints/src/fallible_impl_from.rs | 6 ++---- clippy_lints/src/format.rs | 4 ++-- clippy_lints/src/inherent_to_string.rs | 4 ++-- clippy_lints/src/len_zero.rs | 4 ++-- clippy_lints/src/match_on_vec_items.rs | 5 ++--- clippy_lints/src/matches.rs | 4 ++-- clippy_lints/src/methods/mod.rs | 22 ++++++++++----------- clippy_lints/src/misc.rs | 6 +++--- clippy_lints/src/mut_key.rs | 4 ++-- clippy_lints/src/open_options.rs | 6 +++--- clippy_lints/src/path_buf_push_overwrite.rs | 4 ++-- clippy_lints/src/repeat_once.rs | 4 ++-- clippy_lints/src/strings.rs | 4 ++-- clippy_lints/src/swap.rs | 3 +-- clippy_lints/src/unwrap_in_result.rs | 6 +++--- clippy_lints/src/utils/internal_lints.rs | 6 +++--- clippy_lints/src/utils/mod.rs | 8 -------- 20 files changed, 51 insertions(+), 64 deletions(-) diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index 189c07427ae99..d7d02ebf985c8 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -1,6 +1,5 @@ use crate::utils::{ - contains_name, get_pat_name, match_type, paths, single_segment_path, snippet_with_applicability, - span_lint_and_sugg, walk_ptrs_ty, + contains_name, get_pat_name, match_type, paths, single_segment_path, snippet_with_applicability, span_lint_and_sugg, }; use if_chain::if_chain; use rustc_ast::ast::UintTy; @@ -53,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for ByteCount { if let ExprKind::Binary(ref op, ref l, ref r) = body.value.kind; if op.node == BinOpKind::Eq; if match_type(cx, - walk_ptrs_ty(cx.typeck_results().expr_ty(&filter_args[0])), + cx.typeck_results().expr_ty(&filter_args[0]).peel_refs(), &paths::SLICE_ITER); then { let needle = match get_path_name(l) { @@ -63,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for ByteCount { _ => { return; } } }; - if ty::Uint(UintTy::U8) != *walk_ptrs_ty(cx.typeck_results().expr_ty(needle)).kind() { + if ty::Uint(UintTy::U8) != *cx.typeck_results().expr_ty(needle).peel_refs().kind() { return; } let haystack = if let ExprKind::MethodCall(ref path, _, ref args, _) = diff --git a/clippy_lints/src/duration_subsec.rs b/clippy_lints/src/duration_subsec.rs index 8ece44878fe32..c0529a34cc411 100644 --- a/clippy_lints/src/duration_subsec.rs +++ b/clippy_lints/src/duration_subsec.rs @@ -7,7 +7,7 @@ use rustc_span::source_map::Spanned; use crate::consts::{constant, Constant}; use crate::utils::paths; -use crate::utils::{match_type, snippet_with_applicability, span_lint_and_sugg, walk_ptrs_ty}; +use crate::utils::{match_type, snippet_with_applicability, span_lint_and_sugg}; declare_clippy_lint! { /// **What it does:** Checks for calculation of subsecond microseconds or milliseconds @@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for DurationSubsec { if_chain! { if let ExprKind::Binary(Spanned { node: BinOpKind::Div, .. }, ref left, ref right) = expr.kind; if let ExprKind::MethodCall(ref method_path, _ , ref args, _) = left.kind; - if match_type(cx, walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0])), &paths::DURATION); + if match_type(cx, cx.typeck_results().expr_ty(&args[0]).peel_refs(), &paths::DURATION); if let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right); then { let suggested_fn = match (method_path.ident.as_str().as_ref(), divisor) { diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index d616502a82a0c..35a5d00f4aa5a 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -1,6 +1,6 @@ use crate::utils::SpanlessEq; use crate::utils::{get_item_name, higher, is_type_diagnostic_item, match_type, paths, snippet, snippet_opt}; -use crate::utils::{snippet_with_applicability, span_lint_and_then, walk_ptrs_ty}; +use crate::utils::{snippet_with_applicability, span_lint_and_then}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; @@ -106,7 +106,7 @@ fn check_cond<'a>(cx: &LateContext<'_>, check: &'a Expr<'a>) -> Option<(&'static if let ExprKind::AddrOf(BorrowKind::Ref, _, ref key) = params[1].kind; then { let map = ¶ms[0]; - let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(map)); + let obj_ty = cx.typeck_results().expr_ty(map).peel_refs(); return if match_type(cx, obj_ty, &paths::BTREEMAP) { Some(("BTreeMap", map, key)) diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 000762334f61e..a9e05fddbe762 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -1,7 +1,5 @@ use crate::utils::paths::{BEGIN_PANIC, BEGIN_PANIC_FMT, FROM_TRAIT}; -use crate::utils::{ - is_expn_of, is_type_diagnostic_item, match_def_path, method_chain_args, span_lint_and_then, walk_ptrs_ty, -}; +use crate::utils::{is_expn_of, is_type_diagnostic_item, match_def_path, method_chain_args, span_lint_and_then}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; @@ -96,7 +94,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h // check for `unwrap` if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { - let reciever_ty = walk_ptrs_ty(self.typeck_results.expr_ty(&arglists[0][0])); + let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type)) || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type)) { diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 8bd85af87682a..d6541010bca23 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,7 +1,7 @@ use crate::utils::paths; use crate::utils::{ is_expn_of, is_type_diagnostic_item, last_path_segment, match_def_path, match_function_call, snippet, - span_lint_and_then, walk_ptrs_ty, + span_lint_and_then, }; use if_chain::if_chain; use rustc_ast::ast::LitKind; @@ -90,7 +90,7 @@ fn on_argumentv1_new<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arms: & if let PatKind::Tuple(ref pats, None) = arms[0].pat.kind; if pats.len() == 1; then { - let ty = walk_ptrs_ty(cx.typeck_results().pat_ty(&pats[0])); + let ty = cx.typeck_results().pat_ty(&pats[0]).peel_refs(); if *ty.kind() != rustc_middle::ty::Str && !is_type_diagnostic_item(cx, ty, sym!(string_type)) { return None; } diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index f330fa8fab8f4..0877b44d90138 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -5,7 +5,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use crate::utils::{ get_trait_def_id, implements_trait, is_type_diagnostic_item, paths, return_ty, span_lint_and_help, - trait_ref_of_method, walk_ptrs_ty, + trait_ref_of_method, }; declare_clippy_lint! { @@ -125,7 +125,7 @@ fn show_lint(cx: &LateContext<'_>, item: &ImplItem<'_>) { // Get the real type of 'self' let fn_def_id = cx.tcx.hir().local_def_id(item.hir_id); let self_type = cx.tcx.fn_sig(fn_def_id).input(0); - let self_type = walk_ptrs_ty(self_type.skip_binder()); + let self_type = self_type.skip_binder().peel_refs(); // Emit either a warning or an error if implements_trait(cx, self_type, display_trait_id, &[]) { diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 42a98dc963d20..c9c4891bb08ac 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -1,4 +1,4 @@ -use crate::utils::{get_item_name, snippet_with_applicability, span_lint, span_lint_and_sugg, walk_ptrs_ty}; +use crate::utils::{get_item_name, snippet_with_applicability, span_lint, span_lint_and_sugg}; use rustc_ast::ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -285,7 +285,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { }) } - let ty = &walk_ptrs_ty(cx.typeck_results().expr_ty(expr)); + let ty = &cx.typeck_results().expr_ty(expr).peel_refs(); match ty.kind() { ty::Dynamic(ref tt, ..) => tt.principal().map_or(false, |principal| { cx.tcx diff --git a/clippy_lints/src/match_on_vec_items.rs b/clippy_lints/src/match_on_vec_items.rs index 57966452253d5..331b6c6c34a94 100644 --- a/clippy_lints/src/match_on_vec_items.rs +++ b/clippy_lints/src/match_on_vec_items.rs @@ -1,4 +1,3 @@ -use crate::utils::walk_ptrs_ty; use crate::utils::{is_type_diagnostic_item, is_type_lang_item, snippet, span_lint_and_sugg}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -90,12 +89,12 @@ fn is_vec_indexing<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opti fn is_vector(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let ty = cx.typeck_results().expr_ty(expr); - let ty = walk_ptrs_ty(ty); + let ty = ty.peel_refs(); is_type_diagnostic_item(cx, ty, sym!(vec_type)) } fn is_full_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let ty = cx.typeck_results().expr_ty(expr); - let ty = walk_ptrs_ty(ty); + let ty = ty.peel_refs(); is_type_lang_item(cx, ty, LangItem::RangeFull) } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 7ba7397c29cb6..11380f83316f8 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -6,7 +6,7 @@ use crate::utils::{ expr_block, get_arg_name, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of, is_refutable, is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, multispan_sugg, remove_blocks, snippet, snippet_block, snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, - span_lint_and_then, walk_ptrs_ty, + span_lint_and_then, }; use if_chain::if_chain; use rustc_ast::ast::LitKind; @@ -794,7 +794,7 @@ fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms } fn check_wild_err_arm(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { - let ex_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(ex)); + let ex_ty = cx.typeck_results().expr_ty(ex).peel_refs(); if is_type_diagnostic_item(cx, ex_ty, sym!(result_type)) { for arm in arms { if let PatKind::TupleStruct(ref path, ref inner, _) = arm.pat.kind { diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 184aee95efa7b..dadd0f8ebb7c8 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -32,8 +32,8 @@ use crate::utils::{ is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls, method_chain_args, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, - span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty, - walk_ptrs_ty_depth, SpanlessEq, + span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty_depth, + SpanlessEq, }; declare_clippy_lint! { @@ -1774,7 +1774,7 @@ fn lint_or_fun_call<'tcx>( ) { if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = &arg.kind { if path.ident.as_str() == "len" { - let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0])); + let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); match ty.kind() { ty::Slice(_) | ty::Array(_, _) => return, @@ -1881,7 +1881,7 @@ fn lint_expect_fun_call( && (method_name.ident.name == sym!(as_str) || method_name.ident.name == sym!(as_ref)) && { let arg_type = cx.typeck_results().expr_ty(&call_args[0]); - let base_type = walk_ptrs_ty(arg_type); + let base_type = arg_type.peel_refs(); *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym!(string_type)) } { @@ -2142,7 +2142,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Exp } fn lint_clone_on_ref_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) { - let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(arg)); + let obj_ty = cx.typeck_results().expr_ty(arg).peel_refs(); if let ty::Adt(_, subst) = obj_ty.kind() { let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) { @@ -2173,7 +2173,7 @@ fn lint_string_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::E let arg = &args[1]; if let Some(arglists) = method_chain_args(arg, &["chars"]) { let target = &arglists[0][0]; - let self_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(target)); + let self_ty = cx.typeck_results().expr_ty(target).peel_refs(); let ref_str = if *self_ty.kind() == ty::Str { "" } else if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) { @@ -2201,7 +2201,7 @@ fn lint_string_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::E } fn lint_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { - let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0])); + let obj_ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); if is_type_diagnostic_item(cx, obj_ty, sym!(string_type)) { lint_string_extend(cx, expr, args); } @@ -2384,7 +2384,7 @@ fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_ } } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(caller_expr), sym!(vec_type)) || matches!( - &walk_ptrs_ty(cx.typeck_results().expr_ty(caller_expr)).kind(), + &cx.typeck_results().expr_ty(caller_expr).peel_refs().kind(), ty::Array(_, _) ) { @@ -2587,7 +2587,7 @@ fn derefs_to_slice<'tcx>( /// lint use of `unwrap()` for `Option`s and `Result`s fn lint_unwrap(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::Expr<'_>]) { - let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&unwrap_args[0])); + let obj_ty = cx.typeck_results().expr_ty(&unwrap_args[0]).peel_refs(); let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) { Some((UNWRAP_USED, "an Option", "None")) @@ -2615,7 +2615,7 @@ fn lint_unwrap(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::E /// lint use of `expect()` for `Option`s and `Result`s fn lint_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, expect_args: &[hir::Expr<'_>]) { - let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&expect_args[0])); + let obj_ty = cx.typeck_results().expr_ty(&expect_args[0]).peel_refs(); let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) { Some((EXPECT_USED, "an Option", "None")) @@ -3134,7 +3134,7 @@ fn lint_chars_cmp( if segment.ident.name == sym!(Some); then { let mut applicability = Applicability::MachineApplicable; - let self_ty = walk_ptrs_ty(cx.typeck_results().expr_ty_adjusted(&args[0][0])); + let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs(); if *self_ty.kind() != ty::Str { return false; diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 67a3685fd0dc3..909e79f661a6d 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -17,7 +17,7 @@ use crate::utils::sugg::Sugg; use crate::utils::{ get_item_name, get_parent_expr, higher, implements_trait, in_constant, is_integer_const, iter_input_pats, last_path_segment, match_qpath, match_trait_method, paths, snippet, snippet_opt, span_lint, span_lint_and_sugg, - span_lint_and_then, span_lint_hir_and_then, walk_ptrs_ty, SpanlessEq, + span_lint_and_then, span_lint_hir_and_then, SpanlessEq, }; declare_clippy_lint! { @@ -561,7 +561,7 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } fn is_float(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - let value = &walk_ptrs_ty(cx.typeck_results().expr_ty(expr)).kind(); + let value = &cx.typeck_results().expr_ty(expr).peel_refs().kind(); if let ty::Array(arr_ty, _) = value { return matches!(arr_ty.kind(), ty::Float(_)); @@ -571,7 +571,7 @@ fn is_float(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } fn is_array(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - matches!(&walk_ptrs_ty(cx.typeck_results().expr_ty(expr)).kind(), ty::Array(_, _)) + matches!(&cx.typeck_results().expr_ty(expr).peel_refs().kind(), ty::Array(_, _)) } fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) { diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 0826ad0ab55bb..8a2dbdc50eaea 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -1,4 +1,4 @@ -use crate::utils::{match_def_path, paths, span_lint, trait_ref_of_method, walk_ptrs_ty}; +use crate::utils::{match_def_path, paths, span_lint, trait_ref_of_method}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{Adt, Array, RawPtr, Ref, Slice, Tuple, Ty, TypeAndMut}; @@ -98,7 +98,7 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, item_hir_id: hir::HirId, decl: &hir:: // We want to lint 1. sets or maps with 2. not immutable key types and 3. no unerased // generics (because the compiler cannot ensure immutability for unknown types). fn check_ty<'tcx>(cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) { - let ty = walk_ptrs_ty(ty); + let ty = ty.peel_refs(); if let Adt(def, substs) = ty.kind() { if [&paths::HASHMAP, &paths::BTREEMAP, &paths::HASHSET, &paths::BTREESET] .iter() diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/open_options.rs index e99d0317ba2e8..73a99a3a2f870 100644 --- a/clippy_lints/src/open_options.rs +++ b/clippy_lints/src/open_options.rs @@ -1,4 +1,4 @@ -use crate::utils::{match_type, paths, span_lint, walk_ptrs_ty}; +use crate::utils::{match_type, paths, span_lint}; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -30,7 +30,7 @@ declare_lint_pass!(OpenOptions => [NONSENSICAL_OPEN_OPTIONS]); impl<'tcx> LateLintPass<'tcx> for OpenOptions { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { if let ExprKind::MethodCall(ref path, _, ref arguments, _) = e.kind { - let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&arguments[0])); + let obj_ty = cx.typeck_results().expr_ty(&arguments[0]).peel_refs(); if path.ident.name == sym!(open) && match_type(cx, obj_ty, &paths::OPEN_OPTIONS) { let mut options = Vec::new(); get_open_options(cx, &arguments[0], &mut options); @@ -58,7 +58,7 @@ enum OpenOption { fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) { if let ExprKind::MethodCall(ref path, _, ref arguments, _) = argument.kind { - let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&arguments[0])); + let obj_ty = cx.typeck_results().expr_ty(&arguments[0]).peel_refs(); // Only proceed if this is a call on some object of type std::fs::OpenOptions if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 2 { diff --git a/clippy_lints/src/path_buf_push_overwrite.rs b/clippy_lints/src/path_buf_push_overwrite.rs index b8583402928b4..6eeb031d383c8 100644 --- a/clippy_lints/src/path_buf_push_overwrite.rs +++ b/clippy_lints/src/path_buf_push_overwrite.rs @@ -1,4 +1,4 @@ -use crate::utils::{match_type, paths, span_lint_and_sugg, walk_ptrs_ty}; +use crate::utils::{match_type, paths, span_lint_and_sugg}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -46,7 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for PathBufPushOverwrite { if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind; if path.ident.name == sym!(push); if args.len() == 2; - if match_type(cx, walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0])), &paths::PATH_BUF); + if match_type(cx, cx.typeck_results().expr_ty(&args[0]).peel_refs(), &paths::PATH_BUF); if let Some(get_index_arg) = args.get(1); if let ExprKind::Lit(ref lit) = get_index_arg.kind; if let LitKind::Str(ref path_lit, _) = lit.node; diff --git a/clippy_lints/src/repeat_once.rs b/clippy_lints/src/repeat_once.rs index c0890018d46ab..ae6013530091e 100644 --- a/clippy_lints/src/repeat_once.rs +++ b/clippy_lints/src/repeat_once.rs @@ -1,5 +1,5 @@ use crate::consts::{constant_context, Constant}; -use crate::utils::{in_macro, is_type_diagnostic_item, snippet, span_lint_and_sugg, walk_ptrs_ty}; +use crate::utils::{in_macro, is_type_diagnostic_item, snippet, span_lint_and_sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; @@ -44,7 +44,7 @@ impl<'tcx> LateLintPass<'tcx> for RepeatOnce { if let Some(Constant::Int(1)) = constant_context(cx, cx.typeck_results()).expr(&count); if !in_macro(receiver.span); then { - let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&receiver)); + let ty = cx.typeck_results().expr_ty(&receiver).peel_refs(); if ty.is_str() { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 7a659bf779c0c..15b66684eab70 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -8,7 +8,7 @@ use rustc_span::source_map::Spanned; 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, walk_ptrs_ty}; +use crate::utils::{get_parent_expr, is_allowed, is_type_diagnostic_item, span_lint, span_lint_and_sugg}; declare_clippy_lint! { /// **What it does:** Checks for string appends of the form `x = x + y` (without @@ -134,7 +134,7 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd { } fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { - is_type_diagnostic_item(cx, walk_ptrs_ty(cx.typeck_results().expr_ty(e)), sym!(string_type)) + is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), sym!(string_type)) } fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool { diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 47a73ca9a24cf..54b38d9f4ced2 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -1,7 +1,6 @@ use crate::utils::sugg::Sugg; use crate::utils::{ differing_macro_contexts, eq_expr_value, is_type_diagnostic_item, snippet_with_applicability, span_lint_and_then, - walk_ptrs_ty, }; use if_chain::if_chain; use rustc_errors::Applicability; @@ -194,7 +193,7 @@ fn check_for_slice<'a>(cx: &LateContext<'_>, lhs1: &'a Expr<'_>, lhs2: &'a Expr< if let ExprKind::Index(ref lhs1, ref idx1) = lhs1.kind { if let ExprKind::Index(ref lhs2, ref idx2) = lhs2.kind { if eq_expr_value(cx, lhs1, lhs2) { - let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(lhs1)); + let ty = cx.typeck_results().expr_ty(lhs1).peel_refs(); if matches!(ty.kind(), ty::Slice(_)) || matches!(ty.kind(), ty::Array(_, _)) diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index 1c7e62ecd3d2c..0f8797243eca3 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -1,4 +1,4 @@ -use crate::utils::{is_type_diagnostic_item, method_chain_args, return_ty, span_lint_and_then, walk_ptrs_ty}; +use crate::utils::{is_type_diagnostic_item, method_chain_args, return_ty, span_lint_and_then}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; @@ -81,7 +81,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { // check for `expect` if let Some(arglists) = method_chain_args(expr, &["expect"]) { - let reciever_ty = walk_ptrs_ty(self.typeck_results.expr_ty(&arglists[0][0])); + let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type)) || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type)) { @@ -91,7 +91,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> { // check for `unwrap` if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { - let reciever_ty = walk_ptrs_ty(self.typeck_results.expr_ty(&arglists[0][0])); + let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type)) || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type)) { diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index f201494a02466..bfe426a25eb89 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -1,6 +1,6 @@ use crate::utils::{ is_expn_of, match_def_path, match_qpath, match_type, method_calls, path_to_res, paths, qpath_res, run_lints, - snippet, span_lint, span_lint_and_help, span_lint_and_sugg, walk_ptrs_ty, SpanlessEq, + snippet, span_lint, span_lint_and_help, span_lint_and_sugg, SpanlessEq, }; use if_chain::if_chain; use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, NodeId}; @@ -427,7 +427,7 @@ impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions { if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind; let fn_name = path.ident; if let Some(sugg) = self.map.get(&*fn_name.as_str()); - let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0])); + let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); if match_type(cx, ty, &paths::EARLY_CONTEXT) || match_type(cx, ty, &paths::LATE_CONTEXT); then { @@ -460,7 +460,7 @@ impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass { let args = arg_lists[1]; if args.len() == 1; let self_arg = &args[0]; - let self_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(self_arg)); + let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT); then { span_lint_and_sugg( diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 95eedf881784b..ea52741b7cc42 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -754,14 +754,6 @@ pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> { } } -/// Returns the base type for references and raw pointers. -pub fn walk_ptrs_ty(ty: Ty<'_>) -> Ty<'_> { - match ty.kind() { - ty::Ref(_, ty, _) => walk_ptrs_ty(ty), - _ => ty, - } -} - /// Returns the base type for references and raw pointers, and count reference /// depth. pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) { From 57b2da808c36fa2acf991379cd971639091122f7 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 16 Sep 2020 15:19:13 -0700 Subject: [PATCH 0527/1052] library/unwind: Consolidate RV32 and RV64 Signed-off-by: Alistair Francis --- library/unwind/src/libunwind.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index 2d65ded390916..677843e12e1be 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -54,10 +54,7 @@ pub const unwinder_private_data_size: usize = 2; #[cfg(target_arch = "sparc64")] pub const unwinder_private_data_size: usize = 2; -#[cfg(target_arch = "riscv64")] -pub const unwinder_private_data_size: usize = 2; - -#[cfg(target_arch = "riscv32")] +#[cfg(any(target_arch = "riscv64", target_arch = "riscv32")] pub const unwinder_private_data_size: usize = 2; #[cfg(target_os = "emscripten")] From 57eb29cd2dc30c47b613ced135422a4120bc6a78 Mon Sep 17 00:00:00 2001 From: Camelid Date: Wed, 16 Sep 2020 15:31:56 -0700 Subject: [PATCH 0528/1052] Update based on review suggestions --- compiler/rustc_middle/src/mir/mod.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index e6bb746f618fb..58b69d022d985 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1076,20 +1076,24 @@ pub struct VarDebugInfo<'tcx> { // BasicBlock rustc_index::newtype_index! { - /// The unit of the MIR [control-flow graph][CFG]. + /// A node in the MIR [control-flow graph][CFG]. /// /// There are no branches (e.g., `if`s, function calls, etc.) within a basic block, which makes /// it easier to do [data-flow analyses] and optimizations. Instead, branches are represented /// as an edge in a graph between basic blocks. /// /// Basic blocks consist of a series of [statements][Statement], ending with a - /// [terminator][Terminator]. Basic blocks can have multiple predecessors and successors. + /// [terminator][Terminator]. Basic blocks can have multiple predecessors and successors, + /// however there is a MIR pass ([`CriticalCallEdges`]) that removes *critical edges*, which + /// are edges that go from a multi-successor node to a multi-predecessor node. This pass is + /// needed because some analyses require that there are no critical edges in the CFG. /// /// Read more about basic blocks in the [rustc-dev-guide][guide-mir]. /// /// [CFG]: https://rustc-dev-guide.rust-lang.org/appendix/background.html#cfg /// [data-flow analyses]: /// https://rustc-dev-guide.rust-lang.org/appendix/background.html#what-is-a-dataflow-analysis + /// [`CriticalCallEdges`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/transform/add_call_guards/enum.AddCallGuards.html#variant.CriticalCallEdges /// [guide-mir]: https://rustc-dev-guide.rust-lang.org/mir/ pub struct BasicBlock { derive [HashStable] From 27200855c34445bdf50185fbaed12b5c0d60eb9b Mon Sep 17 00:00:00 2001 From: Robin Schoonover Date: Wed, 16 Sep 2020 17:19:35 -0600 Subject: [PATCH 0529/1052] Move rc_buffer lint into perf category --- clippy_lints/src/lib.rs | 3 ++- clippy_lints/src/types.rs | 2 +- src/lintlist/mod.rs | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 239eeb10bb421..06f41be8a2a93 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1480,6 +1480,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::CHAR_LIT_AS_U8), LintId::of(&types::FN_TO_NUMERIC_CAST), LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), + LintId::of(&types::RC_BUFFER), LintId::of(&types::REDUNDANT_ALLOCATION), LintId::of(&types::TYPE_COMPLEXITY), LintId::of(&types::UNIT_ARG), @@ -1780,6 +1781,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE), LintId::of(&types::BOX_VEC), + LintId::of(&types::RC_BUFFER), LintId::of(&types::REDUNDANT_ALLOCATION), LintId::of(&vec::USELESS_VEC), ]); @@ -1805,7 +1807,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE), LintId::of(&redundant_pub_crate::REDUNDANT_PUB_CRATE), LintId::of(&transmute::USELESS_TRANSMUTE), - LintId::of(&types::RC_BUFFER), LintId::of(&use_self::USE_SELF), ]); } diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index da04d07885b9f..a29a199b8c3aa 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -241,7 +241,7 @@ declare_clippy_lint! { /// fn foo(interned: Rc) { ... } /// ``` pub RC_BUFFER, - nursery, + perf, "shared ownership of a buffer type" } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index d0c6a1d63d97b..e5563151b48ea 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1853,7 +1853,7 @@ pub static ref ALL_LINTS: Vec = vec![ }, Lint { name: "rc_buffer", - group: "nursery", + group: "perf", desc: "shared ownership of a buffer type", deprecation: None, module: "types", From 0e3414248a683aa4490c84500cba772c3d920c2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Tue, 15 Sep 2020 23:10:24 +0200 Subject: [PATCH 0530/1052] don't lazily evaulate some trivial values for Option::None replacements (clippy::unnecessary_lazy_evaluations) --- compiler/rustc_lint/src/builtin.rs | 2 +- compiler/rustc_metadata/src/native_libs.rs | 4 ++-- compiler/rustc_mir/src/dataflow/move_paths/builder.rs | 5 +---- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index efdb7489ba5b0..5b5dbcf192ca1 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -961,7 +961,7 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: & continue; } - let span = sugared_span.take().unwrap_or_else(|| attr.span); + let span = sugared_span.take().unwrap_or(attr.span); if attr.is_doc_comment() || cx.sess().check_name(attr, sym::doc) { cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| { diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 3976475cb063e..e76c2cb356f3f 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -170,7 +170,7 @@ impl Collector<'tcx> { feature_err( &self.tcx.sess.parse_sess, sym::static_nobundle, - span.unwrap_or_else(|| rustc_span::DUMMY_SP), + span.unwrap_or(rustc_span::DUMMY_SP), "kind=\"static-nobundle\" is unstable", ) .emit(); @@ -179,7 +179,7 @@ impl Collector<'tcx> { feature_err( &self.tcx.sess.parse_sess, sym::raw_dylib, - span.unwrap_or_else(|| rustc_span::DUMMY_SP), + span.unwrap_or(rustc_span::DUMMY_SP), "kind=\"raw-dylib\" is unstable", ) .emit(); diff --git a/compiler/rustc_mir/src/dataflow/move_paths/builder.rs b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs index eb92461672259..5c3e353840180 100644 --- a/compiler/rustc_mir/src/dataflow/move_paths/builder.rs +++ b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs @@ -480,10 +480,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { }; let base_ty = base_place.ty(self.builder.body, self.builder.tcx).ty; let len: u64 = match base_ty.kind() { - ty::Array(_, size) => { - let length: u64 = size.eval_usize(self.builder.tcx, self.builder.param_env); - length - } + ty::Array(_, size) => size.eval_usize(self.builder.tcx, self.builder.param_env), _ => bug!("from_end: false slice pattern of non-array type"), }; for offset in from..to { From b7c8bea6cbf0aff4cbb36b127edc0bb4c66c4cf9 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Thu, 17 Sep 2020 09:07:19 +0800 Subject: [PATCH 0531/1052] Fix wording in mir doc --- compiler/rustc_middle/src/mir/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 29daf7e9309aa..467d0192a8144 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2285,7 +2285,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { /// Constants /// /// Two constants are equal if they are the same constant. Note that -/// this does not necessarily mean that they are `==` in Rust -- in +/// this does not necessarily mean that they are `==` in Rust. In /// particular, one must be wary of `NaN`! #[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, HashStable)] From f4a7149f499a4b91d296678002f0bce4ded85038 Mon Sep 17 00:00:00 2001 From: Hanif Bin Ariffin Date: Thu, 17 Sep 2020 10:56:08 +0800 Subject: [PATCH 0532/1052] Don't compile regex at every function call. Use `SyncOnceCell` to only compile it once. I believe this still adds some kind of locking mechanism? --- compiler/rustc_mir/src/dataflow/framework/graphviz.rs | 10 +++++++++- compiler/rustc_mir/src/lib.rs | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/dataflow/framework/graphviz.rs b/compiler/rustc_mir/src/dataflow/framework/graphviz.rs index 94151fbd0903a..5d4c4251961d2 100644 --- a/compiler/rustc_mir/src/dataflow/framework/graphviz.rs +++ b/compiler/rustc_mir/src/dataflow/framework/graphviz.rs @@ -1,6 +1,7 @@ //! A helpful diagram for debugging dataflow problems. use std::borrow::Cow; +use std::lazy::SyncOnceCell; use std::{io, ops, str}; use regex::Regex; @@ -570,6 +571,13 @@ where } } +macro_rules! regex { + ($re:literal $(,)?) => {{ + static RE: SyncOnceCell = SyncOnceCell::new(); + RE.get_or_init(|| Regex::new($re).unwrap()) + }}; +} + fn diff_pretty(new: T, old: T, ctxt: &C) -> String where T: DebugWithContext, @@ -578,7 +586,7 @@ where return String::new(); } - let re = Regex::new("\t?\u{001f}([+-])").unwrap(); + let re = regex!("\t?\u{001f}([+-])"); let raw_diff = format!("{:#?}", DebugDiffWithAdapter { new, old, ctxt }); diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index 42717f273843a..8d2253b4d826b 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -27,6 +27,7 @@ Rust MIR: a lowered representation of Rust. #![feature(trait_alias)] #![feature(option_expect_none)] #![feature(or_patterns)] +#![feature(once_cell)] #![recursion_limit = "256"] #[macro_use] From b47913962097874257ad10227b943ef7af85d49f Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 17 Sep 2020 06:12:40 +0200 Subject: [PATCH 0533/1052] Remove intrinsics::arith_offset use from libarena The use of arith_offset was added in 803e9ae67b770d8500c4ab5862e988d29118356a before the stable wrapper of the intrinsic was available. https://doc.rust-lang.org/stable/std/intrinsics/fn.arith_offset.html --- compiler/rustc_arena/src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 5e6a0340d12a0..16f735f055f92 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -11,7 +11,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/", test(no_crate_inject, attr(deny(warnings))) )] -#![feature(core_intrinsics)] #![feature(dropck_eyepatch)] #![feature(raw_vec_internals)] #![cfg_attr(test, feature(test))] @@ -25,7 +24,6 @@ use smallvec::SmallVec; use std::alloc::Layout; use std::cell::{Cell, RefCell}; use std::cmp; -use std::intrinsics; use std::marker::{PhantomData, Send}; use std::mem; use std::ptr; @@ -130,7 +128,7 @@ impl TypedArena { unsafe { if mem::size_of::() == 0 { - self.ptr.set(intrinsics::arith_offset(self.ptr.get() as *mut u8, 1) as *mut T); + self.ptr.set((self.ptr.get() as *mut u8).wrapping_offset(1) as *mut T); let ptr = mem::align_of::() as *mut T; // Don't drop the object. This `write` is equivalent to `forget`. ptr::write(ptr, object); From 2f1bfd6399cfe439fbf2e446beafa5c55d1bb843 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Thu, 17 Sep 2020 00:03:00 -0400 Subject: [PATCH 0534/1052] Preserve doc-comments when generating queries This also changes some comments into doc-comments. --- compiler/rustc_macros/src/query.rs | 29 ++++++++++------ compiler/rustc_middle/src/query/mod.rs | 48 +++++++++++++------------- 2 files changed, 43 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 95096ef3fc4cf..204e8e800cd48 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -5,8 +5,8 @@ use syn::parse::{Parse, ParseStream, Result}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::{ - braced, parenthesized, parse_macro_input, Attribute, Block, Error, Expr, Ident, ReturnType, - Token, Type, + braced, parenthesized, parse_macro_input, AttrStyle, Attribute, Block, Error, Expr, Ident, + ReturnType, Token, Type, }; #[allow(non_camel_case_types)] @@ -128,17 +128,25 @@ impl Parse for QueryModifier { } /// Ensures only doc comment attributes are used -fn check_attributes(attrs: Vec) -> Result<()> { - for attr in attrs { +fn check_attributes(attrs: Vec) -> Result> { + let inner = |attr: Attribute| { if !attr.path.is_ident("doc") { - return Err(Error::new(attr.span(), "attributes not supported on queries")); + Err(Error::new(attr.span(), "attributes not supported on queries")) + } else if attr.style != AttrStyle::Outer { + Err(Error::new( + attr.span(), + "attributes must be outer attributes (`///`), not inner attributes", + )) + } else { + Ok(attr) } - } - Ok(()) + }; + attrs.into_iter().map(inner).collect() } /// A compiler query. `query ... { ... }` struct Query { + doc_comments: Vec, modifiers: List, name: Ident, key: IdentOrWild, @@ -148,7 +156,7 @@ struct Query { impl Parse for Query { fn parse(input: ParseStream<'_>) -> Result { - check_attributes(input.call(Attribute::parse_outer)?)?; + let doc_comments = check_attributes(input.call(Attribute::parse_outer)?)?; // Parse the query declaration. Like `query type_of(key: DefId) -> Ty<'tcx>` input.parse::()?; @@ -165,7 +173,7 @@ impl Parse for Query { braced!(content in input); let modifiers = content.parse()?; - Ok(Query { modifiers, name, key, arg, result }) + Ok(Query { doc_comments, modifiers, name, key, arg, result }) } } @@ -476,9 +484,10 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { }; let attribute_stream = quote! {#(#attributes),*}; - + let doc_comments = query.doc_comments.iter(); // Add the query to the group group_stream.extend(quote! { + #(#doc_comments)* [#attribute_stream] fn #name: #name(#arg) #result, }); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 15e3110bc851e..6a54d91769460 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -42,48 +42,48 @@ rustc_queries! { } Other { - // Represents crate as a whole (as distinct from the top-level crate module). - // If you call `hir_crate` (e.g., indirectly by calling `tcx.hir().krate()`), - // we will have to assume that any change means that you need to be recompiled. - // This is because the `hir_crate` query gives you access to all other items. - // To avoid this fate, do not call `tcx.hir().krate()`; instead, - // prefer wrappers like `tcx.visit_all_items_in_krate()`. + /// Represents crate as a whole (as distinct from the top-level crate module). + /// If you call `hir_crate` (e.g., indirectly by calling `tcx.hir().krate()`), + /// we will have to assume that any change means that you need to be recompiled. + /// This is because the `hir_crate` query gives you access to all other items. + /// To avoid this fate, do not call `tcx.hir().krate()`; instead, + /// prefer wrappers like `tcx.visit_all_items_in_krate()`. query hir_crate(key: CrateNum) -> &'tcx Crate<'tcx> { eval_always no_hash desc { "get the crate HIR" } } - // The indexed HIR. This can be conveniently accessed by `tcx.hir()`. - // Avoid calling this query directly. + /// The indexed HIR. This can be conveniently accessed by `tcx.hir()`. + /// Avoid calling this query directly. query index_hir(_: CrateNum) -> &'tcx map::IndexedHir<'tcx> { eval_always no_hash desc { "index HIR" } } - // The items in a module. - // - // This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`. - // Avoid calling this query directly. + /// The items in a module. + /// + /// This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`. + /// Avoid calling this query directly. query hir_module_items(key: LocalDefId) -> &'tcx hir::ModuleItems { eval_always desc { |tcx| "HIR module items in `{}`", tcx.def_path_str(key.to_def_id()) } } - // Gives access to the HIR node for the HIR owner `key`. - // - // This can be conveniently accessed by methods on `tcx.hir()`. - // Avoid calling this query directly. + /// Gives access to the HIR node for the HIR owner `key`. + /// + /// This can be conveniently accessed by methods on `tcx.hir()`. + /// Avoid calling this query directly. query hir_owner(key: LocalDefId) -> Option<&'tcx crate::hir::Owner<'tcx>> { eval_always desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) } } - // Gives access to the HIR nodes and bodies inside the HIR owner `key`. - // - // This can be conveniently accessed by methods on `tcx.hir()`. - // Avoid calling this query directly. + /// Gives access to the HIR nodes and bodies inside the HIR owner `key`. + /// + /// This can be conveniently accessed by methods on `tcx.hir()`. + /// Avoid calling this query directly. query hir_owner_nodes(key: LocalDefId) -> Option<&'tcx crate::hir::OwnerNodes<'tcx>> { eval_always desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) } @@ -305,9 +305,9 @@ rustc_queries! { } TypeChecking { - // Erases regions from `ty` to yield a new type. - // Normally you would just use `tcx.erase_regions(&value)`, - // however, which uses this query as a kind of cache. + /// Erases regions from `ty` to yield a new type. + /// Normally you would just use `tcx.erase_regions(&value)`, + /// however, which uses this query as a kind of cache. query erase_regions_ty(ty: Ty<'tcx>) -> Ty<'tcx> { // This query is not expected to have input -- as a result, it // is not a good candidates for "replay" because it is essentially a @@ -1514,7 +1514,7 @@ rustc_queries! { desc { "looking up supported target features" } } - // Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning. + /// Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning. query instance_def_size_estimate(def: ty::InstanceDef<'tcx>) -> usize { desc { |tcx| "estimating size for `{}`", tcx.def_path_str(def.def_id()) } From 4fe6ca37898bcd65488764f2679e27c936879ade Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 17 Sep 2020 07:08:34 +0200 Subject: [PATCH 0535/1052] Replace const_generics feature gate with min_const_generics The latter is on the path to stabilization. --- compiler/rustc_data_structures/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 88c160e93b66a..b339261189b9c 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -26,7 +26,7 @@ #![feature(thread_id_value)] #![feature(extend_one)] #![feature(const_panic)] -#![feature(const_generics)] +#![feature(min_const_generics)] #![feature(once_cell)] #![allow(rustc::default_hash_types)] From ebdea011436dfea810ff1bbd827636ac75f6f092 Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 17 Sep 2020 07:46:35 +0200 Subject: [PATCH 0536/1052] Remove redundant #![feature(...)] 's from compiler/ --- compiler/rustc_ast/src/lib.rs | 4 ---- compiler/rustc_codegen_ssa/src/lib.rs | 2 -- compiler/rustc_data_structures/src/lib.rs | 1 - compiler/rustc_expand/src/lib.rs | 1 - compiler/rustc_infer/src/lib.rs | 2 -- compiler/rustc_middle/src/lib.rs | 5 ----- compiler/rustc_mir/src/lib.rs | 3 --- compiler/rustc_parse/src/lib.rs | 1 - compiler/rustc_parse_format/src/lib.rs | 2 -- compiler/rustc_privacy/src/lib.rs | 1 - compiler/rustc_span/src/lib.rs | 2 -- compiler/rustc_traits/src/lib.rs | 1 - compiler/rustc_ty/src/lib.rs | 1 - 13 files changed, 26 deletions(-) diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index b556c1a446b7b..76b84d9da8334 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -5,17 +5,13 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] -#![feature(bool_to_option)] #![feature(box_syntax)] #![feature(const_fn)] // For the `transmute` in `P::new` #![feature(const_panic)] -#![feature(const_fn_transmute)] #![feature(crate_visibility_modifier)] #![feature(label_break_value)] #![feature(nll)] #![feature(or_patterns)] -#![feature(try_trait)] -#![feature(unicode_internals)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 73e3336917587..a87ce1446ba14 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -8,8 +8,6 @@ #![feature(or_patterns)] #![feature(trusted_len)] #![feature(associated_type_bounds)] -#![feature(const_fn)] // for rustc_index::newtype_index -#![feature(const_panic)] // for rustc_index::newtype_index #![recursion_limit = "256"] //! This crate contains codegen code that is used by all codegen backends (LLVM and others). diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index b339261189b9c..e5dd7107ff3ad 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -11,7 +11,6 @@ #![feature(control_flow_enum)] #![feature(in_band_lifetimes)] #![feature(unboxed_closures)] -#![feature(generators)] #![feature(generator_trait)] #![feature(fn_traits)] #![feature(min_specialization)] diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 5436b1ef737f5..47247294f5dc6 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -1,5 +1,4 @@ #![feature(bool_to_option)] -#![feature(cow_is_borrowed)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] #![feature(or_patterns)] diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index e05041d88460e..504b66bae7329 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -13,7 +13,6 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] -#![feature(bindings_after_at)] #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] @@ -23,7 +22,6 @@ #![feature(never_type)] #![feature(or_patterns)] #![feature(in_band_lifetimes)] -#![feature(crate_visibility_modifier)] #![recursion_limit = "512"] // For rustdoc #[macro_use] diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index a675aae5b17d4..6b411ef8f09ee 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -30,12 +30,9 @@ #![feature(cmp_min_max_by)] #![feature(const_fn)] #![feature(const_panic)] -#![feature(const_fn_transmute)] #![feature(core_intrinsics)] #![feature(discriminant_kind)] -#![feature(drain_filter)] #![feature(never_type)] -#![feature(exhaustive_patterns)] #![feature(extern_types)] #![feature(nll)] #![feature(once_cell)] @@ -43,13 +40,11 @@ #![feature(or_patterns)] #![feature(min_specialization)] #![feature(trusted_len)] -#![feature(stmt_expr_attributes)] #![feature(test)] #![feature(in_band_lifetimes)] #![feature(crate_visibility_modifier)] #![feature(associated_type_bounds)] #![feature(rustc_attrs)] -#![feature(hash_raw_entry)] #![feature(int_error_matching)] #![recursion_limit = "512"] diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index 42717f273843a..fae4a261b3e32 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -13,15 +13,12 @@ Rust MIR: a lowered representation of Rust. #![feature(const_panic)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] -#![feature(drain_filter)] #![feature(exact_size_is_empty)] #![feature(exhaustive_patterns)] -#![feature(iter_order_by)] #![feature(never_type)] #![feature(min_specialization)] #![feature(trusted_len)] #![feature(try_blocks)] -#![feature(associated_type_bounds)] #![feature(associated_type_defaults)] #![feature(stmt_expr_attributes)] #![feature(trait_alias)] diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 0becdf24c532b..72a34b86ae20b 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -3,7 +3,6 @@ #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(bindings_after_at)] -#![feature(try_blocks)] #![feature(or_patterns)] use rustc_ast as ast; diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index e07b8b86aef8e..dde162681b773 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -11,8 +11,6 @@ )] #![feature(nll)] #![feature(or_patterns)] -#![feature(rustc_private)] -#![feature(unicode_internals)] #![feature(bool_to_option)] pub use Alignment::*; diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 03cc718b8995d..d451a383b12a3 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1,7 +1,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(in_band_lifetimes)] #![feature(nll)] -#![feature(or_patterns)] #![recursion_limit = "256"] use rustc_attr as attr; diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index e38cd516b91ac..1d1013967b7db 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -10,10 +10,8 @@ #![feature(const_panic)] #![feature(negative_impls)] #![feature(nll)] -#![feature(optin_builtin_traits)] #![feature(min_specialization)] #![feature(option_expect_none)] -#![feature(refcell_take)] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs index 6fea4732dda3f..d0b05beb4e63c 100644 --- a/compiler/rustc_traits/src/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -4,7 +4,6 @@ #![feature(crate_visibility_modifier)] #![feature(in_band_lifetimes)] #![feature(nll)] -#![feature(or_patterns)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_ty/src/lib.rs b/compiler/rustc_ty/src/lib.rs index 6e9042d1ba7c8..8dd6aa3c7fcc1 100644 --- a/compiler/rustc_ty/src/lib.rs +++ b/compiler/rustc_ty/src/lib.rs @@ -5,7 +5,6 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] -#![feature(bool_to_option)] #![feature(nll)] #![recursion_limit = "256"] From d655c0a938c16d30ae6824713165c749eff7210f Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Tue, 25 Aug 2020 15:13:40 +1200 Subject: [PATCH 0537/1052] Change the criteria of `interior_mutable_const` * stop linting associated types and generic type parameters * start linting ones in trait impls whose corresponding definitions in the traits are generic * remove the `is_copy` check as presumably the only purpose of it is to allow generics with `Copy` bounds as `Freeze` is internal and generics are no longer linted * remove the term 'copy' from the tests as being `Copy` no longer have meaning --- clippy_lints/src/non_copy_const.rs | 93 ++++++++++++------- tests/ui/borrow_interior_mutable_const.rs | 20 +++- tests/ui/borrow_interior_mutable_const.stderr | 44 +++++---- tests/ui/declare_interior_mutable_const.rs | 62 +++++++------ .../ui/declare_interior_mutable_const.stderr | 62 ++++--------- 5 files changed, 156 insertions(+), 125 deletions(-) diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 73eabd4207e77..28c68a2b68c57 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -6,14 +6,17 @@ use std::ptr; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp}; +use rustc_infer::traits::specialization_graph; use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_middle::ty::adjustment::Adjust; -use rustc_middle::ty::{Ty, TypeFlags}; +use rustc_middle::ty::fold::TypeFoldable as _; +use rustc_middle::ty::{AssocKind, Ty, TypeFlags}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{InnerSpan, Span, DUMMY_SP}; use rustc_typeck::hir_ty_to_ty; -use crate::utils::{in_constant, is_copy, qpath_res, span_lint_and_then}; +use crate::utils::{in_constant, qpath_res, span_lint_and_then}; +use if_chain::if_chain; declare_clippy_lint! { /// **What it does:** Checks for declaration of `const` items which is interior @@ -83,11 +86,10 @@ declare_clippy_lint! { "referencing `const` with interior mutability" } -#[allow(dead_code)] #[derive(Copy, Clone)] enum Source { Item { item: Span }, - Assoc { item: Span, ty: Span }, + Assoc { item: Span }, Expr { expr: Span }, } @@ -110,10 +112,15 @@ impl Source { } fn verify_ty_bound<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, source: Source) { - if ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env) || is_copy(cx, ty) { - // An `UnsafeCell` is `!Copy`, and an `UnsafeCell` is also the only type which - // is `!Freeze`, thus if our type is `Copy` we can be sure it must be `Freeze` - // as well. + // 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`. + // 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; } @@ -127,11 +134,7 @@ fn verify_ty_bound<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, source: Source) { let const_kw_span = span.from_inner(InnerSpan::new(0, 5)); diag.span_label(const_kw_span, "make this a static item (maybe with lazy_static)"); }, - Source::Assoc { ty: ty_span, .. } => { - if ty.flags().intersects(TypeFlags::HAS_FREE_LOCAL_NAMES) { - diag.span_label(ty_span, &format!("consider requiring `{}` to be `Copy`", ty)); - } - }, + Source::Assoc { .. } => (), Source::Expr { .. } => { diag.help("assign this const to a local or static variable, and use the variable here"); }, @@ -152,14 +155,10 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'_>) { if let TraitItemKind::Const(hir_ty, ..) = &trait_item.kind { let ty = hir_ty_to_ty(cx.tcx, hir_ty); - verify_ty_bound( - cx, - ty, - Source::Assoc { - ty: hir_ty.span, - item: trait_item.span, - }, - ); + // 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 }); } } @@ -167,17 +166,47 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { if let ImplItemKind::Const(hir_ty, ..) = &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); - // Ensure the impl is an inherent impl. - if let ItemKind::Impl { of_trait: None, .. } = item.kind { - let ty = hir_ty_to_ty(cx.tcx, hir_ty); - verify_ty_bound( - cx, - ty, - Source::Assoc { - ty: hir_ty.span, - item: impl_item.span, - }, - ); + + match &item.kind { + ItemKind::Impl { + of_trait: Some(of_trait_ref), + .. + } => { + if_chain! { + // Lint a trait impl item only when the definition is a generic type, + // assuming a assoc const is not meant to be a interior mutable type. + if let Some(of_trait_def_id) = of_trait_ref.trait_def_id(); + if let Some(of_assoc_item) = specialization_graph::Node::Trait(of_trait_def_id) + .item(cx.tcx, impl_item.ident, AssocKind::Const, of_trait_def_id); + if cx.tcx + // Normalize assoc types because ones originated from generic params + // bounded other traits could have their bound at the trait defs; + // and, in that case, the definition is *not* generic. + .normalize_erasing_regions( + cx.tcx.param_env(of_trait_def_id), + cx.tcx.type_of(of_assoc_item.def_id), + ) + .has_type_flags(TypeFlags::HAS_PROJECTION | TypeFlags::HAS_TY_PARAM); + 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, + }, + ); + } + } + }, + ItemKind::Impl { of_trait: None, .. } => { + 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 }); + }, + _ => (), } } } diff --git a/tests/ui/borrow_interior_mutable_const.rs b/tests/ui/borrow_interior_mutable_const.rs index 39f8751054850..9fcc9ece49bb7 100644 --- a/tests/ui/borrow_interior_mutable_const.rs +++ b/tests/ui/borrow_interior_mutable_const.rs @@ -19,16 +19,30 @@ const NO_ANN: &dyn Display = &70; static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING); const ONCE_INIT: Once = Once::new(); -trait Trait: Copy { - type NonCopyType; +trait Trait { + type AssocType; const ATOMIC: AtomicUsize; + const INPUT: T; + const ASSOC: Self::AssocType; + + fn function() { + let _ = &Self::INPUT; + let _ = &Self::ASSOC; + } } impl Trait for u64 { - type NonCopyType = u16; + 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, diff --git a/tests/ui/borrow_interior_mutable_const.stderr b/tests/ui/borrow_interior_mutable_const.stderr index 5800af7e960f4..ed726a6b46e64 100644 --- a/tests/ui/borrow_interior_mutable_const.stderr +++ b/tests/ui/borrow_interior_mutable_const.stderr @@ -1,14 +1,22 @@ error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:66:5 + --> $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 | ^^^^^^ | - = 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:67:16 + --> $DIR/borrow_interior_mutable_const.rs:81:16 | LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability | ^^^^^^ @@ -16,7 +24,7 @@ LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutabi = 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:70:22 + --> $DIR/borrow_interior_mutable_const.rs:84:22 | LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -24,7 +32,7 @@ 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:71:25 + --> $DIR/borrow_interior_mutable_const.rs:85:25 | LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -32,7 +40,7 @@ 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:72:27 + --> $DIR/borrow_interior_mutable_const.rs:86:27 | LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -40,7 +48,7 @@ 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:73:26 + --> $DIR/borrow_interior_mutable_const.rs:87:26 | LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -48,7 +56,7 @@ 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:84:14 + --> $DIR/borrow_interior_mutable_const.rs:98:14 | LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -56,7 +64,7 @@ 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:85:14 + --> $DIR/borrow_interior_mutable_const.rs:99:14 | LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -64,7 +72,7 @@ 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:86:19 + --> $DIR/borrow_interior_mutable_const.rs:100:19 | LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -72,7 +80,7 @@ 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:87:14 + --> $DIR/borrow_interior_mutable_const.rs:101:14 | LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -80,7 +88,7 @@ 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:88:13 + --> $DIR/borrow_interior_mutable_const.rs:102:13 | LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -88,7 +96,7 @@ LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mu = 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:94:13 + --> $DIR/borrow_interior_mutable_const.rs:108:13 | LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -96,7 +104,7 @@ 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:99:5 + --> $DIR/borrow_interior_mutable_const.rs:113:5 | LL | CELL.set(2); //~ ERROR interior mutability | ^^^^ @@ -104,7 +112,7 @@ 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:100:16 + --> $DIR/borrow_interior_mutable_const.rs:114:16 | LL | assert_eq!(CELL.get(), 6); //~ ERROR interior mutability | ^^^^ @@ -112,7 +120,7 @@ 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:113:5 + --> $DIR/borrow_interior_mutable_const.rs:127:5 | LL | u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^^^^^^ @@ -120,12 +128,12 @@ 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:114:16 + --> $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 16 previous errors +error: aborting due to 17 previous errors diff --git a/tests/ui/declare_interior_mutable_const.rs b/tests/ui/declare_interior_mutable_const.rs index b4003ed8932d3..7471b36054067 100644 --- a/tests/ui/declare_interior_mutable_const.rs +++ b/tests/ui/declare_interior_mutable_const.rs @@ -34,60 +34,64 @@ static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING); #[allow(clippy::declare_interior_mutable_const)] const ONCE_INIT: Once = Once::new(); -trait Trait: Copy { - type NonCopyType; +struct Wrapper(T); + +trait Trait> { + type AssocType; + type AssocType2; + type AssocType3; const ATOMIC: AtomicUsize; //~ ERROR interior mutable const INTEGER: u64; const STRING: String; - const SELF: Self; // (no error) + const SELF: Self; const INPUT: T; - //~^ ERROR interior mutable - //~| HELP consider requiring `T` to be `Copy` - const ASSOC: Self::NonCopyType; - //~^ ERROR interior mutable - //~| HELP consider requiring `>::NonCopyType` to be `Copy` + const INPUT_ASSOC: T::AssocType4; + const INPUT_ASSOC_2: T::AssocType5; //~ ERROR interior mutable + const ASSOC: Self::AssocType; + const ASSOC_2: Self::AssocType2; + const WRAPPED_ASSOC_2: Wrapper; + const WRAPPED_ASSOC_3: Wrapper; const AN_INPUT: T = Self::INPUT; - //~^ ERROR interior mutable - //~| ERROR consider requiring `T` to be `Copy` - declare_const!(ANOTHER_INPUT: T = Self::INPUT); //~ ERROR interior mutable + declare_const!(ANOTHER_INPUT: T = Self::INPUT); + declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ ERROR interior mutable } trait Trait2 { - type CopyType: Copy; + type AssocType4; + type AssocType5; const SELF_2: Self; - //~^ ERROR interior mutable - //~| HELP consider requiring `Self` to be `Copy` - const ASSOC_2: Self::CopyType; // (no error) + const ASSOC_4: Self::AssocType4; } -// we don't lint impl of traits, because an impl has no power to change the interface. -impl Trait for u64 { - type NonCopyType = u16; +impl> Trait for u64 { + type AssocType = u16; + type AssocType2 = AtomicUsize; + type AssocType3 = T; const ATOMIC: AtomicUsize = AtomicUsize::new(9); const INTEGER: u64 = 10; const STRING: String = String::new(); const SELF: Self = 11; - const INPUT: u32 = 12; - const ASSOC: Self::NonCopyType = 13; + const INPUT: T = T::SELF_2; + const INPUT_ASSOC: T::AssocType4 = T::ASSOC_4; + const INPUT_ASSOC_2: T::AssocType5 = AtomicUsize::new(16); + const ASSOC: Self::AssocType = 13; + const ASSOC_2: Self::AssocType2 = AtomicUsize::new(15); //~ ERROR interior mutable + const WRAPPED_ASSOC_2: Wrapper = Wrapper(AtomicUsize::new(16)); //~ ERROR interior mutable + const WRAPPED_ASSOC_3: Wrapper = Wrapper(T::SELF_2); } struct Local(T, U); -impl, U: Trait2> Local { - const ASSOC_3: AtomicUsize = AtomicUsize::new(14); //~ ERROR interior mutable +impl, U: Trait2> Local { + const ASSOC_5: AtomicUsize = AtomicUsize::new(14); //~ ERROR interior mutable const COW: Cow<'static, str> = Cow::Borrowed("tuvwxy"); - const T_SELF: T = T::SELF_2; const U_SELF: U = U::SELF_2; - //~^ ERROR interior mutable - //~| HELP consider requiring `U` to be `Copy` - const T_ASSOC: T::NonCopyType = T::ASSOC; - //~^ ERROR interior mutable - //~| HELP consider requiring `>::NonCopyType` to be `Copy` - const U_ASSOC: U::CopyType = U::ASSOC_2; + const T_ASSOC: T::AssocType = T::ASSOC; + const U_ASSOC: U::AssocType5 = AtomicUsize::new(17); //~ ERROR interior mutable } fn main() {} diff --git a/tests/ui/declare_interior_mutable_const.stderr b/tests/ui/declare_interior_mutable_const.stderr index 6a9a57361f9f3..0fcb726db46ee 100644 --- a/tests/ui/declare_interior_mutable_const.stderr +++ b/tests/ui/declare_interior_mutable_const.stderr @@ -36,34 +36,16 @@ LL | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable = 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:40:5 + --> $DIR/declare_interior_mutable_const.rs:44:5 | LL | const ATOMIC: AtomicUsize; //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:44:5 - | -LL | const INPUT: T; - | ^^^^^^^^^^^^^-^ - | | - | consider requiring `T` to be `Copy` - -error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:47:5 + --> $DIR/declare_interior_mutable_const.rs:50:5 | -LL | const ASSOC: Self::NonCopyType; - | ^^^^^^^^^^^^^-----------------^ - | | - | consider requiring `>::NonCopyType` to be `Copy` - -error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:51:5 - | -LL | const AN_INPUT: T = Self::INPUT; - | ^^^^^^^^^^^^^^^^-^^^^^^^^^^^^^^^ - | | - | consider requiring `T` to be `Copy` +LL | const INPUT_ASSOC_2: T::AssocType5; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable --> $DIR/declare_interior_mutable_const.rs:16:9 @@ -71,40 +53,34 @@ error: a `const` item should never be interior mutable LL | const $name: $ty = $e; | ^^^^^^^^^^^^^^^^^^^^^^ ... -LL | declare_const!(ANOTHER_INPUT: T = Self::INPUT); //~ ERROR interior mutable - | ----------------------------------------------- in this macro invocation +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:60:5 + --> $DIR/declare_interior_mutable_const.rs:82:5 | -LL | const SELF_2: Self; - | ^^^^^^^^^^^^^^----^ - | | - | consider requiring `Self` to be `Copy` +LL | const ASSOC_2: Self::AssocType2 = AtomicUsize::new(15); //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:81:5 + --> $DIR/declare_interior_mutable_const.rs:83:5 | -LL | const ASSOC_3: AtomicUsize = AtomicUsize::new(14); //~ ERROR interior mutable - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | const WRAPPED_ASSOC_2: Wrapper = Wrapper(AtomicUsize::new(16)); //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:84:5 + --> $DIR/declare_interior_mutable_const.rs:90:5 | -LL | const U_SELF: U = U::SELF_2; - | ^^^^^^^^^^^^^^-^^^^^^^^^^^^^ - | | - | consider requiring `U` to be `Copy` +LL | const ASSOC_5: AtomicUsize = AtomicUsize::new(14); //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:87:5 + --> $DIR/declare_interior_mutable_const.rs:94:5 | -LL | const T_ASSOC: T::NonCopyType = T::ASSOC; - | ^^^^^^^^^^^^^^^--------------^^^^^^^^^^^^ - | | - | consider requiring `>::NonCopyType` to be `Copy` +LL | const U_ASSOC: U::AssocType5 = AtomicUsize::new(17); //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 13 previous errors +error: aborting due to 11 previous errors From 2fc9064921ce0afd2c07c5b576f95c7adf731541 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Thu, 17 Sep 2020 19:37:42 +1200 Subject: [PATCH 0538/1052] rewrite the test and fix a minor fp * rewrite the test for `declare_interior_mutable_const from scratch` * fix a minor false positive where `Cell<"const T>` gets linted twice --- clippy_lints/src/non_copy_const.rs | 24 +-- tests/ui/declare_interior_mutable_const.rs | 159 +++++++++++++----- .../ui/declare_interior_mutable_const.stderr | 58 ++++--- 3 files changed, 166 insertions(+), 75 deletions(-) diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 28c68a2b68c57..bb44eeb6adc51 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -9,8 +9,7 @@ use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, Node, Tr use rustc_infer::traits::specialization_graph; use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_middle::ty::adjustment::Adjust; -use rustc_middle::ty::fold::TypeFoldable as _; -use rustc_middle::ty::{AssocKind, Ty, TypeFlags}; +use rustc_middle::ty::{AssocKind, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{InnerSpan, Span, DUMMY_SP}; use rustc_typeck::hir_ty_to_ty; @@ -178,15 +177,18 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { if let Some(of_trait_def_id) = of_trait_ref.trait_def_id(); if let Some(of_assoc_item) = specialization_graph::Node::Trait(of_trait_def_id) .item(cx.tcx, impl_item.ident, AssocKind::Const, of_trait_def_id); - if cx.tcx - // Normalize assoc types because ones originated from generic params - // bounded other traits could have their bound at the trait defs; - // and, in that case, the definition is *not* generic. - .normalize_erasing_regions( - cx.tcx.param_env(of_trait_def_id), - cx.tcx.type_of(of_assoc_item.def_id), - ) - .has_type_flags(TypeFlags::HAS_PROJECTION | TypeFlags::HAS_TY_PARAM); + if cx + .tcx + .layout_of(cx.tcx.param_env(of_trait_def_id).and( + // Normalize assoc types because ones originated from generic params + // bounded other traits could have their bound at the trait defs; + // and, in that case, the definition is *not* generic. + cx.tcx.normalize_erasing_regions( + cx.tcx.param_env(of_trait_def_id), + cx.tcx.type_of(of_assoc_item.def_id), + ), + )) + .is_err(); then { let ty = hir_ty_to_ty(cx.tcx, hir_ty); let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); diff --git a/tests/ui/declare_interior_mutable_const.rs b/tests/ui/declare_interior_mutable_const.rs index 7471b36054067..646d3ec8b472e 100644 --- a/tests/ui/declare_interior_mutable_const.rs +++ b/tests/ui/declare_interior_mutable_const.rs @@ -34,64 +34,135 @@ static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING); #[allow(clippy::declare_interior_mutable_const)] const ONCE_INIT: Once = Once::new(); -struct Wrapper(T); - -trait Trait> { - type AssocType; - type AssocType2; - type AssocType3; - +// 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; - const SELF: Self; - const INPUT: T; - const INPUT_ASSOC: T::AssocType4; - const INPUT_ASSOC_2: T::AssocType5; //~ ERROR interior mutable - const ASSOC: Self::AssocType; - const ASSOC_2: Self::AssocType2; - const WRAPPED_ASSOC_2: Wrapper; - const WRAPPED_ASSOC_3: Wrapper; - - const AN_INPUT: T = Self::INPUT; - declare_const!(ANOTHER_INPUT: T = Self::INPUT); declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ ERROR interior mutable } -trait Trait2 { - type AssocType4; - type AssocType5; +impl ConcreteTypes for u64 { + const ATOMIC: AtomicUsize = AtomicUsize::new(9); + const INTEGER: u64 = 10; + const STRING: String = String::new(); +} - const SELF_2: Self; - const ASSOC_4: Self::AssocType4; +// a helper trait used below +trait ConstDefault { + const DEFAULT: Self; } -impl> Trait for u64 { - type AssocType = u16; - type AssocType2 = AtomicUsize; - type AssocType3 = T; +// a constant whose type is a generic type should be linted at the implementation site. +trait GenericTypes { + const TO_REMAIN_GENERIC: T; + const TO_BE_CONCRETE: U; - const ATOMIC: AtomicUsize = AtomicUsize::new(9); - const INTEGER: u64 = 10; - const STRING: String = String::new(); - const SELF: Self = 11; - const INPUT: T = T::SELF_2; - const INPUT_ASSOC: T::AssocType4 = T::ASSOC_4; - const INPUT_ASSOC_2: T::AssocType5 = AtomicUsize::new(16); - const ASSOC: Self::AssocType = 13; - const ASSOC_2: Self::AssocType2 = AtomicUsize::new(15); //~ ERROR interior mutable - const WRAPPED_ASSOC_2: Wrapper = Wrapper(AtomicUsize::new(16)); //~ ERROR interior mutable - const WRAPPED_ASSOC_3: Wrapper = Wrapper(T::SELF_2); + const HAVING_DEFAULT: T = Self::TO_REMAIN_GENERIC; + declare_const!(IN_MACRO: T = Self::TO_REMAIN_GENERIC); +} + +impl GenericTypes 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); + +// 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; + // to ensure it can handle things when a generic type remains after normalization. + const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper; +} + +impl AssocTypes for Vec { + 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 = Wrapper(AtomicUsize::new(14)); //~ ERROR interior mutable + const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper = Wrapper(T::DEFAULT); } -struct Local(T, U); +// a helper trait used below +trait AssocTypesHelper { + type NotToBeBounded; + type ToBeBounded; -impl, U: Trait2> Local { - const ASSOC_5: AtomicUsize = AtomicUsize::new(14); //~ ERROR interior mutable + 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 +where + T: AssocTypesHelper, +{ + const NOT_BOUNDED: T::NotToBeBounded; + const BOUNDED: T::ToBeBounded; //~ ERROR interior mutable +} + +impl AssocTypesFromGenericParam for u64 +where + T: AssocTypesHelper, +{ + // 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); +} + +trait SelfType { + const SELF: Self; +} + +impl SelfType for u64 { + const SELF: Self = 16; +} + +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 +} + +// 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 { + // this is a false negative in the current implementation. + const DIRECT: Cell; + const INDIRECT: Cell<*const T>; //~ ERROR interior mutable +} + +impl BothOfCellAndGeneric for u64 { + const DIRECT: Cell = Cell::new(T::DEFAULT); + const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null()); +} + +struct Local(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 Local +where + T: ConstDefault + AssocTypesHelper, +{ + const ATOMIC: AtomicUsize = AtomicUsize::new(18); //~ ERROR interior mutable const COW: Cow<'static, str> = Cow::Borrowed("tuvwxy"); - const U_SELF: U = U::SELF_2; - const T_ASSOC: T::AssocType = T::ASSOC; - const U_ASSOC: U::AssocType5 = AtomicUsize::new(17); //~ ERROR interior mutable + + 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() {} diff --git a/tests/ui/declare_interior_mutable_const.stderr b/tests/ui/declare_interior_mutable_const.stderr index 0fcb726db46ee..0a0b818b8b7f1 100644 --- a/tests/ui/declare_interior_mutable_const.stderr +++ b/tests/ui/declare_interior_mutable_const.stderr @@ -36,17 +36,11 @@ LL | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable = 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:44:5 + --> $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:50:5 - | -LL | const INPUT_ASSOC_2: T::AssocType5; //~ ERROR interior mutable - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: a `const` item should never be interior mutable --> $DIR/declare_interior_mutable_const.rs:16:9 | @@ -59,28 +53,52 @@ LL | declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ ERROR i = 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:82:5 + --> $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 = 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:135:5 | -LL | const ASSOC_2: Self::AssocType2 = AtomicUsize::new(15); //~ ERROR interior mutable - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +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:83:5 + --> $DIR/declare_interior_mutable_const.rs:143:5 | -LL | const WRAPPED_ASSOC_2: Wrapper = Wrapper(AtomicUsize::new(16)); //~ ERROR interior mutable - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | const INDIRECT: Cell<*const T>; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:90:5 + --> $DIR/declare_interior_mutable_const.rs:159:5 | -LL | const ASSOC_5: AtomicUsize = AtomicUsize::new(14); //~ ERROR interior mutable - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +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:94:5 + --> $DIR/declare_interior_mutable_const.rs:165:5 | -LL | const U_ASSOC: U::AssocType5 = AtomicUsize::new(17); //~ ERROR interior mutable - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 11 previous errors +error: aborting due to 14 previous errors From 5f58e00ca565c8964dbf89f510236f72951d0bab Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 17 Sep 2020 09:53:19 +0200 Subject: [PATCH 0539/1052] fix array_windows docs --- library/core/src/slice/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 8e9d1eb98a86b..9e716c487c169 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1034,7 +1034,7 @@ impl [T] { /// /// This is the const generic equivalent of [`windows`]. /// - /// If `N` is smaller than the size of the array, it will return no windows. + /// If `N` is greater than the size of the array, it will return no windows. /// /// # Panics /// From 012974da7ad3737b296af4a401dfed2e8dcc22df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Thu, 17 Sep 2020 10:13:16 +0200 Subject: [PATCH 0540/1052] use strip_prefix over starts_with and manual slicing based on pattern length (clippy::manual_strip) --- compiler/rustc_driver/src/args.rs | 3 +-- .../borrow_check/diagnostics/move_errors.rs | 4 ++-- .../diagnostics/mutability_errors.rs | 5 ++--- .../rustc_resolve/src/late/diagnostics.rs | 4 ++-- compiler/rustc_session/src/search_paths.rs | 20 +++++++++---------- compiler/rustc_typeck/src/check/demand.rs | 6 +++++- compiler/rustc_typeck/src/check/op.rs | 8 ++++---- compiler/rustc_typeck/src/collect.rs | 4 ++-- 8 files changed, 28 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_driver/src/args.rs b/compiler/rustc_driver/src/args.rs index 5686819c61b40..4f2febf04b135 100644 --- a/compiler/rustc_driver/src/args.rs +++ b/compiler/rustc_driver/src/args.rs @@ -4,8 +4,7 @@ use std::fs; use std::io; pub fn arg_expand(arg: String) -> Result, Error> { - if arg.starts_with('@') { - let path = &arg[1..]; + if let Some(path) = arg.strip_prefix('@') { let file = match fs::read_to_string(path) { Ok(file) => file, Err(ref err) if err.kind() == io::ErrorKind::InvalidData => { diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs index e256fb55b124b..629e9be9ddd45 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs @@ -492,8 +492,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { { if let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span) { - if pat_snippet.starts_with('&') { - let pat_snippet = pat_snippet[1..].trim_start(); + if let Some(stripped) = pat_snippet.strip_prefix('&') { + let pat_snippet = stripped.trim_start(); let (suggestion, to_remove) = if pat_snippet.starts_with("mut") && pat_snippet["mut".len()..].starts_with(rustc_lexer::is_whitespace) { diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs index 8b0121cf360e0..d4cdf02104ace 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs @@ -631,9 +631,8 @@ fn suggest_ampmut<'tcx>( let lt_name = &src[1..ws_pos]; let ty = &src[ws_pos..]; return (assignment_rhs_span, format!("&{} mut {}", lt_name, ty)); - } else if src.starts_with('&') { - let borrowed_expr = &src[1..]; - return (assignment_rhs_span, format!("&mut {}", borrowed_expr)); + } else if let Some(stripped) = src.strip_prefix('&') { + return (assignment_rhs_span, format!("&mut {}", stripped)); } } } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 2cc87dc637566..ced272e474d11 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1418,9 +1418,9 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { if snippet.starts_with('&') && !snippet.starts_with("&'") { introduce_suggestion .push((param.span, format!("&{} {}", lt_name, &snippet[1..]))); - } else if snippet.starts_with("&'_ ") { + } else if let Some(stripped) = snippet.strip_prefix("&'_ ") { introduce_suggestion - .push((param.span, format!("&{} {}", lt_name, &snippet[4..]))); + .push((param.span, format!("&{} {}", lt_name, stripped))); } } } diff --git a/compiler/rustc_session/src/search_paths.rs b/compiler/rustc_session/src/search_paths.rs index e12364b7dac7c..83b737a73b1e8 100644 --- a/compiler/rustc_session/src/search_paths.rs +++ b/compiler/rustc_session/src/search_paths.rs @@ -56,16 +56,16 @@ impl PathKind { impl SearchPath { pub fn from_cli_opt(path: &str, output: config::ErrorOutputType) -> Self { - let (kind, path) = if path.starts_with("native=") { - (PathKind::Native, &path["native=".len()..]) - } else if path.starts_with("crate=") { - (PathKind::Crate, &path["crate=".len()..]) - } else if path.starts_with("dependency=") { - (PathKind::Dependency, &path["dependency=".len()..]) - } else if path.starts_with("framework=") { - (PathKind::Framework, &path["framework=".len()..]) - } else if path.starts_with("all=") { - (PathKind::All, &path["all=".len()..]) + let (kind, path) = if let Some(stripped) = path.strip_prefix("native=") { + (PathKind::Native, stripped) + } else if let Some(stripped) = path.strip_prefix("crate=") { + (PathKind::Crate, stripped) + } else if let Some(stripped) = path.strip_prefix("dependency=") { + (PathKind::Dependency, stripped) + } else if let Some(stripped) = path.strip_prefix("framework=") { + (PathKind::Framework, stripped) + } else if let Some(stripped) = path.strip_prefix("all=") { + (PathKind::All, stripped) } else { (PathKind::All, path) }; diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index f6b768bb12220..c7ce5008c3354 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -370,7 +370,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let s = s.as_ref(); let old = old.as_ref(); - if s.starts_with(old) { Some(new.as_ref().to_owned() + &s[old.len()..]) } else { None } + if let Some(stripped) = s.strip_prefix(old) { + Some(new.as_ref().to_owned() + stripped) + } else { + None + } } /// This function is used to determine potential "simple" improvements or users' errors and diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index 529b8525a4a8d..66975f32a1f4a 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -589,10 +589,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { msg }, - if lstring.starts_with('&') { + if let Some(stripped) = lstring.strip_prefix('&') { // let a = String::new(); // let _ = &a + "bar"; - lstring[1..].to_string() + stripped.to_string() } else { format!("{}.to_owned()", lstring) }, @@ -617,10 +617,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { is_assign, ) { (Ok(l), Ok(r), IsAssign::No) => { - let to_string = if l.starts_with('&') { + let to_string = if let Some(stripped) = l.strip_prefix('&') { // let a = String::new(); let b = String::new(); // let _ = &a + b; - l[1..].to_string() + stripped.to_string() } else { format!("{}.to_owned()", l) }; diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 9b8427a46955c..504b5a330f00c 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2341,8 +2341,8 @@ fn from_target_feature( item.span(), format!("`{}` is not valid for this target", feature), ); - if feature.starts_with('+') { - let valid = supported_target_features.contains_key(&feature[1..]); + if let Some(stripped) = feature.strip_prefix('+') { + let valid = supported_target_features.contains_key(stripped); if valid { err.help("consider removing the leading `+` in the feature name"); } From 764d307963db8c50a47a9828a4c2eeea74d54007 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 17 Sep 2020 10:30:28 +0200 Subject: [PATCH 0541/1052] docs `array` -> `slice` Co-authored-by: est31 --- library/core/src/slice/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 9e716c487c169..a3a1715b75e31 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1034,7 +1034,7 @@ impl [T] { /// /// This is the const generic equivalent of [`windows`]. /// - /// If `N` is greater than the size of the array, it will return no windows. + /// If `N` is greater than the size of the slice, it will return no windows. /// /// # Panics /// From d5af360bb2de24235d2873e926d0b6f21135ae38 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Thu, 17 Sep 2020 21:14:14 +1200 Subject: [PATCH 0542/1052] add `WRAPPED_SELF: Option` in the test --- tests/ui/declare_interior_mutable_const.rs | 8 +++++++- tests/ui/declare_interior_mutable_const.stderr | 16 +++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/tests/ui/declare_interior_mutable_const.rs b/tests/ui/declare_interior_mutable_const.rs index 646d3ec8b472e..3afcdca2f04dd 100644 --- a/tests/ui/declare_interior_mutable_const.rs +++ b/tests/ui/declare_interior_mutable_const.rs @@ -121,18 +121,24 @@ where const BOUNDED: T::ToBeBounded = AtomicUsize::new(15); } -trait SelfType { +// 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; } impl SelfType for u64 { const SELF: Self = 16; + const WRAPPED_SELF: Option = 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 = Some(AtomicUsize::new(21)); //~ ERROR interior mutable } // Even though a constant contains a generic type, if it also have a interior mutable type, diff --git a/tests/ui/declare_interior_mutable_const.stderr b/tests/ui/declare_interior_mutable_const.stderr index 0a0b818b8b7f1..5cb10be88d89c 100644 --- a/tests/ui/declare_interior_mutable_const.stderr +++ b/tests/ui/declare_interior_mutable_const.stderr @@ -77,28 +77,34 @@ LL | const BOUNDED: T::ToBeBounded; //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:135:5 + --> $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:143:5 + --> $DIR/declare_interior_mutable_const.rs:141:5 + | +LL | const WRAPPED_SELF: Option = 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:159:5 + --> $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:165:5 + --> $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 14 previous errors +error: aborting due to 15 previous errors From 9fe9c6da3e7d1d71b6fcb9d99a29ccba8decf04e Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Wed, 16 Sep 2020 09:42:05 +0000 Subject: [PATCH 0543/1052] Using ::new instead of exposing internal fields --- library/core/src/slice/iter.rs | 250 +++++++++++++++++++++++++-------- library/core/src/slice/mod.rs | 52 ++++--- 2 files changed, 218 insertions(+), 84 deletions(-) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 84fa34c75e3a2..1c004f2d3fafc 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -8,7 +8,7 @@ use crate::cmp::Ordering; use crate::fmt; use crate::intrinsics::{assume, exact_div, unchecked_sub}; use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccess}; -use crate::marker::{self, Send, Sized, Sync}; +use crate::marker::{PhantomData, Send, Sized, Sync}; use crate::mem; use crate::ptr::NonNull; @@ -62,11 +62,11 @@ fn size_from_ptr(_: *const T) -> usize { /// [slices]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, T: 'a> { - pub(super) ptr: NonNull, - pub(super) end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that + ptr: NonNull, + end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that // ptr == end is a quick test for the Iterator being empty, that works // for both ZST and non-ZST. - pub(super) _marker: marker::PhantomData<&'a T>, + _marker: PhantomData<&'a T>, } #[stable(feature = "core_impl_debug", since = "1.9.0")] @@ -82,6 +82,10 @@ unsafe impl Sync for Iter<'_, T> {} unsafe impl Send for Iter<'_, T> {} impl<'a, T> Iter<'a, T> { + pub(super) fn new(ptr: NonNull, end: *const T) -> Self { + Self { ptr, end, _marker: PhantomData } + } + /// Views the underlying data as a subslice of the original data. /// /// This has the same lifetime as the original slice, and so the @@ -164,11 +168,11 @@ impl AsRef<[T]> for Iter<'_, T> { /// [slices]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, T: 'a> { - pub(super) ptr: NonNull, - pub(super) end: *mut T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that + ptr: NonNull, + end: *mut T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that // ptr == end is a quick test for the Iterator being empty, that works // for both ZST and non-ZST. - pub(super) _marker: marker::PhantomData<&'a mut T>, + _marker: PhantomData<&'a mut T>, } #[stable(feature = "core_impl_debug", since = "1.9.0")] @@ -184,6 +188,10 @@ unsafe impl Sync for IterMut<'_, T> {} unsafe impl Send for IterMut<'_, T> {} impl<'a, T> IterMut<'a, T> { + pub(super) fn new(ptr: NonNull, end: *mut T) -> Self { + Self { ptr, end, _marker: PhantomData } + } + /// Views the underlying data as a subslice of the original data. /// /// To avoid creating `&mut` references that alias, this is forced @@ -277,9 +285,15 @@ pub struct Split<'a, T: 'a, P> where P: FnMut(&T) -> bool, { - pub(super) v: &'a [T], - pub(super) pred: P, - pub(super) finished: bool, + v: &'a [T], + pred: P, + finished: bool, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> Split<'a, T, P> { + pub(super) fn new(slice: &'a [T], pred: P, finished: bool) -> Self { + Self { v: slice, pred, finished } + } } #[stable(feature = "core_impl_debug", since = "1.9.0")] @@ -385,9 +399,15 @@ pub struct SplitInclusive<'a, T: 'a, P> where P: FnMut(&T) -> bool, { - pub(super) v: &'a [T], - pub(super) pred: P, - pub(super) finished: bool, + v: &'a [T], + pred: P, + finished: bool, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitInclusive<'a, T, P> { + pub(super) fn new(slice: &'a [T], pred: P, finished: bool) -> Self { + Self { v: slice, pred, finished } + } } #[unstable(feature = "split_inclusive", issue = "72360")] @@ -483,9 +503,15 @@ pub struct SplitMut<'a, T: 'a, P> where P: FnMut(&T) -> bool, { - pub(super) v: &'a mut [T], - pub(super) pred: P, - pub(super) finished: bool, + v: &'a mut [T], + pred: P, + finished: bool, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitMut<'a, T, P> { + pub(super) fn new(slice: &'a mut [T], pred: P, finished: bool) -> Self { + Self { v: slice, pred, finished } + } } #[stable(feature = "core_impl_debug", since = "1.9.0")] @@ -598,9 +624,15 @@ pub struct SplitInclusiveMut<'a, T: 'a, P> where P: FnMut(&T) -> bool, { - pub(super) v: &'a mut [T], - pub(super) pred: P, - pub(super) finished: bool, + v: &'a mut [T], + pred: P, + finished: bool, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitInclusiveMut<'a, T, P> { + pub(super) fn new(slice: &'a mut [T], pred: P, finished: bool) -> Self { + Self { v: slice, pred, finished } + } } #[unstable(feature = "split_inclusive", issue = "72360")] @@ -706,7 +738,13 @@ pub struct RSplit<'a, T: 'a, P> where P: FnMut(&T) -> bool, { - pub(super) inner: Split<'a, T, P>, + inner: Split<'a, T, P>, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplit<'a, T, P> { + pub(super) fn new(slice: &'a [T], pred: P, finished: bool) -> Self { + Self { inner: Split::new(slice, pred, finished) } + } } #[stable(feature = "slice_rsplit", since = "1.27.0")] @@ -777,7 +815,13 @@ pub struct RSplitMut<'a, T: 'a, P> where P: FnMut(&T) -> bool, { - pub(super) inner: SplitMut<'a, T, P>, + inner: SplitMut<'a, T, P>, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplitMut<'a, T, P> { + pub(super) fn new(slice: &'a mut [T], pred: P, finished: bool) -> Self { + Self { inner: SplitMut::new(slice, pred, finished) } + } } #[stable(feature = "slice_rsplit", since = "1.27.0")] @@ -840,9 +884,9 @@ impl FusedIterator for RSplitMut<'_, T, P> where P: FnMut(&T) -> bool {} /// match a predicate function, splitting at most a fixed number of /// times. #[derive(Debug)] -pub(super) struct GenericSplitN { - pub(super) iter: I, - pub(super) count: usize, +struct GenericSplitN { + iter: I, + count: usize, } impl> Iterator for GenericSplitN { @@ -882,7 +926,13 @@ pub struct SplitN<'a, T: 'a, P> where P: FnMut(&T) -> bool, { - pub(super) inner: GenericSplitN>, + inner: GenericSplitN>, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitN<'a, T, P> { + pub(super) fn new(s: Split<'a, T, P>, n: usize) -> Self { + Self { inner: GenericSplitN { iter: s, count: n } } + } } #[stable(feature = "core_impl_debug", since = "1.9.0")] @@ -908,7 +958,13 @@ pub struct RSplitN<'a, T: 'a, P> where P: FnMut(&T) -> bool, { - pub(super) inner: GenericSplitN>, + inner: GenericSplitN>, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplitN<'a, T, P> { + pub(super) fn new(s: RSplit<'a, T, P>, n: usize) -> Self { + Self { inner: GenericSplitN { iter: s, count: n } } + } } #[stable(feature = "core_impl_debug", since = "1.9.0")] @@ -933,7 +989,13 @@ pub struct SplitNMut<'a, T: 'a, P> where P: FnMut(&T) -> bool, { - pub(super) inner: GenericSplitN>, + inner: GenericSplitN>, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitNMut<'a, T, P> { + pub(super) fn new(s: SplitMut<'a, T, P>, n: usize) -> Self { + Self { inner: GenericSplitN { iter: s, count: n } } + } } #[stable(feature = "core_impl_debug", since = "1.9.0")] @@ -959,7 +1021,13 @@ pub struct RSplitNMut<'a, T: 'a, P> where P: FnMut(&T) -> bool, { - pub(super) inner: GenericSplitN>, + inner: GenericSplitN>, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplitNMut<'a, T, P> { + pub(super) fn new(s: RSplitMut<'a, T, P>, n: usize) -> Self { + Self { inner: GenericSplitN { iter: s, count: n } } + } } #[stable(feature = "core_impl_debug", since = "1.9.0")] @@ -986,8 +1054,14 @@ forward_iterator! { RSplitNMut: T, &'a mut [T] } #[derive(Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Windows<'a, T: 'a> { - pub(super) v: &'a [T], - pub(super) size: usize, + v: &'a [T], + size: usize, +} + +impl<'a, T: 'a> Windows<'a, T> { + pub(super) fn new(slice: &'a [T], size: usize) -> Self { + Self { v: slice, size } + } } // FIXME(#26925) Remove in favor of `#[derive(Clone)]` @@ -1118,8 +1192,14 @@ unsafe impl<'a, T> TrustedRandomAccess for Windows<'a, T> { #[derive(Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Chunks<'a, T: 'a> { - pub(super) v: &'a [T], - pub(super) chunk_size: usize, + v: &'a [T], + chunk_size: usize, +} + +impl<'a, T: 'a> Chunks<'a, T> { + pub(super) fn new(slice: &'a [T], size: usize) -> Self { + Self { v: slice, chunk_size: size } + } } // FIXME(#26925) Remove in favor of `#[derive(Clone)]` @@ -1272,8 +1352,14 @@ unsafe impl<'a, T> TrustedRandomAccess for Chunks<'a, T> { #[derive(Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct ChunksMut<'a, T: 'a> { - pub(super) v: &'a mut [T], - pub(super) chunk_size: usize, + v: &'a mut [T], + chunk_size: usize, +} + +impl<'a, T: 'a> ChunksMut<'a, T> { + pub(super) fn new(slice: &'a mut [T], size: usize) -> Self { + Self { v: slice, chunk_size: size } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1425,9 +1511,15 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> { #[derive(Debug)] #[stable(feature = "chunks_exact", since = "1.31.0")] pub struct ChunksExact<'a, T: 'a> { - pub(super) v: &'a [T], - pub(super) rem: &'a [T], - pub(super) chunk_size: usize, + v: &'a [T], + rem: &'a [T], + chunk_size: usize, +} + +impl<'a, T: 'a> ChunksExact<'a, T> { + pub(super) fn new(slice: &'a [T], rem: &'a [T], size: usize) -> Self { + Self { v: slice, rem, chunk_size: size } + } } impl<'a, T> ChunksExact<'a, T> { @@ -1565,9 +1657,15 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> { #[derive(Debug)] #[stable(feature = "chunks_exact", since = "1.31.0")] pub struct ChunksExactMut<'a, T: 'a> { - pub(super) v: &'a mut [T], - pub(super) rem: &'a mut [T], - pub(super) chunk_size: usize, + v: &'a mut [T], + rem: &'a mut [T], + chunk_size: usize, +} + +impl<'a, T: 'a> ChunksExactMut<'a, T> { + pub(super) fn new(slice: &'a mut [T], rem: &'a mut [T], size: usize) -> Self { + Self { v: slice, rem, chunk_size: size } + } } impl<'a, T> ChunksExactMut<'a, T> { @@ -1697,9 +1795,15 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> { #[derive(Debug, Clone, Copy)] #[unstable(feature = "array_windows", issue = "75027")] pub struct ArrayWindows<'a, T: 'a, const N: usize> { - pub(crate) slice_head: *const T, - pub(crate) num: usize, - pub(crate) marker: marker::PhantomData<&'a [T; N]>, + slice_head: *const T, + num: usize, + marker: PhantomData<&'a [T; N]>, +} + +impl<'a, T: 'a, const N: usize> ArrayWindows<'a, T, N> { + pub(super) fn new(head: *const T, num: usize) -> Self { + Self { slice_head: head, num, marker: PhantomData } + } } #[unstable(feature = "array_windows", issue = "75027")] @@ -1802,8 +1906,14 @@ impl ExactSizeIterator for ArrayWindows<'_, T, N> { #[derive(Debug)] #[unstable(feature = "array_chunks", issue = "74985")] pub struct ArrayChunks<'a, T: 'a, const N: usize> { - pub(super) iter: Iter<'a, [T; N]>, - pub(super) rem: &'a [T], + iter: Iter<'a, [T; N]>, + rem: &'a [T], +} + +impl<'a, T: 'a, const N: usize> ArrayChunks<'a, T, N> { + pub(super) fn new(iter: Iter<'a, [T; N]>, rem: &'a [T]) -> Self { + Self { iter, rem } + } } impl<'a, T, const N: usize> ArrayChunks<'a, T, N> { @@ -1909,8 +2019,14 @@ unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> #[derive(Debug)] #[unstable(feature = "array_chunks", issue = "74985")] pub struct ArrayChunksMut<'a, T: 'a, const N: usize> { - pub(super) iter: IterMut<'a, [T; N]>, - pub(super) rem: &'a mut [T], + iter: IterMut<'a, [T; N]>, + rem: &'a mut [T], +} + +impl<'a, T: 'a, const N: usize> ArrayChunksMut<'a, T, N> { + pub(super) fn new(iter: IterMut<'a, [T; N]>, rem: &'a mut [T]) -> Self { + Self { iter, rem } + } } impl<'a, T, const N: usize> ArrayChunksMut<'a, T, N> { @@ -2006,8 +2122,14 @@ unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunksMut<'a, T, #[derive(Debug)] #[stable(feature = "rchunks", since = "1.31.0")] pub struct RChunks<'a, T: 'a> { - pub(super) v: &'a [T], - pub(super) chunk_size: usize, + v: &'a [T], + chunk_size: usize, +} + +impl<'a, T: 'a> RChunks<'a, T> { + pub(super) fn new(slice: &'a [T], size: usize) -> Self { + Self { v: slice, chunk_size: size } + } } // FIXME(#26925) Remove in favor of `#[derive(Clone)]` @@ -2156,8 +2278,14 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> { #[derive(Debug)] #[stable(feature = "rchunks", since = "1.31.0")] pub struct RChunksMut<'a, T: 'a> { - pub(super) v: &'a mut [T], - pub(super) chunk_size: usize, + v: &'a mut [T], + chunk_size: usize, +} + +impl<'a, T: 'a> RChunksMut<'a, T> { + pub(super) fn new(slice: &'a mut [T], size: usize) -> Self { + Self { v: slice, chunk_size: size } + } } #[stable(feature = "rchunks", since = "1.31.0")] @@ -2306,12 +2434,16 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> { #[derive(Debug)] #[stable(feature = "rchunks", since = "1.31.0")] pub struct RChunksExact<'a, T: 'a> { - pub(super) v: &'a [T], - pub(super) rem: &'a [T], - pub(super) chunk_size: usize, + v: &'a [T], + rem: &'a [T], + chunk_size: usize, } impl<'a, T> RChunksExact<'a, T> { + pub(super) fn new(slice: &'a [T], rem: &'a [T], size: usize) -> Self { + Self { v: slice, rem, chunk_size: size } + } + /// Returns the remainder of the original slice that is not going to be /// returned by the iterator. The returned slice has at most `chunk_size-1` /// elements. @@ -2451,12 +2583,16 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> { #[derive(Debug)] #[stable(feature = "rchunks", since = "1.31.0")] pub struct RChunksExactMut<'a, T: 'a> { - pub(super) v: &'a mut [T], - pub(super) rem: &'a mut [T], - pub(super) chunk_size: usize, + v: &'a mut [T], + rem: &'a mut [T], + chunk_size: usize, } impl<'a, T> RChunksExactMut<'a, T> { + pub(super) fn new(slice: &'a mut [T], rem: &'a mut [T], size: usize) -> Self { + Self { v: slice, rem, chunk_size: size } + } + /// Returns the remainder of the original slice that is not going to be /// returned by the iterator. The returned slice has at most `chunk_size-1` /// elements. diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 8e9d1eb98a86b..238e5c209d392 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -10,7 +10,7 @@ use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::intrinsics::assume; -use crate::marker::{self, Copy}; +use crate::marker::Copy; use crate::mem; use crate::ops::{FnMut, Range, RangeBounds}; use crate::option::Option; @@ -35,8 +35,6 @@ mod raw; mod rotate; mod sort; -use iter::GenericSplitN; - #[stable(feature = "rust1", since = "1.0.0")] pub use iter::{Chunks, ChunksMut, Windows}; #[stable(feature = "rust1", since = "1.0.0")] @@ -707,7 +705,7 @@ impl [T] { ptr.add(self.len()) }; - Iter { ptr: NonNull::new_unchecked(ptr as *mut T), end, _marker: marker::PhantomData } + Iter::new(NonNull::new_unchecked(ptr as *mut T), end) } } @@ -751,7 +749,7 @@ impl [T] { ptr.add(self.len()) }; - IterMut { ptr: NonNull::new_unchecked(ptr), end, _marker: marker::PhantomData } + IterMut::new(NonNull::new_unchecked(ptr), end) } } @@ -785,7 +783,7 @@ impl [T] { #[inline] pub fn windows(&self, size: usize) -> Windows<'_, T> { assert_ne!(size, 0); - Windows { v: self, size } + Windows::new(self, size) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the @@ -819,7 +817,7 @@ impl [T] { #[inline] pub fn chunks(&self, chunk_size: usize) -> Chunks<'_, T> { assert_ne!(chunk_size, 0); - Chunks { v: self, chunk_size } + Chunks::new(self, chunk_size) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the @@ -857,7 +855,7 @@ impl [T] { #[inline] pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<'_, T> { assert_ne!(chunk_size, 0); - ChunksMut { v: self, chunk_size } + ChunksMut::new(self, chunk_size) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the @@ -898,7 +896,7 @@ impl [T] { let fst_len = self.len() - rem; // SAFETY: 0 <= fst_len <= self.len() by construction above let (fst, snd) = unsafe { self.split_at_unchecked(fst_len) }; - ChunksExact { v: fst, rem: snd, chunk_size } + ChunksExact::new(fst, snd, chunk_size) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the @@ -944,7 +942,7 @@ impl [T] { let fst_len = self.len() - rem; // SAFETY: 0 <= fst_len <= self.len() by construction above let (fst, snd) = unsafe { self.split_at_mut_unchecked(fst_len) }; - ChunksExactMut { v: fst, rem: snd, chunk_size } + ChunksExactMut::new(fst, snd, chunk_size) } /// Returns an iterator over `N` elements of the slice at a time, starting at the @@ -983,7 +981,7 @@ impl [T] { // SAFETY: We cast a slice of `len * N` elements into // a slice of `len` many `N` elements chunks. let array_slice: &[[T; N]] = unsafe { from_raw_parts(fst.as_ptr().cast(), len) }; - ArrayChunks { iter: array_slice.iter(), rem: snd } + ArrayChunks::new(array_slice.iter(), snd) } /// Returns an iterator over `N` elements of the slice at a time, starting at the @@ -1025,7 +1023,7 @@ impl [T] { // a slice of `len` many `N` elements chunks. unsafe { let array_slice: &mut [[T; N]] = from_raw_parts_mut(fst.as_mut_ptr().cast(), len); - ArrayChunksMut { iter: array_slice.iter_mut(), rem: snd } + ArrayChunksMut::new(array_slice.iter_mut(), snd) } } @@ -1060,7 +1058,7 @@ impl [T] { assert_ne!(N, 0); let num_windows = self.len().saturating_sub(N - 1); - ArrayWindows { slice_head: self.as_ptr(), num: num_windows, marker: marker::PhantomData } + ArrayWindows::new(self.as_ptr(), num_windows) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end @@ -1094,7 +1092,7 @@ impl [T] { #[inline] pub fn rchunks(&self, chunk_size: usize) -> RChunks<'_, T> { assert!(chunk_size != 0); - RChunks { v: self, chunk_size } + RChunks::new(self, chunk_size) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end @@ -1132,7 +1130,7 @@ impl [T] { #[inline] pub fn rchunks_mut(&mut self, chunk_size: usize) -> RChunksMut<'_, T> { assert!(chunk_size != 0); - RChunksMut { v: self, chunk_size } + RChunksMut::new(self, chunk_size) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the @@ -1174,7 +1172,7 @@ impl [T] { let rem = self.len() % chunk_size; // SAFETY: 0 <= rem <= self.len() by construction above let (fst, snd) = unsafe { self.split_at_unchecked(rem) }; - RChunksExact { v: snd, rem: fst, chunk_size } + RChunksExact::new(snd, fst, chunk_size) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end @@ -1220,7 +1218,7 @@ impl [T] { let rem = self.len() % chunk_size; // SAFETY: 0 <= rem <= self.len() by construction above let (fst, snd) = unsafe { self.split_at_mut_unchecked(rem) }; - RChunksExactMut { v: snd, rem: fst, chunk_size } + RChunksExactMut::new(snd, fst, chunk_size) } /// Divides one slice into two at an index. @@ -1439,7 +1437,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - Split { v: self, pred, finished: false } + Split::new(self, pred, false) } /// Returns an iterator over mutable subslices separated by elements that @@ -1461,7 +1459,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - SplitMut { v: self, pred, finished: false } + SplitMut::new(self, pred, false) } /// Returns an iterator over subslices separated by elements that match @@ -1499,7 +1497,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - SplitInclusive { v: self, pred, finished: false } + SplitInclusive::new(self, pred, false) } /// Returns an iterator over mutable subslices separated by elements that @@ -1524,7 +1522,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - SplitInclusiveMut { v: self, pred, finished: false } + SplitInclusiveMut::new(self, pred, false) } /// Returns an iterator over subslices separated by elements that match @@ -1560,7 +1558,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - RSplit { inner: self.split(pred) } + RSplit::new(self, pred, false) } /// Returns an iterator over mutable subslices separated by elements that @@ -1586,7 +1584,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - RSplitMut { inner: self.split_mut(pred) } + RSplitMut::new(self, pred, false) } /// Returns an iterator over subslices separated by elements that match @@ -1614,7 +1612,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - SplitN { inner: GenericSplitN { iter: self.split(pred), count: n } } + SplitN::new(self.split(pred), n) } /// Returns an iterator over subslices separated by elements that match @@ -1640,7 +1638,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - SplitNMut { inner: GenericSplitN { iter: self.split_mut(pred), count: n } } + SplitNMut::new(self.split_mut(pred), n) } /// Returns an iterator over subslices separated by elements that match @@ -1669,7 +1667,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - RSplitN { inner: GenericSplitN { iter: self.rsplit(pred), count: n } } + RSplitN::new(self.rsplit(pred), n) } /// Returns an iterator over subslices separated by elements that match @@ -1696,7 +1694,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - RSplitNMut { inner: GenericSplitN { iter: self.rsplit_mut(pred), count: n } } + RSplitNMut::new(self.rsplit_mut(pred), n) } /// Returns `true` if the slice contains an element with the given value. From c946c40d9d47328fc1a08919dec174a77c12fd6b Mon Sep 17 00:00:00 2001 From: khyperia Date: Thu, 17 Sep 2020 12:01:12 +0200 Subject: [PATCH 0544/1052] Let backends define custom targets Add a target_override hook that takes priority over builtin targets. --- compiler/rustc_codegen_llvm/src/lib.rs | 5 +++++ compiler/rustc_codegen_ssa/src/traits/backend.rs | 5 +++++ compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_interface/src/util.rs | 15 +++++++++------ compiler/rustc_session/src/config.rs | 9 +++++---- compiler/rustc_session/src/session.rs | 3 ++- 6 files changed, 27 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 2e2abe9fb30f8..21e19696fffc9 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -32,6 +32,7 @@ use rustc_serialize::json; use rustc_session::config::{self, OptLevel, OutputFilenames, PrintRequest}; use rustc_session::Session; use rustc_span::symbol::Symbol; +use rustc_target::spec::Target; use std::any::Any; use std::ffi::CStr; @@ -244,6 +245,10 @@ impl CodegenBackend for LlvmCodegenBackend { target_features(sess) } + fn target_override(&self, _opts: &config::Options) -> Option { + None + } + fn metadata_loader(&self) -> Box { Box::new(metadata::LlvmMetadataLoader) } diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 3522ea0115334..224c8c2350f1c 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -15,6 +15,7 @@ use rustc_session::{ }; use rustc_span::symbol::Symbol; use rustc_target::abi::LayoutOf; +use rustc_target::spec::Target; pub use rustc_data_structures::sync::MetadataRef; @@ -54,6 +55,10 @@ pub trait CodegenBackend { fn print_passes(&self) {} fn print_version(&self) {} + /// If this plugin provides additional builtin targets, provide them here. + /// Be careful: this is called *before* init() is called. + fn target_override(&self, opts: &config::Options) -> Option; + fn metadata_loader(&self) -> Box; fn provide(&self, _providers: &mut Providers); fn provide_extern(&self, _providers: &mut Providers); diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index dc4fa807f7868..72e10bc4304d0 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -40,6 +40,7 @@ fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) { DiagnosticOutput::Default, Default::default(), None, + None, ); (sess, cfg) } diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index f15eb413833ae..c4d89850dad50 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -65,6 +65,10 @@ pub fn create_session( lint_caps: FxHashMap, descriptions: Registry, ) -> (Lrc, Lrc>) { + let codegen_backend = get_codegen_backend(sopts.debugging_opts.codegen_backend.as_deref()); + // target_override is documented to be called before init(), so this is okay + let target_override = codegen_backend.target_override(&sopts); + let mut sess = session::build_session( sopts, input_path, @@ -72,9 +76,10 @@ pub fn create_session( diagnostic_output, lint_caps, file_loader, + target_override, ); - let codegen_backend = get_codegen_backend(&sess); + codegen_backend.init(&sess); let mut cfg = config::build_configuration(&sess, config::to_crate_config(cfg)); add_configuration(&mut cfg, &mut sess, &*codegen_backend); @@ -219,13 +224,13 @@ fn load_backend_from_dylib(path: &Path) -> fn() -> Box { } } -pub fn get_codegen_backend(sess: &Session) -> Box { +pub fn get_codegen_backend(codegen_name: Option<&str>) -> Box { static INIT: Once = Once::new(); static mut LOAD: fn() -> Box = || unreachable!(); INIT.call_once(|| { - let codegen_name = sess.opts.debugging_opts.codegen_backend.as_deref().unwrap_or("llvm"); + let codegen_name = codegen_name.unwrap_or("llvm"); let backend = match codegen_name { filename if filename.contains('.') => load_backend_from_dylib(filename.as_ref()), codegen_name => get_builtin_codegen_backend(codegen_name), @@ -235,9 +240,7 @@ pub fn get_codegen_backend(sess: &Session) -> Box { LOAD = backend; } }); - let backend = unsafe { LOAD() }; - backend.init(sess); - backend + unsafe { LOAD() } } // This is used for rustdoc, but it uses similar machinery to codegen backend diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 3f12596a236ab..8d004675d7f4d 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -818,10 +818,11 @@ pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateCo user_cfg } -pub fn build_target_config(opts: &Options, error_format: ErrorOutputType) -> Config { - let target = Target::search(&opts.target_triple).unwrap_or_else(|e| { +pub fn build_target_config(opts: &Options, target_override: Option) -> Config { + let target_result = target_override.map_or_else(|| Target::search(&opts.target_triple), Ok); + let target = target_result.unwrap_or_else(|e| { early_error( - error_format, + opts.error_format, &format!( "Error loading target specification: {}. \ Use `--print target-list` for a list of built-in targets", @@ -835,7 +836,7 @@ pub fn build_target_config(opts: &Options, error_format: ErrorOutputType) -> Con "32" => 32, "64" => 64, w => early_error( - error_format, + opts.error_format, &format!( "target specification was invalid: \ unrecognized target-pointer-width {}", diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 974f4c31bb6a4..ff67d3cb107d9 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1234,6 +1234,7 @@ pub fn build_session( diagnostics_output: DiagnosticOutput, driver_lint_caps: FxHashMap, file_loader: Option>, + target_override: Option, ) -> Session { // FIXME: This is not general enough to make the warning lint completely override // normal diagnostic warnings, since the warning lint can also be denied and changed @@ -1253,7 +1254,7 @@ pub fn build_session( DiagnosticOutput::Raw(write) => Some(write), }; - let target_cfg = config::build_target_config(&sopts, sopts.error_format); + let target_cfg = config::build_target_config(&sopts, target_override); let host_triple = TargetTriple::from_triple(config::host_triple()); let host = Target::search(&host_triple).unwrap_or_else(|e| { early_error(sopts.error_format, &format!("Error loading host specification: {}", e)) From 48655c2d2ca8590c7627f32839ba921297290a1a Mon Sep 17 00:00:00 2001 From: khyperia Date: Thu, 17 Sep 2020 12:14:18 +0200 Subject: [PATCH 0545/1052] PR feedback --- compiler/rustc_codegen_llvm/src/lib.rs | 5 ----- compiler/rustc_codegen_ssa/src/traits/backend.rs | 6 ++++-- compiler/rustc_interface/src/util.rs | 6 +++--- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 21e19696fffc9..2e2abe9fb30f8 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -32,7 +32,6 @@ use rustc_serialize::json; use rustc_session::config::{self, OptLevel, OutputFilenames, PrintRequest}; use rustc_session::Session; use rustc_span::symbol::Symbol; -use rustc_target::spec::Target; use std::any::Any; use std::ffi::CStr; @@ -245,10 +244,6 @@ impl CodegenBackend for LlvmCodegenBackend { target_features(sess) } - fn target_override(&self, _opts: &config::Options) -> Option { - None - } - fn metadata_loader(&self) -> Box { Box::new(metadata::LlvmMetadataLoader) } diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 224c8c2350f1c..90520f77e3c04 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -55,9 +55,11 @@ pub trait CodegenBackend { fn print_passes(&self) {} fn print_version(&self) {} - /// If this plugin provides additional builtin targets, provide them here. + /// If this plugin provides additional builtin targets, provide the one enabled by the options here. /// Be careful: this is called *before* init() is called. - fn target_override(&self, opts: &config::Options) -> Option; + fn target_override(&self, _opts: &config::Options) -> Option { + None + } fn metadata_loader(&self) -> Box; fn provide(&self, _providers: &mut Providers); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index c4d89850dad50..0eed6938c3169 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -65,7 +65,7 @@ pub fn create_session( lint_caps: FxHashMap, descriptions: Registry, ) -> (Lrc, Lrc>) { - let codegen_backend = get_codegen_backend(sopts.debugging_opts.codegen_backend.as_deref()); + let codegen_backend = get_codegen_backend(&sopts); // target_override is documented to be called before init(), so this is okay let target_override = codegen_backend.target_override(&sopts); @@ -224,13 +224,13 @@ fn load_backend_from_dylib(path: &Path) -> fn() -> Box { } } -pub fn get_codegen_backend(codegen_name: Option<&str>) -> Box { +pub fn get_codegen_backend(sopts: &config::Options) -> Box { static INIT: Once = Once::new(); static mut LOAD: fn() -> Box = || unreachable!(); INIT.call_once(|| { - let codegen_name = codegen_name.unwrap_or("llvm"); + let codegen_name = sopts.debugging_opts.codegen_backend.as_deref().unwrap_or("llvm"); let backend = match codegen_name { filename if filename.contains('.') => load_backend_from_dylib(filename.as_ref()), codegen_name => get_builtin_codegen_backend(codegen_name), From 7b5d9836c47509e16900a274ed0b552a2e30a36a Mon Sep 17 00:00:00 2001 From: Juan Aguilar Santillana Date: Thu, 17 Sep 2020 10:27:04 +0000 Subject: [PATCH 0546/1052] Remove redundant to_string --- compiler/rustc_errors/src/emitter.rs | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 4555168af0ab5..98cbf98df92b4 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1227,18 +1227,14 @@ impl EmitterWriter { } draw_note_separator(&mut buffer, 0, max_line_num_len + 1); if *level != Level::FailureNote { - let level_str = level.to_string(); - if !level_str.is_empty() { - buffer.append(0, &level_str, Style::MainHeaderMsg); - buffer.append(0, ": ", Style::NoStyle); - } + buffer.append(0, level.to_str(), Style::MainHeaderMsg); + buffer.append(0, ": ", Style::NoStyle); } self.msg_to_buffer(&mut buffer, msg, max_line_num_len, "note", None); } else { - let level_str = level.to_string(); // The failure note level itself does not provide any useful diagnostic information - if *level != Level::FailureNote && !level_str.is_empty() { - buffer.append(0, &level_str, Style::Level(*level)); + if *level != Level::FailureNote { + buffer.append(0, level.to_str(), Style::Level(*level)); } // only render error codes, not lint codes if let Some(DiagnosticId::Error(ref code)) = *code { @@ -1246,7 +1242,7 @@ impl EmitterWriter { buffer.append(0, &code, Style::Level(*level)); buffer.append(0, "]", Style::Level(*level)); } - if *level != Level::FailureNote && !level_str.is_empty() { + if *level != Level::FailureNote { buffer.append(0, ": ", header_style); } for &(ref text, _) in msg.iter() { @@ -1548,11 +1544,9 @@ impl EmitterWriter { let mut buffer = StyledBuffer::new(); // Render the suggestion message - let level_str = level.to_string(); - if !level_str.is_empty() { - buffer.append(0, &level_str, Style::Level(*level)); - buffer.append(0, ": ", Style::HeaderMsg); - } + buffer.append(0, level.to_str(), Style::Level(*level)); + buffer.append(0, ": ", Style::HeaderMsg); + self.msg_to_buffer( &mut buffer, &[(suggestion.msg.to_owned(), Style::NoStyle)], From 026922ad60a9529f16b792e8c2fe805ab3906259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Thu, 17 Sep 2020 13:11:01 +0200 Subject: [PATCH 0547/1052] make replace_prefix only take &str as arguments https://github.com/rust-lang/rust/pull/76828#issuecomment-694078200 --- compiler/rustc_typeck/src/check/demand.rs | 25 ++++++++--------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index c7ce5008c3354..247bbf637ceaf 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -362,16 +362,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } - fn replace_prefix(&self, s: A, old: B, new: C) -> Option - where - A: AsRef, - B: AsRef, - C: AsRef, - { - let s = s.as_ref(); - let old = old.as_ref(); + fn replace_prefix(&self, s: &str, old: &str, new: &str) -> Option { if let Some(stripped) = s.strip_prefix(old) { - Some(new.as_ref().to_owned() + stripped) + Some(new.to_string() + stripped) } else { None } @@ -422,7 +415,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (&ty::Str, &ty::Array(arr, _) | &ty::Slice(arr)) if arr == self.tcx.types.u8 => { if let hir::ExprKind::Lit(_) = expr.kind { if let Ok(src) = sm.span_to_snippet(sp) { - if let Some(src) = self.replace_prefix(src, "b\"", "\"") { + if let Some(src) = self.replace_prefix(&src, "b\"", "\"") { return Some(( sp, "consider removing the leading `b`", @@ -436,7 +429,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (&ty::Array(arr, _) | &ty::Slice(arr), &ty::Str) if arr == self.tcx.types.u8 => { if let hir::ExprKind::Lit(_) = expr.kind { if let Ok(src) = sm.span_to_snippet(sp) { - if let Some(src) = self.replace_prefix(src, "\"", "b\"") { + if let Some(src) = self.replace_prefix(&src, "\"", "b\"") { return Some(( sp, "consider adding a leading `b`", @@ -561,7 +554,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // we may want to suggest removing a `&`. if sm.is_imported(expr.span) { if let Ok(src) = sm.span_to_snippet(sp) { - if let Some(src) = self.replace_prefix(src, "&", "") { + if let Some(src) = self.replace_prefix(&src, "&", "") { return Some(( sp, "consider removing the borrow", @@ -598,7 +591,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match mutbl_a { hir::Mutability::Mut => { if let Some(s) = - self.replace_prefix(src, "&mut ", new_prefix) + self.replace_prefix(&src, "&mut ", &new_prefix) { Some((s, Applicability::MachineApplicable)) } else { @@ -607,7 +600,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } hir::Mutability::Not => { if let Some(s) = - self.replace_prefix(src, "&", new_prefix) + self.replace_prefix(&src, "&", &new_prefix) { Some((s, Applicability::Unspecified)) } else { @@ -621,7 +614,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match mutbl_a { hir::Mutability::Mut => { if let Some(s) = - self.replace_prefix(src, "&mut ", new_prefix) + self.replace_prefix(&src, "&mut ", &new_prefix) { Some((s, Applicability::MachineApplicable)) } else { @@ -630,7 +623,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } hir::Mutability::Not => { if let Some(s) = - self.replace_prefix(src, "&", new_prefix) + self.replace_prefix(&src, "&", &new_prefix) { Some((s, Applicability::MachineApplicable)) } else { From 1dd3df6738b5bbe676b6ae5b561c491ca483f017 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 17 Sep 2020 08:59:30 +0200 Subject: [PATCH 0548/1052] black_box: silence unused_mut warning when building with cfg(miri) --- library/core/src/hint.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 1192b9e164a14..fdf5bbf61441f 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -110,7 +110,7 @@ pub fn spin_loop() { /// backend used. Programs cannot rely on `black_box` for *correctness* in any way. #[inline] #[unstable(feature = "test", issue = "50297")] -#[allow(unreachable_code)] // this makes #[cfg] a bit easier below. +#[cfg_attr(miri, allow(unused_mut))] pub fn black_box(mut dummy: T) -> T { // We need to "use" the argument in some way LLVM can't introspect, and on // targets that support it we can typically leverage inline assembly to do From dbd7226d299ac23647975068bea1168cf56e0feb Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Thu, 17 Sep 2020 09:29:39 -0400 Subject: [PATCH 0549/1052] [mir-opt] Disable the `ConsideredEqual` logic in SimplifyBranchSame opt The logic is currently broken and we need to disable it to fix a beta regression (see #76803) --- .../rustc_mir/src/transform/simplify_try.rs | 11 ++++++-- .../simplify_arm.id.SimplifyBranchSame.diff | 27 +++++++++---------- .../ui/mir/issue-76803-branches-not-same.rs | 19 +++++++++++++ 3 files changed, 40 insertions(+), 17 deletions(-) create mode 100644 src/test/ui/mir/issue-76803-branches-not-same.rs diff --git a/compiler/rustc_mir/src/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs index 76a60c45575b8..9a11d92724020 100644 --- a/compiler/rustc_mir/src/transform/simplify_try.rs +++ b/compiler/rustc_mir/src/transform/simplify_try.rs @@ -612,7 +612,7 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { && bb_l.terminator().kind == bb_r.terminator().kind; let statement_check = || { bb_l.statements.iter().zip(&bb_r.statements).try_fold(StatementEquality::TrivialEqual, |acc,(l,r)| { - let stmt_equality = self.statement_equality(*adt_matched_on, &l, bb_l_idx, &r, bb_r_idx); + let stmt_equality = self.statement_equality(*adt_matched_on, &l, bb_l_idx, &r, bb_r_idx, self.tcx.sess.opts.debugging_opts.mir_opt_level); if matches!(stmt_equality, StatementEquality::NotEqual) { // short circuit None @@ -672,6 +672,7 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { x_bb_idx: BasicBlock, y: &Statement<'tcx>, y_bb_idx: BasicBlock, + mir_opt_level: usize, ) -> StatementEquality { let helper = |rhs: &Rvalue<'tcx>, place: &Place<'tcx>, @@ -690,7 +691,13 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { match rhs { Rvalue::Use(operand) if operand.place() == Some(adt_matched_on) => { - StatementEquality::ConsideredEqual(side_to_choose) + // FIXME(76803): This logic is currently broken because it does not take into + // account the current discriminant value. + if mir_opt_level > 2 { + StatementEquality::ConsideredEqual(side_to_choose) + } else { + StatementEquality::NotEqual + } } _ => { trace!( diff --git a/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff b/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff index 81a0e6ba0b4ee..06f359da2e70d 100644 --- a/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff +++ b/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff @@ -13,27 +13,24 @@ bb0: { _2 = discriminant(_1); // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16 -- switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16 -+ goto -> bb1; // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16 + switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16 } bb1: { -- discriminant(_0) = 0; // scope 0 at $DIR/simplify-arm.rs:12:17: 12:21 -- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6 -- } -- -- bb2: { -- unreachable; // scope 0 at $DIR/simplify-arm.rs:10:11: 10:12 -- } -- -- bb3: { + discriminant(_0) = 0; // scope 0 at $DIR/simplify-arm.rs:12:17: 12:21 + goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6 + } + + bb2: { + unreachable; // scope 0 at $DIR/simplify-arm.rs:10:11: 10:12 + } + + bb3: { _0 = move _1; // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27 -- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6 -+ goto -> bb2; // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6 + goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6 } -- bb4: { -+ bb2: { + bb4: { return; // scope 0 at $DIR/simplify-arm.rs:14:2: 14:2 } } diff --git a/src/test/ui/mir/issue-76803-branches-not-same.rs b/src/test/ui/mir/issue-76803-branches-not-same.rs new file mode 100644 index 0000000000000..a6a5762200548 --- /dev/null +++ b/src/test/ui/mir/issue-76803-branches-not-same.rs @@ -0,0 +1,19 @@ +// run-pass + +#[derive(Debug, Eq, PartialEq)] +pub enum Type { + A, + B, +} + + +pub fn encode(v: Type) -> Type { + match v { + Type::A => Type::B, + _ => v, + } +} + +fn main() { + assert_eq!(Type::B, encode(Type::A)); +} From 3d1b6d6cc29587ace6895814fa32ec38a49d8a68 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 17 Sep 2020 07:10:10 -0700 Subject: [PATCH 0550/1052] library/unwind: Add missing ) Signed-off-by: Alistair Francis --- library/unwind/src/libunwind.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index 677843e12e1be..dcf4fcd4e5aab 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -54,7 +54,7 @@ pub const unwinder_private_data_size: usize = 2; #[cfg(target_arch = "sparc64")] pub const unwinder_private_data_size: usize = 2; -#[cfg(any(target_arch = "riscv64", target_arch = "riscv32")] +#[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))] pub const unwinder_private_data_size: usize = 2; #[cfg(target_os = "emscripten")] From 76ec3f8d2b9b1ae547652762d8ab5909eaa5793d Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Thu, 17 Sep 2020 17:25:06 +0200 Subject: [PATCH 0551/1052] Move to intra doc links in core/src/future --- library/core/src/future/pending.rs | 2 -- library/core/src/future/poll_fn.rs | 2 -- library/core/src/future/ready.rs | 2 -- 3 files changed, 6 deletions(-) diff --git a/library/core/src/future/pending.rs b/library/core/src/future/pending.rs index 4fec219ede2bc..388b9e7bdb0e7 100644 --- a/library/core/src/future/pending.rs +++ b/library/core/src/future/pending.rs @@ -9,8 +9,6 @@ use crate::task::{Context, Poll}; /// /// This `struct` is created by the [`pending`] function. See its /// documentation for more. -/// -/// [`pending`]: fn.pending.html #[stable(feature = "future_readiness_fns", since = "1.48.0")] #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct Pending { diff --git a/library/core/src/future/poll_fn.rs b/library/core/src/future/poll_fn.rs index 9ab3bfcea1c71..3fe7eb88d0ff3 100644 --- a/library/core/src/future/poll_fn.rs +++ b/library/core/src/future/poll_fn.rs @@ -35,8 +35,6 @@ where /// /// This `struct` is created by the [`poll_fn`] function. See its /// documentation for more. -/// -/// [`poll_fn`]: fn.poll_fn.html #[must_use = "futures do nothing unless you `.await` or poll them"] #[unstable(feature = "future_poll_fn", issue = "72302")] pub struct PollFn { diff --git a/library/core/src/future/ready.rs b/library/core/src/future/ready.rs index fcfd8779b0ad2..ad93157c3454d 100644 --- a/library/core/src/future/ready.rs +++ b/library/core/src/future/ready.rs @@ -6,8 +6,6 @@ use crate::task::{Context, Poll}; /// /// This `struct` is created by the [`ready`] function. See its /// documentation for more. -/// -/// [`ready`]: fn.ready.html #[stable(feature = "future_readiness_fns", since = "1.48.0")] #[derive(Debug, Clone)] #[must_use = "futures do nothing unless you `.await` or poll them"] From e03f4164d9229d8a79ab2d9c20221d0b646734ae Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Tue, 1 Sep 2020 12:28:55 -0700 Subject: [PATCH 0552/1052] Default to implicit (not explicit) rules for promotability in `const fn` --- compiler/rustc_mir/src/transform/promote_consts.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index 1d2295a37dddf..b6124049579fd 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -734,7 +734,14 @@ impl<'tcx> Validator<'_, 'tcx> { ) -> Result<(), Unpromotable> { let fn_ty = callee.ty(self.body, self.tcx); - if !self.explicit && self.const_kind.is_none() { + // `const` and `static` use the explicit rules for promotion regardless of the `Candidate`, + // meaning calls to `const fn` can be promoted. + let context_uses_explicit_promotion_rules = matches!( + self.const_kind, + Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) + ); + + if !self.explicit && !context_uses_explicit_promotion_rules { if let ty::FnDef(def_id, _) = *fn_ty.kind() { // Never promote runtime `const fn` calls of // functions without `#[rustc_promotable]`. From 451f7f6b125111588feb19d2e9675aa995a2e53f Mon Sep 17 00:00:00 2001 From: Camelid Date: Thu, 17 Sep 2020 11:38:40 -0700 Subject: [PATCH 0553/1052] Use relative link instead of absolute --- compiler/rustc_middle/src/mir/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 58b69d022d985..ac2c273f74b0c 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1093,7 +1093,7 @@ rustc_index::newtype_index! { /// [CFG]: https://rustc-dev-guide.rust-lang.org/appendix/background.html#cfg /// [data-flow analyses]: /// https://rustc-dev-guide.rust-lang.org/appendix/background.html#what-is-a-dataflow-analysis - /// [`CriticalCallEdges`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/transform/add_call_guards/enum.AddCallGuards.html#variant.CriticalCallEdges + /// [`CriticalCallEdges`]: ../../rustc_mir/transform/add_call_guards/enum.AddCallGuards.html#variant.CriticalCallEdges /// [guide-mir]: https://rustc-dev-guide.rust-lang.org/mir/ pub struct BasicBlock { derive [HashStable] From 363aff0a9d0b85285b7501cb04dd8263d29d273a Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 17 Sep 2020 16:03:42 -0400 Subject: [PATCH 0554/1052] Add test for x.py build cross-compilation --- src/bootstrap/builder/tests.rs | 48 ++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index f96925f927086..77b39cbb87ed9 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -90,6 +90,54 @@ mod defaults { assert!(builder.cache.all::().is_empty()); } + #[test] + fn build_cross_compile() { + let config = Config { stage: 1, ..configure("build", &["B"], &["B"]) }; + let build = Build::new(config); + let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); + + let a = TargetSelection::from_user("A"); + let b = TargetSelection::from_user("B"); + + // Ideally, this build wouldn't actually have `target: a` + // rustdoc/rustcc/std here (the user only requested a host=B build, so + // there's not really a need for us to build for target A in this case + // (since we're producing stage 1 libraries/binaries). But currently + // rustbuild is just a bit buggy here; this should be fixed though. + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, + compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, + compile::Std { compiler: Compiler { host: a, stage: 0 }, target: b }, + compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } }, + compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } }, + compile::Assemble { target_compiler: Compiler { host: b, stage: 1 } }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } }, + tool::Rustdoc { compiler: Compiler { host: b, stage: 1 } }, + ], + ); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a }, + compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: b }, + ] + ); + } + #[test] fn doc_default() { let mut config = configure("doc", &[], &[]); From 076e52d0c9cb7856186d33203e33e04a3db898c4 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Thu, 17 Sep 2020 21:32:02 +0100 Subject: [PATCH 0555/1052] Put bit qualifier before mir/diff --- src/tools/compiletest/src/runtest.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 965b20f5202e0..7fcbfe9bd0d5f 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -3181,7 +3181,7 @@ impl<'test> TestCx<'test> { let trimmed = test_name.trim_end_matches(".diff"); let test_against = format!("{}.after.mir", trimmed); from_file = format!("{}.before.mir", trimmed); - expected_file = format!("{}{}", test_name, bit_width); + expected_file = format!("{}{}.diff", trimmed, bit_width); assert!( test_names.next().is_none(), "two mir pass names specified for MIR diff" @@ -3199,7 +3199,7 @@ impl<'test> TestCx<'test> { from_file = format!("{}.{}.mir", test_name, first_pass); to_file = Some(second_file); } else { - expected_file = format!("{}{}", test_name, bit_width); + expected_file = format!("{}{}.mir", test_name.trim_end_matches(".mir"), bit_width); from_file = test_name.to_string(); assert!( test_names.next().is_none(), From 4f23cec3f917143c7d6c52825f867a21f642beec Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Thu, 17 Sep 2020 21:35:21 +0100 Subject: [PATCH 0556/1052] Rename 64 bit mir files to be more tool friendly See #75746 --- ...mplifyCfg-elaborate-drops.after.64bit.mir} | 0 ...ne_array_len.norm2.InstCombine.64bit.diff} | 0 ...allocation.main.ConstProp.after.64bit.mir} | 0 ...llocation2.main.ConstProp.after.64bit.mir} | 0 ...llocation3.main.ConstProp.after.64bit.mir} | 0 ... => array_index.main.ConstProp.64bit.diff} | 0 ..._oob_for_slices.main.ConstProp.64bit.diff} | 0 ...=> discriminant.main.ConstProp.64bit.diff} | 0 ...rge_array_index.main.ConstProp.64bit.diff} | 0 ...s_into_variable.main.ConstProp.64bit.diff} | 0 ...iable.main.SimplifyLocals.after.64bit.mir} | 0 ...64bit => repeat.main.ConstProp.64bit.diff} | 0 ...it => slice_len.main.ConstProp.64bit.diff} | 0 .../mir-opt/graphviz.main.mir_map.0.dot.mir | 10 +++ ...ine_into_box_place.main.Inline.64bit.diff} | 0 ...implifyCfg-promote-consts.after.64bit.mir} | 0 ...it => issue_72181.bar.mir_map.0.64bit.mir} | 0 ...it => issue_72181.foo.mir_map.0.64bit.mir} | 0 ...t => issue_72181.main.mir_map.0.64bit.mir} | 0 ...=> issue_73223.main.PreCodegen.64bit.diff} | 0 ...73223.main.SimplifyArmIdentity.64bit.diff} | 0 ....bar.MatchBranchSimplification.64bit.diff} | 0 ....foo.MatchBranchSimplification.64bit.diff} | 0 ...atch.MatchBranchSimplification.64bit.diff} | 0 ...h_i8.MatchBranchSimplification.64bit.diff} | 0 ...gion_subtyping_basic.main.nll.0.64bit.mir} | 0 ...mplifyCfg-elaborate-drops.after.64bit.mir} | 0 ...mple_match.match_bool.mir_map.0.64bit.mir} | 0 ...ntity.main.SimplifyArmIdentity.64bit.diff} | 0 ...inant_reads.map.SimplifyLocals.64bit.diff} | 0 ...].AddMovesForPackedDrops.before.64bit.mir} | 0 .../spanview_block.main.mir_map.0.html.mir | 67 +++++++++++++++++++ ...spanview_statement.main.mir_map.0.html.mir | 67 +++++++++++++++++++ ...panview_terminator.main.mir_map.0.html.mir | 66 ++++++++++++++++++ ...ypes.E-V-{{constant}}.mir_map.0.64bit.mir} | 0 ...est-X-{{constructor}}.mir_map.0.64bit.mir} | 0 ..._.AddMovesForPackedDrops.before.64bit.mir} | 0 ...}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir} | 0 ...ops.change_loop_body.ConstProp.64bit.diff} | 0 ...ange_loop_body.PreCodegen.after.64bit.mir} | 0 40 files changed, 210 insertions(+) rename src/test/mir-opt/{array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.64bit => array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir} (100%) rename src/test/mir-opt/{combine_array_len.norm2.InstCombine.diff.64bit => combine_array_len.norm2.InstCombine.64bit.diff} (100%) rename src/test/mir-opt/{const_allocation.main.ConstProp.after.mir.64bit => const_allocation.main.ConstProp.after.64bit.mir} (100%) rename src/test/mir-opt/{const_allocation2.main.ConstProp.after.mir.64bit => const_allocation2.main.ConstProp.after.64bit.mir} (100%) rename src/test/mir-opt/{const_allocation3.main.ConstProp.after.mir.64bit => const_allocation3.main.ConstProp.after.64bit.mir} (100%) rename src/test/mir-opt/const_prop/{array_index.main.ConstProp.diff.64bit => array_index.main.ConstProp.64bit.diff} (100%) rename src/test/mir-opt/const_prop/{bad_op_unsafe_oob_for_slices.main.ConstProp.diff.64bit => bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff} (100%) rename src/test/mir-opt/const_prop/{discriminant.main.ConstProp.diff.64bit => discriminant.main.ConstProp.64bit.diff} (100%) rename src/test/mir-opt/const_prop/{large_array_index.main.ConstProp.diff.64bit => large_array_index.main.ConstProp.64bit.diff} (100%) rename src/test/mir-opt/const_prop/{optimizes_into_variable.main.ConstProp.diff.64bit => optimizes_into_variable.main.ConstProp.64bit.diff} (100%) rename src/test/mir-opt/const_prop/{optimizes_into_variable.main.SimplifyLocals.after.mir.64bit => optimizes_into_variable.main.SimplifyLocals.after.64bit.mir} (100%) rename src/test/mir-opt/const_prop/{repeat.main.ConstProp.diff.64bit => repeat.main.ConstProp.64bit.diff} (100%) rename src/test/mir-opt/const_prop/{slice_len.main.ConstProp.diff.64bit => slice_len.main.ConstProp.64bit.diff} (100%) create mode 100644 src/test/mir-opt/graphviz.main.mir_map.0.dot.mir rename src/test/mir-opt/inline/{inline_into_box_place.main.Inline.diff.64bit => inline_into_box_place.main.Inline.64bit.diff} (100%) rename src/test/mir-opt/{issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.64bit => issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.64bit.mir} (100%) rename src/test/mir-opt/{issue_72181.bar.mir_map.0.mir.64bit => issue_72181.bar.mir_map.0.64bit.mir} (100%) rename src/test/mir-opt/{issue_72181.foo.mir_map.0.mir.64bit => issue_72181.foo.mir_map.0.64bit.mir} (100%) rename src/test/mir-opt/{issue_72181.main.mir_map.0.mir.64bit => issue_72181.main.mir_map.0.64bit.mir} (100%) rename src/test/mir-opt/{issue_73223.main.PreCodegen.diff.64bit => issue_73223.main.PreCodegen.64bit.diff} (100%) rename src/test/mir-opt/{issue_73223.main.SimplifyArmIdentity.diff.64bit => issue_73223.main.SimplifyArmIdentity.64bit.diff} (100%) rename src/test/mir-opt/{matches_reduce_branches.bar.MatchBranchSimplification.diff.64bit => matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff} (100%) rename src/test/mir-opt/{matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit => matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff} (100%) rename src/test/mir-opt/{matches_u8.exhaustive_match.MatchBranchSimplification.diff.64bit => matches_u8.exhaustive_match.MatchBranchSimplification.64bit.diff} (100%) rename src/test/mir-opt/{matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.64bit => matches_u8.exhaustive_match_i8.MatchBranchSimplification.64bit.diff} (100%) rename src/test/mir-opt/nll/{region_subtyping_basic.main.nll.0.mir.64bit => region_subtyping_basic.main.nll.0.64bit.mir} (100%) rename src/test/mir-opt/{packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir.64bit => packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir} (100%) rename src/test/mir-opt/{simple_match.match_bool.mir_map.0.mir.64bit => simple_match.match_bool.mir_map.0.64bit.mir} (100%) rename src/test/mir-opt/{simplify_arm_identity.main.SimplifyArmIdentity.diff.64bit => simplify_arm_identity.main.SimplifyArmIdentity.64bit.diff} (100%) rename src/test/mir-opt/{simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.64bit => simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff} (100%) rename src/test/mir-opt/{slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir.64bit => slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.64bit.mir} (100%) create mode 100644 src/test/mir-opt/spanview_block.main.mir_map.0.html.mir create mode 100644 src/test/mir-opt/spanview_statement.main.mir_map.0.html.mir create mode 100644 src/test/mir-opt/spanview_terminator.main.mir_map.0.html.mir rename src/test/mir-opt/{unusual_item_types.E-V-{{constant}}.mir_map.0.mir.64bit => unusual_item_types.E-V-{{constant}}.mir_map.0.64bit.mir} (100%) rename src/test/mir-opt/{unusual_item_types.Test-X-{{constructor}}.mir_map.0.mir.64bit => unusual_item_types.Test-X-{{constructor}}.mir_map.0.64bit.mir} (100%) rename src/test/mir-opt/{unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir.64bit => unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir} (100%) rename src/test/mir-opt/{unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.mir.64bit => unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir} (100%) rename src/test/mir-opt/{while_let_loops.change_loop_body.ConstProp.diff.64bit => while_let_loops.change_loop_body.ConstProp.64bit.diff} (100%) rename src/test/mir-opt/{while_let_loops.change_loop_body.PreCodegen.after.mir.64bit => while_let_loops.change_loop_body.PreCodegen.after.64bit.mir} (100%) diff --git a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.64bit b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir similarity index 100% rename from src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.64bit rename to src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir diff --git a/src/test/mir-opt/combine_array_len.norm2.InstCombine.diff.64bit b/src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff similarity index 100% rename from src/test/mir-opt/combine_array_len.norm2.InstCombine.diff.64bit rename to src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff diff --git a/src/test/mir-opt/const_allocation.main.ConstProp.after.mir.64bit b/src/test/mir-opt/const_allocation.main.ConstProp.after.64bit.mir similarity index 100% rename from src/test/mir-opt/const_allocation.main.ConstProp.after.mir.64bit rename to src/test/mir-opt/const_allocation.main.ConstProp.after.64bit.mir diff --git a/src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.64bit b/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir similarity index 100% rename from src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.64bit rename to src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir diff --git a/src/test/mir-opt/const_allocation3.main.ConstProp.after.mir.64bit b/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir similarity index 100% rename from src/test/mir-opt/const_allocation3.main.ConstProp.after.mir.64bit rename to src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir diff --git a/src/test/mir-opt/const_prop/array_index.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff similarity index 100% rename from src/test/mir-opt/const_prop/array_index.main.ConstProp.diff.64bit rename to src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff similarity index 100% rename from src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.diff.64bit rename to src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff diff --git a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff similarity index 100% rename from src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.64bit rename to src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff diff --git a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.diff similarity index 100% rename from src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.64bit rename to src/test/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.diff diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff similarity index 100% rename from src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.64bit rename to src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.mir.64bit b/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.64bit.mir similarity index 100% rename from src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.mir.64bit rename to src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.64bit.mir diff --git a/src/test/mir-opt/const_prop/repeat.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/repeat.main.ConstProp.64bit.diff similarity index 100% rename from src/test/mir-opt/const_prop/repeat.main.ConstProp.diff.64bit rename to src/test/mir-opt/const_prop/repeat.main.ConstProp.64bit.diff diff --git a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff similarity index 100% rename from src/test/mir-opt/const_prop/slice_len.main.ConstProp.diff.64bit rename to src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff diff --git a/src/test/mir-opt/graphviz.main.mir_map.0.dot.mir b/src/test/mir-opt/graphviz.main.mir_map.0.dot.mir new file mode 100644 index 0000000000000..df4f11f0f2169 --- /dev/null +++ b/src/test/mir-opt/graphviz.main.mir_map.0.dot.mir @@ -0,0 +1,10 @@ +digraph Mir_0_3 { + graph [fontname="Courier, monospace"]; + node [fontname="Courier, monospace"]; + edge [fontname="Courier, monospace"]; + label=>; + bb0__0_3 [shape="none", label=<
0
_0 = const ()
goto
>]; + bb1__0_3 [shape="none", label=<
1
resume
>]; + bb2__0_3 [shape="none", label=<
2
return
>]; + bb0__0_3 -> bb2__0_3 [label=""]; +} diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff.64bit b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff similarity index 100% rename from src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff.64bit rename to src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff diff --git a/src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.64bit b/src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.64bit.mir similarity index 100% rename from src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.64bit rename to src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.64bit.mir diff --git a/src/test/mir-opt/issue_72181.bar.mir_map.0.mir.64bit b/src/test/mir-opt/issue_72181.bar.mir_map.0.64bit.mir similarity index 100% rename from src/test/mir-opt/issue_72181.bar.mir_map.0.mir.64bit rename to src/test/mir-opt/issue_72181.bar.mir_map.0.64bit.mir diff --git a/src/test/mir-opt/issue_72181.foo.mir_map.0.mir.64bit b/src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir similarity index 100% rename from src/test/mir-opt/issue_72181.foo.mir_map.0.mir.64bit rename to src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir diff --git a/src/test/mir-opt/issue_72181.main.mir_map.0.mir.64bit b/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir similarity index 100% rename from src/test/mir-opt/issue_72181.main.mir_map.0.mir.64bit rename to src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.diff.64bit b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff similarity index 100% rename from src/test/mir-opt/issue_73223.main.PreCodegen.diff.64bit rename to src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.64bit b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff similarity index 100% rename from src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.64bit rename to src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.64bit b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff similarity index 100% rename from src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.64bit rename to src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff similarity index 100% rename from src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit rename to src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff diff --git a/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff.64bit b/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.64bit.diff similarity index 100% rename from src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff.64bit rename to src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.64bit.diff diff --git a/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.64bit b/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.64bit.diff similarity index 100% rename from src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.64bit rename to src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.64bit.diff diff --git a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.mir.64bit b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir similarity index 100% rename from src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.mir.64bit rename to src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir diff --git a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir.64bit b/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir similarity index 100% rename from src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir.64bit rename to src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir diff --git a/src/test/mir-opt/simple_match.match_bool.mir_map.0.mir.64bit b/src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir similarity index 100% rename from src/test/mir-opt/simple_match.match_bool.mir_map.0.mir.64bit rename to src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir diff --git a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.64bit b/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.64bit.diff similarity index 100% rename from src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.64bit rename to src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.64bit.diff diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.64bit b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff similarity index 100% rename from src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.64bit rename to src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff diff --git a/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir.64bit b/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.64bit.mir similarity index 100% rename from src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir.64bit rename to src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.64bit.mir diff --git a/src/test/mir-opt/spanview_block.main.mir_map.0.html.mir b/src/test/mir-opt/spanview_block.main.mir_map.0.html.mir new file mode 100644 index 0000000000000..8f6b1307971b6 --- /dev/null +++ b/src/test/mir-opt/spanview_block.main.mir_map.0.html.mir @@ -0,0 +1,67 @@ + + + + coverage_of_if_else - Code Regions + + + +