From 679f6f347355726f9335fdcbf0d3b81b2e490c38 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Sun, 10 Jan 2021 11:36:45 +0100 Subject: [PATCH 01/21] 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/21] 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/21] 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/21] 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 495f7cca85b2ca3762ad2bc812238621e4f28c60 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Tue, 19 Jan 2021 19:38:50 +0100 Subject: [PATCH 05/21] BTreeMap: compile-test all borrowing interfaces and test more chaotic order --- .../alloc/src/collections/btree/map/tests.rs | 88 ++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index f92aed8ce15bf..ba5a4442f56e6 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -777,7 +777,7 @@ fn test_range_backwards_4() { #[test] #[should_panic] -fn test_range_backwards_5() { +fn test_range_finding_ill_order_in_map() { let mut map = BTreeMap::new(); map.insert(Cyclic3::B, ()); // Lacking static_assert, call `range` conditionally, to emphasise that @@ -788,6 +788,47 @@ fn test_range_backwards_5() { } } +#[test] +#[should_panic] +fn test_range_finding_ill_order_in_range_ord() { + // Has proper order the first time asked, then flips around. + struct EvilTwin(i32); + + impl PartialOrd for EvilTwin { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } + } + + static COMPARES: AtomicUsize = AtomicUsize::new(0); + impl Ord for EvilTwin { + fn cmp(&self, other: &Self) -> Ordering { + let ord = self.0.cmp(&other.0); + if COMPARES.fetch_add(1, SeqCst) > 0 { ord.reverse() } else { ord } + } + } + + impl PartialEq for EvilTwin { + fn eq(&self, other: &Self) -> bool { + self.0.eq(&other.0) + } + } + + impl Eq for EvilTwin {} + + #[derive(PartialEq, Eq, PartialOrd, Ord)] + struct CompositeKey(i32, EvilTwin); + + impl Borrow for CompositeKey { + fn borrow(&self) -> &EvilTwin { + &self.1 + } + } + + let map = (0..12).map(|i| (CompositeKey(i, EvilTwin(i)), ())).collect::>(); + map.range(EvilTwin(5)..=EvilTwin(7)); +} + #[test] fn test_range_1000() { // Miri is too slow @@ -1222,6 +1263,51 @@ fn test_borrow() { map.insert(Rc::new(0), 1); assert_eq!(map[&0], 1); } + + #[allow(dead_code)] + fn get(v: &BTreeMap, ()>, t: &T) { + v.get(t); + } + + #[allow(dead_code)] + fn get_mut(v: &mut BTreeMap, ()>, t: &T) { + v.get_mut(t); + } + + #[allow(dead_code)] + fn get_key_value(v: &BTreeMap, ()>, t: &T) { + v.get_key_value(t); + } + + #[allow(dead_code)] + fn contains_key(v: &BTreeMap, ()>, t: &T) { + v.contains_key(t); + } + + #[allow(dead_code)] + fn range(v: &BTreeMap, ()>, t: T) { + v.range(t..); + } + + #[allow(dead_code)] + fn range_mut(v: &mut BTreeMap, ()>, t: T) { + v.range_mut(t..); + } + + #[allow(dead_code)] + fn remove(v: &mut BTreeMap, ()>, t: &T) { + v.remove(t); + } + + #[allow(dead_code)] + fn remove_entry(v: &mut BTreeMap, ()>, t: &T) { + v.remove_entry(t); + } + + #[allow(dead_code)] + fn split_off(v: &mut BTreeMap, ()>, t: &T) { + v.split_off(t); + } } #[test] From 1d03648e67b2dc3ea86a8d7f6f0c376142d500e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20=C3=85kerblom?= Date: Sun, 24 Jan 2021 20:31:42 +0100 Subject: [PATCH 06/21] Fix spelling in documentation for error E0207 I have trouble parsing the the wording "type parameter parameter". --- compiler/rustc_error_codes/src/error_codes/E0207.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0207.md b/compiler/rustc_error_codes/src/error_codes/E0207.md index cb4f5d5157d9b..8a7923ac93f98 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0207.md +++ b/compiler/rustc_error_codes/src/error_codes/E0207.md @@ -14,7 +14,7 @@ impl Foo { } ``` -Any type parameter parameter of an `impl` must meet at least one of +Any type parameter of an `impl` must meet at least one of the following criteria: - it appears in the _implementing type_ of the impl, e.g. `impl Foo` From 2be19932335f76cb4a97c275038a019751fbba6a Mon Sep 17 00:00:00 2001 From: Camelid Date: Sun, 24 Jan 2021 19:38:10 -0800 Subject: [PATCH 07/21] 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 59195a277246ec194ca3a02ecc563c4dd9c06857 Mon Sep 17 00:00:00 2001 From: Tyson Nottingham Date: Sun, 24 Jan 2021 21:23:38 -0800 Subject: [PATCH 08/21] rustc_codegen_ssa: use wall time for codegen_to_LLVM_IR time-passes entry Use elapsed wall time spent on codegen_to_LLVM_IR for all CGUs as a whole, rather than the sum for each CGU (the distinction matters for parallel builds, where some CGUs are processed in parallel). --- compiler/rustc_codegen_ssa/src/base.rs | 31 ++++++++++++-------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 2ce5fe5ad504b..ad72dc0086b61 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -13,7 +13,7 @@ use crate::{CachedModuleCodegen, CrateInfo, MemFlags, ModuleCodegen, ModuleKind} use rustc_attr as attr; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::profiling::print_time_passes_entry; -use rustc_data_structures::sync::{par_iter, Lock, ParallelIterator}; +use rustc_data_structures::sync::{par_iter, ParallelIterator}; use rustc_hir as hir; use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; @@ -554,8 +554,6 @@ pub fn codegen_crate( codegen_units }; - let total_codegen_time = Lock::new(Duration::new(0, 0)); - // The non-parallel compiler can only translate codegen units to LLVM IR // on a single thread, leading to a staircase effect where the N LLVM // threads have to wait on the single codegen threads to generate work @@ -578,23 +576,25 @@ pub fn codegen_crate( .collect(); // Compile the found CGUs in parallel. - par_iter(cgus) + let start_time = Instant::now(); + + let pre_compiled_cgus = par_iter(cgus) .map(|(i, _)| { - let start_time = Instant::now(); let module = backend.compile_codegen_unit(tcx, codegen_units[i].name()); - let mut time = total_codegen_time.lock(); - *time += start_time.elapsed(); (i, module) }) - .collect() + .collect(); + + (pre_compiled_cgus, start_time.elapsed()) }) } else { - FxHashMap::default() + (FxHashMap::default(), Duration::new(0, 0)) } }; let mut cgu_reuse = Vec::new(); let mut pre_compiled_cgus: Option> = None; + let mut total_codegen_time = Duration::new(0, 0); for (i, cgu) in codegen_units.iter().enumerate() { ongoing_codegen.wait_for_signal_to_codegen_item(); @@ -607,7 +607,9 @@ pub fn codegen_crate( codegen_units.iter().map(|cgu| determine_cgu_reuse(tcx, &cgu)).collect() }); // Pre compile some CGUs - pre_compiled_cgus = Some(pre_compile_cgus(&cgu_reuse)); + let (compiled_cgus, codegen_time) = pre_compile_cgus(&cgu_reuse); + pre_compiled_cgus = Some(compiled_cgus); + total_codegen_time += codegen_time; } let cgu_reuse = cgu_reuse[i]; @@ -621,8 +623,7 @@ pub fn codegen_crate( } else { let start_time = Instant::now(); let module = backend.compile_codegen_unit(tcx, cgu.name()); - let mut time = total_codegen_time.lock(); - *time += start_time.elapsed(); + total_codegen_time += start_time.elapsed(); module }; submit_codegened_module_to_llvm( @@ -663,11 +664,7 @@ pub fn codegen_crate( // Since the main thread is sometimes blocked during codegen, we keep track // -Ztime-passes output manually. - print_time_passes_entry( - tcx.sess.time_passes(), - "codegen_to_LLVM_IR", - total_codegen_time.into_inner(), - ); + print_time_passes_entry(tcx.sess.time_passes(), "codegen_to_LLVM_IR", total_codegen_time); ongoing_codegen.check_for_errors(tcx.sess); 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 09/21] 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 10/21] 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 11/21] 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 12/21] 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 { From 1c0a52d304cdebfcdf57c528b413457030659eb0 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 25 Jan 2021 11:00:02 -0800 Subject: [PATCH 13/21] rustdoc: Document CommonMark extensions. --- .../rustdoc/src/how-to-write-documentation.md | 66 ++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/src/doc/rustdoc/src/how-to-write-documentation.md b/src/doc/rustdoc/src/how-to-write-documentation.md index ca6db26da3130..41736e5ee3a7e 100644 --- a/src/doc/rustdoc/src/how-to-write-documentation.md +++ b/src/doc/rustdoc/src/how-to-write-documentation.md @@ -153,11 +153,73 @@ and finally provides a code example. ## Markdown -`rustdoc` uses the [commonmark markdown specification]. You might be +`rustdoc` uses the [CommonMark markdown specification]. You might be interested into taking a look at their website to see what's possible to do. - [commonmark quick reference] - [current spec] +In addition to the standard CommonMark syntax, `rustdoc` supports several +extensions: + +### Strikethrough + +Text may be rendered with a horizontal line through the center by wrapping the +text with two tilde characters on each side: + +```text +An example of ~~strikethrough text~~. +``` + +This example will render as: + +> An example of ~~strikethrough text~~. + +This follows the [GitHub Strikethrough extension][strikethrough]. + +### Footnotes + +A footnote generates a small numbered link in the text which when clicked +takes the reader to the footnote text at the bottom of the item. The footnote +label is written similarly to a link reference with a caret at the front. The +footnote text is written like a link reference definition, with the text +following the label. Example: + +```text +This is an example of a footnote[^note]. + +[^note]: This text is the contents of the footnote, which will be rendered + towards the bottom. +``` + +This example will render as: + +> This is an example of a footnote[^note]. +> +> [^note]: This text is the contents of the footnote, which will be rendered +> towards the bottom. + +The footnotes are automatically numbered based on the order the footnotes are +written. + +### Tables + +Tables can be written using pipes and dashes to draw the rows and columns of +the table. These will be translated to HTML table matching the shape. Example: + +```text +| Header1 | Header2 | +|---------|---------| +| abc | def | +``` + +This example will render similarly to this: + +> | Header1 | Header2 | +> |---------|---------| +> | abc | def | + +See the specification for the [GitHub Tables extension][tables] for more +details on the exact syntax supported. [`backtrace`]: https://docs.rs/backtrace/0.3.50/backtrace/ [commonmark markdown specification]: https://commonmark.org/ @@ -170,3 +232,5 @@ interested into taking a look at their website to see what's possible to do. [standard library]: https://doc.rust-lang.org/stable/std/index.html [current spec]: https://spec.commonmark.org/current/ [`std::env`]: https://doc.rust-lang.org/stable/std/env/index.html#functions +[strikethrough]: https://github.github.com/gfm/#strikethrough-extension- +[tables]: https://github.github.com/gfm/#tables-extension- From 3eebf9bb8085461d1d46c2fd204e75e7284aee16 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 25 Jan 2021 12:28:29 -0800 Subject: [PATCH 14/21] tidy: Remove cargo check. The cargo check was checking that every dependency had an `extern crate`. The compiler has not used `extern crate` in a long time (edition 2018). The test was broken (the call to `!super::filter_dirs(path)` was backwards). This just removes it since it is no longer valid. --- src/tools/tidy/src/cargo.rs | 90 ------------------------------------- src/tools/tidy/src/lib.rs | 1 - src/tools/tidy/src/main.rs | 4 -- 3 files changed, 95 deletions(-) delete mode 100644 src/tools/tidy/src/cargo.rs diff --git a/src/tools/tidy/src/cargo.rs b/src/tools/tidy/src/cargo.rs deleted file mode 100644 index e06616a59f38c..0000000000000 --- a/src/tools/tidy/src/cargo.rs +++ /dev/null @@ -1,90 +0,0 @@ -//! Tidy check to ensure that `[dependencies]` and `extern crate` are in sync. -//! -//! This tidy check ensures that all crates listed in the `[dependencies]` -//! section of a `Cargo.toml` are present in the corresponding `lib.rs` as -//! `extern crate` declarations. This should help us keep the DAG correctly -//! structured through various refactorings to prune out unnecessary edges. - -use std::fs; -use std::path::Path; - -pub fn check(path: &Path, bad: &mut bool) { - if !super::filter_dirs(path) { - return; - } - for entry in t!(path.read_dir(), path).map(|e| t!(e)) { - // Look for `Cargo.toml` with a sibling `src/lib.rs` or `lib.rs`. - if entry.file_name().to_str() == Some("Cargo.toml") { - if path.join("src/lib.rs").is_file() { - verify(&entry.path(), &path.join("src/lib.rs"), bad) - } - if path.join("lib.rs").is_file() { - verify(&entry.path(), &path.join("lib.rs"), bad) - } - } else if t!(entry.file_type()).is_dir() { - check(&entry.path(), bad); - } - } -} - -/// Verifies that the dependencies in Cargo.toml at `tomlfile` are synced with -/// the `extern crate` annotations in the lib.rs at `libfile`. -fn verify(tomlfile: &Path, libfile: &Path, bad: &mut bool) { - let toml = t!(fs::read_to_string(&tomlfile)); - let librs = t!(fs::read_to_string(&libfile)); - - if toml.contains("name = \"bootstrap\"") { - return; - } - - // "Poor man's TOML parser" -- just assume we use one syntax for now. - // - // We just look for: - // - // ```` - // [dependencies] - // name = ... - // name2 = ... - // name3 = ... - // ``` - // - // If we encounter a line starting with `[` then we assume it's the end of - // the dependency section and bail out. - let deps = match toml.find("[dependencies]") { - Some(i) => &toml[i + 1..], - None => return, - }; - for line in deps.lines() { - if line.starts_with('[') { - break; - } - - let krate = match line.split_once('=') { - None => continue, - Some((krate, _)) => krate.trim(), - }; - - // Don't worry about depending on core/std while not writing `extern crate - // core/std` -- that's intentional. - if krate == "core" || krate == "std" { - continue; - } - - // This is intentional -- this dependency just makes the crate available - // for others later on. - let allowed = krate.starts_with("panic"); - if toml.contains("name = \"std\"") && allowed { - continue; - } - - if !librs.contains(&format!("extern crate {}", krate)) { - tidy_error!( - bad, - "{} doesn't have `extern crate {}`, but Cargo.toml \ - depends on it", - libfile.display(), - krate - ); - } - } -} diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index d282d240d8234..27972c4992442 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -40,7 +40,6 @@ macro_rules! tidy_error { } pub mod bins; -pub mod cargo; pub mod debug_artifacts; pub mod deps; pub mod edition; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 080e16316242b..2ac96e404acb9 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -49,10 +49,6 @@ fn main() { style::check(&compiler_path, &mut bad); style::check(&library_path, &mut bad); - cargo::check(&src_path, &mut bad); - cargo::check(&compiler_path, &mut bad); - cargo::check(&library_path, &mut bad); - edition::check(&src_path, &mut bad); edition::check(&compiler_path, &mut bad); edition::check(&library_path, &mut bad); From d9807154d693df43552c1e312dceb320f124dff6 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 25 Jan 2021 12:40:22 -0800 Subject: [PATCH 15/21] tidy: Remove edition filter exceptions. These exceptions are no longer necessary. --- src/tools/tidy/src/edition.rs | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/tools/tidy/src/edition.rs b/src/tools/tidy/src/edition.rs index 7761ae64ee0c6..283c43e325c05 100644 --- a/src/tools/tidy/src/edition.rs +++ b/src/tools/tidy/src/edition.rs @@ -2,20 +2,6 @@ use std::path::Path; -fn filter_dirs(path: &Path) -> bool { - // FIXME: just use super::filter_dirs after the submodules are updated. - if super::filter_dirs(path) { - return true; - } - let skip = [ - "src/doc/book/second-edition", - "src/doc/book/2018-edition", - "src/doc/book/ci/stable-check", - "src/doc/reference/stable-check", - ]; - skip.iter().any(|p| path.ends_with(p)) -} - fn is_edition_2018(mut line: &str) -> bool { line = line.trim(); line == "edition = \"2018\"" || line == "edition = \'2018\'" @@ -24,7 +10,7 @@ fn is_edition_2018(mut line: &str) -> bool { pub fn check(path: &Path, bad: &mut bool) { super::walk( path, - &mut |path| filter_dirs(path) || path.ends_with("src/test"), + &mut |path| super::filter_dirs(path) || path.ends_with("src/test"), &mut |entry, contents| { let file = entry.path(); let filename = file.file_name().unwrap(); From 6f22f512ec8e4fce13d2d3675b6549e867bea824 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 25 Jan 2021 12:43:17 -0800 Subject: [PATCH 16/21] tidy: Remove unnecessary trailing semicolon. This will cause a failure due to the warning after the next beta branch as https://github.com/rust-lang/rust/pull/79812 will hit beta. --- src/tools/tidy/src/features.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index d3a4454275965..cb84fd8be6fec 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -422,7 +422,7 @@ fn map_lib_features( mf(Err($msg), file, i + 1); continue; }}; - }; + } if let Some((ref name, ref mut f)) = becoming_feature { if f.tracking_issue.is_none() { f.tracking_issue = find_attr_val(line, "issue").and_then(handle_issue_none); From fdd592acd07265adc9fdb0e618b3c1fd481e8200 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 25 Jan 2021 15:10:10 -0800 Subject: [PATCH 17/21] Update books --- src/doc/book | 2 +- src/doc/nomicon | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/book b/src/doc/book index ac57a0ddd23d1..e724bd826580f 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit ac57a0ddd23d173b26731ccf939f3ba729753275 +Subproject commit e724bd826580ff95df48a8533af7dec1080693d4 diff --git a/src/doc/nomicon b/src/doc/nomicon index a8584998eacde..bbf06ad39d1f4 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit a8584998eacdea7106a1dfafcbf6c1c06fcdf925 +Subproject commit bbf06ad39d1f45654047e9596b750cc6e6d1b693 diff --git a/src/doc/reference b/src/doc/reference index 50af691f83893..f02b09eb6e8af 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 50af691f838937c300b47812d0507c6d88c14f97 +Subproject commit f02b09eb6e8af340ad1256a54adb7aae2ff3163e diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 03e23af01f0b4..f633769acef68 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 03e23af01f0b4f83a3a513da280e1ca92587f2ec +Subproject commit f633769acef68574427a6fae6c06f13bc2199573 From d035be8e6f7f618ad2e78f2d5a3790c6e310fd67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= Date: Sun, 24 Jan 2021 10:32:24 +0300 Subject: [PATCH 18/21] typeck: Don't suggest converting LHS exprs Converting LHS of an assignment does not work, so avoid suggesting that. Fixes #81293 --- compiler/rustc_middle/src/hir/map/mod.rs | 11 +++++++++++ compiler/rustc_typeck/src/check/demand.rs | 7 +++++++ src/test/ui/typeck/issue-81293.rs | 9 +++++++++ src/test/ui/typeck/issue-81293.stderr | 24 +++++++++++++++++++++++ 4 files changed, 51 insertions(+) create mode 100644 src/test/ui/typeck/issue-81293.rs create mode 100644 src/test/ui/typeck/issue-81293.stderr diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 9b01a64de8415..3598a4cb4898d 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -564,6 +564,17 @@ impl<'hir> Map<'hir> { ) } + /// Checks if the node is left-hand side of an assignment. + pub fn is_lhs(&self, id: HirId) -> bool { + match self.find(self.get_parent_node(id)) { + Some(Node::Expr(expr)) => match expr.kind { + ExprKind::Assign(lhs, _rhs, _span) => lhs.hir_id == id, + _ => false, + }, + _ => false, + } + } + /// Whether the expression pointed at by `hir_id` belongs to a `const` evaluation context. /// Used exclusively for diagnostics, to avoid suggestion function calls. pub fn is_inside_const_context(&self, hir_id: HirId) -> bool { diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index c22f001744639..3c9c683f4b0cb 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -816,6 +816,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |err: &mut DiagnosticBuilder<'_>, found_to_exp_is_fallible: bool, exp_to_found_is_fallible: bool| { + let exp_is_lhs = + expected_ty_expr.map(|e| self.tcx.hir().is_lhs(e.hir_id)).unwrap_or(false); + + if exp_is_lhs { + return; + } + let always_fallible = found_to_exp_is_fallible && (exp_to_found_is_fallible || expected_ty_expr.is_none()); let msg = if literal_is_ty_suffixed(expr) { diff --git a/src/test/ui/typeck/issue-81293.rs b/src/test/ui/typeck/issue-81293.rs new file mode 100644 index 0000000000000..076b8c944b8a4 --- /dev/null +++ b/src/test/ui/typeck/issue-81293.rs @@ -0,0 +1,9 @@ +fn main() { + let a: u16; + let b: u16 = 42; + let c: usize = 5; + + a = c + b * 5; //~ ERROR: mismatched types [E0308] + //~| ERROR: mismatched types [E0308] + //~| ERROR: cannot add `u16` to `usize` [E0277] +} diff --git a/src/test/ui/typeck/issue-81293.stderr b/src/test/ui/typeck/issue-81293.stderr new file mode 100644 index 0000000000000..1e6ff3b5f9ee7 --- /dev/null +++ b/src/test/ui/typeck/issue-81293.stderr @@ -0,0 +1,24 @@ +error[E0308]: mismatched types + --> $DIR/issue-81293.rs:6:13 + | +LL | a = c + b * 5; + | ^^^^^ expected `usize`, found `u16` + +error[E0308]: mismatched types + --> $DIR/issue-81293.rs:6:9 + | +LL | a = c + b * 5; + | ^^^^^^^^^ expected `u16`, found `usize` + +error[E0277]: cannot add `u16` to `usize` + --> $DIR/issue-81293.rs:6:11 + | +LL | a = c + b * 5; + | ^ no implementation for `usize + u16` + | + = help: the trait `Add` is not implemented for `usize` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. From 8ddc1c83f2fe56c2087bd5ee743720ec607b76df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= Date: Tue, 26 Jan 2021 13:10:54 +0300 Subject: [PATCH 19/21] Refine "remove semicolon" suggestion in trait selection Don't suggest it if the last statement doesn't have a semicolon Fixes #81098 See also #54771 for why this suggestion was added --- .../src/traits/error_reporting/suggestions.rs | 6 +++-- src/test/ui/suggestions/issue-81098.rs | 13 +++++++++++ src/test/ui/suggestions/issue-81098.stderr | 23 +++++++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/suggestions/issue-81098.rs create mode 100644 src/test/ui/suggestions/issue-81098.stderr 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..7f2efcdfbc647 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -888,8 +888,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // no return, suggest removal of semicolon on last statement. // Once that is added, close #54771. if let Some(ref stmt) = blk.stmts.last() { - let sp = self.tcx.sess.source_map().end_point(stmt.span); - err.span_label(sp, "consider removing this semicolon"); + if let hir::StmtKind::Semi(_) = stmt.kind { + let sp = self.tcx.sess.source_map().end_point(stmt.span); + err.span_label(sp, "consider removing this semicolon"); + } } } } diff --git a/src/test/ui/suggestions/issue-81098.rs b/src/test/ui/suggestions/issue-81098.rs new file mode 100644 index 0000000000000..a601b5866f43e --- /dev/null +++ b/src/test/ui/suggestions/issue-81098.rs @@ -0,0 +1,13 @@ +// Don't suggest removing a semicolon if the last statement isn't an expression with semicolon +// (#81098) +fn wat() -> impl core::fmt::Display { //~ ERROR: `()` doesn't implement `std::fmt::Display` + fn why() {} +} + +// Do it if the last statement is an expression with semicolon +// (#54771) +fn ok() -> impl core::fmt::Display { //~ ERROR: `()` doesn't implement `std::fmt::Display` + 1; +} + +fn main() {} diff --git a/src/test/ui/suggestions/issue-81098.stderr b/src/test/ui/suggestions/issue-81098.stderr new file mode 100644 index 0000000000000..2a72159e5774b --- /dev/null +++ b/src/test/ui/suggestions/issue-81098.stderr @@ -0,0 +1,23 @@ +error[E0277]: `()` doesn't implement `std::fmt::Display` + --> $DIR/issue-81098.rs:3:13 + | +LL | fn wat() -> impl core::fmt::Display { + | ^^^^^^^^^^^^^^^^^^^^^^^ `()` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `()` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + +error[E0277]: `()` doesn't implement `std::fmt::Display` + --> $DIR/issue-81098.rs:9:12 + | +LL | fn ok() -> impl core::fmt::Display { + | ^^^^^^^^^^^^^^^^^^^^^^^ `()` cannot be formatted with the default formatter +LL | 1; + | - consider removing this semicolon + | + = help: the trait `std::fmt::Display` is not implemented for `()` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. From 39e24f745baeb6136dbc9870e26de60b26a96ce7 Mon Sep 17 00:00:00 2001 From: Erin Power Date: Fri, 8 Jan 2021 12:05:48 +0000 Subject: [PATCH 20/21] Update RELEASES.md for 1.50.0 --- RELEASES.md | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 4409b6ad7b1d6..18492213a5dd3 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,123 @@ +Version 1.50.0 (2021-02-11) +============================ + +Language +----------------------- +- [You can now use `const` values for `x` in `[x; N]` array expressions.][79270] + This has been technically possible since 1.38.0, as it was unintentionally stabilized. +- [Assignments to `ManuallyDrop` union fields are now considered safe.][78068] + +Compiler +----------------------- +- [Added tier 3\* support for the `armv5te-unknown-linux-uclibceabi` target.][78142] +- [Added tier 3 support for the `aarch64-apple-ios-macabi` target.][77484] +- [The `x86_64-unknown-freebsd` is now built with the full toolset.][79484] + +\* Refer to Rust's [platform support page][forge-platform-support] for more +information on Rust's tiered platform support. + +Libraries +----------------------- + +- [`proc_macro::Punct` now implements `PartialEq`.][78636] +- [`ops::{Index, IndexMut}` are now implemented for fixed sized arrays of any length.][74989] +- [On Unix platforms, the `std::fs::File` type now has a "niche" of `-1`.][74699] + This value cannot be a valid file descriptor, and now means `Option` takes + up the same amount of space as `File`. + +Stabilized APIs +--------------- + +- [`bool::then`] +- [`btree_map::Entry::or_insert_with_key`] +- [`f32::clamp`] +- [`f64::clamp`] +- [`hash_map::Entry::or_insert_with_key`] +- [`Ord::clamp`] +- [`RefCell::take`] +- [`slice::fill`] +- [`UnsafeCell::get_mut`] + +The following previously stable methods are now `const`. + +- [`IpAddr::is_ipv4`] +- [`IpAddr::is_ipv6`] +- [`Layout::size`] +- [`Layout::align`] +- [`Layout::from_size_align`] +- `pow` for all integer types. +- `checked_pow` for all integer types. +- `saturating_pow` for all integer types. +- `wrapping_pow` for all integer types. +- `next_power_of_two` for all unsigned integer types. +- `checked_power_of_two` for all unsigned integer types. + +Cargo +----------------------- + +- [Added the `[build.rustc-workspace-wrapper]` option.][cargo/8976] + This option sets a wrapper to execute instead of `rustc`, for workspace members only. +- [`cargo:rerun-if-changed` will now, if provided a directory, scan the entire + contents of that directory for changes.][cargo/8973] +- [Added the `--workspace` flag to the `cargo update` command.][cargo/8725] + +Misc +---- + +- [The search results tab and the help button are focusable with keyboard in rustdoc.][79896] +- [Running tests will now print the total time taken to execute.][75752] + +Compatibility Notes +------------------- + +- [The `compare_and_swap` method on atomics has been deprecated.][79261] It's + recommended to use the `compare_exchange` and `compare_exchange_weak` methods instead. +- [Changes in how `TokenStream`s are checked have fixed some cases where you could write + unhygenic `macro_rules!` macros.][79472] +- [`#![test]` as an inner attribute is now considered unstable like other inner macro + attributes, and reports an error by default through the `soft_unstable` lint.][79003] +- [Overriding a `forbid` lint at the same level that it was set is now a hard error.][78864] +- [Dropped support for all cloudabi targets.][78439] +- [You can no longer intercept `panic!` calls by supplying your own macro.][78343] It's + recommended to use the `#[panic_handler]` attribute to provide your own implementation. +- [Semi-colons after item statements (e.g. `struct Foo {};`) now produce a warning.][78296] + +[74989]: https://github.com/rust-lang/rust/pull/74989 +[79261]: https://github.com/rust-lang/rust/pull/79261 +[79896]: https://github.com/rust-lang/rust/pull/79896 +[79484]: https://github.com/rust-lang/rust/pull/79484 +[79472]: https://github.com/rust-lang/rust/pull/79472 +[79270]: https://github.com/rust-lang/rust/pull/79270 +[79003]: https://github.com/rust-lang/rust/pull/79003 +[78864]: https://github.com/rust-lang/rust/pull/78864 +[78636]: https://github.com/rust-lang/rust/pull/78636 +[78439]: https://github.com/rust-lang/rust/pull/78439 +[78343]: https://github.com/rust-lang/rust/pull/78343 +[78296]: https://github.com/rust-lang/rust/pull/78296 +[78068]: https://github.com/rust-lang/rust/pull/78068 +[75752]: https://github.com/rust-lang/rust/pull/75752 +[74699]: https://github.com/rust-lang/rust/pull/74699 +[78142]: https://github.com/rust-lang/rust/pull/78142 +[77484]: https://github.com/rust-lang/rust/pull/77484 +[cargo/8976]: https://github.com/rust-lang/cargo/pull/8976 +[cargo/8973]: https://github.com/rust-lang/cargo/pull/8973 +[cargo/8725]: https://github.com/rust-lang/cargo/pull/8725 +[`IpAddr::is_ipv4`]: https://doc.rust-lang.org/stable/std/net/enum.IpAddr.html#method.is_ipv4 +[`IpAddr::is_ipv6`]: https://doc.rust-lang.org/stable/std/net/enum.IpAddr.html#method.is_ipv6 +[`Layout::align`]: https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.align +[`Layout::from_size_align`]: https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.from_size_align +[`Layout::size`]: https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.size +[`Ord::clamp`]: https://doc.rust-lang.org/stable/std/cmp/trait.Ord.html#method.clamp +[`RefCell::take`]: https://doc.rust-lang.org/stable/std/cell/struct.RefCell.html#method.take +[`UnsafeCell::get_mut`]: https://doc.rust-lang.org/stable/std/cell/struct.UnsafeCell.html#method.get_mut +[`bool::then`]: https://doc.rust-lang.org/stable/std/primitive.bool.html#method.then +[`btree_map::Entry::or_insert_with_key`]: https://doc.rust-lang.org/stable/std/collections/btree_map/enum.Entry.html#method.or_insert_with_key +[`f32::clamp`]: https://doc.rust-lang.org/stable/std/primitive.f32.html#method.clamp +[`f64::clamp`]: https://doc.rust-lang.org/stable/std/primitive.f64.html#method.clamp +[`hash_map::Entry::or_insert_with_key`]: https://doc.rust-lang.org/stable/std/collections/hash_map/enum.Entry.html#method.or_insert_with_key +[`slice::fill`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.fill + + Version 1.49.0 (2020-12-31) ============================ From f52066726dd24ae07b1991b53f48ffa25c2b716d Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Tue, 26 Jan 2021 23:21:00 +0800 Subject: [PATCH 21/21] Fix assertion in `MaybeUninit::array_assume_init()` for zero-length arrays --- library/core/src/mem/maybe_uninit.rs | 2 +- library/core/tests/mem.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index fda0553f94c5f..05bcd90d3ca76 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -839,7 +839,7 @@ impl MaybeUninit { // * MaybeUnint does not drop, so there are no double-frees // And thus the conversion is safe unsafe { - intrinsics::assert_inhabited::(); + intrinsics::assert_inhabited::<[T; N]>(); (&array as *const _ as *const [T; N]).read() } } diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 2279a16429f98..38084f401bce6 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -152,6 +152,8 @@ fn uninit_array_assume_init() { let array = unsafe { MaybeUninit::array_assume_init(array) }; assert_eq!(array, [3, 1, 4, 1, 5]); + + let [] = unsafe { MaybeUninit::::array_assume_init([]) }; } #[test]