From 679f6f347355726f9335fdcbf0d3b81b2e490c38 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Sun, 10 Jan 2021 11:36:45 +0100 Subject: [PATCH 01/13] Add `unwrap_unchecked()` methods for `Option` and `Result` In particular: - `unwrap_unchecked()` for `Option`. - `unwrap_unchecked()` and `unwrap_err_unchecked()` for `Result`. These complement other `*_unchecked()` methods in `core` etc. Currently there are a couple of places it may be used inside rustc (`LinkedList`, `BTree`). It is also easy to find other repositories with similar functionality. Fixes #48278. Signed-off-by: Miguel Ojeda --- library/core/src/option.rs | 31 +++++++++++++++++ library/core/src/result.rs | 64 +++++++++++++++++++++++++++++++++++- library/core/tests/lib.rs | 1 + library/core/tests/option.rs | 7 ++++ library/core/tests/result.rs | 12 +++++++ 5 files changed, 114 insertions(+), 1 deletion(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 0051c9eede070..18b494b3175b6 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -428,6 +428,37 @@ impl Option { } } + /// Returns the contained [`Some`] value, consuming the `self` value, + /// without checking that the value is not [`None`]. + /// + /// # Safety + /// + /// Undefined behavior if the value is [`None`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(option_result_unwrap_unchecked)] + /// let x = Some("air"); + /// assert_eq!(unsafe { x.unwrap_unchecked() }, "air"); + /// ``` + /// + /// ```no_run + /// #![feature(option_result_unwrap_unchecked)] + /// let x: Option<&str> = None; + /// assert_eq!(unsafe { x.unwrap_unchecked() }, "air"); // Undefined behavior! + /// ``` + #[inline] + #[track_caller] + #[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "none")] + pub unsafe fn unwrap_unchecked(self) -> T { + debug_assert!(self.is_some()); + match self { + Some(val) => val, + None => unsafe { hint::unreachable_unchecked() }, + } + } + ///////////////////////////////////////////////////////////////////////// // Transforming contained values ///////////////////////////////////////////////////////////////////////// diff --git a/library/core/src/result.rs b/library/core/src/result.rs index d6d1762572928..a0f5c7746cc75 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -229,7 +229,7 @@ use crate::iter::{self, FromIterator, FusedIterator, TrustedLen}; use crate::ops::{self, Deref, DerefMut}; -use crate::{convert, fmt}; +use crate::{convert, fmt, hint}; /// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]). /// @@ -821,6 +821,68 @@ impl Result { Err(e) => op(e), } } + + /// Returns the contained [`Ok`] value, consuming the `self` value, + /// without checking that the value is not an [`Err`]. + /// + /// # Safety + /// + /// Undefined behavior if the value is an [`Err`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(option_result_unwrap_unchecked)] + /// let x: Result = Ok(2); + /// assert_eq!(unsafe { x.unwrap_unchecked() }, 2); + /// ``` + /// + /// ```no_run + /// #![feature(option_result_unwrap_unchecked)] + /// let x: Result = Err("emergency failure"); + /// unsafe { x.unwrap_unchecked(); } // Undefined behavior! + /// ``` + #[inline] + #[track_caller] + #[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "none")] + pub unsafe fn unwrap_unchecked(self) -> T { + debug_assert!(self.is_ok()); + match self { + Ok(t) => t, + Err(_) => unsafe { hint::unreachable_unchecked() }, + } + } + + /// Returns the contained [`Err`] value, consuming the `self` value, + /// without checking that the value is not an [`Ok`]. + /// + /// # Safety + /// + /// Undefined behavior if the value is an [`Ok`]. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(option_result_unwrap_unchecked)] + /// let x: Result = Ok(2); + /// unsafe { x.unwrap_err_unchecked() }; // Undefined behavior! + /// ``` + /// + /// ``` + /// #![feature(option_result_unwrap_unchecked)] + /// let x: Result = Err("emergency failure"); + /// assert_eq!(unsafe { x.unwrap_err_unchecked() }, "emergency failure"); + /// ``` + #[inline] + #[track_caller] + #[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "none")] + pub unsafe fn unwrap_err_unchecked(self) -> E { + debug_assert!(self.is_err()); + match self { + Ok(_) => unsafe { hint::unreachable_unchecked() }, + Err(e) => e, + } + } } impl Result<&T, E> { diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index e01aaa4cbf179..285e6cdfd39f9 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -62,6 +62,7 @@ #![feature(const_raw_ptr_deref)] #![feature(never_type)] #![feature(unwrap_infallible)] +#![feature(option_result_unwrap_unchecked)] #![feature(option_unwrap_none)] #![feature(peekable_next_if)] #![feature(peekable_peek_mut)] diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs index 5388b4756245a..9470451278cc4 100644 --- a/library/core/tests/option.rs +++ b/library/core/tests/option.rs @@ -160,6 +160,13 @@ fn test_unwrap_or_else() { assert_eq!(x.unwrap_or_else(|| 2), 2); } +#[test] +fn test_unwrap_unchecked() { + assert_eq!(unsafe { Some(1).unwrap_unchecked() }, 1); + let s = unsafe { Some("hello".to_string()).unwrap_unchecked() }; + assert_eq!(s, "hello"); +} + #[test] fn test_iter() { let val = 5; diff --git a/library/core/tests/result.rs b/library/core/tests/result.rs index 81660870e95e4..7aa44c6e593b3 100644 --- a/library/core/tests/result.rs +++ b/library/core/tests/result.rs @@ -119,6 +119,18 @@ pub fn test_unwrap_or_else_panic() { let _: isize = bad_err.unwrap_or_else(handler); } +#[test] +fn test_unwrap_unchecked() { + let ok: Result = Ok(100); + assert_eq!(unsafe { ok.unwrap_unchecked() }, 100); +} + +#[test] +fn test_unwrap_err_unchecked() { + let ok_err: Result = Err("Err"); + assert_eq!(unsafe { ok_err.unwrap_err_unchecked() }, "Err"); +} + #[test] pub fn test_expect_ok() { let ok: Result = Ok(100); From 76299b3f42a402aa896b76fccd725f52080f374d Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Sun, 10 Jan 2021 15:59:17 +0100 Subject: [PATCH 02/13] Add `SAFETY` annotations Signed-off-by: Miguel Ojeda --- library/core/src/option.rs | 1 + library/core/src/result.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 18b494b3175b6..5d34f5ca155bf 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -455,6 +455,7 @@ impl Option { debug_assert!(self.is_some()); match self { Some(val) => val, + // SAFETY: the safety contract must be upheld by the caller. None => unsafe { hint::unreachable_unchecked() }, } } diff --git a/library/core/src/result.rs b/library/core/src/result.rs index a0f5c7746cc75..a357750b92f9d 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -849,6 +849,7 @@ impl Result { debug_assert!(self.is_ok()); match self { Ok(t) => t, + // SAFETY: the safety contract must be upheld by the caller. Err(_) => unsafe { hint::unreachable_unchecked() }, } } @@ -879,6 +880,7 @@ impl Result { pub unsafe fn unwrap_err_unchecked(self) -> E { debug_assert!(self.is_err()); match self { + // SAFETY: the safety contract must be upheld by the caller. Ok(_) => unsafe { hint::unreachable_unchecked() }, Err(e) => e, } From def0e9b8a495fa2a44e1d2cd948f7d4b6d81344f Mon Sep 17 00:00:00 2001 From: Camelid Date: Sun, 10 Jan 2021 19:55:54 -0800 Subject: [PATCH 03/13] Fix ICE with `ReadPointerAsBytes` validation error --- compiler/rustc_mir/src/interpret/validity.rs | 6 +++- src/test/ui/issues/issue-79690.rs | 29 ++++++++++++++++++++ src/test/ui/issues/issue-79690.stderr | 11 ++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/issues/issue-79690.rs create mode 100644 src/test/ui/issues/issue-79690.stderr diff --git a/compiler/rustc_mir/src/interpret/validity.rs b/compiler/rustc_mir/src/interpret/validity.rs index 423d1270ac865..0b7492631c41d 100644 --- a/compiler/rustc_mir/src/interpret/validity.rs +++ b/compiler/rustc_mir/src/interpret/validity.rs @@ -515,7 +515,11 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' Ok(true) } ty::Float(_) | ty::Int(_) | ty::Uint(_) => { - let value = self.ecx.read_scalar(value)?; + let value = try_validation!( + self.ecx.read_scalar(value), + self.path, + err_unsup!(ReadPointerAsBytes) => { "read of part of a pointer" }, + ); // NOTE: Keep this in sync with the array optimization for int/float // types below! if self.ctfe_mode.is_some() { diff --git a/src/test/ui/issues/issue-79690.rs b/src/test/ui/issues/issue-79690.rs new file mode 100644 index 0000000000000..6a38b3c8c2c71 --- /dev/null +++ b/src/test/ui/issues/issue-79690.rs @@ -0,0 +1,29 @@ +union Transmute { + t: T, + u: U, +} +trait Bar { + fn bar(&self) -> u32; +} +struct Foo { + foo: u32, + bar: bool, +} +impl Bar for Foo { + fn bar(&self) -> u32 { + self.foo + } +} +#[derive(Copy, Clone)] +struct Fat<'a>(&'a Foo, &'static VTable); +struct VTable { + size: Foo, +} +const FOO: &dyn Bar = &Foo { + foo: 128, + bar: false, +}; +const G: Fat = unsafe { Transmute { t: FOO }.u }; +//~^ ERROR it is undefined behavior to use this value + +fn main() {} diff --git a/src/test/ui/issues/issue-79690.stderr b/src/test/ui/issues/issue-79690.stderr new file mode 100644 index 0000000000000..c7f9c6a55e712 --- /dev/null +++ b/src/test/ui/issues/issue-79690.stderr @@ -0,0 +1,11 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/issue-79690.rs:26:1 + | +LL | const G: Fat = unsafe { Transmute { t: FOO }.u }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered read of part of a pointer at .1..size.foo + | + = 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 previous error + +For more information about this error, try `rustc --explain E0080`. From a7b7a435ea14cd0d2b83ea8a229e7d9cc4c651f1 Mon Sep 17 00:00:00 2001 From: Camelid Date: Sun, 10 Jan 2021 20:40:47 -0800 Subject: [PATCH 04/13] Move test to `src/test/ui/consts/` Apparently `tidy` has a hard limit of 2830 tests in the `src/test/ui/issues/` directory, and this test hit that limit. `src/test/ui/consts/` is probably a better location anyway. --- src/test/ui/{issues => consts}/issue-79690.rs | 0 src/test/ui/{issues => consts}/issue-79690.stderr | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{issues => consts}/issue-79690.rs (100%) rename src/test/ui/{issues => consts}/issue-79690.stderr (100%) diff --git a/src/test/ui/issues/issue-79690.rs b/src/test/ui/consts/issue-79690.rs similarity index 100% rename from src/test/ui/issues/issue-79690.rs rename to src/test/ui/consts/issue-79690.rs diff --git a/src/test/ui/issues/issue-79690.stderr b/src/test/ui/consts/issue-79690.stderr similarity index 100% rename from src/test/ui/issues/issue-79690.stderr rename to src/test/ui/consts/issue-79690.stderr From e25959b417fe2a08d808f9ddc737c2c9742d6d6a Mon Sep 17 00:00:00 2001 From: flip1995 Date: Fri, 22 Jan 2021 18:07:00 +0100 Subject: [PATCH 05/13] Make more traits of the From/Into family diagnostic items Following traits are now diagnostic items: - `From` (unchanged) - `Into` - `TryFrom` - `TryInto` This also adds symbols for those items: - `into_trait` - `try_from_trait` - `try_into_trait` --- compiler/rustc_span/src/symbol.rs | 3 +++ library/core/src/convert/mod.rs | 3 +++ src/tools/clippy/clippy_lints/src/fallible_impl_from.rs | 7 ++----- src/tools/clippy/clippy_lints/src/utils/paths.rs | 1 - 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 7b90e5b611cd1..2e7c9701c0c67 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -622,6 +622,7 @@ symbols! { intel, into_iter, into_result, + into_trait, intra_doc_pointers, intrinsics, irrefutable_let_patterns, @@ -1159,6 +1160,8 @@ symbols! { truncf32, truncf64, try_blocks, + try_from_trait, + try_into_trait, try_trait, tt, tuple, diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 139863bbe7f81..a6d3b5ef813f1 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -267,6 +267,7 @@ pub trait AsMut { /// /// [`String`]: ../../std/string/struct.String.html /// [`Vec`]: ../../std/vec/struct.Vec.html +#[rustc_diagnostic_item = "into_trait"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Into: Sized { /// Performs the conversion. @@ -382,6 +383,7 @@ pub trait From: Sized { /// /// This suffers the same restrictions and reasoning as implementing /// [`Into`], see there for details. +#[rustc_diagnostic_item = "try_into_trait"] #[stable(feature = "try_from", since = "1.34.0")] pub trait TryInto: Sized { /// The type returned in the event of a conversion error. @@ -462,6 +464,7 @@ pub trait TryInto: Sized { /// /// [`try_from`]: TryFrom::try_from /// [`!`]: ../../std/primitive.never.html +#[rustc_diagnostic_item = "try_from_trait"] #[stable(feature = "try_from", since = "1.34.0")] pub trait TryFrom: Sized { /// The type returned in the event of a conversion error. diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs index 9f389c8d2f9e7..527905e375d28 100644 --- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs +++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs @@ -1,7 +1,4 @@ -use crate::utils::paths::FROM_TRAIT; -use crate::utils::{ - is_expn_of, is_type_diagnostic_item, match_def_path, match_panic_def_id, method_chain_args, span_lint_and_then, -}; +use crate::utils::{is_expn_of, is_type_diagnostic_item, match_panic_def_id, method_chain_args, span_lint_and_then}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; @@ -59,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for FallibleImplFrom { if_chain! { if let hir::ItemKind::Impl(impl_) = &item.kind; if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(impl_def_id); - if match_def_path(cx, impl_trait_ref.def_id, &FROM_TRAIT); + if cx.tcx.is_diagnostic_item(sym::from_trait, impl_trait_ref.def_id); then { lint_impl_body(cx, item.span, impl_.items); } diff --git a/src/tools/clippy/clippy_lints/src/utils/paths.rs b/src/tools/clippy/clippy_lints/src/utils/paths.rs index c0b203b5388dc..432cc5b59f684 100644 --- a/src/tools/clippy/clippy_lints/src/utils/paths.rs +++ b/src/tools/clippy/clippy_lints/src/utils/paths.rs @@ -48,7 +48,6 @@ pub const FN_MUT: [&str; 3] = ["core", "ops", "FnMut"]; pub const FN_ONCE: [&str; 3] = ["core", "ops", "FnOnce"]; pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"]; pub const FROM_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "FromIterator"]; -pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"]; pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"]; pub const HASH: [&str; 3] = ["core", "hash", "Hash"]; pub const HASHMAP: [&str; 5] = ["std", "collections", "hash", "map", "HashMap"]; From 6d4e03af1e092b469825d998f6ea6b7e27def4d4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Jan 2021 12:12:08 +0100 Subject: [PATCH 06/13] codegen: assume constants cannot fail to evaluate --- compiler/rustc_codegen_ssa/src/mir/mod.rs | 21 ++++++++++++++++ compiler/rustc_codegen_ssa/src/mir/operand.rs | 25 +++---------------- compiler/rustc_mir/src/interpret/operand.rs | 4 +++ 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 285140060be45..8a009b66b593e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -188,8 +188,10 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut bx); + let mut all_consts_ok = true; for const_ in &mir.required_consts { if let Err(err) = fx.eval_mir_constant(const_) { + all_consts_ok = false; match err { // errored or at least linted ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted => {} @@ -199,6 +201,25 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } } } + if !all_consts_ok { + // There is no delay_span_bug here, we just have to rely on a hard error actually having + // been raised. + bx.abort(); + // `abort` does not terminate the block, so we still need to generate + // an `unreachable` terminator after it. + bx.unreachable(); + // We also have to delete all the other basic blocks again... + for bb in mir.basic_blocks().indices() { + if bb != mir::START_BLOCK { + unsafe { + bx.delete_basic_block(fx.blocks[bb]); + } + } + } + // FIXME: Can we somehow avoid all this by evaluating the consts before creating the basic + // blocks? The tricky part is doing that without duplicating `fx.eval_mir_constant`. + return; + } let memory_locals = analyze::non_ssa_locals(&fx); diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 08a4ae3962bee..25e84c38ed315 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -6,9 +6,8 @@ use crate::glue; use crate::traits::*; use crate::MemFlags; -use rustc_errors::ErrorReported; use rustc_middle::mir; -use rustc_middle::mir::interpret::{ConstValue, ErrorHandled, Pointer, Scalar}; +use rustc_middle::mir::interpret::{ConstValue, Pointer, Scalar}; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::Ty; use rustc_target::abi::{Abi, Align, LayoutOf, Size}; @@ -439,25 +438,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::Operand::Constant(ref constant) => { - self.eval_mir_constant_to_operand(bx, constant).unwrap_or_else(|err| { - match err { - // errored or at least linted - ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted => {} - ErrorHandled::TooGeneric => { - bug!("codegen encountered polymorphic constant") - } - } - // Allow RalfJ to sleep soundly knowing that even refactorings that remove - // the above error (or silence it under some conditions) will not cause UB. - bx.abort(); - // We still have to return an operand but it doesn't matter, - // this code is unreachable. - let ty = self.monomorphize(constant.literal.ty); - let layout = bx.cx().layout_of(ty); - bx.load_operand(PlaceRef::new_sized( - bx.cx().const_undef(bx.cx().type_ptr_to(bx.cx().backend_type(layout))), - layout, - )) + // This cannot fail because we checked all required_consts in advance. + self.eval_mir_constant_to_operand(bx, constant).unwrap_or_else(|_err| { + span_bug!(constant.span, "erroneous constant not captured by required_consts") }) } } diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs index d9437a312aec0..88236458a213a 100644 --- a/compiler/rustc_mir/src/interpret/operand.rs +++ b/compiler/rustc_mir/src/interpret/operand.rs @@ -511,6 +511,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Constant(ref constant) => { let val = self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal); + // This can still fail: + // * During ConstProp, with `TooGeneric` or since the `requried_consts` were not all + // checked yet. + // * During CTFE, since promoteds in `const`/`static` initializer bodies can fail. self.const_to_op(val, layout)? } }; From 57c72ab8469883fd761a9bba9c4f49771e48256f Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Sun, 24 Jan 2021 18:16:31 -0800 Subject: [PATCH 07/13] libtest: Wait for test threads to exit after they report completion Otherwise we can miss bugs where a test reports that it succeeded but then panics within a TLS destructor. Signed-off-by: Anders Kaseorg --- library/test/src/lib.rs | 59 +++++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 656d9669e81d2..f6b692404606d 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -25,6 +25,7 @@ #![feature(nll)] #![feature(available_concurrency)] #![feature(internal_output_capture)] +#![feature(option_unwrap_none)] #![feature(panic_unwind)] #![feature(staged_api)] #![feature(termination_trait_lib)] @@ -208,9 +209,15 @@ where use std::collections::{self, HashMap}; use std::hash::BuildHasherDefault; use std::sync::mpsc::RecvTimeoutError; + + struct RunningTest { + timeout: Instant, + join_handle: Option>, + } + // Use a deterministic hasher type TestMap = - HashMap>; + HashMap>; let tests_len = tests.len(); @@ -260,7 +267,11 @@ where let now = Instant::now(); let timed_out = running_tests .iter() - .filter_map(|(desc, timeout)| if &now >= timeout { Some(desc.clone()) } else { None }) + .filter_map( + |(desc, running_test)| { + if now >= running_test.timeout { Some(desc.clone()) } else { None } + }, + ) .collect(); for test in &timed_out { running_tests.remove(test); @@ -269,9 +280,9 @@ where } fn calc_timeout(running_tests: &TestMap) -> Option { - running_tests.values().min().map(|next_timeout| { + running_tests.values().map(|running_test| running_test.timeout).min().map(|next_timeout| { let now = Instant::now(); - if *next_timeout >= now { *next_timeout - now } else { Duration::new(0, 0) } + if next_timeout >= now { next_timeout - now } else { Duration::new(0, 0) } }) } @@ -280,7 +291,8 @@ where let test = remaining.pop().unwrap(); let event = TestEvent::TeWait(test.desc.clone()); notify_about_test_event(event)?; - run_test(opts, !opts.run_tests, test, run_strategy, tx.clone(), Concurrent::No); + run_test(opts, !opts.run_tests, test, run_strategy, tx.clone(), Concurrent::No) + .unwrap_none(); let completed_test = rx.recv().unwrap(); let event = TestEvent::TeResult(completed_test); @@ -291,11 +303,19 @@ where while pending < concurrency && !remaining.is_empty() { let test = remaining.pop().unwrap(); let timeout = time::get_default_test_timeout(); - running_tests.insert(test.desc.clone(), timeout); + let desc = test.desc.clone(); let event = TestEvent::TeWait(test.desc.clone()); notify_about_test_event(event)?; //here no pad - run_test(opts, !opts.run_tests, test, run_strategy, tx.clone(), Concurrent::Yes); + let join_handle = run_test( + opts, + !opts.run_tests, + test, + run_strategy, + tx.clone(), + Concurrent::Yes, + ); + running_tests.insert(desc, RunningTest { timeout, join_handle }); pending += 1; } @@ -323,8 +343,16 @@ where } } - let completed_test = res.unwrap(); - running_tests.remove(&completed_test.desc); + let mut completed_test = res.unwrap(); + let running_test = running_tests.remove(&completed_test.desc).unwrap(); + if let Some(join_handle) = running_test.join_handle { + if let Err(_) = join_handle.join() { + if let TrOk = completed_test.result { + completed_test.result = + TrFailedMsg("panicked after reporting success".to_string()); + } + } + } let event = TestEvent::TeResult(completed_test); notify_about_test_event(event)?; @@ -415,7 +443,7 @@ pub fn run_test( strategy: RunStrategy, monitor_ch: Sender, concurrency: Concurrent, -) { +) -> Option> { let TestDescAndFn { desc, testfn } = test; // Emscripten can catch panics but other wasm targets cannot @@ -426,7 +454,7 @@ pub fn run_test( if force_ignore || desc.ignore || ignore_because_no_process_support { let message = CompletedTest::new(desc, TrIgnored, None, Vec::new()); monitor_ch.send(message).unwrap(); - return; + return None; } struct TestRunOpts { @@ -441,7 +469,7 @@ pub fn run_test( monitor_ch: Sender, testfn: Box, opts: TestRunOpts, - ) { + ) -> Option> { let concurrency = opts.concurrency; let name = desc.name.clone(); @@ -469,9 +497,10 @@ pub fn run_test( let supports_threads = !cfg!(target_os = "emscripten") && !cfg!(target_arch = "wasm32"); if concurrency == Concurrent::Yes && supports_threads { let cfg = thread::Builder::new().name(name.as_slice().to_owned()); - cfg.spawn(runtest).unwrap(); + Some(cfg.spawn(runtest).unwrap()) } else { runtest(); + None } } @@ -484,10 +513,12 @@ pub fn run_test( crate::bench::benchmark(desc, monitor_ch, opts.nocapture, |harness| { bencher.run(harness) }); + None } StaticBenchFn(benchfn) => { // Benchmarks aren't expected to panic, so we run them all in-process. crate::bench::benchmark(desc, monitor_ch, opts.nocapture, benchfn); + None } DynTestFn(f) => { match strategy { @@ -499,7 +530,7 @@ pub fn run_test( monitor_ch, Box::new(move || __rust_begin_short_backtrace(f)), test_run_opts, - ); + ) } StaticTestFn(f) => run_test_inner( desc, From 2be19932335f76cb4a97c275038a019751fbba6a Mon Sep 17 00:00:00 2001 From: Camelid Date: Sun, 24 Jan 2021 19:38:10 -0800 Subject: [PATCH 08/13] Ignore test on 32-bit architectures --- src/test/ui/consts/issue-79690.rs | 3 +++ src/test/ui/consts/issue-79690.stderr | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/test/ui/consts/issue-79690.rs b/src/test/ui/consts/issue-79690.rs index 6a38b3c8c2c71..a2e7b97b3187d 100644 --- a/src/test/ui/consts/issue-79690.rs +++ b/src/test/ui/consts/issue-79690.rs @@ -1,3 +1,6 @@ +// ignore-32bit +// This test gives a different error on 32-bit architectures. + union Transmute { t: T, u: U, diff --git a/src/test/ui/consts/issue-79690.stderr b/src/test/ui/consts/issue-79690.stderr index c7f9c6a55e712..918dd4c20f96c 100644 --- a/src/test/ui/consts/issue-79690.stderr +++ b/src/test/ui/consts/issue-79690.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/issue-79690.rs:26:1 + --> $DIR/issue-79690.rs:29:1 | LL | const G: Fat = unsafe { Transmute { t: FOO }.u }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered read of part of a pointer at .1..size.foo From 26b4baf46ea66d3651281c8b66d76853e6362c65 Mon Sep 17 00:00:00 2001 From: 1000teslas <47207223+1000teslas@users.noreply.github.com> Date: Mon, 18 Jan 2021 19:04:55 +1100 Subject: [PATCH 09/13] Point to span of upvar making closure FnMut Add expected error Add comment Tweak comment wording Fix after rebase to updated master Fix after rebase to updated master Distinguish mutation in normal and move closures Tweak error message Fix error message for nested closures Refactor code showing mutated upvar in closure Remove debug assert B --- .../diagnostics/mutability_errors.rs | 56 ++++++++++++++++++- .../borrow-raw-address-of-mutability.stderr | 4 +- .../issue-80313-mutable-borrow-in-closure.rs | 7 +++ ...sue-80313-mutable-borrow-in-closure.stderr | 14 +++++ ...ue-80313-mutable-borrow-in-move-closure.rs | 7 +++ ...0313-mutable-borrow-in-move-closure.stderr | 14 +++++ .../issue-80313-mutation-in-closure.rs | 7 +++ .../issue-80313-mutation-in-closure.stderr | 14 +++++ .../issue-80313-mutation-in-move-closure.rs | 7 +++ ...ssue-80313-mutation-in-move-closure.stderr | 14 +++++ ...es-infer-fnmut-calling-fnmut-no-mut.stderr | 4 ++ ...ed-closures-infer-fnmut-missing-mut.stderr | 4 +- ...osures-infer-fnmut-move-missing-mut.stderr | 4 +- 13 files changed, 152 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/closures/issue-80313-mutable-borrow-in-closure.rs create mode 100644 src/test/ui/closures/issue-80313-mutable-borrow-in-closure.stderr create mode 100644 src/test/ui/closures/issue-80313-mutable-borrow-in-move-closure.rs create mode 100644 src/test/ui/closures/issue-80313-mutable-borrow-in-move-closure.stderr create mode 100644 src/test/ui/closures/issue-80313-mutation-in-closure.rs create mode 100644 src/test/ui/closures/issue-80313-mutation-in-closure.stderr create mode 100644 src/test/ui/closures/issue-80313-mutation-in-move-closure.rs create mode 100644 src/test/ui/closures/issue-80313-mutation-in-move-closure.stderr 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 e1af6fc07cf8f..73196c732f5bb 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs @@ -1,9 +1,12 @@ use rustc_hir as hir; use rustc_hir::Node; use rustc_index::vec::Idx; -use rustc_middle::mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, Location}; use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem}; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::{ + hir::place::PlaceBase, + mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, Location}, +}; use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::{kw, Symbol}; use rustc_span::Span; @@ -241,6 +244,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { format!("mut {}", self.local_names[local].unwrap()), Applicability::MachineApplicable, ); + let tcx = self.infcx.tcx; + if let ty::Closure(id, _) = the_place_err.ty(self.body, tcx).ty.kind() { + self.show_mutating_upvar(tcx, id, the_place_err, &mut err); + } } // Also suggest adding mut for upvars @@ -271,6 +278,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ); } } + + let tcx = self.infcx.tcx; + if let ty::Ref(_, ty, Mutability::Mut) = the_place_err.ty(self.body, tcx).ty.kind() + { + if let ty::Closure(id, _) = ty.kind() { + self.show_mutating_upvar(tcx, id, the_place_err, &mut err); + } + } } // complete hack to approximate old AST-borrowck @@ -463,6 +478,45 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { err.buffer(&mut self.errors_buffer); } + // point to span of upvar making closure call require mutable borrow + fn show_mutating_upvar( + &self, + tcx: TyCtxt<'_>, + id: &hir::def_id::DefId, + the_place_err: PlaceRef<'tcx>, + err: &mut DiagnosticBuilder<'_>, + ) { + let id = id.expect_local(); + let tables = tcx.typeck(id); + let hir_id = tcx.hir().local_def_id_to_hir_id(id); + let (span, place) = &tables.closure_kind_origins()[hir_id]; + let reason = if let PlaceBase::Upvar(upvar_id) = place.base { + let upvar = ty::place_to_string_for_capture(tcx, place); + match tables.upvar_capture(upvar_id) { + ty::UpvarCapture::ByRef(ty::UpvarBorrow { + kind: ty::BorrowKind::MutBorrow, + .. + }) => { + format!("mutable borrow of `{}`", upvar) + } + ty::UpvarCapture::ByValue(_) => { + format!("possible mutation of `{}`", upvar) + } + _ => bug!("upvar `{}` borrowed, but not mutably", upvar), + } + } else { + bug!("not an upvar") + }; + err.span_label( + *span, + format!( + "calling `{}` requires mutable binding due to {}", + self.describe_place(the_place_err).unwrap(), + reason + ), + ); + } + /// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected. fn expected_fn_found_fn_mut_call(&self, err: &mut DiagnosticBuilder<'_>, sp: Span, act: &str) { err.span_label(sp, format!("cannot {}", act)); diff --git a/src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr b/src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr index 44dde0fd80b0d..ea74fb966846f 100644 --- a/src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr +++ b/src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr @@ -20,7 +20,9 @@ error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable | LL | let f = || { | - help: consider changing this to be mutable: `mut f` -... +LL | let y = &raw mut x; + | - calling `f` requires mutable binding due to mutable borrow of `x` +LL | }; LL | f(); | ^ cannot borrow as mutable diff --git a/src/test/ui/closures/issue-80313-mutable-borrow-in-closure.rs b/src/test/ui/closures/issue-80313-mutable-borrow-in-closure.rs new file mode 100644 index 0000000000000..ff210ae06a3bd --- /dev/null +++ b/src/test/ui/closures/issue-80313-mutable-borrow-in-closure.rs @@ -0,0 +1,7 @@ +fn main() { + let mut my_var = false; + let callback = || { + &mut my_var; + }; + callback(); //~ ERROR E0596 +} diff --git a/src/test/ui/closures/issue-80313-mutable-borrow-in-closure.stderr b/src/test/ui/closures/issue-80313-mutable-borrow-in-closure.stderr new file mode 100644 index 0000000000000..bf9e1febdbba4 --- /dev/null +++ b/src/test/ui/closures/issue-80313-mutable-borrow-in-closure.stderr @@ -0,0 +1,14 @@ +error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable + --> $DIR/issue-80313-mutable-borrow-in-closure.rs:6:5 + | +LL | let callback = || { + | -------- help: consider changing this to be mutable: `mut callback` +LL | &mut my_var; + | ------ calling `callback` requires mutable binding due to mutable borrow of `my_var` +LL | }; +LL | callback(); + | ^^^^^^^^ cannot borrow as mutable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/closures/issue-80313-mutable-borrow-in-move-closure.rs b/src/test/ui/closures/issue-80313-mutable-borrow-in-move-closure.rs new file mode 100644 index 0000000000000..8f2d8a676302c --- /dev/null +++ b/src/test/ui/closures/issue-80313-mutable-borrow-in-move-closure.rs @@ -0,0 +1,7 @@ +fn main() { + let mut my_var = false; + let callback = move || { + &mut my_var; + }; + callback(); //~ ERROR E0596 +} diff --git a/src/test/ui/closures/issue-80313-mutable-borrow-in-move-closure.stderr b/src/test/ui/closures/issue-80313-mutable-borrow-in-move-closure.stderr new file mode 100644 index 0000000000000..b67cec6a609f0 --- /dev/null +++ b/src/test/ui/closures/issue-80313-mutable-borrow-in-move-closure.stderr @@ -0,0 +1,14 @@ +error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable + --> $DIR/issue-80313-mutable-borrow-in-move-closure.rs:6:5 + | +LL | let callback = move || { + | -------- help: consider changing this to be mutable: `mut callback` +LL | &mut my_var; + | ------ calling `callback` requires mutable binding due to possible mutation of `my_var` +LL | }; +LL | callback(); + | ^^^^^^^^ cannot borrow as mutable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/closures/issue-80313-mutation-in-closure.rs b/src/test/ui/closures/issue-80313-mutation-in-closure.rs new file mode 100644 index 0000000000000..e082ea562ef22 --- /dev/null +++ b/src/test/ui/closures/issue-80313-mutation-in-closure.rs @@ -0,0 +1,7 @@ +fn main() { + let mut my_var = false; + let callback = || { + my_var = true; + }; + callback(); //~ ERROR E0596 +} diff --git a/src/test/ui/closures/issue-80313-mutation-in-closure.stderr b/src/test/ui/closures/issue-80313-mutation-in-closure.stderr new file mode 100644 index 0000000000000..6e98549f6b84f --- /dev/null +++ b/src/test/ui/closures/issue-80313-mutation-in-closure.stderr @@ -0,0 +1,14 @@ +error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable + --> $DIR/issue-80313-mutation-in-closure.rs:6:5 + | +LL | let callback = || { + | -------- help: consider changing this to be mutable: `mut callback` +LL | my_var = true; + | ------ calling `callback` requires mutable binding due to mutable borrow of `my_var` +LL | }; +LL | callback(); + | ^^^^^^^^ cannot borrow as mutable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/closures/issue-80313-mutation-in-move-closure.rs b/src/test/ui/closures/issue-80313-mutation-in-move-closure.rs new file mode 100644 index 0000000000000..f66bf4e062831 --- /dev/null +++ b/src/test/ui/closures/issue-80313-mutation-in-move-closure.rs @@ -0,0 +1,7 @@ +fn main() { + let mut my_var = false; + let callback = move || { + my_var = true; + }; + callback(); //~ ERROR E0596 +} diff --git a/src/test/ui/closures/issue-80313-mutation-in-move-closure.stderr b/src/test/ui/closures/issue-80313-mutation-in-move-closure.stderr new file mode 100644 index 0000000000000..edd55422a0bd4 --- /dev/null +++ b/src/test/ui/closures/issue-80313-mutation-in-move-closure.stderr @@ -0,0 +1,14 @@ +error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable + --> $DIR/issue-80313-mutation-in-move-closure.rs:6:5 + | +LL | let callback = move || { + | -------- help: consider changing this to be mutable: `mut callback` +LL | my_var = true; + | ------ calling `callback` requires mutable binding due to possible mutation of `my_var` +LL | }; +LL | callback(); + | ^^^^^^^^ cannot borrow as mutable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr index 5dea424596e9c..a0ed56d4bcf7b 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr @@ -3,6 +3,8 @@ error[E0596]: cannot borrow `tick1` as mutable, as it is not declared as mutable | LL | let tick1 = || { | ----- help: consider changing this to be mutable: `mut tick1` +LL | counter += 1; + | ------- calling `tick1` requires mutable binding due to mutable borrow of `counter` ... LL | tick1(); | ^^^^^ cannot borrow as mutable @@ -12,6 +14,8 @@ error[E0596]: cannot borrow `tick2` as mutable, as it is not declared as mutable | LL | let tick2 = || { | ----- help: consider changing this to be mutable: `mut tick2` +LL | tick1(); + | ----- calling `tick2` requires mutable binding due to mutable borrow of `tick1` ... LL | tick2(); | ^^^^^ cannot borrow as mutable diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.stderr index eb398628846dd..27d23e3fa044b 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.stderr @@ -2,7 +2,9 @@ error[E0596]: cannot borrow `tick` as mutable, as it is not declared as mutable --> $DIR/unboxed-closures-infer-fnmut-missing-mut.rs:7:5 | LL | let tick = || counter += 1; - | ---- help: consider changing this to be mutable: `mut tick` + | ---- ------- calling `tick` requires mutable binding due to mutable borrow of `counter` + | | + | help: consider changing this to be mutable: `mut tick` LL | tick(); | ^^^^ cannot borrow as mutable diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.stderr index b9d76d9a752ce..c00f986c397a7 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.stderr @@ -2,7 +2,9 @@ error[E0596]: cannot borrow `tick` as mutable, as it is not declared as mutable --> $DIR/unboxed-closures-infer-fnmut-move-missing-mut.rs:7:5 | LL | let tick = move || counter += 1; - | ---- help: consider changing this to be mutable: `mut tick` + | ---- ------- calling `tick` requires mutable binding due to possible mutation of `counter` + | | + | help: consider changing this to be mutable: `mut tick` LL | tick(); | ^^^^ cannot borrow as mutable From 088c89d9ffe47fb6d1b51c8edfd8ad652ee2a7f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 19 Jan 2021 12:44:49 -0800 Subject: [PATCH 10/13] Account for generics when suggesting bound Fix #81175. --- .../src/traits/error_reporting/suggestions.rs | 35 +++++--- src/test/ui/bound-suggestions.fixed | 27 +++++- src/test/ui/bound-suggestions.rs | 27 +++++- src/test/ui/bound-suggestions.stderr | 82 ++++++++++++++++++- 4 files changed, 156 insertions(+), 15 deletions(-) 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 1830aaa4471a6..0ab00fddfafc8 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -286,21 +286,32 @@ fn suggest_restriction( ); } else { // Trivial case: `T` needs an extra bound: `T: Bound`. - let (sp, suggestion) = match super_traits { - None => predicate_constraint( + let (sp, suggestion) = match ( + generics + .params + .iter() + .filter( + |p| !matches!(p.kind, hir::GenericParamKind::Type { synthetic: Some(_), ..}), + ) + .next(), + super_traits, + ) { + (_, None) => predicate_constraint( generics, trait_ref.without_const().to_predicate(tcx).to_string(), ), - Some((ident, bounds)) => match bounds { - [.., bound] => ( - bound.span().shrink_to_hi(), - format!(" + {}", trait_ref.print_only_trait_path().to_string()), - ), - [] => ( - ident.span.shrink_to_hi(), - format!(": {}", trait_ref.print_only_trait_path().to_string()), - ), - }, + (None, Some((ident, []))) => ( + ident.span.shrink_to_hi(), + format!(": {}", trait_ref.print_only_trait_path().to_string()), + ), + (_, Some((_, [.., bounds]))) => ( + bounds.span().shrink_to_hi(), + format!(" + {}", trait_ref.print_only_trait_path().to_string()), + ), + (Some(_), Some((_, []))) => ( + generics.span.shrink_to_hi(), + format!(": {}", trait_ref.print_only_trait_path().to_string()), + ), }; err.span_suggestion_verbose( diff --git a/src/test/ui/bound-suggestions.fixed b/src/test/ui/bound-suggestions.fixed index a3fe67a95954f..be61b7dda256a 100644 --- a/src/test/ui/bound-suggestions.fixed +++ b/src/test/ui/bound-suggestions.fixed @@ -40,4 +40,29 @@ fn test_many_bounds_where(x: X) where X: Sized, X: Sized, X: Debug { //~^ ERROR doesn't implement } -pub fn main() { } +trait Foo: Sized { + const SIZE: usize = core::mem::size_of::(); + //~^ ERROR the size for values of type `Self` cannot be known at compilation time +} + +trait Bar: std::fmt::Display + Sized { + const SIZE: usize = core::mem::size_of::(); + //~^ ERROR the size for values of type `Self` cannot be known at compilation time +} + +trait Baz: Sized where Self: std::fmt::Display { + const SIZE: usize = core::mem::size_of::(); + //~^ ERROR the size for values of type `Self` cannot be known at compilation time +} + +trait Qux: Sized where Self: std::fmt::Display { + const SIZE: usize = core::mem::size_of::(); + //~^ ERROR the size for values of type `Self` cannot be known at compilation time +} + +trait Bat: std::fmt::Display + Sized { + const SIZE: usize = core::mem::size_of::(); + //~^ ERROR the size for values of type `Self` cannot be known at compilation time +} + +fn main() { } diff --git a/src/test/ui/bound-suggestions.rs b/src/test/ui/bound-suggestions.rs index de6133d7f59ac..86f708d42f5e7 100644 --- a/src/test/ui/bound-suggestions.rs +++ b/src/test/ui/bound-suggestions.rs @@ -40,4 +40,29 @@ fn test_many_bounds_where(x: X) where X: Sized, X: Sized { //~^ ERROR doesn't implement } -pub fn main() { } +trait Foo { + const SIZE: usize = core::mem::size_of::(); + //~^ ERROR the size for values of type `Self` cannot be known at compilation time +} + +trait Bar: std::fmt::Display { + const SIZE: usize = core::mem::size_of::(); + //~^ ERROR the size for values of type `Self` cannot be known at compilation time +} + +trait Baz where Self: std::fmt::Display { + const SIZE: usize = core::mem::size_of::(); + //~^ ERROR the size for values of type `Self` cannot be known at compilation time +} + +trait Qux where Self: std::fmt::Display { + const SIZE: usize = core::mem::size_of::(); + //~^ ERROR the size for values of type `Self` cannot be known at compilation time +} + +trait Bat: std::fmt::Display { + const SIZE: usize = core::mem::size_of::(); + //~^ ERROR the size for values of type `Self` cannot be known at compilation time +} + +fn main() { } diff --git a/src/test/ui/bound-suggestions.stderr b/src/test/ui/bound-suggestions.stderr index 010f95d8ad6f0..12e67e90265ab 100644 --- a/src/test/ui/bound-suggestions.stderr +++ b/src/test/ui/bound-suggestions.stderr @@ -76,6 +76,86 @@ help: consider further restricting type parameter `X` LL | fn test_many_bounds_where(x: X) where X: Sized, X: Sized, X: Debug { | ^^^^^^^^^^ -error: aborting due to 6 previous errors +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/bound-suggestions.rs:44:46 + | +LL | const SIZE: usize = core::mem::size_of::(); + | ^^^^ doesn't have a size known at compile-time + | + ::: $SRC_DIR/core/src/mem/mod.rs:LL:COL + | +LL | pub const fn size_of() -> usize { + | - required by this bound in `std::mem::size_of` + | +help: consider further restricting `Self` + | +LL | trait Foo: Sized { + | ^^^^^^^ + +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/bound-suggestions.rs:49:46 + | +LL | const SIZE: usize = core::mem::size_of::(); + | ^^^^ doesn't have a size known at compile-time + | + ::: $SRC_DIR/core/src/mem/mod.rs:LL:COL + | +LL | pub const fn size_of() -> usize { + | - required by this bound in `std::mem::size_of` + | +help: consider further restricting `Self` + | +LL | trait Bar: std::fmt::Display + Sized { + | ^^^^^^^ + +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/bound-suggestions.rs:54:46 + | +LL | const SIZE: usize = core::mem::size_of::(); + | ^^^^ doesn't have a size known at compile-time + | + ::: $SRC_DIR/core/src/mem/mod.rs:LL:COL + | +LL | pub const fn size_of() -> usize { + | - required by this bound in `std::mem::size_of` + | +help: consider further restricting `Self` + | +LL | trait Baz: Sized where Self: std::fmt::Display { + | ^^^^^^^ + +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/bound-suggestions.rs:59:46 + | +LL | const SIZE: usize = core::mem::size_of::(); + | ^^^^ doesn't have a size known at compile-time + | + ::: $SRC_DIR/core/src/mem/mod.rs:LL:COL + | +LL | pub const fn size_of() -> usize { + | - required by this bound in `std::mem::size_of` + | +help: consider further restricting `Self` + | +LL | trait Qux: Sized where Self: std::fmt::Display { + | ^^^^^^^ + +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/bound-suggestions.rs:64:46 + | +LL | const SIZE: usize = core::mem::size_of::(); + | ^^^^ doesn't have a size known at compile-time + | + ::: $SRC_DIR/core/src/mem/mod.rs:LL:COL + | +LL | pub const fn size_of() -> usize { + | - required by this bound in `std::mem::size_of` + | +help: consider further restricting `Self` + | +LL | trait Bat: std::fmt::Display + Sized { + | ^^^^^^^ + +error: aborting due to 11 previous errors For more information about this error, try `rustc --explain E0277`. From 042facb9357f9b6248b0b2b6c5624742c3948e47 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 23 Jan 2021 14:55:24 +0100 Subject: [PATCH 11/13] Fix some bugs reported by eslint --- src/librustdoc/html/static/main.js | 50 +++++++++------------ src/librustdoc/html/static/settings.js | 2 +- src/librustdoc/html/static/source-script.js | 2 + src/librustdoc/html/static/storage.js | 10 ++++- 4 files changed, 33 insertions(+), 31 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 74bd348e9ac1c..53f0831852456 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -1,9 +1,6 @@ -// From rust: -/* global ALIASES */ - // Local js definitions: -/* global addClass, getCurrentValue, hasClass */ -/* global onEachLazy, hasOwnProperty, removeClass, updateLocalStorage */ +/* global addClass, getSettingValue, hasClass */ +/* global onEach, onEachLazy, hasOwnProperty, removeClass, updateLocalStorage */ /* global hideThemeButtonState, showThemeButtonState */ if (!String.prototype.startsWith) { @@ -2214,7 +2211,7 @@ function defocusSearchBar() { } } - function toggleAllDocs(pageId, fromAutoCollapse) { + function toggleAllDocs(fromAutoCollapse) { var innerToggle = document.getElementById(toggleAllDocsId); if (!innerToggle) { return; @@ -2257,14 +2254,14 @@ function defocusSearchBar() { } if (!parent || !superParent || superParent.id !== "main" || hasClass(parent, "impl") === false) { - collapseDocs(e, "hide", pageId); + collapseDocs(e, "hide"); } }); } } } - function collapseDocs(toggle, mode, pageId) { + function collapseDocs(toggle, mode) { if (!toggle || !toggle.parentNode) { return; } @@ -2384,27 +2381,27 @@ function defocusSearchBar() { } } - function collapser(pageId, e, collapse) { + function collapser(e, collapse) { // inherent impl ids are like "impl" or impl-'. // they will never be hidden by default. var n = e.parentElement; if (n.id.match(/^impl(?:-\d+)?$/) === null) { // Automatically minimize all non-inherent impls if (collapse || hasClass(n, "impl")) { - collapseDocs(e, "hide", pageId); + collapseDocs(e, "hide"); } } } - function autoCollapse(pageId, collapse) { + function autoCollapse(collapse) { if (collapse) { - toggleAllDocs(pageId, true); + toggleAllDocs(true); } else if (getSettingValue("auto-hide-trait-implementations") !== "false") { var impl_list = document.getElementById("trait-implementations-list"); if (impl_list !== null) { onEachLazy(impl_list.getElementsByClassName("collapse-toggle"), function(e) { - collapser(pageId, e, collapse); + collapser(e, collapse); }); } @@ -2412,7 +2409,7 @@ function defocusSearchBar() { if (blanket_list !== null) { onEachLazy(blanket_list.getElementsByClassName("collapse-toggle"), function(e) { - collapser(pageId, e, collapse); + collapser(e, collapse); }); } } @@ -2475,7 +2472,6 @@ function defocusSearchBar() { var toggle = createSimpleToggle(false); var hideMethodDocs = getSettingValue("auto-hide-method-docs") === "true"; var hideImplementors = getSettingValue("auto-collapse-implementors") !== "false"; - var pageId = getPageId(); var func = function(e) { var next = e.nextElementSibling; @@ -2489,7 +2485,7 @@ function defocusSearchBar() { var newToggle = toggle.cloneNode(true); insertAfter(newToggle, e.childNodes[e.childNodes.length - 1]); if (hideMethodDocs === true && hasClass(e, "method") === true) { - collapseDocs(newToggle, "hide", pageId); + collapseDocs(newToggle, "hide"); } } }; @@ -2513,7 +2509,7 @@ function defocusSearchBar() { // In case the option "auto-collapse implementors" is not set to false, we collapse // all implementors. if (hideImplementors === true && e.parentNode.id === "implementors-list") { - collapseDocs(newToggle, "hide", pageId); + collapseDocs(newToggle, "hide"); } } }; @@ -2527,7 +2523,7 @@ function defocusSearchBar() { if (e.id.match(/^impl(?:-\d+)?$/) === null) { // Automatically minimize all non-inherent impls if (hasClass(e, "impl") === true) { - collapseDocs(newToggle, "hide", pageId); + collapseDocs(newToggle, "hide"); } } }; @@ -2562,14 +2558,12 @@ function defocusSearchBar() { } onEachLazy(document.getElementsByClassName("impl-items"), function(e) { onEachLazy(e.getElementsByClassName("associatedconstant"), func); - var hiddenElems = e.getElementsByClassName("hidden"); - var needToggle = false; - - var needToggle = onEachLazy(e.getElementsByClassName("hidden"), function(hiddenElem) { - if (hasClass(hiddenElem, "content") === false && - hasClass(hiddenElem, "docblock") === false) { - return true; - } + // We transform the DOM iterator into a vec of DOM elements to prevent performance + // issues on webkit browsers. + var hiddenElems = Array.prototype.slice.call(e.getElementsByClassName("hidden")); + var needToggle = hiddenElems.some(function(hiddenElem) { + return hasClass(hiddenElem, "content") === false && + hasClass(hiddenElem, "docblock") === false; }); if (needToggle === true) { var inner_toggle = newToggle.cloneNode(true); @@ -2672,10 +2666,10 @@ function defocusSearchBar() { onEachLazy(document.getElementsByClassName("docblock"), buildToggleWrapper); onEachLazy(document.getElementsByClassName("sub-variant"), buildToggleWrapper); - var pageId = getPageId(); - autoCollapse(pageId, getSettingValue("collapse") === "true"); + autoCollapse(getSettingValue("collapse") === "true"); + var pageId = getPageId(); if (pageId !== null) { expandSection(pageId); } diff --git a/src/librustdoc/html/static/settings.js b/src/librustdoc/html/static/settings.js index bc14420232c4d..4f10e14e8558c 100644 --- a/src/librustdoc/html/static/settings.js +++ b/src/librustdoc/html/static/settings.js @@ -1,5 +1,5 @@ // Local js definitions: -/* global getCurrentValue, getVirtualKey, updateLocalStorage, updateSystemTheme */ +/* global getSettingValue, getVirtualKey, onEachLazy, updateLocalStorage, updateSystemTheme */ (function () { function changeSetting(settingName, value) { diff --git a/src/librustdoc/html/static/source-script.js b/src/librustdoc/html/static/source-script.js index a9cc0ffdf79b0..42b54e4cc1e46 100644 --- a/src/librustdoc/html/static/source-script.js +++ b/src/librustdoc/html/static/source-script.js @@ -113,6 +113,8 @@ function createSidebarToggle() { return sidebarToggle; } +// This function is called from "source-files.js", generated in `html/render/mod.rs`. +// eslint-disable-next-line no-unused-vars function createSourceSidebar() { if (window.rootPath.endsWith("/") === false) { window.rootPath += "/"; diff --git a/src/librustdoc/html/static/storage.js b/src/librustdoc/html/static/storage.js index d081781f14be1..9c5ac1625afea 100644 --- a/src/librustdoc/html/static/storage.js +++ b/src/librustdoc/html/static/storage.js @@ -1,5 +1,5 @@ // From rust: -/* global resourcesSuffix, getSettingValue */ +/* global resourcesSuffix */ var darkThemes = ["dark", "ayu"]; var currentTheme = document.getElementById("themeStyle"); @@ -35,10 +35,12 @@ var localStoredTheme = getSettingValue("theme"); var savedHref = []; +// eslint-disable-next-line no-unused-vars function hasClass(elem, className) { return elem && elem.classList && elem.classList.contains(className); } +// eslint-disable-next-line no-unused-vars function addClass(elem, className) { if (!elem || !elem.classList) { return; @@ -46,6 +48,7 @@ function addClass(elem, className) { elem.classList.add(className); } +// eslint-disable-next-line no-unused-vars function removeClass(elem, className) { if (!elem || !elem.classList) { return; @@ -81,6 +84,7 @@ function onEachLazy(lazyArray, func, reversed) { reversed); } +// eslint-disable-next-line no-unused-vars function hasOwnProperty(obj, property) { return Object.prototype.hasOwnProperty.call(obj, property); } @@ -148,6 +152,8 @@ function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) { } } +// This function is called from "theme.js", generated in `html/render/mod.rs`. +// eslint-disable-next-line no-unused-vars function useSystemTheme(value) { if (value === undefined) { value = true; @@ -172,7 +178,7 @@ var updateSystemTheme = (function() { switchTheme( currentTheme, mainTheme, - JSON.parse(cssTheme) || light, + JSON.parse(cssTheme) || "light", true ); }; From 0140dacabbc6b5a33f19f88c22b531f318ef8f37 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Mon, 25 Jan 2021 14:53:19 +0100 Subject: [PATCH 12/13] Link the reference about undefined behavior Suggested-by: Mara Bos Signed-off-by: Miguel Ojeda --- library/core/src/option.rs | 4 +++- library/core/src/result.rs | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 5d34f5ca155bf..9f89bfd674a74 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -433,7 +433,9 @@ impl Option { /// /// # Safety /// - /// Undefined behavior if the value is [`None`]. + /// Calling this method on [`None`] is *[undefined behavior]*. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html /// /// # Examples /// diff --git a/library/core/src/result.rs b/library/core/src/result.rs index a357750b92f9d..436f4bf20c7e7 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -827,7 +827,9 @@ impl Result { /// /// # Safety /// - /// Undefined behavior if the value is an [`Err`]. + /// Calling this method on an [`Err`] is *[undefined behavior]*. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html /// /// # Examples /// @@ -859,7 +861,9 @@ impl Result { /// /// # Safety /// - /// Undefined behavior if the value is an [`Ok`]. + /// Calling this method on an [`Ok`] is *[undefined behavior]*. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html /// /// # Examples /// From 01250fcec6c77552b0f7aac11ed833412294ccba Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Mon, 25 Jan 2021 14:58:09 +0100 Subject: [PATCH 13/13] Add tracking issue Signed-off-by: Miguel Ojeda --- library/core/src/option.rs | 2 +- library/core/src/result.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 9f89bfd674a74..14e4e4da3b96d 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -452,7 +452,7 @@ impl Option { /// ``` #[inline] #[track_caller] - #[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "none")] + #[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "81383")] pub unsafe fn unwrap_unchecked(self) -> T { debug_assert!(self.is_some()); match self { diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 436f4bf20c7e7..a43ba5882edcd 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -846,7 +846,7 @@ impl Result { /// ``` #[inline] #[track_caller] - #[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "none")] + #[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "81383")] pub unsafe fn unwrap_unchecked(self) -> T { debug_assert!(self.is_ok()); match self { @@ -880,7 +880,7 @@ impl Result { /// ``` #[inline] #[track_caller] - #[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "none")] + #[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "81383")] pub unsafe fn unwrap_err_unchecked(self) -> E { debug_assert!(self.is_err()); match self {