From 9ee16e14c51668309f446636e8960b7fbbac066d Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 20 Dec 2019 23:15:50 +0100 Subject: [PATCH 01/21] Require const stability attributes on intrinsics to be able to use them in constant contexts --- src/libcore/intrinsics.rs | 29 +++++- src/libcore/lib.rs | 2 + src/libcore/macros/mod.rs | 1 + src/librustc/ty/constness.rs | 98 +------------------ .../consts/const-eval/simd/insert_extract.rs | 4 + src/test/ui/consts/const-fn-type-name.rs | 1 + 6 files changed, 38 insertions(+), 97 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index b02acce2d00bb..a194db52eb2a8 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -667,6 +667,7 @@ extern "rust-intrinsic" { /// /// The stabilized version of this intrinsic is /// [`std::mem::size_of`](../../std/mem/fn.size_of.html). + #[rustc_const_stable(feature = "const_size_of", since = "1.40.0")] pub fn size_of() -> usize; /// Moves a value to an uninitialized memory location. @@ -674,7 +675,9 @@ extern "rust-intrinsic" { /// Drop glue is not run on the destination. pub fn move_val_init(dst: *mut T, src: T); + #[rustc_const_stable(feature = "const_min_align_of", since = "1.40.0")] pub fn min_align_of() -> usize; + #[rustc_const_unstable(feature = "const_pref_align_of", issue = "0")] pub fn pref_align_of() -> usize; /// The size of the referenced value in bytes. @@ -685,11 +688,13 @@ extern "rust-intrinsic" { pub fn min_align_of_val(_: &T) -> usize; /// Gets a static string slice containing the name of a type. + #[rustc_const_unstable(feature = "const_type_name", issue = "0")] pub fn type_name() -> &'static str; /// Gets an identifier which is globally unique to the specified type. This /// function will return the same value for a type regardless of whichever /// crate it is invoked in. + #[rustc_const_unstable(feature = "const_type_id", issue = "0")] pub fn type_id() -> u64; /// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited: @@ -697,6 +702,7 @@ extern "rust-intrinsic" { pub fn panic_if_uninhabited(); /// Gets a reference to a static `Location` indicating where it was called. + #[rustc_const_unstable(feature = "const_caller_location", issue = "47809")] pub fn caller_location() -> &'static crate::panic::Location<'static>; /// Creates a value initialized to zero. @@ -951,6 +957,7 @@ extern "rust-intrinsic" { /// /// The stabilized version of this intrinsic is /// [`std::mem::needs_drop`](../../std/mem/fn.needs_drop.html). + #[rustc_const_stable(feature = "const_needs_drop", since = "1.40.0")] pub fn needs_drop() -> bool; /// Calculates the offset from a pointer. @@ -1150,6 +1157,7 @@ extern "rust-intrinsic" { /// Returns the number of bits set in an integer type `T` + #[rustc_const_stable(feature = "const_ctpop", since = "1.40.0")] pub fn ctpop(x: T) -> T; /// Returns the number of leading unset bits (zeroes) in an integer type `T`. @@ -1177,6 +1185,7 @@ extern "rust-intrinsic" { /// let num_leading = ctlz(x); /// assert_eq!(num_leading, 16); /// ``` + #[rustc_const_stable(feature = "const_ctlz", since = "1.40.0")] pub fn ctlz(x: T) -> T; /// Like `ctlz`, but extra-unsafe as it returns `undef` when @@ -1193,6 +1202,7 @@ extern "rust-intrinsic" { /// let num_leading = unsafe { ctlz_nonzero(x) }; /// assert_eq!(num_leading, 3); /// ``` + #[rustc_const_unstable(feature = "constctlz", issue = "0")] pub fn ctlz_nonzero(x: T) -> T; /// Returns the number of trailing unset bits (zeroes) in an integer type `T`. @@ -1220,6 +1230,7 @@ extern "rust-intrinsic" { /// let num_trailing = cttz(x); /// assert_eq!(num_trailing, 16); /// ``` + #[rustc_const_stable(feature = "const_cttz", since = "1.40.0")] pub fn cttz(x: T) -> T; /// Like `cttz`, but extra-unsafe as it returns `undef` when @@ -1236,30 +1247,36 @@ extern "rust-intrinsic" { /// let num_trailing = unsafe { cttz_nonzero(x) }; /// assert_eq!(num_trailing, 3); /// ``` + #[rustc_const_unstable(feature = "const_cttz", issue = "0")] pub fn cttz_nonzero(x: T) -> T; /// Reverses the bytes in an integer type `T`. + #[rustc_const_stable(feature = "const_bswap", since = "1.40.0")] pub fn bswap(x: T) -> T; /// Reverses the bits in an integer type `T`. + #[rustc_const_stable(feature = "const_bitreverse", since = "1.40.0")] pub fn bitreverse(x: T) -> T; /// Performs checked integer addition. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `overflowing_add` method. For example, /// [`std::u32::overflowing_add`](../../std/primitive.u32.html#method.overflowing_add) + #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")] pub fn add_with_overflow(x: T, y: T) -> (T, bool); /// Performs checked integer subtraction /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `overflowing_sub` method. For example, /// [`std::u32::overflowing_sub`](../../std/primitive.u32.html#method.overflowing_sub) + #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")] pub fn sub_with_overflow(x: T, y: T) -> (T, bool); /// Performs checked integer multiplication /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `overflowing_mul` method. For example, /// [`std::u32::overflowing_mul`](../../std/primitive.u32.html#method.overflowing_mul) + #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")] pub fn mul_with_overflow(x: T, y: T) -> (T, bool); /// Performs an exact division, resulting in undefined behavior where @@ -1275,9 +1292,11 @@ extern "rust-intrinsic" { /// Performs an unchecked left shift, resulting in undefined behavior when /// y < 0 or y >= N, where N is the width of T in bits. + #[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")] pub fn unchecked_shl(x: T, y: T) -> T; /// Performs an unchecked right shift, resulting in undefined behavior when /// y < 0 or y >= N, where N is the width of T in bits. + #[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")] pub fn unchecked_shr(x: T, y: T) -> T; /// Returns the result of an unchecked addition, resulting in @@ -1296,39 +1315,46 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `rotate_left` method. For example, /// [`std::u32::rotate_left`](../../std/primitive.u32.html#method.rotate_left) + #[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")] pub fn rotate_left(x: T, y: T) -> T; /// Performs rotate right. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `rotate_right` method. For example, - /// [`std::u32::rotate_right`](../../std/primitive.u32.html#method.rotate_right) + /// [`std::u32::rotate_right`](../../std/primitive.u32.html#method.rotate_right + #[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")] pub fn rotate_right(x: T, y: T) -> T; /// Returns (a + b) mod 2N, where N is the width of T in bits. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_add` method. For example, /// [`std::u32::wrapping_add`](../../std/primitive.u32.html#method.wrapping_add) + #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")] pub fn wrapping_add(a: T, b: T) -> T; /// Returns (a - b) mod 2N, where N is the width of T in bits. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_sub` method. For example, /// [`std::u32::wrapping_sub`](../../std/primitive.u32.html#method.wrapping_sub) + #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")] pub fn wrapping_sub(a: T, b: T) -> T; /// Returns (a * b) mod 2N, where N is the width of T in bits. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_mul` method. For example, /// [`std::u32::wrapping_mul`](../../std/primitive.u32.html#method.wrapping_mul) + #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")] pub fn wrapping_mul(a: T, b: T) -> T; /// Computes `a + b`, while saturating at numeric bounds. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `saturating_add` method. For example, /// [`std::u32::saturating_add`](../../std/primitive.u32.html#method.saturating_add) + #[rustc_const_stable(feature = "const_int_saturating", since = "1.40.0")] pub fn saturating_add(a: T, b: T) -> T; /// Computes `a - b`, while saturating at numeric bounds. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `saturating_sub` method. For example, /// [`std::u32::saturating_sub`](../../std/primitive.u32.html#method.saturating_sub) + #[rustc_const_stable(feature = "const_int_saturating", since = "1.40.0")] pub fn saturating_sub(a: T, b: T) -> T; /// Returns the value of the discriminant for the variant in 'v', @@ -1350,6 +1376,7 @@ extern "rust-intrinsic" { pub fn nontemporal_store(ptr: *mut T, val: T); /// See documentation of `<*const T>::offset_from` for details. + #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "0")] pub fn ptr_offset_from(ptr: *const T, base: *const T) -> isize; /// Internal hook used by Miri to implement unwinding. diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index a2ab85e64baa1..74dc56c156aea 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -128,6 +128,8 @@ #![feature(maybe_uninit_slice)] #![feature(external_doc)] #![feature(associated_type_bounds)] +#![feature(const_type_id)] +#![feature(const_caller_location)] #[prelude_import] #[allow(unused)] diff --git a/src/libcore/macros/mod.rs b/src/libcore/macros/mod.rs index dd06da7a6d23e..b1475f2ad9fc4 100644 --- a/src/libcore/macros/mod.rs +++ b/src/libcore/macros/mod.rs @@ -5,6 +5,7 @@ // the `caller_location` intrinsic, but once `#[track_caller]` is implemented, // `panicking::{panic, panic_fmt}` can use that instead of a `Location` argument. core_intrinsics, + const_caller_location, )] #[stable(feature = "core", since = "1.6.0")] macro_rules! panic { diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs index 897a3678c4004..7fe950ef7b7f6 100644 --- a/src/librustc/ty/constness.rs +++ b/src/librustc/ty/constness.rs @@ -2,7 +2,7 @@ use crate::ty::query::Providers; use crate::hir::def_id::DefId; use crate::hir; use crate::ty::TyCtxt; -use syntax_pos::symbol::{sym, Symbol}; +use syntax_pos::symbol::Symbol; use rustc_target::spec::abi::Abi; use crate::hir::map::blocks::FnLikeNode; use syntax::attr; @@ -41,51 +41,12 @@ impl<'tcx> TyCtxt<'tcx> { } } - /// Returns `true` if the `def_id` refers to an intrisic which we've whitelisted - /// for being called from stable `const fn`s (`min_const_fn`). - /// - /// Adding more intrinsics requires sign-off from @rust-lang/lang. - /// - /// This list differs from the list in `is_const_intrinsic` in the sense that any item on this - /// list must be on the `is_const_intrinsic` list, too, because if an intrinsic is callable from - /// stable, it must be callable at all. - fn is_intrinsic_min_const_fn(self, def_id: DefId) -> bool { - match self.item_name(def_id) { - | sym::size_of - | sym::min_align_of - | sym::needs_drop - // Arithmetic: - | sym::add_with_overflow // ~> .overflowing_add - | sym::sub_with_overflow // ~> .overflowing_sub - | sym::mul_with_overflow // ~> .overflowing_mul - | sym::wrapping_add // ~> .wrapping_add - | sym::wrapping_sub // ~> .wrapping_sub - | sym::wrapping_mul // ~> .wrapping_mul - | sym::saturating_add // ~> .saturating_add - | sym::saturating_sub // ~> .saturating_sub - | sym::unchecked_shl // ~> .wrapping_shl - | sym::unchecked_shr // ~> .wrapping_shr - | sym::rotate_left // ~> .rotate_left - | sym::rotate_right // ~> .rotate_right - | sym::ctpop // ~> .count_ones - | sym::ctlz // ~> .leading_zeros - | sym::cttz // ~> .trailing_zeros - | sym::bswap // ~> .swap_bytes - | sym::bitreverse // ~> .reverse_bits - => true, - _ => false, - } - } - /// Returns `true` if this function must conform to `min_const_fn` pub fn is_min_const_fn(self, def_id: DefId) -> bool { // Bail out if the signature doesn't contain `const` if !self.is_const_fn_raw(def_id) { return false; } - if let Abi::RustIntrinsic = self.fn_sig(def_id).abi() { - return self.is_intrinsic_min_const_fn(def_id); - } if self.features().staged_api { // In order for a libstd function to be considered min_const_fn @@ -134,62 +95,7 @@ pub fn provide(providers: &mut Providers<'_>) { fn is_const_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> Option { match tcx.fn_sig(def_id).abi() { Abi::RustIntrinsic | - Abi::PlatformIntrinsic => { - // FIXME: deduplicate these two lists as much as possible - match tcx.item_name(def_id) { - // Keep this list in the same order as the match patterns in - // `librustc_mir/interpret/intrinsics.rs` - - // This whitelist is a list of intrinsics that have a miri-engine implementation - // and can thus be called when enabling enough feature gates. The similar - // whitelist in `is_intrinsic_min_const_fn` (in this file), exists for allowing - // the intrinsics to be called by stable const fns. - | sym::caller_location - - | sym::min_align_of - | sym::pref_align_of - | sym::needs_drop - | sym::size_of - | sym::type_id - | sym::type_name - - | sym::ctpop - | sym::cttz - | sym::cttz_nonzero - | sym::ctlz - | sym::ctlz_nonzero - | sym::bswap - | sym::bitreverse - - | sym::wrapping_add - | sym::wrapping_sub - | sym::wrapping_mul - | sym::add_with_overflow - | sym::sub_with_overflow - | sym::mul_with_overflow - - | sym::saturating_add - | sym::saturating_sub - - | sym::unchecked_shl - | sym::unchecked_shr - - | sym::rotate_left - | sym::rotate_right - - | sym::ptr_offset_from - - | sym::transmute - - | sym::simd_insert - - | sym::simd_extract - - => Some(true), - - _ => Some(false) - } - } + Abi::PlatformIntrinsic => Some(tcx.lookup_const_stability(def_id).is_some()), _ => None } } diff --git a/src/test/ui/consts/const-eval/simd/insert_extract.rs b/src/test/ui/consts/const-eval/simd/insert_extract.rs index d3462d802ea4e..92231d4ced321 100644 --- a/src/test/ui/consts/const-eval/simd/insert_extract.rs +++ b/src/test/ui/consts/const-eval/simd/insert_extract.rs @@ -2,6 +2,8 @@ #![feature(const_fn)] #![feature(repr_simd)] #![feature(platform_intrinsics)] +#![feature(staged_api)] +#![stable(feature = "foo", since = "1.33.7")] #![allow(non_camel_case_types)] #[repr(simd)] struct i8x1(i8); @@ -9,7 +11,9 @@ #[repr(simd)] struct f32x3(f32, f32, f32); extern "platform-intrinsic" { + #[rustc_const_stable(feature = "foo", since = "1.3.37")] fn simd_insert(x: T, idx: u32, val: U) -> T; + #[rustc_const_stable(feature = "foo", since = "1.3.37")] fn simd_extract(x: T, idx: u32) -> U; } diff --git a/src/test/ui/consts/const-fn-type-name.rs b/src/test/ui/consts/const-fn-type-name.rs index 2bb1aeecf376d..72fac19c19173 100644 --- a/src/test/ui/consts/const-fn-type-name.rs +++ b/src/test/ui/consts/const-fn-type-name.rs @@ -2,6 +2,7 @@ #![feature(core_intrinsics)] #![feature(const_fn)] +#![feature(const_type_name)] #![allow(dead_code)] const fn type_name_wrapper(_: &T) -> &'static str { From 032d810e24a39aad311c15d05dfef4dc4d6829c4 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 21 Dec 2019 00:07:36 +0100 Subject: [PATCH 02/21] Add a big notice about const intrinsics --- src/libcore/intrinsics.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index a194db52eb2a8..544fd4fb99fa1 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1,6 +1,22 @@ //! Compiler intrinsics. //! //! The corresponding definitions are in `librustc_codegen_llvm/intrinsic.rs`. +//! The corresponding const implementations are in `librustc_mir/interpret/intrinsics.rs` +//! +//! # Const intrinsics +//! +//! Note: any changes to the constness of intrinsics should be discussed with the language team. +//! This includes changes in the stability of the constness. +//! +//! In order to make an intrinsic usable at compile-time, one needs to copy the implementation +//! from https://github.com/rust-lang/miri/blob/master/src/shims/intrinsics.rs to +//! `librustc_mir/interpret/intrinsics.rs` and add a +//! `#[rustc_const_unstable(feature = "foo", issue = "01234")]` to the intrinsic. +//! +//! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute, +//! the intrinsic's attribute must be `rustc_const_stable`, too. Such a change should not be done +//! without T-lang consulation, because it bakes a feature into the language that cannot be +//! replicated in user code without compiler support. //! //! # Volatiles //! From 89986a39a8236a3e4bfbb74b4d3a0a03667e8b56 Mon Sep 17 00:00:00 2001 From: Luro02 <24826124+Luro02@users.noreply.github.com> Date: Wed, 11 Dec 2019 17:59:32 +0100 Subject: [PATCH 03/21] add partialeq and eq to cursor --- src/libstd/io/cursor.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index a94176e710005..1cdedd859d338 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -72,7 +72,7 @@ use core::convert::TryInto; /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct Cursor { inner: T, pos: u64, @@ -902,4 +902,16 @@ mod tests { c.set_position(::max_value() as u64 + 1); assert!(c.write_all(&[1, 2, 3]).is_err()); } + + #[test] + fn test_partial_eq() { + assert_eq!(Cursor::new(Vec::::new()), Cursor::new(Vec::::new())); + } + + #[test] + fn test_eq() { + struct AssertEq(pub T); + + let _: AssertEq>> = AssertEq(Cursor::new(Vec::new())); + } } From 4ce2384501833127fa3c9e995240d78b07f0ab2f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 22 Dec 2019 14:14:37 +0100 Subject: [PATCH 04/21] Improve JS code a bit by avoid erasing all event handlers --- src/librustdoc/html/static/main.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 1459e8f37cd32..ad988557f9bcc 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -324,6 +324,7 @@ function getSearchElement() { } function handleEscape(ev) { + debugger; var help = getHelpElement(); var search = getSearchElement(); hideModal(); @@ -390,8 +391,8 @@ function getSearchElement() { return null; } - document.onkeypress = handleShortcut; - document.onkeydown = handleShortcut; + document.addEventListener("keypress", handleShortcut); + document.addEventListener("keydown", handleShortcut); var handleSourceHighlight = (function() { var prev_line_id = 0; @@ -430,7 +431,7 @@ function getSearchElement() { } })(); - document.onclick = function(ev) { + document.addEventListener("click", function(ev) { if (hasClass(ev.target, "collapse-toggle")) { collapseDocs(ev.target, "toggle"); } else if (hasClass(ev.target.parentNode, "collapse-toggle")) { @@ -452,7 +453,7 @@ function getSearchElement() { expandSection(a.hash.replace(/^#/, "")); } } - }; + }); var x = document.getElementsByClassName("version-selector"); if (x.length > 0) { From b67701347abd3469a92577cfe748206ecfc25694 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 22 Dec 2019 15:42:10 +0100 Subject: [PATCH 05/21] Improve code readability --- src/librustdoc/html/static/main.js | 80 ++++++++++++++---------------- 1 file changed, 37 insertions(+), 43 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index ad988557f9bcc..d0c44cd40b21a 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -138,6 +138,22 @@ function getSearchElement() { } } + function showSearchResults(search) { + if (search === null || typeof search === 'undefined') { + search = getSearchElement(); + } + addClass(main, "hidden"); + removeClass(search, "hidden"); + } + + function hideSearchResults(search) { + if (search === null || typeof search === 'undefined') { + search = getSearchElement(); + } + addClass(search, "hidden"); + removeClass(main, "hidden"); + } + // used for special search precedence var TY_PRIMITIVE = itemTypes.indexOf("primitive"); var TY_KEYWORD = itemTypes.indexOf("keyword"); @@ -169,8 +185,7 @@ function getSearchElement() { if (ev !== null && search && !hasClass(search, "hidden") && ev.newURL) { // This block occurs when clicking on an element in the navbar while // in a search. - addClass(search, "hidden"); - removeClass(main, "hidden"); + hideSearchResults(search); var hash = ev.newURL.slice(ev.newURL.indexOf("#") + 1); if (browserSupportsHistoryApi()) { history.replaceState(hash, "", "?search=#" + hash); @@ -324,7 +339,6 @@ function getSearchElement() { } function handleEscape(ev) { - debugger; var help = getHelpElement(); var search = getSearchElement(); hideModal(); @@ -332,8 +346,7 @@ function getSearchElement() { displayHelp(false, ev, help); } else if (hasClass(search, "hidden") === false) { ev.preventDefault(); - addClass(search, "hidden"); - removeClass(main, "hidden"); + hideSearchResults(search); document.title = titleBeforeSearch; } defocusSearchBar(); @@ -1265,8 +1278,7 @@ function getSearchElement() { } dst = dst[0]; if (window.location.pathname === dst.pathname) { - addClass(getSearchElement(), "hidden"); - removeClass(main, "hidden"); + hideSearchResults(); document.location.href = dst.href; } }; @@ -1341,8 +1353,6 @@ function getSearchElement() { e.preventDefault(); } else if (e.which === 16) { // shift // Does nothing, it's just to avoid losing "focus" on the highlighted element. - } else if (e.which === 27) { // escape - handleEscape(e); } else if (actives[currentTab].length > 0) { removeClass(actives[currentTab][0], "highlighted"); } @@ -1492,10 +1502,9 @@ function getSearchElement() { "
" + ret_others[0] + ret_in_args[0] + ret_returned[0] + "
"; - addClass(main, "hidden"); var search = getSearchElement(); - removeClass(search, "hidden"); search.innerHTML = output; + showSearchResults(search); var tds = search.getElementsByTagName("td"); var td_width = 0; if (tds.length > 0) { @@ -1700,13 +1709,7 @@ function getSearchElement() { if (browserSupportsHistoryApi()) { history.replaceState("", window.currentCrate + " - Rust", "?search="); } - if (hasClass(main, "content")) { - removeClass(main, "hidden"); - } - var search_c = getSearchElement(); - if (hasClass(search_c, "content")) { - addClass(search_c, "hidden"); - } + hideSearchResults(); } else { searchTimeout = setTimeout(search, 500); } @@ -1742,19 +1745,8 @@ function getSearchElement() { // Store the previous so we can revert back to it later. var previousTitle = document.title; - window.onpopstate = function(e) { + window.addEventListener("popstate", function(e) { var params = getQueryStringParams(); - // When browsing back from search results the main page - // visibility must be reset. - if (!params.search) { - if (hasClass(main, "content")) { - removeClass(main, "hidden"); - } - var search_c = getSearchElement(); - if (hasClass(search_c, "content")) { - addClass(search_c, "hidden"); - } - } // Revert to the previous title manually since the History // API ignores the title parameter. document.title = previousTitle; @@ -1766,18 +1758,21 @@ function getSearchElement() { // perform the search. This will empty the bar if there's // nothing there, which lets you really go back to a // previous state with nothing in the bar. - if (params.search) { + if (params.search && params.search.length > 0) { search_input.value = params.search; + // Some browsers fire "onpopstate" for every page load + // (Chrome), while others fire the event only when actually + // popping a state (Firefox), which is why search() is + // called both here and at the end of the startSearch() + // function. + search(e); } else { search_input.value = ""; + // When browsing back from search results the main page + // visibility must be reset. + hideSearchResults(); } - // Some browsers fire "onpopstate" for every page load - // (Chrome), while others fire the event only when actually - // popping a state (Firefox), which is why search() is - // called both here and at the end of the startSearch() - // function. - search(); - }; + }); } search(); } @@ -2523,9 +2518,9 @@ function getSearchElement() { } function putBackSearch(search_input) { - if (search_input.value !== "") { - addClass(main, "hidden"); - removeClass(getSearchElement(), "hidden"); + var search = getSearchElement(); + if (search_input.value !== "" && hasClass(search, "hidden")) { + showSearchResults(search); if (browserSupportsHistoryApi()) { history.replaceState(search_input.value, "", @@ -2542,10 +2537,9 @@ function getSearchElement() { var params = getQueryStringParams(); if (params && params.search) { - addClass(main, "hidden"); var search = getSearchElement(); - removeClass(search, "hidden"); search.innerHTML = "<h3 style=\"text-align: center;\">Loading search results...</h3>"; + showSearchResults(search); } var sidebar_menu = document.getElementsByClassName("sidebar-menu")[0]; From 71ff18fb8965712cc0a35a9d968cdc41c6561386 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez <guillaume1.gomez@gmail.com> Date: Sun, 22 Dec 2019 15:42:29 +0100 Subject: [PATCH 06/21] Fix invalid results showing back --- src/librustdoc/html/static/main.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index d0c44cd40b21a..8ccb74d6f15d3 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -1722,6 +1722,10 @@ function getSearchElement() { search(); }; search_input.onchange = function(e) { + if (e.target !== document.activeElement) { + // To prevent doing anything when it's from a blur event. + return; + } // Do NOT e.preventDefault() here. It will prevent pasting. clearTimeout(searchTimeout); // zero-timeout necessary here because at the time of event handler execution the From 056dff5748270249d81a03b355bc7ddd8da7f900 Mon Sep 17 00:00:00 2001 From: Oliver Scherer <github35764891676564198441@oli-obk.de> Date: Mon, 23 Dec 2019 01:24:11 +0100 Subject: [PATCH 07/21] Fix ICE in mir interpretation --- src/librustc_mir/interpret/place.rs | 3 ++- src/test/ui/consts/const_prop_slice_pat_ice.rs | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/consts/const_prop_slice_pat_ice.rs diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 8923b167fdee8..6e7fa302abcbb 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -530,11 +530,12 @@ where // This can only be reached in ConstProp and non-rustc-MIR. throw_ub!(BoundsCheckFailed { len: min_length as u64, index: n as u64 }); } - assert!(offset < min_length); let index = if from_end { + assert!(offset - 1 < min_length); n - u64::from(offset) } else { + assert!(offset < min_length); u64::from(offset) }; diff --git a/src/test/ui/consts/const_prop_slice_pat_ice.rs b/src/test/ui/consts/const_prop_slice_pat_ice.rs new file mode 100644 index 0000000000000..5fec36e44bd8c --- /dev/null +++ b/src/test/ui/consts/const_prop_slice_pat_ice.rs @@ -0,0 +1,9 @@ +// check-pass +#![feature(slice_patterns)] + +fn main() { + match &[0, 1] as &[i32] { + [a @ .., x] => {} + &[] => {} + } +} From c205f6a06a8360367a7f6242f0d2615e94824024 Mon Sep 17 00:00:00 2001 From: Mark Rousskov <mark.simulacrum@gmail.com> Date: Sat, 21 Dec 2019 21:43:13 -0500 Subject: [PATCH 08/21] Remove mem::uninitalized from tests This purges uses of uninitialized where possible from test cases. Some are merely moved over to the equally bad pattern of MaybeUninit::uninit().assume_init() but with an annotation that this is "the best we can do". --- .../run-make-fulldeps/sanitizer-memory/Makefile | 2 ++ .../sanitizer-memory/maybeuninit.rs | 8 ++++++++ .../sanitizer-memory/uninit.rs | 6 +++--- src/test/rustdoc/issue-52873.rs | 5 ++--- src/test/ui/abi/stack-probes.rs | 15 ++++++++------- .../ui/const-generics/issues/issue-61422.rs | 12 ++++++++++++ .../ui/for-loop-while/for-loop-has-unit-body.rs | 4 ++-- src/test/ui/issues/issue-48131.rs | 6 +++--- src/test/ui/issues/issue-58212.rs | 9 ++++----- .../enum-non-c-like-repr-c-and-int.rs | 6 ++++-- .../ui/structs-enums/enum-non-c-like-repr-c.rs | 7 +++++-- .../structs-enums/enum-non-c-like-repr-int.rs | 6 ++++-- .../uninhabited-matches-feature-gated.rs | 17 ++++++++++------- .../uninhabited-matches-feature-gated.stderr | 14 +++++++------- src/test/ui/uninit-empty-types.rs | 12 +++++++----- 15 files changed, 81 insertions(+), 48 deletions(-) create mode 100644 src/test/run-make-fulldeps/sanitizer-memory/maybeuninit.rs diff --git a/src/test/run-make-fulldeps/sanitizer-memory/Makefile b/src/test/run-make-fulldeps/sanitizer-memory/Makefile index b3376f8a72358..f5787903a2b59 100644 --- a/src/test/run-make-fulldeps/sanitizer-memory/Makefile +++ b/src/test/run-make-fulldeps/sanitizer-memory/Makefile @@ -7,3 +7,5 @@ all: $(RUSTC) -g -Z sanitizer=memory -Z print-link-args uninit.rs | $(CGREP) librustc_msan $(TMPDIR)/uninit 2>&1 | $(CGREP) use-of-uninitialized-value + $(RUSTC) -g -Z sanitizer=memory -Z print-link-args maybeuninit.rs | $(CGREP) librustc_msan + $(TMPDIR)/maybeuninit 2>&1 | $(CGREP) use-of-uninitialized-value diff --git a/src/test/run-make-fulldeps/sanitizer-memory/maybeuninit.rs b/src/test/run-make-fulldeps/sanitizer-memory/maybeuninit.rs new file mode 100644 index 0000000000000..a9ae85f57639e --- /dev/null +++ b/src/test/run-make-fulldeps/sanitizer-memory/maybeuninit.rs @@ -0,0 +1,8 @@ +use std::mem::MaybeUninit; + +fn main() { + // This is technically not sound -- but we're literally trying to test + // that the sanitizer catches this, so I guess "intentionally unsound"? + let xs: [u8; 4] = unsafe { MaybeUninit::uninit().assume_init() }; + let y = xs[0] + xs[1]; +} diff --git a/src/test/run-make-fulldeps/sanitizer-memory/uninit.rs b/src/test/run-make-fulldeps/sanitizer-memory/uninit.rs index cb857e3bc38d3..eae52508f6585 100644 --- a/src/test/run-make-fulldeps/sanitizer-memory/uninit.rs +++ b/src/test/run-make-fulldeps/sanitizer-memory/uninit.rs @@ -1,7 +1,7 @@ -use std::mem; - fn main() { + // This is technically not sound -- but we're literally trying to test + // that the sanitizer catches this, so I guess "intentionally unsound"? #[allow(deprecated)] - let xs: [u8; 4] = unsafe { mem::uninitialized() }; + let xs: [u8; 4] = unsafe { std::mem::uninitialized() }; let y = xs[0] + xs[1]; } diff --git a/src/test/rustdoc/issue-52873.rs b/src/test/rustdoc/issue-52873.rs index 653c004c04b23..8000ce73bd42f 100644 --- a/src/test/rustdoc/issue-52873.rs +++ b/src/test/rustdoc/issue-52873.rs @@ -105,8 +105,7 @@ impl<U: Unsigned, B: Bit> Add<B0> for UInt<U, B> { impl<U: Unsigned> Add<U> for UTerm { type Output = U; fn add(self, _: U) -> Self::Output { - #[allow(deprecated)] - unsafe { ::std::mem::uninitialized() } + unimplemented!() } } @@ -137,7 +136,7 @@ where { type Output = UInt<Prod<Ul, UInt<Ur, B>>, B0>; fn mul(self, _: UInt<Ur, B>) -> Self::Output { - unsafe { ::std::mem::uninitialized() } + unimplemented!() } } diff --git a/src/test/ui/abi/stack-probes.rs b/src/test/ui/abi/stack-probes.rs index 1ab1d6df66d4b..1d5b362e29dfe 100644 --- a/src/test/ui/abi/stack-probes.rs +++ b/src/test/ui/abi/stack-probes.rs @@ -13,7 +13,7 @@ // ignore-sgx no processes // ignore-musl FIXME #31506 -use std::mem; +use std::mem::MaybeUninit; use std::process::Command; use std::thread; use std::env; @@ -28,8 +28,8 @@ fn main() { let args = env::args().skip(1).collect::<Vec<_>>(); if args.len() > 0 { match &args[0][..] { - "main-thread" => recurse(&[]), - "child-thread" => thread::spawn(|| recurse(&[])).join().unwrap(), + "main-thread" => recurse(&MaybeUninit::uninit()), + "child-thread" => thread::spawn(|| recurse(&MaybeUninit::uninit())).join().unwrap(), _ => panic!(), } return @@ -48,10 +48,11 @@ fn main() { } #[allow(unconditional_recursion)] -fn recurse(array: &[u64]) { - unsafe { black_box(array.as_ptr() as u64); } - #[allow(deprecated)] - let local: [_; 1024] = unsafe { mem::uninitialized() }; +fn recurse(array: &MaybeUninit<[u64; 1024]>) { + unsafe { + black_box(array.as_ptr() as u64); + } + let local: MaybeUninit<[u64; 1024]> = MaybeUninit::uninit(); recurse(&local); } diff --git a/src/test/ui/const-generics/issues/issue-61422.rs b/src/test/ui/const-generics/issues/issue-61422.rs index 45d37b6a2f3c5..4fa150ffef09e 100644 --- a/src/test/ui/const-generics/issues/issue-61422.rs +++ b/src/test/ui/const-generics/issues/issue-61422.rs @@ -5,6 +5,10 @@ use std::mem; +// Neither of the uninits below are currently accepted as not UB, however, +// this code does not run and is merely checking that we do not ICE on this pattern, +// so this is fine. + fn foo<const SIZE: usize>() { let arr: [u8; SIZE] = unsafe { #[allow(deprecated)] @@ -13,4 +17,12 @@ fn foo<const SIZE: usize>() { }; } +fn bar<const SIZE: usize>() { + let arr: [u8; SIZE] = unsafe { + let array: [u8; SIZE] = mem::MaybeUninit::uninit().assume_init(); + array + }; +} + + fn main() {} diff --git a/src/test/ui/for-loop-while/for-loop-has-unit-body.rs b/src/test/ui/for-loop-while/for-loop-has-unit-body.rs index 38c34d2dc2e6f..eba385461b951 100644 --- a/src/test/ui/for-loop-while/for-loop-has-unit-body.rs +++ b/src/test/ui/for-loop-while/for-loop-has-unit-body.rs @@ -2,8 +2,8 @@ fn main() { // Check that the tail statement in the body unifies with something for _ in 0..3 { - #[allow(deprecated)] - unsafe { std::mem::uninitialized() } + // `()` is fine to zero-initialize as it is zero sized and inhabited. + unsafe { std::mem::zeroed() } } // Check that the tail statement in the body can be unit diff --git a/src/test/ui/issues/issue-48131.rs b/src/test/ui/issues/issue-48131.rs index c8540729352b2..85664e62eaded 100644 --- a/src/test/ui/issues/issue-48131.rs +++ b/src/test/ui/issues/issue-48131.rs @@ -1,7 +1,7 @@ // This note is annotated because the purpose of the test // is to ensure that certain other notes are not generated. #![deny(unused_unsafe)] //~ NOTE -#![allow(deprecated)] + // (test that no note is generated on this unsafe fn) pub unsafe fn a() { @@ -20,8 +20,8 @@ pub fn b() { unsafe { /* unnecessary */ } //~ ERROR unnecessary `unsafe` //~^ NOTE } - - let () = ::std::mem::uninitialized(); + // `()` is fine to zero-initialize as it is zero sized and inhabited. + let () = ::std::mem::zeroed(); inner() } diff --git a/src/test/ui/issues/issue-58212.rs b/src/test/ui/issues/issue-58212.rs index 21dcdd56bf60c..4695497c3a184 100644 --- a/src/test/ui/issues/issue-58212.rs +++ b/src/test/ui/issues/issue-58212.rs @@ -1,13 +1,12 @@ -// run-pass +// check-pass trait FromUnchecked { - unsafe fn from_unchecked(); + fn from_unchecked(); } impl FromUnchecked for [u8; 1] { - unsafe fn from_unchecked() { - #[allow(deprecated)] - let mut array: Self = std::mem::uninitialized(); + fn from_unchecked() { + let mut array: Self = [0; 1]; let _ptr = &mut array as *mut [u8] as *mut u8; } } diff --git a/src/test/ui/structs-enums/enum-non-c-like-repr-c-and-int.rs b/src/test/ui/structs-enums/enum-non-c-like-repr-c-and-int.rs index 78d8e5e3a5dbf..7d15d607dd606 100644 --- a/src/test/ui/structs-enums/enum-non-c-like-repr-c-and-int.rs +++ b/src/test/ui/structs-enums/enum-non-c-like-repr-c-and-int.rs @@ -69,8 +69,10 @@ fn main() { unsafe { // This should be safe, because we don't match on it unless it's fully formed, // and it doesn't have a destructor. - #[allow(deprecated)] - let mut dest: MyEnum = mem::uninitialized(); + // + // MyEnum is repr(C, u8) so it is guaranteed to have a separate discriminant and each + // variant can be zero initialized. + let mut dest: MyEnum = mem::zeroed(); while buf.len() > 0 { match parse_my_enum(&mut dest, &mut buf) { Ok(()) => output.push(Ok(dest)), diff --git a/src/test/ui/structs-enums/enum-non-c-like-repr-c.rs b/src/test/ui/structs-enums/enum-non-c-like-repr-c.rs index 1209533efda82..fc9efdeca7d19 100644 --- a/src/test/ui/structs-enums/enum-non-c-like-repr-c.rs +++ b/src/test/ui/structs-enums/enum-non-c-like-repr-c.rs @@ -69,8 +69,11 @@ fn main() { unsafe { // This should be safe, because we don't match on it unless it's fully formed, // and it doesn't have a destructor. - #[allow(deprecated)] - let mut dest: MyEnum = mem::uninitialized(); + // + // Furthermore, there are no types within MyEnum which cannot be initialized with zero, + // specifically, though padding and such are present, there are no references or similar + // types. + let mut dest: MyEnum = mem::zeroed(); while buf.len() > 0 { match parse_my_enum(&mut dest, &mut buf) { Ok(()) => output.push(Ok(dest)), diff --git a/src/test/ui/structs-enums/enum-non-c-like-repr-int.rs b/src/test/ui/structs-enums/enum-non-c-like-repr-int.rs index 5dd9c1863d62d..f9e96c1a0f4ae 100644 --- a/src/test/ui/structs-enums/enum-non-c-like-repr-int.rs +++ b/src/test/ui/structs-enums/enum-non-c-like-repr-int.rs @@ -65,8 +65,10 @@ fn main() { unsafe { // This should be safe, because we don't match on it unless it's fully formed, // and it doesn't have a destructor. - #[allow(deprecated)] - let mut dest: MyEnum = mem::uninitialized(); + // + // MyEnum is repr(u8) so it is guaranteed to have a separate discriminant and each variant + // can be zero initialized. + let mut dest: MyEnum = mem::zeroed(); while buf.len() > 0 { match parse_my_enum(&mut dest, &mut buf) { Ok(()) => output.push(Ok(dest)), diff --git a/src/test/ui/uninhabited/uninhabited-matches-feature-gated.rs b/src/test/ui/uninhabited/uninhabited-matches-feature-gated.rs index a5360fa13c4ea..e804afcf9ed99 100644 --- a/src/test/ui/uninhabited/uninhabited-matches-feature-gated.rs +++ b/src/test/ui/uninhabited/uninhabited-matches-feature-gated.rs @@ -1,5 +1,4 @@ -#![allow(deprecated)] - +use std::mem::zeroed; enum Void {} fn main() { @@ -8,21 +7,25 @@ fn main() { Ok(n) => n, }; - let x: &Void = unsafe { std::mem::uninitialized() }; + // This is pretty much instant UB. However, we have no choice -- we need to + // test matching on a reference to `&Void`; we cannot do anything other than + // just accept the fact that this is UB if `main` did run, but it doesn't; + // this test only checks that these are feature-gated. + let x: &Void = unsafe { zeroed() }; let _ = match x {}; //~ ERROR non-exhaustive - let x: (Void,) = unsafe { std::mem::uninitialized() }; + let x: (Void,) = unsafe { zeroed() }; let _ = match x {}; //~ ERROR non-exhaustive - let x: [Void; 1] = unsafe { std::mem::uninitialized() }; + let x: [Void; 1] = unsafe { zeroed() }; let _ = match x {}; //~ ERROR non-exhaustive - let x: &[Void] = unsafe { std::mem::uninitialized() }; + let x: &[Void] = unsafe { zeroed() }; let _ = match x { //~ ERROR non-exhaustive &[] => (), }; - let x: Void = unsafe { std::mem::uninitialized() }; + let x: Void = unsafe { zeroed() }; let _ = match x {}; // okay let x: Result<u32, Void> = Ok(23); diff --git a/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr b/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr index 18ffdccb9b2db..a667e1fe2da3a 100644 --- a/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr +++ b/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: `Err(_)` not covered - --> $DIR/uninhabited-matches-feature-gated.rs:7:19 + --> $DIR/uninhabited-matches-feature-gated.rs:6:19 | LL | let _ = match x { | ^ pattern `Err(_)` not covered @@ -7,7 +7,7 @@ LL | let _ = match x { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: type `&Void` is non-empty - --> $DIR/uninhabited-matches-feature-gated.rs:12:19 + --> $DIR/uninhabited-matches-feature-gated.rs:15:19 | LL | enum Void {} | ------------ `Void` defined here @@ -18,7 +18,7 @@ LL | let _ = match x {}; = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: type `(Void,)` is non-empty - --> $DIR/uninhabited-matches-feature-gated.rs:15:19 + --> $DIR/uninhabited-matches-feature-gated.rs:18:19 | LL | let _ = match x {}; | ^ @@ -26,7 +26,7 @@ LL | let _ = match x {}; = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: type `[Void; 1]` is non-empty - --> $DIR/uninhabited-matches-feature-gated.rs:18:19 + --> $DIR/uninhabited-matches-feature-gated.rs:21:19 | LL | let _ = match x {}; | ^ @@ -34,7 +34,7 @@ LL | let _ = match x {}; = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered - --> $DIR/uninhabited-matches-feature-gated.rs:21:19 + --> $DIR/uninhabited-matches-feature-gated.rs:24:19 | LL | let _ = match x { | ^ pattern `&[_, ..]` not covered @@ -42,7 +42,7 @@ LL | let _ = match x { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `Err(_)` not covered - --> $DIR/uninhabited-matches-feature-gated.rs:29:19 + --> $DIR/uninhabited-matches-feature-gated.rs:32:19 | LL | let _ = match x { | ^ pattern `Err(_)` not covered @@ -50,7 +50,7 @@ LL | let _ = match x { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0005]: refutable pattern in local binding: `Err(_)` not covered - --> $DIR/uninhabited-matches-feature-gated.rs:34:9 + --> $DIR/uninhabited-matches-feature-gated.rs:37:9 | LL | let Ok(x) = x; | ^^^^^ pattern `Err(_)` not covered diff --git a/src/test/ui/uninit-empty-types.rs b/src/test/ui/uninit-empty-types.rs index 0d1235776a6ef..b21de882b2ceb 100644 --- a/src/test/ui/uninit-empty-types.rs +++ b/src/test/ui/uninit-empty-types.rs @@ -1,17 +1,19 @@ -// run-pass +// build-pass // Test the uninit() construct returning various empty types. // pretty-expanded FIXME #23616 -use std::mem; +use std::mem::MaybeUninit; -#[derive(Clone)] struct Foo; #[allow(deprecated)] pub fn main() { unsafe { - let _x: Foo = mem::uninitialized(); - let _x: [Foo; 2] = mem::uninitialized(); + // `Foo` and `[Foo; 2]` are both zero sized and inhabited, so this is safe. + let _x: Foo = MaybeUninit::uninit().assume_init(); + let _x: [Foo; 2] = MaybeUninit::uninit().assume_init(); + let _x: Foo = std::mem::uninitialized(); + let _x: [Foo; 2] = std::mem::uninitialized(); } } From 5b8df34203d1d6f308da7413c9f27b0b0887b438 Mon Sep 17 00:00:00 2001 From: Oliver Scherer <github35764891676564198441@oli-obk.de> Date: Mon, 23 Dec 2019 11:27:34 +0100 Subject: [PATCH 09/21] Update src/librustc_mir/interpret/place.rs Co-Authored-By: Ralf Jung <post@ralfj.de> --- src/librustc_mir/interpret/place.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 6e7fa302abcbb..37540d8a3ccb1 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -532,7 +532,7 @@ where } let index = if from_end { - assert!(offset - 1 < min_length); + assert!(0 < offset && offset - 1 < min_length); n - u64::from(offset) } else { assert!(offset < min_length); From 45acee30903f6a84d22a5afa29df965265ca486b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad <twingoow@gmail.com> Date: Sun, 22 Dec 2019 20:46:14 +0100 Subject: [PATCH 10/21] Move `{hir::lowering -> hir}::is_range_literal`. The function is never used inside lowering, but only ever in external crates. By moving it, we faciliate lowering as its own crate. --- src/librustc/hir/lowering.rs | 62 ------------------------------------ src/librustc/hir/mod.rs | 62 ++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 62 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 83869951ea2a1..a702eb839845e 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -3437,65 +3437,3 @@ fn body_ids(bodies: &BTreeMap<hir::BodyId, hir::Body<'hir>>) -> Vec<hir::BodyId> body_ids.sort_by_key(|b| bodies[b].value.span); body_ids } - -/// Checks if the specified expression is a built-in range literal. -/// (See: `LoweringContext::lower_expr()`). -pub fn is_range_literal(sess: &Session, expr: &hir::Expr) -> bool { - use hir::{Path, QPath, ExprKind, TyKind}; - - // Returns whether the given path represents a (desugared) range, - // either in std or core, i.e. has either a `::std::ops::Range` or - // `::core::ops::Range` prefix. - fn is_range_path(path: &Path) -> bool { - let segs: Vec<_> = path.segments.iter().map(|seg| seg.ident.to_string()).collect(); - let segs: Vec<_> = segs.iter().map(|seg| &**seg).collect(); - - // "{{root}}" is the equivalent of `::` prefix in `Path`. - if let ["{{root}}", std_core, "ops", range] = segs.as_slice() { - (*std_core == "std" || *std_core == "core") && range.starts_with("Range") - } else { - false - } - }; - - // Check whether a span corresponding to a range expression is a - // range literal, rather than an explicit struct or `new()` call. - fn is_lit(sess: &Session, span: &Span) -> bool { - let source_map = sess.source_map(); - let end_point = source_map.end_point(*span); - - if let Ok(end_string) = source_map.span_to_snippet(end_point) { - !(end_string.ends_with("}") || end_string.ends_with(")")) - } else { - false - } - }; - - match expr.kind { - // All built-in range literals but `..=` and `..` desugar to `Struct`s. - ExprKind::Struct(ref qpath, _, _) => { - if let QPath::Resolved(None, ref path) = **qpath { - return is_range_path(&path) && is_lit(sess, &expr.span); - } - } - - // `..` desugars to its struct path. - ExprKind::Path(QPath::Resolved(None, ref path)) => { - return is_range_path(&path) && is_lit(sess, &expr.span); - } - - // `..=` desugars into `::std::ops::RangeInclusive::new(...)`. - ExprKind::Call(ref func, _) => { - if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.kind { - if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.kind { - let new_call = segment.ident.name == sym::new; - return is_range_path(&path) && is_lit(sess, &expr.span) && new_call; - } - } - } - - _ => {} - } - - false -} diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 4aa8c12a219ca..55a30a7cc3a19 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1564,6 +1564,68 @@ impl fmt::Debug for Expr { } } +/// Checks if the specified expression is a built-in range literal. +/// (See: `LoweringContext::lower_expr()`). +pub fn is_range_literal(sess: &Session, expr: &hir::Expr) -> bool { + use hir::{Path, QPath, ExprKind, TyKind}; + + // Returns whether the given path represents a (desugared) range, + // either in std or core, i.e. has either a `::std::ops::Range` or + // `::core::ops::Range` prefix. + fn is_range_path(path: &Path) -> bool { + let segs: Vec<_> = path.segments.iter().map(|seg| seg.ident.to_string()).collect(); + let segs: Vec<_> = segs.iter().map(|seg| &**seg).collect(); + + // "{{root}}" is the equivalent of `::` prefix in `Path`. + if let ["{{root}}", std_core, "ops", range] = segs.as_slice() { + (*std_core == "std" || *std_core == "core") && range.starts_with("Range") + } else { + false + } + }; + + // Check whether a span corresponding to a range expression is a + // range literal, rather than an explicit struct or `new()` call. + fn is_lit(sess: &Session, span: &Span) -> bool { + let source_map = sess.source_map(); + let end_point = source_map.end_point(*span); + + if let Ok(end_string) = source_map.span_to_snippet(end_point) { + !(end_string.ends_with("}") || end_string.ends_with(")")) + } else { + false + } + }; + + match expr.kind { + // All built-in range literals but `..=` and `..` desugar to `Struct`s. + ExprKind::Struct(ref qpath, _, _) => { + if let QPath::Resolved(None, ref path) = **qpath { + return is_range_path(&path) && is_lit(sess, &expr.span); + } + } + + // `..` desugars to its struct path. + ExprKind::Path(QPath::Resolved(None, ref path)) => { + return is_range_path(&path) && is_lit(sess, &expr.span); + } + + // `..=` desugars into `::std::ops::RangeInclusive::new(...)`. + ExprKind::Call(ref func, _) => { + if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.kind { + if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.kind { + let new_call = segment.ident.name == sym::new; + return is_range_path(&path) && is_lit(sess, &expr.span) && new_call; + } + } + } + + _ => {} + } + + false +} + #[derive(RustcEncodable, RustcDecodable, Debug, HashStable)] pub enum ExprKind { /// A `box x` expression. From a5991c57cf4430d1f67886637c65f2178ff1b372 Mon Sep 17 00:00:00 2001 From: varkor <github@varkor.com> Date: Sun, 22 Dec 2019 18:18:49 +0000 Subject: [PATCH 11/21] Add the full issue reference to equality constraints in `where` clauses --- src/librustc_passes/ast_validation.rs | 10 ++++++++-- .../ui/where-clauses/where-equality-constraints.rs | 4 ++-- .../ui/where-clauses/where-equality-constraints.stderr | 8 ++++++-- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index ee6a67802ade3..1d5e65c6d27cd 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -737,8 +737,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> { for predicate in &generics.where_clause.predicates { if let WherePredicate::EqPredicate(ref predicate) = *predicate { self.err_handler() - .span_err(predicate.span, "equality constraints are not yet \ - supported in where clauses (see #20041)"); + .struct_span_err( + predicate.span, + "equality constraints are not yet supported in `where` clauses", + ) + .note( + "for more information, see https://github.com/rust-lang/rust/issues/20041", + ) + .emit(); } } diff --git a/src/test/ui/where-clauses/where-equality-constraints.rs b/src/test/ui/where-clauses/where-equality-constraints.rs index f2349144b88ae..8828f09d92d33 100644 --- a/src/test/ui/where-clauses/where-equality-constraints.rs +++ b/src/test/ui/where-clauses/where-equality-constraints.rs @@ -1,6 +1,6 @@ fn f() where u8 = u16 {} -//~^ ERROR equality constraints are not yet supported in where clauses +//~^ ERROR equality constraints are not yet supported in `where` clauses fn g() where for<'a> &'static (u8,) == u16, {} -//~^ ERROR equality constraints are not yet supported in where clauses +//~^ ERROR equality constraints are not yet supported in `where` clauses fn main() {} diff --git a/src/test/ui/where-clauses/where-equality-constraints.stderr b/src/test/ui/where-clauses/where-equality-constraints.stderr index 220447079c629..c0241fe708f64 100644 --- a/src/test/ui/where-clauses/where-equality-constraints.stderr +++ b/src/test/ui/where-clauses/where-equality-constraints.stderr @@ -1,14 +1,18 @@ -error: equality constraints are not yet supported in where clauses (see #20041) +error: equality constraints are not yet supported in `where` clauses --> $DIR/where-equality-constraints.rs:1:14 | LL | fn f() where u8 = u16 {} | ^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/20041 -error: equality constraints are not yet supported in where clauses (see #20041) +error: equality constraints are not yet supported in `where` clauses --> $DIR/where-equality-constraints.rs:3:14 | LL | fn g() where for<'a> &'static (u8,) == u16, {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/20041 error: aborting due to 2 previous errors From b7bfdbe68147f2ea8ca4870270643180bef76e02 Mon Sep 17 00:00:00 2001 From: varkor <github@varkor.com> Date: Sun, 22 Dec 2019 18:42:15 +0000 Subject: [PATCH 12/21] Improve invalid assignment error --- src/librustc_typeck/check/expr.rs | 9 ++++-- src/librustc_typeck/check/op.rs | 8 ++--- src/test/ui/bad/bad-expr-lhs.rs | 10 +++--- src/test/ui/bad/bad-expr-lhs.stderr | 32 ++++++++++++------- src/test/ui/error-codes/E0067.stderr | 8 +++-- src/test/ui/error-codes/E0070.stderr | 18 +++++++---- src/test/ui/issues/issue-13407.rs | 2 +- src/test/ui/issues/issue-13407.stderr | 6 ++-- src/test/ui/issues/issue-26093.rs | 4 ++- src/test/ui/issues/issue-26093.stderr | 26 ++++++++++++--- src/test/ui/issues/issue-34334.rs | 2 +- src/test/ui/issues/issue-34334.stderr | 6 ++-- .../type-check/assignment-expected-bool.rs | 2 +- .../assignment-expected-bool.stderr | 6 ++-- .../ui/type/type-check/assignment-in-if.rs | 2 +- 15 files changed, 92 insertions(+), 49 deletions(-) diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 6ecf3ccd6e7ed..27f6b3cb45f4b 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -753,9 +753,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } err.emit(); } else if !lhs.is_syntactic_place_expr() { - struct_span_err!(self.tcx.sess, expr.span, E0070, "invalid left-hand side expression") - .span_label(expr.span, "left-hand of expression not valid") - .emit(); + struct_span_err!( + self.tcx.sess, + expr.span, + E0070, + "invalid left-hand side of assignment", + ).span_label(lhs.span, "cannot assign to this expression").emit(); } self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized); diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 53475569b2c3f..eeee7dea4d1c1 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -36,12 +36,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !lhs_expr.is_syntactic_place_expr() { struct_span_err!( self.tcx.sess, - lhs_expr.span, + op.span, E0067, - "invalid left-hand side expression" - ) - .span_label(lhs_expr.span, "invalid expression for left-hand side") - .emit(); + "invalid left-hand side of assignment", + ).span_label(lhs_expr.span, "cannot assign to this expression").emit(); } ty } diff --git a/src/test/ui/bad/bad-expr-lhs.rs b/src/test/ui/bad/bad-expr-lhs.rs index 2cd8bc9d47333..d7cf1b7700514 100644 --- a/src/test/ui/bad/bad-expr-lhs.rs +++ b/src/test/ui/bad/bad-expr-lhs.rs @@ -1,10 +1,10 @@ fn main() { - 1 = 2; //~ ERROR invalid left-hand side expression - 1 += 2; //~ ERROR invalid left-hand side expression - (1, 2) = (3, 4); //~ ERROR invalid left-hand side expression + 1 = 2; //~ ERROR invalid left-hand side of assignment + 1 += 2; //~ ERROR invalid left-hand side of assignment + (1, 2) = (3, 4); //~ ERROR invalid left-hand side of assignment let (a, b) = (1, 2); - (a, b) = (3, 4); //~ ERROR invalid left-hand side expression + (a, b) = (3, 4); //~ ERROR invalid left-hand side of assignment - None = Some(3); //~ ERROR invalid left-hand side expression + None = Some(3); //~ ERROR invalid left-hand side of assignment } diff --git a/src/test/ui/bad/bad-expr-lhs.stderr b/src/test/ui/bad/bad-expr-lhs.stderr index a0de6a73797e2..07cffbe97a8d9 100644 --- a/src/test/ui/bad/bad-expr-lhs.stderr +++ b/src/test/ui/bad/bad-expr-lhs.stderr @@ -1,32 +1,42 @@ -error[E0070]: invalid left-hand side expression +error[E0070]: invalid left-hand side of assignment --> $DIR/bad-expr-lhs.rs:2:5 | LL | 1 = 2; - | ^^^^^ left-hand of expression not valid + | -^^^^ + | | + | cannot assign to this expression -error[E0067]: invalid left-hand side expression - --> $DIR/bad-expr-lhs.rs:3:5 +error[E0067]: invalid left-hand side of assignment + --> $DIR/bad-expr-lhs.rs:3:7 | LL | 1 += 2; - | ^ invalid expression for left-hand side + | - ^^ + | | + | cannot assign to this expression -error[E0070]: invalid left-hand side expression +error[E0070]: invalid left-hand side of assignment --> $DIR/bad-expr-lhs.rs:4:5 | LL | (1, 2) = (3, 4); - | ^^^^^^^^^^^^^^^ left-hand of expression not valid + | ------^^^^^^^^^ + | | + | cannot assign to this expression -error[E0070]: invalid left-hand side expression +error[E0070]: invalid left-hand side of assignment --> $DIR/bad-expr-lhs.rs:7:5 | LL | (a, b) = (3, 4); - | ^^^^^^^^^^^^^^^ left-hand of expression not valid + | ------^^^^^^^^^ + | | + | cannot assign to this expression -error[E0070]: invalid left-hand side expression +error[E0070]: invalid left-hand side of assignment --> $DIR/bad-expr-lhs.rs:9:5 | LL | None = Some(3); - | ^^^^^^^^^^^^^^ left-hand of expression not valid + | ----^^^^^^^^^^ + | | + | cannot assign to this expression error: aborting due to 5 previous errors diff --git a/src/test/ui/error-codes/E0067.stderr b/src/test/ui/error-codes/E0067.stderr index 0334565840f83..526503798b3d4 100644 --- a/src/test/ui/error-codes/E0067.stderr +++ b/src/test/ui/error-codes/E0067.stderr @@ -8,11 +8,13 @@ LL | LinkedList::new() += 1; | = note: an implementation of `std::ops::AddAssign` might be missing for `std::collections::LinkedList<_>` -error[E0067]: invalid left-hand side expression - --> $DIR/E0067.rs:4:5 +error[E0067]: invalid left-hand side of assignment + --> $DIR/E0067.rs:4:23 | LL | LinkedList::new() += 1; - | ^^^^^^^^^^^^^^^^^ invalid expression for left-hand side + | ----------------- ^^ + | | + | cannot assign to this expression error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0070.stderr b/src/test/ui/error-codes/E0070.stderr index 845833bc82f70..1fb812d94672f 100644 --- a/src/test/ui/error-codes/E0070.stderr +++ b/src/test/ui/error-codes/E0070.stderr @@ -1,14 +1,18 @@ -error[E0070]: invalid left-hand side expression +error[E0070]: invalid left-hand side of assignment --> $DIR/E0070.rs:6:5 | LL | SOME_CONST = 14; - | ^^^^^^^^^^^^^^^ left-hand of expression not valid + | ----------^^^^^ + | | + | cannot assign to this expression -error[E0070]: invalid left-hand side expression +error[E0070]: invalid left-hand side of assignment --> $DIR/E0070.rs:7:5 | LL | 1 = 3; - | ^^^^^ left-hand of expression not valid + | -^^^^ + | | + | cannot assign to this expression error[E0308]: mismatched types --> $DIR/E0070.rs:8:25 @@ -16,11 +20,13 @@ error[E0308]: mismatched types LL | some_other_func() = 4; | ^ expected `()`, found integer -error[E0070]: invalid left-hand side expression +error[E0070]: invalid left-hand side of assignment --> $DIR/E0070.rs:8:5 | LL | some_other_func() = 4; - | ^^^^^^^^^^^^^^^^^^^^^ left-hand of expression not valid + | -----------------^^^^ + | | + | cannot assign to this expression error: aborting due to 4 previous errors diff --git a/src/test/ui/issues/issue-13407.rs b/src/test/ui/issues/issue-13407.rs index 322e67cc13180..fa53d55f5b3d7 100644 --- a/src/test/ui/issues/issue-13407.rs +++ b/src/test/ui/issues/issue-13407.rs @@ -4,7 +4,7 @@ mod A { fn main() { A::C = 1; - //~^ ERROR: invalid left-hand side expression + //~^ ERROR: invalid left-hand side of assignment //~| ERROR: mismatched types //~| ERROR: struct `C` is private } diff --git a/src/test/ui/issues/issue-13407.stderr b/src/test/ui/issues/issue-13407.stderr index 5a465cc533bb7..05fd97b025f60 100644 --- a/src/test/ui/issues/issue-13407.stderr +++ b/src/test/ui/issues/issue-13407.stderr @@ -10,11 +10,13 @@ error[E0308]: mismatched types LL | A::C = 1; | ^ expected struct `A::C`, found integer -error[E0070]: invalid left-hand side expression +error[E0070]: invalid left-hand side of assignment --> $DIR/issue-13407.rs:6:5 | LL | A::C = 1; - | ^^^^^^^^ left-hand of expression not valid + | ----^^^^ + | | + | cannot assign to this expression error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-26093.rs b/src/test/ui/issues/issue-26093.rs index 7895c90068fe2..c838515caf997 100644 --- a/src/test/ui/issues/issue-26093.rs +++ b/src/test/ui/issues/issue-26093.rs @@ -1,7 +1,9 @@ macro_rules! not_a_place { ($thing:expr) => { $thing = 42; - //~^ ERROR invalid left-hand side expression + //~^ ERROR invalid left-hand side of assignment + $thing += 42; + //~^ ERROR invalid left-hand side of assignment } } diff --git a/src/test/ui/issues/issue-26093.stderr b/src/test/ui/issues/issue-26093.stderr index 947c52f08d2e6..48f72cef0a85a 100644 --- a/src/test/ui/issues/issue-26093.stderr +++ b/src/test/ui/issues/issue-26093.stderr @@ -1,12 +1,28 @@ -error[E0070]: invalid left-hand side expression +error[E0070]: invalid left-hand side of assignment --> $DIR/issue-26093.rs:3:9 | LL | $thing = 42; - | ^^^^^^^^^^^ left-hand of expression not valid + | ^^^^^^^^^^^ ... LL | not_a_place!(99); - | ----------------- in this macro invocation + | ----------------- + | | | + | | cannot assign to this expression + | in this macro invocation -error: aborting due to previous error +error[E0067]: invalid left-hand side of assignment + --> $DIR/issue-26093.rs:5:16 + | +LL | $thing += 42; + | ^^ +... +LL | not_a_place!(99); + | ----------------- + | | | + | | cannot assign to this expression + | in this macro invocation + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0070`. +Some errors have detailed explanations: E0067, E0070. +For more information about an error, try `rustc --explain E0067`. diff --git a/src/test/ui/issues/issue-34334.rs b/src/test/ui/issues/issue-34334.rs index 4457d71cbb4a7..e34b5c9a0f47e 100644 --- a/src/test/ui/issues/issue-34334.rs +++ b/src/test/ui/issues/issue-34334.rs @@ -3,7 +3,7 @@ fn main () { //~^ ERROR expected one of `,` or `>`, found `=` //~| ERROR expected value, found struct `Vec` //~| ERROR mismatched types - //~| ERROR invalid left-hand side expression + //~| ERROR invalid left-hand side of assignment //~| ERROR expected expression, found reserved identifier `_` //~| ERROR expected expression, found reserved identifier `_` let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect(); diff --git a/src/test/ui/issues/issue-34334.stderr b/src/test/ui/issues/issue-34334.stderr index fc90e0674cf55..e54f0c77cd973 100644 --- a/src/test/ui/issues/issue-34334.stderr +++ b/src/test/ui/issues/issue-34334.stderr @@ -35,11 +35,13 @@ LL | let sr: Vec<(u32, _, _) = vec![]; found struct `std::vec::Vec<_>` = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) -error[E0070]: invalid left-hand side expression +error[E0070]: invalid left-hand side of assignment --> $DIR/issue-34334.rs:2:13 | LL | let sr: Vec<(u32, _, _) = vec![]; - | ^^^^^^^^^^^^^^^^^^^^^^^^ left-hand of expression not valid + | ---------------^^^^^^^^^ + | | + | cannot assign to this expression error[E0599]: no method named `iter` found for type `()` in the current scope --> $DIR/issue-34334.rs:9:36 diff --git a/src/test/ui/type/type-check/assignment-expected-bool.rs b/src/test/ui/type/type-check/assignment-expected-bool.rs index 03830fea062cf..191939bdb705b 100644 --- a/src/test/ui/type/type-check/assignment-expected-bool.rs +++ b/src/test/ui/type/type-check/assignment-expected-bool.rs @@ -30,5 +30,5 @@ fn main() { // A test to check that not expecting `bool` behaves well: let _: usize = 0 = 0; //~^ ERROR mismatched types [E0308] - //~| ERROR invalid left-hand side expression [E0070] + //~| ERROR invalid left-hand side of assignment [E0070] } diff --git a/src/test/ui/type/type-check/assignment-expected-bool.stderr b/src/test/ui/type/type-check/assignment-expected-bool.stderr index 9a1cf5b25625c..bbd961f845016 100644 --- a/src/test/ui/type/type-check/assignment-expected-bool.stderr +++ b/src/test/ui/type/type-check/assignment-expected-bool.stderr @@ -97,11 +97,13 @@ LL | || (0 = 0); | expected `bool`, found `()` | help: try comparing for equality: `0 == 0` -error[E0070]: invalid left-hand side expression +error[E0070]: invalid left-hand side of assignment --> $DIR/assignment-expected-bool.rs:31:20 | LL | let _: usize = 0 = 0; - | ^^^^^ left-hand of expression not valid + | -^^^^ + | | + | cannot assign to this expression error[E0308]: mismatched types --> $DIR/assignment-expected-bool.rs:31:20 diff --git a/src/test/ui/type/type-check/assignment-in-if.rs b/src/test/ui/type/type-check/assignment-in-if.rs index 77b122b0a794a..8da7b32b47b14 100644 --- a/src/test/ui/type/type-check/assignment-in-if.rs +++ b/src/test/ui/type/type-check/assignment-in-if.rs @@ -26,7 +26,7 @@ fn main() { //~^ ERROR mismatched types println!("{}", x); } - // "invalid left-hand side expression" error is suppresed + // "invalid left-hand side of assignment" error is suppresed if 3 = x { //~^ ERROR mismatched types println!("{}", x); From 5fa02ecc291f0a6b356fbb3b1e14649082b93a2f Mon Sep 17 00:00:00 2001 From: varkor <github@varkor.com> Date: Sun, 22 Dec 2019 20:14:08 +0000 Subject: [PATCH 13/21] Add note about destructuring assignments --- src/librustc_typeck/check/expr.rs | 44 +++++-- src/librustc_typeck/check/op.rs | 20 ++-- src/test/ui/bad/bad-expr-lhs.stderr | 3 + src/test/ui/bad/destructuring-assignment.rs | 21 ++++ .../ui/bad/destructuring-assignment.stderr | 111 ++++++++++++++++++ 5 files changed, 178 insertions(+), 21 deletions(-) create mode 100644 src/test/ui/bad/destructuring-assignment.rs create mode 100644 src/test/ui/bad/destructuring-assignment.stderr diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 27f6b3cb45f4b..9085528c84e9f 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -17,7 +17,7 @@ use crate::check::TupleArgumentsFlag::DontTupleArguments; use crate::util::common::ErrorReported; use crate::util::nodemap::FxHashMap; -use errors::{pluralize, Applicability, DiagnosticBuilder}; +use errors::{pluralize, Applicability, DiagnosticBuilder, DiagnosticId}; use rustc::hir; use rustc::hir::def::{CtorKind, DefKind, Res}; use rustc::hir::def_id::DefId; @@ -723,6 +723,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } + pub(crate) fn check_lhs_assignable( + &self, + lhs: &'tcx hir::Expr, + err_code: &'static str, + expr_span: &Span, + ) { + if !lhs.is_syntactic_place_expr() { + let mut err = self.tcx.sess.struct_span_err_with_code( + *expr_span, + "invalid left-hand side of assignment", + DiagnosticId::Error(err_code.into()), + ); + err.span_label(lhs.span, "cannot assign to this expression"); + let destructuring_assignment = match &lhs.kind { + ExprKind::Array(comps) | ExprKind::Tup(comps) => { + comps.iter().all(|e| e.is_syntactic_place_expr()) + } + ExprKind::Struct(_path, fields, rest) => { + rest.as_ref().map(|e| e.is_syntactic_place_expr()).unwrap_or(true) && + fields.iter().all(|f| f.expr.is_syntactic_place_expr()) + } + _ => false, + }; + if destructuring_assignment { + err.note("destructuring assignments are not yet supported"); + err.note( + "for more information, see https://github.com/rust-lang/rfcs/issues/372", + ); + } + err.emit(); + } + } + /// Type check assignment expression `expr` of form `lhs = rhs`. /// The expected type is `()` and is passsed to the function for the purposes of diagnostics. fn check_expr_assign( @@ -752,13 +785,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.help(msg); } err.emit(); - } else if !lhs.is_syntactic_place_expr() { - struct_span_err!( - self.tcx.sess, - expr.span, - E0070, - "invalid left-hand side of assignment", - ).span_label(lhs.span, "cannot assign to this expression").emit(); + } else { + self.check_lhs_assignable(lhs, "E0070", &expr.span); } self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized); diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index eeee7dea4d1c1..dfa55e324a625 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -19,28 +19,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, expr: &'tcx hir::Expr, op: hir::BinOp, - lhs_expr: &'tcx hir::Expr, - rhs_expr: &'tcx hir::Expr, + lhs: &'tcx hir::Expr, + rhs: &'tcx hir::Expr, ) -> Ty<'tcx> { let (lhs_ty, rhs_ty, return_ty) = - self.check_overloaded_binop(expr, lhs_expr, rhs_expr, op, IsAssign::Yes); + self.check_overloaded_binop(expr, lhs, rhs, op, IsAssign::Yes); let ty = - if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) { - self.enforce_builtin_binop_types(lhs_expr, lhs_ty, rhs_expr, rhs_ty, op); + if !lhs.is_ty_var() && !rhs.is_ty_var() && is_builtin_binop(lhs, rhs, op) { + self.enforce_builtin_binop_types(lhs_expr, lhs, rhs_expr, rhs, op); self.tcx.mk_unit() } else { return_ty }; - if !lhs_expr.is_syntactic_place_expr() { - struct_span_err!( - self.tcx.sess, - op.span, - E0067, - "invalid left-hand side of assignment", - ).span_label(lhs_expr.span, "cannot assign to this expression").emit(); - } + self.check_lhs_assignable(lhs, "E0067", &op.span); + ty } diff --git a/src/test/ui/bad/bad-expr-lhs.stderr b/src/test/ui/bad/bad-expr-lhs.stderr index 07cffbe97a8d9..61c25bb471c37 100644 --- a/src/test/ui/bad/bad-expr-lhs.stderr +++ b/src/test/ui/bad/bad-expr-lhs.stderr @@ -29,6 +29,9 @@ LL | (a, b) = (3, 4); | ------^^^^^^^^^ | | | cannot assign to this expression + | + = note: destructuring assignments are not yet supported + = note: for more information, see https://github.com/rust-lang/rfcs/issues/372 error[E0070]: invalid left-hand side of assignment --> $DIR/bad-expr-lhs.rs:9:5 diff --git a/src/test/ui/bad/destructuring-assignment.rs b/src/test/ui/bad/destructuring-assignment.rs new file mode 100644 index 0000000000000..7112cedfd0009 --- /dev/null +++ b/src/test/ui/bad/destructuring-assignment.rs @@ -0,0 +1,21 @@ +struct S { x: u8, y: u8 } + +fn main() { + let (a, b) = (1, 2); + + (a, b) = (3, 4); //~ ERROR invalid left-hand side of assignment + (a, b) += (3, 4); //~ ERROR invalid left-hand side of assignment + //~^ ERROR binary assignment operation `+=` cannot be applied + + [a, b] = [3, 4]; //~ ERROR invalid left-hand side of assignment + [a, b] += [3, 4]; //~ ERROR invalid left-hand side of assignment + //~^ ERROR binary assignment operation `+=` cannot be applied + + let s = S { x: 3, y: 4 }; + + S { x: a, y: b } = s; //~ ERROR invalid left-hand side of assignment + S { x: a, y: b } += s; //~ ERROR invalid left-hand side of assignment + //~^ ERROR binary assignment operation `+=` cannot be applied + + S { x: a, ..s } = S { x: 3, y: 4 }; //~ ERROR invalid left-hand side of assignment +} diff --git a/src/test/ui/bad/destructuring-assignment.stderr b/src/test/ui/bad/destructuring-assignment.stderr new file mode 100644 index 0000000000000..676576b7bc526 --- /dev/null +++ b/src/test/ui/bad/destructuring-assignment.stderr @@ -0,0 +1,111 @@ +error[E0070]: invalid left-hand side of assignment + --> $DIR/destructuring-assignment.rs:6:5 + | +LL | (a, b) = (3, 4); + | ------^^^^^^^^^ + | | + | cannot assign to this expression + | + = note: destructuring assignments are not yet supported + = note: for more information, see https://github.com/rust-lang/rfcs/issues/372 + +error[E0368]: binary assignment operation `+=` cannot be applied to type `({integer}, {integer})` + --> $DIR/destructuring-assignment.rs:7:5 + | +LL | (a, b) += (3, 4); + | ------^^^^^^^^^^ + | | + | cannot use `+=` on type `({integer}, {integer})` + | + = note: an implementation of `std::ops::AddAssign` might be missing for `({integer}, {integer})` + +error[E0067]: invalid left-hand side of assignment + --> $DIR/destructuring-assignment.rs:7:12 + | +LL | (a, b) += (3, 4); + | ------ ^^ + | | + | cannot assign to this expression + | + = note: destructuring assignments are not yet supported + = note: for more information, see https://github.com/rust-lang/rfcs/issues/372 + +error[E0070]: invalid left-hand side of assignment + --> $DIR/destructuring-assignment.rs:10:5 + | +LL | [a, b] = [3, 4]; + | ------^^^^^^^^^ + | | + | cannot assign to this expression + | + = note: destructuring assignments are not yet supported + = note: for more information, see https://github.com/rust-lang/rfcs/issues/372 + +error[E0368]: binary assignment operation `+=` cannot be applied to type `[{integer}; 2]` + --> $DIR/destructuring-assignment.rs:11:5 + | +LL | [a, b] += [3, 4]; + | ------^^^^^^^^^^ + | | + | cannot use `+=` on type `[{integer}; 2]` + | + = note: an implementation of `std::ops::AddAssign` might be missing for `[{integer}; 2]` + +error[E0067]: invalid left-hand side of assignment + --> $DIR/destructuring-assignment.rs:11:12 + | +LL | [a, b] += [3, 4]; + | ------ ^^ + | | + | cannot assign to this expression + | + = note: destructuring assignments are not yet supported + = note: for more information, see https://github.com/rust-lang/rfcs/issues/372 + +error[E0070]: invalid left-hand side of assignment + --> $DIR/destructuring-assignment.rs:16:5 + | +LL | S { x: a, y: b } = s; + | ----------------^^^^ + | | + | cannot assign to this expression + | + = note: destructuring assignments are not yet supported + = note: for more information, see https://github.com/rust-lang/rfcs/issues/372 + +error[E0368]: binary assignment operation `+=` cannot be applied to type `S` + --> $DIR/destructuring-assignment.rs:17:5 + | +LL | S { x: a, y: b } += s; + | ----------------^^^^^ + | | + | cannot use `+=` on type `S` + | + = note: an implementation of `std::ops::AddAssign` might be missing for `S` + +error[E0067]: invalid left-hand side of assignment + --> $DIR/destructuring-assignment.rs:17:22 + | +LL | S { x: a, y: b } += s; + | ---------------- ^^ + | | + | cannot assign to this expression + | + = note: destructuring assignments are not yet supported + = note: for more information, see https://github.com/rust-lang/rfcs/issues/372 + +error[E0070]: invalid left-hand side of assignment + --> $DIR/destructuring-assignment.rs:20:5 + | +LL | S { x: a, ..s } = S { x: 3, y: 4 }; + | ---------------^^^^^^^^^^^^^^^^^^^ + | | + | cannot assign to this expression + | + = note: destructuring assignments are not yet supported + = note: for more information, see https://github.com/rust-lang/rfcs/issues/372 + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0067, E0070, E0368. +For more information about an error, try `rustc --explain E0067`. From 5ab4735559aeeece0b5811dad95fdf515b1bcfbd Mon Sep 17 00:00:00 2001 From: varkor <github@varkor.com> Date: Sun, 22 Dec 2019 20:27:42 +0000 Subject: [PATCH 14/21] Recognise nested tuples/arrays/structs --- src/librustc_typeck/check/expr.rs | 25 +++++++++++-------- src/test/ui/bad/destructuring-assignment.rs | 4 +++ .../ui/bad/destructuring-assignment.stderr | 13 +++++++++- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 9085528c84e9f..13046d8002a9b 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -723,6 +723,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } + fn is_destructuring_place_expr(&self, expr: &'tcx hir::Expr) -> bool { + match &expr.kind { + ExprKind::Array(comps) | ExprKind::Tup(comps) => { + comps.iter().all(|e| self.is_destructuring_place_expr(e)) + } + ExprKind::Struct(_path, fields, rest) => { + rest.as_ref().map(|e| self.is_destructuring_place_expr(e)).unwrap_or(true) && + fields.iter().all(|f| self.is_destructuring_place_expr(&f.expr)) + } + _ => expr.is_syntactic_place_expr(), + } + } + pub(crate) fn check_lhs_assignable( &self, lhs: &'tcx hir::Expr, @@ -736,17 +749,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { DiagnosticId::Error(err_code.into()), ); err.span_label(lhs.span, "cannot assign to this expression"); - let destructuring_assignment = match &lhs.kind { - ExprKind::Array(comps) | ExprKind::Tup(comps) => { - comps.iter().all(|e| e.is_syntactic_place_expr()) - } - ExprKind::Struct(_path, fields, rest) => { - rest.as_ref().map(|e| e.is_syntactic_place_expr()).unwrap_or(true) && - fields.iter().all(|f| f.expr.is_syntactic_place_expr()) - } - _ => false, - }; - if destructuring_assignment { + if self.is_destructuring_place_expr(lhs) { err.note("destructuring assignments are not yet supported"); err.note( "for more information, see https://github.com/rust-lang/rfcs/issues/372", diff --git a/src/test/ui/bad/destructuring-assignment.rs b/src/test/ui/bad/destructuring-assignment.rs index 7112cedfd0009..876c9efea2647 100644 --- a/src/test/ui/bad/destructuring-assignment.rs +++ b/src/test/ui/bad/destructuring-assignment.rs @@ -18,4 +18,8 @@ fn main() { //~^ ERROR binary assignment operation `+=` cannot be applied S { x: a, ..s } = S { x: 3, y: 4 }; //~ ERROR invalid left-hand side of assignment + + let c = 3; + + ((a, b), c) = ((3, 4), 5); //~ ERROR invalid left-hand side of assignment } diff --git a/src/test/ui/bad/destructuring-assignment.stderr b/src/test/ui/bad/destructuring-assignment.stderr index 676576b7bc526..845008b06937c 100644 --- a/src/test/ui/bad/destructuring-assignment.stderr +++ b/src/test/ui/bad/destructuring-assignment.stderr @@ -105,7 +105,18 @@ LL | S { x: a, ..s } = S { x: 3, y: 4 }; = note: destructuring assignments are not yet supported = note: for more information, see https://github.com/rust-lang/rfcs/issues/372 -error: aborting due to 10 previous errors +error[E0070]: invalid left-hand side of assignment + --> $DIR/destructuring-assignment.rs:24:5 + | +LL | ((a, b), c) = ((3, 4), 5); + | -----------^^^^^^^^^^^^^^ + | | + | cannot assign to this expression + | + = note: destructuring assignments are not yet supported + = note: for more information, see https://github.com/rust-lang/rfcs/issues/372 + +error: aborting due to 11 previous errors Some errors have detailed explanations: E0067, E0070, E0368. For more information about an error, try `rustc --explain E0067`. From 35979a92bf6dba402885a1488ecfd84046e4bd71 Mon Sep 17 00:00:00 2001 From: varkor <github@varkor.com> Date: Sun, 22 Dec 2019 21:08:53 +0000 Subject: [PATCH 15/21] Add span information to `ExprKind::Assign` --- src/librustc/hir/intravisit.rs | 6 +++--- src/librustc/hir/lowering/expr.rs | 11 ++++++---- src/librustc/hir/mod.rs | 2 +- src/librustc/hir/print.rs | 4 ++-- src/librustc_lint/unused.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 2 +- src/librustc_parse/parser/expr.rs | 4 +++- src/librustc_passes/liveness.rs | 4 ++-- src/librustc_privacy/lib.rs | 2 +- src/librustc_typeck/check/demand.rs | 2 +- src/librustc_typeck/check/expr.rs | 8 +++++--- src/librustc_typeck/expr_use_visitor.rs | 2 +- src/libsyntax/ast.rs | 2 +- src/libsyntax/mut_visit.rs | 2 +- src/libsyntax/print/pprust.rs | 2 +- src/libsyntax/util/parser.rs | 2 +- src/libsyntax/visit.rs | 6 +++--- src/test/ui-fulldeps/pprust-expr-roundtrip.rs | 4 ++-- src/test/ui/bad/bad-expr-lhs.stderr | 16 +++++++-------- .../ui/bad/destructuring-assignment.stderr | 20 +++++++++---------- src/test/ui/error-codes/E0070.stderr | 12 +++++------ src/test/ui/issues/issue-13407.stderr | 4 ++-- src/test/ui/issues/issue-26093.stderr | 4 ++-- src/test/ui/issues/issue-34334.stderr | 4 ++-- .../assignment-expected-bool.stderr | 4 ++-- 25 files changed, 69 insertions(+), 62 deletions(-) diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index dc2008fdd9743..a7a8673d49eb1 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -1043,9 +1043,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { walk_list!(visitor, visit_label, opt_label); visitor.visit_block(block); } - ExprKind::Assign(ref left_hand_expression, ref right_hand_expression) => { - visitor.visit_expr(right_hand_expression); - visitor.visit_expr(left_hand_expression) + ExprKind::Assign(ref lhs, ref rhs, _) => { + visitor.visit_expr(rhs); + visitor.visit_expr(lhs) } ExprKind::AssignOp(_, ref left_expression, ref right_expression) => { visitor.visit_expr(right_expression); diff --git a/src/librustc/hir/lowering/expr.rs b/src/librustc/hir/lowering/expr.rs index 8939b5eef2660..8311b9168e455 100644 --- a/src/librustc/hir/lowering/expr.rs +++ b/src/librustc/hir/lowering/expr.rs @@ -122,8 +122,8 @@ impl LoweringContext<'_, '_> { self.lower_block(blk, opt_label.is_some()), self.lower_label(opt_label), ), - ExprKind::Assign(ref el, ref er) => { - hir::ExprKind::Assign(P(self.lower_expr(el)), P(self.lower_expr(er))) + ExprKind::Assign(ref el, ref er, span) => { + hir::ExprKind::Assign(P(self.lower_expr(el)), P(self.lower_expr(er)), span) } ExprKind::AssignOp(op, ref el, ref er) => hir::ExprKind::AssignOp( self.lower_binop(op), @@ -994,8 +994,11 @@ impl LoweringContext<'_, '_> { let (val_pat, val_pat_hid) = self.pat_ident(pat.span, val_ident); let val_expr = P(self.expr_ident(pat.span, val_ident, val_pat_hid)); let next_expr = P(self.expr_ident(pat.span, next_ident, next_pat_hid)); - let assign = - P(self.expr(pat.span, hir::ExprKind::Assign(next_expr, val_expr), ThinVec::new())); + let assign = P(self.expr( + pat.span, + hir::ExprKind::Assign(next_expr, val_expr, pat.span), + ThinVec::new(), + )); let some_pat = self.pat_some(pat.span, val_pat); self.arm(some_pat, assign) }; diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 4aa8c12a219ca..457851bd7ecdd 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1628,7 +1628,7 @@ pub enum ExprKind { Block(P<Block>, Option<Label>), /// An assignment (e.g., `a = foo()`). - Assign(P<Expr>, P<Expr>), + Assign(P<Expr>, P<Expr>, Span), /// An assignment with an operator. /// /// E.g., `a += 1`. diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 767e53f951901..2f3b6f82ee5ee 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1289,7 +1289,7 @@ impl<'a> State<'a> { self.ibox(0); self.print_block(&blk); } - hir::ExprKind::Assign(ref lhs, ref rhs) => { + hir::ExprKind::Assign(ref lhs, ref rhs, _) => { let prec = AssocOp::Assign.precedence() as i8; self.print_expr_maybe_paren(&lhs, prec + 1); self.s.space(); @@ -2265,7 +2265,7 @@ fn contains_exterior_struct_lit(value: &hir::Expr) -> bool { match value.kind { hir::ExprKind::Struct(..) => true, - hir::ExprKind::Assign(ref lhs, ref rhs) + hir::ExprKind::Assign(ref lhs, ref rhs, _) | hir::ExprKind::AssignOp(_, ref lhs, ref rhs) | hir::ExprKind::Binary(_, ref lhs, ref rhs) => { // `X { y: 1 } + X { y: 2 }` diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 6bdb77bb804f4..5f57aabe8d426 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -490,7 +490,7 @@ impl EarlyLintPass for UnusedParens { (value, "`return` value", false, Some(left), None) } - Assign(_, ref value) => (value, "assigned value", false, None, None), + Assign(_, ref value, _) => (value, "assigned value", false, None, None), AssignOp(.., ref value) => (value, "assigned value", false, None, None), // either function/method call, or something this lint doesn't care about ref call_or_other => { diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index bfeb3c40e28e8..b5cd24bebc33a 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -227,7 +227,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr hir::ExprKind::Block(ref blk, _) => ExprKind::Block { body: &blk }, - hir::ExprKind::Assign(ref lhs, ref rhs) => { + hir::ExprKind::Assign(ref lhs, ref rhs, _) => { ExprKind::Assign { lhs: lhs.to_ref(), rhs: rhs.to_ref() } } diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index fa68ddf272a84..e0eb841f2c0cf 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -281,7 +281,9 @@ impl<'a> Parser<'a> { let binary = self.mk_binary(source_map::respan(cur_op_span, ast_op), lhs, rhs); self.mk_expr(span, binary, AttrVec::new()) } - AssocOp::Assign => self.mk_expr(span, ExprKind::Assign(lhs, rhs), AttrVec::new()), + AssocOp::Assign => { + self.mk_expr(span, ExprKind::Assign(lhs, rhs, cur_op_span), AttrVec::new()) + } AssocOp::AssignOp(k) => { let aop = match k { token::Plus => BinOpKind::Add, diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs index de532421bfb03..1a8abeb7abcdc 100644 --- a/src/librustc_passes/liveness.rs +++ b/src/librustc_passes/liveness.rs @@ -1079,7 +1079,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { .unwrap_or_else(|| span_bug!(expr.span, "continue to unknown label")) } - hir::ExprKind::Assign(ref l, ref r) => { + hir::ExprKind::Assign(ref l, ref r, _) => { // see comment on places in // propagate_through_place_components() let succ = self.write_place(&l, succ, ACC_WRITE); @@ -1373,7 +1373,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> { fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr) { match expr.kind { - hir::ExprKind::Assign(ref l, _) => { + hir::ExprKind::Assign(ref l, ..) => { this.check_place(&l); } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index f7e48907e0141..cdfcb8090e65e 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -1251,7 +1251,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { return; } match expr.kind { - hir::ExprKind::Assign(.., ref rhs) | hir::ExprKind::Match(ref rhs, ..) => { + hir::ExprKind::Assign(_, ref rhs, _) | hir::ExprKind::Match(ref rhs, ..) => { // Do not report duplicate errors for `x = y` and `match x { ... }`. if self.check_expr_pat_type(rhs.hir_id, rhs.span) { return; diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 944b4f8fe56f0..d63d30b7b8d83 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -492,7 +492,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { String::new() }; if let Some(hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Assign(left_expr, _), + kind: hir::ExprKind::Assign(left_expr, ..), .. })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id)) { diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 13046d8002a9b..1ff2ea19b7c14 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -219,7 +219,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::Box(ref subexpr) => self.check_expr_box(subexpr, expected), ExprKind::Lit(ref lit) => self.check_lit(&lit, expected), ExprKind::Binary(op, ref lhs, ref rhs) => self.check_binop(expr, op, lhs, rhs), - ExprKind::AssignOp(op, ref lhs, ref rhs) => self.check_binop_assign(expr, op, lhs, rhs), + ExprKind::Assign(ref lhs, ref rhs, ref span) => { + self.check_binop_assign(expr, op, lhs, rhs) + } ExprKind::Unary(unop, ref oprnd) => { self.check_expr_unary(unop, oprnd, expected, needs, expr) } @@ -245,7 +247,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr), - ExprKind::Assign(ref lhs, ref rhs) => self.check_expr_assign(expr, expected, lhs, rhs), ExprKind::Loop(ref body, _, source) => { self.check_expr_loop(body, source, expected, expr) } @@ -767,6 +768,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Expectation<'tcx>, lhs: &'tcx hir::Expr, rhs: &'tcx hir::Expr, + span: &Span, ) -> Ty<'tcx> { let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace); let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty); @@ -789,7 +791,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } err.emit(); } else { - self.check_lhs_assignable(lhs, "E0070", &expr.span); + self.check_lhs_assignable(lhs, "E0070", span); } self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized); diff --git a/src/librustc_typeck/expr_use_visitor.rs b/src/librustc_typeck/expr_use_visitor.rs index 58baf24438bd0..6c7e3658365a0 100644 --- a/src/librustc_typeck/expr_use_visitor.rs +++ b/src/librustc_typeck/expr_use_visitor.rs @@ -286,7 +286,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } } - hir::ExprKind::Assign(ref lhs, ref rhs) => { + hir::ExprKind::Assign(ref lhs, ref rhs, _) => { self.mutate_expr(lhs); self.consume_expr(rhs); } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 9009faa544004..c00fc761a6a25 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1216,7 +1216,7 @@ pub enum ExprKind { TryBlock(P<Block>), /// An assignment (`a = foo()`). - Assign(P<Expr>, P<Expr>), + Assign(P<Expr>, P<Expr>, Span), /// An assignment with an operator. /// /// E.g., `a += 1`. diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 780323d114eda..f6817c713a4a6 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -1168,7 +1168,7 @@ pub fn noop_visit_expr<T: MutVisitor>(Expr { kind, id, span, attrs }: &mut Expr, vis.visit_block(body); } ExprKind::Await(expr) => vis.visit_expr(expr), - ExprKind::Assign(el, er) => { + ExprKind::Assign(el, er, _) => { vis.visit_expr(el); vis.visit_expr(er); } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index dc01f2472b7f0..b1b667f03bee2 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2041,7 +2041,7 @@ impl<'a> State<'a> { self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX); self.s.word(".await"); } - ast::ExprKind::Assign(ref lhs, ref rhs) => { + ast::ExprKind::Assign(ref lhs, ref rhs, _) => { let prec = AssocOp::Assign.precedence() as i8; self.print_expr_maybe_paren(lhs, prec + 1); self.s.space(); diff --git a/src/libsyntax/util/parser.rs b/src/libsyntax/util/parser.rs index 88e3d8daf7047..98af382efb083 100644 --- a/src/libsyntax/util/parser.rs +++ b/src/libsyntax/util/parser.rs @@ -378,7 +378,7 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool { match value.kind { ast::ExprKind::Struct(..) => true, - ast::ExprKind::Assign(ref lhs, ref rhs) + ast::ExprKind::Assign(ref lhs, ref rhs, _) | ast::ExprKind::AssignOp(_, ref lhs, ref rhs) | ast::ExprKind::Binary(_, ref lhs, ref rhs) => { // X { y: 1 } + X { y: 2 } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index d6573a06647d1..fbc5d1332490f 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -766,9 +766,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { visitor.visit_block(body); } ExprKind::Await(ref expr) => visitor.visit_expr(expr), - ExprKind::Assign(ref left_hand_expression, ref right_hand_expression) => { - visitor.visit_expr(left_hand_expression); - visitor.visit_expr(right_hand_expression); + ExprKind::Assign(ref lhs, ref rhs, _) => { + visitor.visit_expr(lhs); + visitor.visit_expr(rhs); } ExprKind::AssignOp(_, ref left_expression, ref right_expression) => { visitor.visit_expr(left_expression); diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs index 0c050e314133e..36d47cea13b07 100644 --- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs @@ -126,8 +126,8 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) { DUMMY_SP))); }, 12 => { - iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(e, make_x()))); - iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(make_x(), e))); + iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(e, make_x(), DUMMY_SP))); + iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(make_x(), e, DUMMY_SP))); }, 13 => { iter_exprs(depth - 1, &mut |e| g(ExprKind::Field(e, Ident::from_str("f")))); diff --git a/src/test/ui/bad/bad-expr-lhs.stderr b/src/test/ui/bad/bad-expr-lhs.stderr index 61c25bb471c37..ce793d8910b13 100644 --- a/src/test/ui/bad/bad-expr-lhs.stderr +++ b/src/test/ui/bad/bad-expr-lhs.stderr @@ -1,8 +1,8 @@ error[E0070]: invalid left-hand side of assignment - --> $DIR/bad-expr-lhs.rs:2:5 + --> $DIR/bad-expr-lhs.rs:2:7 | LL | 1 = 2; - | -^^^^ + | - ^ | | | cannot assign to this expression @@ -15,18 +15,18 @@ LL | 1 += 2; | cannot assign to this expression error[E0070]: invalid left-hand side of assignment - --> $DIR/bad-expr-lhs.rs:4:5 + --> $DIR/bad-expr-lhs.rs:4:12 | LL | (1, 2) = (3, 4); - | ------^^^^^^^^^ + | ------ ^ | | | cannot assign to this expression error[E0070]: invalid left-hand side of assignment - --> $DIR/bad-expr-lhs.rs:7:5 + --> $DIR/bad-expr-lhs.rs:7:12 | LL | (a, b) = (3, 4); - | ------^^^^^^^^^ + | ------ ^ | | | cannot assign to this expression | @@ -34,10 +34,10 @@ LL | (a, b) = (3, 4); = note: for more information, see https://github.com/rust-lang/rfcs/issues/372 error[E0070]: invalid left-hand side of assignment - --> $DIR/bad-expr-lhs.rs:9:5 + --> $DIR/bad-expr-lhs.rs:9:10 | LL | None = Some(3); - | ----^^^^^^^^^^ + | ---- ^ | | | cannot assign to this expression diff --git a/src/test/ui/bad/destructuring-assignment.stderr b/src/test/ui/bad/destructuring-assignment.stderr index 845008b06937c..3e0925b565806 100644 --- a/src/test/ui/bad/destructuring-assignment.stderr +++ b/src/test/ui/bad/destructuring-assignment.stderr @@ -1,8 +1,8 @@ error[E0070]: invalid left-hand side of assignment - --> $DIR/destructuring-assignment.rs:6:5 + --> $DIR/destructuring-assignment.rs:6:12 | LL | (a, b) = (3, 4); - | ------^^^^^^^^^ + | ------ ^ | | | cannot assign to this expression | @@ -31,10 +31,10 @@ LL | (a, b) += (3, 4); = note: for more information, see https://github.com/rust-lang/rfcs/issues/372 error[E0070]: invalid left-hand side of assignment - --> $DIR/destructuring-assignment.rs:10:5 + --> $DIR/destructuring-assignment.rs:10:12 | LL | [a, b] = [3, 4]; - | ------^^^^^^^^^ + | ------ ^ | | | cannot assign to this expression | @@ -63,10 +63,10 @@ LL | [a, b] += [3, 4]; = note: for more information, see https://github.com/rust-lang/rfcs/issues/372 error[E0070]: invalid left-hand side of assignment - --> $DIR/destructuring-assignment.rs:16:5 + --> $DIR/destructuring-assignment.rs:16:22 | LL | S { x: a, y: b } = s; - | ----------------^^^^ + | ---------------- ^ | | | cannot assign to this expression | @@ -95,10 +95,10 @@ LL | S { x: a, y: b } += s; = note: for more information, see https://github.com/rust-lang/rfcs/issues/372 error[E0070]: invalid left-hand side of assignment - --> $DIR/destructuring-assignment.rs:20:5 + --> $DIR/destructuring-assignment.rs:20:21 | LL | S { x: a, ..s } = S { x: 3, y: 4 }; - | ---------------^^^^^^^^^^^^^^^^^^^ + | --------------- ^ | | | cannot assign to this expression | @@ -106,10 +106,10 @@ LL | S { x: a, ..s } = S { x: 3, y: 4 }; = note: for more information, see https://github.com/rust-lang/rfcs/issues/372 error[E0070]: invalid left-hand side of assignment - --> $DIR/destructuring-assignment.rs:24:5 + --> $DIR/destructuring-assignment.rs:24:17 | LL | ((a, b), c) = ((3, 4), 5); - | -----------^^^^^^^^^^^^^^ + | ----------- ^ | | | cannot assign to this expression | diff --git a/src/test/ui/error-codes/E0070.stderr b/src/test/ui/error-codes/E0070.stderr index 1fb812d94672f..d809bb18dee16 100644 --- a/src/test/ui/error-codes/E0070.stderr +++ b/src/test/ui/error-codes/E0070.stderr @@ -1,16 +1,16 @@ error[E0070]: invalid left-hand side of assignment - --> $DIR/E0070.rs:6:5 + --> $DIR/E0070.rs:6:16 | LL | SOME_CONST = 14; - | ----------^^^^^ + | ---------- ^ | | | cannot assign to this expression error[E0070]: invalid left-hand side of assignment - --> $DIR/E0070.rs:7:5 + --> $DIR/E0070.rs:7:7 | LL | 1 = 3; - | -^^^^ + | - ^ | | | cannot assign to this expression @@ -21,10 +21,10 @@ LL | some_other_func() = 4; | ^ expected `()`, found integer error[E0070]: invalid left-hand side of assignment - --> $DIR/E0070.rs:8:5 + --> $DIR/E0070.rs:8:23 | LL | some_other_func() = 4; - | -----------------^^^^ + | ----------------- ^ | | | cannot assign to this expression diff --git a/src/test/ui/issues/issue-13407.stderr b/src/test/ui/issues/issue-13407.stderr index 05fd97b025f60..b280de3158fed 100644 --- a/src/test/ui/issues/issue-13407.stderr +++ b/src/test/ui/issues/issue-13407.stderr @@ -11,10 +11,10 @@ LL | A::C = 1; | ^ expected struct `A::C`, found integer error[E0070]: invalid left-hand side of assignment - --> $DIR/issue-13407.rs:6:5 + --> $DIR/issue-13407.rs:6:10 | LL | A::C = 1; - | ----^^^^ + | ---- ^ | | | cannot assign to this expression diff --git a/src/test/ui/issues/issue-26093.stderr b/src/test/ui/issues/issue-26093.stderr index 48f72cef0a85a..c96228b518a85 100644 --- a/src/test/ui/issues/issue-26093.stderr +++ b/src/test/ui/issues/issue-26093.stderr @@ -1,8 +1,8 @@ error[E0070]: invalid left-hand side of assignment - --> $DIR/issue-26093.rs:3:9 + --> $DIR/issue-26093.rs:3:16 | LL | $thing = 42; - | ^^^^^^^^^^^ + | ^ ... LL | not_a_place!(99); | ----------------- diff --git a/src/test/ui/issues/issue-34334.stderr b/src/test/ui/issues/issue-34334.stderr index e54f0c77cd973..3055e316a082a 100644 --- a/src/test/ui/issues/issue-34334.stderr +++ b/src/test/ui/issues/issue-34334.stderr @@ -36,10 +36,10 @@ LL | let sr: Vec<(u32, _, _) = vec![]; = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error[E0070]: invalid left-hand side of assignment - --> $DIR/issue-34334.rs:2:13 + --> $DIR/issue-34334.rs:2:29 | LL | let sr: Vec<(u32, _, _) = vec![]; - | ---------------^^^^^^^^^ + | --------------- ^ | | | cannot assign to this expression diff --git a/src/test/ui/type/type-check/assignment-expected-bool.stderr b/src/test/ui/type/type-check/assignment-expected-bool.stderr index bbd961f845016..3f1caddf728cb 100644 --- a/src/test/ui/type/type-check/assignment-expected-bool.stderr +++ b/src/test/ui/type/type-check/assignment-expected-bool.stderr @@ -98,10 +98,10 @@ LL | || (0 = 0); | help: try comparing for equality: `0 == 0` error[E0070]: invalid left-hand side of assignment - --> $DIR/assignment-expected-bool.rs:31:20 + --> $DIR/assignment-expected-bool.rs:31:22 | LL | let _: usize = 0 = 0; - | -^^^^ + | - ^ | | | cannot assign to this expression From 9a602243c422f183f574ff53e5d3e9e85fcc1210 Mon Sep 17 00:00:00 2001 From: varkor <github@varkor.com> Date: Sun, 22 Dec 2019 23:09:54 +0000 Subject: [PATCH 16/21] Add new folder for destructuring assignment tests --- src/librustc/hir/mod.rs | 1 + src/librustc_typeck/check/expr.rs | 2 +- src/libsyntax/ast.rs | 1 + src/test/ui/bad/bad-expr-lhs.stderr | 2 +- .../note-unsupported.rs} | 0 .../note-unsupported.stderr} | 38 +++++++++---------- 6 files changed, 23 insertions(+), 21 deletions(-) rename src/test/ui/{bad/destructuring-assignment.rs => destructuring-assignment/note-unsupported.rs} (100%) rename src/test/ui/{bad/destructuring-assignment.stderr => destructuring-assignment/note-unsupported.stderr} (76%) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 457851bd7ecdd..3c7860ae02fe7 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1628,6 +1628,7 @@ pub enum ExprKind { Block(P<Block>, Option<Label>), /// An assignment (e.g., `a = foo()`). + /// The `Span` argument is the span of the `=` token. Assign(P<Expr>, P<Expr>, Span), /// An assignment with an operator. /// diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 1ff2ea19b7c14..542c2b16c602e 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -751,7 +751,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); err.span_label(lhs.span, "cannot assign to this expression"); if self.is_destructuring_place_expr(lhs) { - err.note("destructuring assignments are not yet supported"); + err.note("destructuring assignments are not currently supported"); err.note( "for more information, see https://github.com/rust-lang/rfcs/issues/372", ); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index c00fc761a6a25..c98942abaf3c2 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1216,6 +1216,7 @@ pub enum ExprKind { TryBlock(P<Block>), /// An assignment (`a = foo()`). + /// The `Span` argument is the span of the `=` token. Assign(P<Expr>, P<Expr>, Span), /// An assignment with an operator. /// diff --git a/src/test/ui/bad/bad-expr-lhs.stderr b/src/test/ui/bad/bad-expr-lhs.stderr index ce793d8910b13..a195e1054d099 100644 --- a/src/test/ui/bad/bad-expr-lhs.stderr +++ b/src/test/ui/bad/bad-expr-lhs.stderr @@ -30,7 +30,7 @@ LL | (a, b) = (3, 4); | | | cannot assign to this expression | - = note: destructuring assignments are not yet supported + = note: destructuring assignments are not currently supported = note: for more information, see https://github.com/rust-lang/rfcs/issues/372 error[E0070]: invalid left-hand side of assignment diff --git a/src/test/ui/bad/destructuring-assignment.rs b/src/test/ui/destructuring-assignment/note-unsupported.rs similarity index 100% rename from src/test/ui/bad/destructuring-assignment.rs rename to src/test/ui/destructuring-assignment/note-unsupported.rs diff --git a/src/test/ui/bad/destructuring-assignment.stderr b/src/test/ui/destructuring-assignment/note-unsupported.stderr similarity index 76% rename from src/test/ui/bad/destructuring-assignment.stderr rename to src/test/ui/destructuring-assignment/note-unsupported.stderr index 3e0925b565806..a6805c32a6e52 100644 --- a/src/test/ui/bad/destructuring-assignment.stderr +++ b/src/test/ui/destructuring-assignment/note-unsupported.stderr @@ -1,16 +1,16 @@ error[E0070]: invalid left-hand side of assignment - --> $DIR/destructuring-assignment.rs:6:12 + --> $DIR/note-unsupported.rs:6:12 | LL | (a, b) = (3, 4); | ------ ^ | | | cannot assign to this expression | - = note: destructuring assignments are not yet supported + = note: destructuring assignments are not currently supported = note: for more information, see https://github.com/rust-lang/rfcs/issues/372 error[E0368]: binary assignment operation `+=` cannot be applied to type `({integer}, {integer})` - --> $DIR/destructuring-assignment.rs:7:5 + --> $DIR/note-unsupported.rs:7:5 | LL | (a, b) += (3, 4); | ------^^^^^^^^^^ @@ -20,29 +20,29 @@ LL | (a, b) += (3, 4); = note: an implementation of `std::ops::AddAssign` might be missing for `({integer}, {integer})` error[E0067]: invalid left-hand side of assignment - --> $DIR/destructuring-assignment.rs:7:12 + --> $DIR/note-unsupported.rs:7:12 | LL | (a, b) += (3, 4); | ------ ^^ | | | cannot assign to this expression | - = note: destructuring assignments are not yet supported + = note: destructuring assignments are not currently supported = note: for more information, see https://github.com/rust-lang/rfcs/issues/372 error[E0070]: invalid left-hand side of assignment - --> $DIR/destructuring-assignment.rs:10:12 + --> $DIR/note-unsupported.rs:10:12 | LL | [a, b] = [3, 4]; | ------ ^ | | | cannot assign to this expression | - = note: destructuring assignments are not yet supported + = note: destructuring assignments are not currently supported = note: for more information, see https://github.com/rust-lang/rfcs/issues/372 error[E0368]: binary assignment operation `+=` cannot be applied to type `[{integer}; 2]` - --> $DIR/destructuring-assignment.rs:11:5 + --> $DIR/note-unsupported.rs:11:5 | LL | [a, b] += [3, 4]; | ------^^^^^^^^^^ @@ -52,29 +52,29 @@ LL | [a, b] += [3, 4]; = note: an implementation of `std::ops::AddAssign` might be missing for `[{integer}; 2]` error[E0067]: invalid left-hand side of assignment - --> $DIR/destructuring-assignment.rs:11:12 + --> $DIR/note-unsupported.rs:11:12 | LL | [a, b] += [3, 4]; | ------ ^^ | | | cannot assign to this expression | - = note: destructuring assignments are not yet supported + = note: destructuring assignments are not currently supported = note: for more information, see https://github.com/rust-lang/rfcs/issues/372 error[E0070]: invalid left-hand side of assignment - --> $DIR/destructuring-assignment.rs:16:22 + --> $DIR/note-unsupported.rs:16:22 | LL | S { x: a, y: b } = s; | ---------------- ^ | | | cannot assign to this expression | - = note: destructuring assignments are not yet supported + = note: destructuring assignments are not currently supported = note: for more information, see https://github.com/rust-lang/rfcs/issues/372 error[E0368]: binary assignment operation `+=` cannot be applied to type `S` - --> $DIR/destructuring-assignment.rs:17:5 + --> $DIR/note-unsupported.rs:17:5 | LL | S { x: a, y: b } += s; | ----------------^^^^^ @@ -84,36 +84,36 @@ LL | S { x: a, y: b } += s; = note: an implementation of `std::ops::AddAssign` might be missing for `S` error[E0067]: invalid left-hand side of assignment - --> $DIR/destructuring-assignment.rs:17:22 + --> $DIR/note-unsupported.rs:17:22 | LL | S { x: a, y: b } += s; | ---------------- ^^ | | | cannot assign to this expression | - = note: destructuring assignments are not yet supported + = note: destructuring assignments are not currently supported = note: for more information, see https://github.com/rust-lang/rfcs/issues/372 error[E0070]: invalid left-hand side of assignment - --> $DIR/destructuring-assignment.rs:20:21 + --> $DIR/note-unsupported.rs:20:21 | LL | S { x: a, ..s } = S { x: 3, y: 4 }; | --------------- ^ | | | cannot assign to this expression | - = note: destructuring assignments are not yet supported + = note: destructuring assignments are not currently supported = note: for more information, see https://github.com/rust-lang/rfcs/issues/372 error[E0070]: invalid left-hand side of assignment - --> $DIR/destructuring-assignment.rs:24:17 + --> $DIR/note-unsupported.rs:24:17 | LL | ((a, b), c) = ((3, 4), 5); | ----------- ^ | | | cannot assign to this expression | - = note: destructuring assignments are not yet supported + = note: destructuring assignments are not currently supported = note: for more information, see https://github.com/rust-lang/rfcs/issues/372 error: aborting due to 11 previous errors From dd7f49301eaf1b9783ee695a7ac43af69a0f4768 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad <twingoow@gmail.com> Date: Sun, 22 Dec 2019 20:53:30 +0100 Subject: [PATCH 17/21] is_range_literal: fix fallout --- src/librustc/hir/mod.rs | 21 +++++++++------------ src/librustc_lint/types.rs | 7 +++---- src/librustc_typeck/check/demand.rs | 6 ++---- 3 files changed, 14 insertions(+), 20 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 55a30a7cc3a19..b4c51cca4d24d 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -29,10 +29,10 @@ use syntax::ast::{AttrVec, Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, pub use syntax::ast::{BorrowKind, ImplPolarity, IsAuto}; pub use syntax::ast::{CaptureBy, Constness, Movability, Mutability, Unsafety}; use syntax::attr::{InlineAttr, OptimizeAttr}; -use syntax::source_map::Spanned; -use syntax::symbol::{kw, Symbol}; use syntax::tokenstream::TokenStream; use syntax::util::parser::ExprPrecedence; +use syntax_pos::source_map::{SourceMap, Spanned}; +use syntax_pos::symbol::{kw, sym, Symbol}; use syntax_pos::{MultiSpan, Span, DUMMY_SP}; /// HIR doesn't commit to a concrete storage type and has its own alias for a vector. @@ -1566,9 +1566,7 @@ impl fmt::Debug for Expr { /// Checks if the specified expression is a built-in range literal. /// (See: `LoweringContext::lower_expr()`). -pub fn is_range_literal(sess: &Session, expr: &hir::Expr) -> bool { - use hir::{Path, QPath, ExprKind, TyKind}; - +pub fn is_range_literal(sm: &SourceMap, expr: &Expr) -> bool { // Returns whether the given path represents a (desugared) range, // either in std or core, i.e. has either a `::std::ops::Range` or // `::core::ops::Range` prefix. @@ -1586,11 +1584,10 @@ pub fn is_range_literal(sess: &Session, expr: &hir::Expr) -> bool { // Check whether a span corresponding to a range expression is a // range literal, rather than an explicit struct or `new()` call. - fn is_lit(sess: &Session, span: &Span) -> bool { - let source_map = sess.source_map(); - let end_point = source_map.end_point(*span); + fn is_lit(sm: &SourceMap, span: &Span) -> bool { + let end_point = sm.end_point(*span); - if let Ok(end_string) = source_map.span_to_snippet(end_point) { + if let Ok(end_string) = sm.span_to_snippet(end_point) { !(end_string.ends_with("}") || end_string.ends_with(")")) } else { false @@ -1601,13 +1598,13 @@ pub fn is_range_literal(sess: &Session, expr: &hir::Expr) -> bool { // All built-in range literals but `..=` and `..` desugar to `Struct`s. ExprKind::Struct(ref qpath, _, _) => { if let QPath::Resolved(None, ref path) = **qpath { - return is_range_path(&path) && is_lit(sess, &expr.span); + return is_range_path(&path) && is_lit(sm, &expr.span); } } // `..` desugars to its struct path. ExprKind::Path(QPath::Resolved(None, ref path)) => { - return is_range_path(&path) && is_lit(sess, &expr.span); + return is_range_path(&path) && is_lit(sm, &expr.span); } // `..=` desugars into `::std::ops::RangeInclusive::new(...)`. @@ -1615,7 +1612,7 @@ pub fn is_range_literal(sess: &Session, expr: &hir::Expr) -> bool { if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.kind { if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.kind { let new_call = segment.ident.name == sym::new; - return is_range_path(&path) && is_lit(sess, &expr.span) && new_call; + return is_range_path(&path) && is_lit(sm, &expr.span) && new_call; } } } diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 8c9279d025d80..45b8666c42b45 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -3,8 +3,7 @@ use crate::hir::def_id::DefId; use lint::{LateContext, LintArray, LintContext}; use lint::{LateLintPass, LintPass}; -use rustc::hir::lowering::is_range_literal; -use rustc::hir::{ExprKind, Node}; +use rustc::hir::{is_range_literal, ExprKind, Node}; use rustc::ty::layout::{self, IntegerExt, LayoutOf, SizeSkeleton, VariantIdx}; use rustc::ty::subst::SubstsRef; use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt}; @@ -266,7 +265,7 @@ fn lint_int_literal<'a, 'tcx>( let par_id = cx.tcx.hir().get_parent_node(e.hir_id); if let Node::Expr(par_e) = cx.tcx.hir().get(par_id) { if let hir::ExprKind::Struct(..) = par_e.kind { - if is_range_literal(cx.sess(), par_e) + if is_range_literal(cx.sess().source_map(), par_e) && lint_overflowing_range_endpoint(cx, lit, v, max, e, par_e, t.name_str()) { // The overflowing literal lint was overridden. @@ -318,7 +317,7 @@ fn lint_uint_literal<'a, 'tcx>( return; } } - hir::ExprKind::Struct(..) if is_range_literal(cx.sess(), par_e) => { + hir::ExprKind::Struct(..) if is_range_literal(cx.sess().source_map(), par_e) => { let t = t.name_str(); if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, par_e, t) { // The overflowing literal lint was overridden. diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 944b4f8fe56f0..3a25786365b48 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -3,9 +3,7 @@ use rustc::infer::InferOk; use rustc::traits::{self, ObligationCause, ObligationCauseCode}; use errors::{Applicability, DiagnosticBuilder}; -use rustc::hir; -use rustc::hir::Node; -use rustc::hir::{lowering::is_range_literal, print}; +use rustc::hir::{self, is_range_literal, print, Node}; use rustc::ty::adjustment::AllowTwoPhase; use rustc::ty::{self, AssocItem, Ty}; use syntax::symbol::sym; @@ -478,7 +476,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // parenthesize if needed (Issue #46756) hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true, // parenthesize borrows of range literals (Issue #54505) - _ if is_range_literal(self.tcx.sess, expr) => true, + _ if is_range_literal(self.tcx.sess.source_map(), expr) => true, _ => false, }; let sugg_expr = if needs_parens { format!("({})", src) } else { src }; From 4bb83468a202c7402de529199dd363db5f307f33 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad <twingoow@gmail.com> Date: Sun, 22 Dec 2019 20:55:27 +0100 Subject: [PATCH 18/21] is_range_literal: leave FIXME --- src/librustc/hir/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index b4c51cca4d24d..915b0afc48fcb 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1566,6 +1566,9 @@ impl fmt::Debug for Expr { /// Checks if the specified expression is a built-in range literal. /// (See: `LoweringContext::lower_expr()`). +/// +/// FIXME(#60607): This function is a hack. If and when we have `QPath::Lang(...)`, +/// we can use that instead as simpler, more reliable mechanism, as opposed to using `SourceMap`. pub fn is_range_literal(sm: &SourceMap, expr: &Expr) -> bool { // Returns whether the given path represents a (desugared) range, // either in std or core, i.e. has either a `::std::ops::Range` or From 9e5081394cac4429de287e6c10b350f698a97f65 Mon Sep 17 00:00:00 2001 From: varkor <github@varkor.com> Date: Mon, 23 Dec 2019 12:39:48 +0000 Subject: [PATCH 19/21] Fix reformatting rebase issues --- src/librustc_typeck/check/expr.rs | 11 +++++------ src/librustc_typeck/check/op.rs | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 542c2b16c602e..5c602ad76cd32 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -220,8 +220,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::Lit(ref lit) => self.check_lit(&lit, expected), ExprKind::Binary(op, ref lhs, ref rhs) => self.check_binop(expr, op, lhs, rhs), ExprKind::Assign(ref lhs, ref rhs, ref span) => { - self.check_binop_assign(expr, op, lhs, rhs) + self.check_expr_assign(expr, expected, lhs, rhs, span) } + ExprKind::AssignOp(op, ref lhs, ref rhs) => self.check_binop_assign(expr, op, lhs, rhs), ExprKind::Unary(unop, ref oprnd) => { self.check_expr_unary(unop, oprnd, expected, needs, expr) } @@ -730,8 +731,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { comps.iter().all(|e| self.is_destructuring_place_expr(e)) } ExprKind::Struct(_path, fields, rest) => { - rest.as_ref().map(|e| self.is_destructuring_place_expr(e)).unwrap_or(true) && - fields.iter().all(|f| self.is_destructuring_place_expr(&f.expr)) + rest.as_ref().map(|e| self.is_destructuring_place_expr(e)).unwrap_or(true) + && fields.iter().all(|f| self.is_destructuring_place_expr(&f.expr)) } _ => expr.is_syntactic_place_expr(), } @@ -752,9 +753,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(lhs.span, "cannot assign to this expression"); if self.is_destructuring_place_expr(lhs) { err.note("destructuring assignments are not currently supported"); - err.note( - "for more information, see https://github.com/rust-lang/rfcs/issues/372", - ); + err.note("for more information, see https://github.com/rust-lang/rfcs/issues/372"); } err.emit(); } diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index dfa55e324a625..c5d3aac136bcb 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -26,8 +26,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_overloaded_binop(expr, lhs, rhs, op, IsAssign::Yes); let ty = - if !lhs.is_ty_var() && !rhs.is_ty_var() && is_builtin_binop(lhs, rhs, op) { - self.enforce_builtin_binop_types(lhs_expr, lhs, rhs_expr, rhs, op); + if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) { + self.enforce_builtin_binop_types(lhs, lhs_ty, rhs, rhs_ty, op); self.tcx.mk_unit() } else { return_ty From a08df28a6fdb5a2c781f01082e630faa2d7ccde9 Mon Sep 17 00:00:00 2001 From: Mark Rousskov <mark.simulacrum@gmail.com> Date: Mon, 23 Dec 2019 08:13:12 -0500 Subject: [PATCH 20/21] Document that calling Drop, even after it panics, is UB --- src/libcore/ops/drop.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libcore/ops/drop.rs b/src/libcore/ops/drop.rs index eae63ea2390a8..5233b475c4646 100644 --- a/src/libcore/ops/drop.rs +++ b/src/libcore/ops/drop.rs @@ -99,9 +99,15 @@ pub trait Drop { /// Given that a [`panic!`] will call `drop` as it unwinds, any [`panic!`] /// in a `drop` implementation will likely abort. /// + /// Note that even if this panics, the value is considered to be dropped; + /// you must not cause `drop` to be called again. This is normally automatically + /// handled by the compiler, but when using unsafe code, can sometimes occur + /// unintentionally, particularly when using [`std::ptr::drop_in_place`]. + /// /// [E0040]: ../../error-index.html#E0040 /// [`panic!`]: ../macro.panic.html /// [`std::mem::drop`]: ../../std/mem/fn.drop.html + /// [`std::ptr::drop_in_place`]: ../../std/ptr/fn.drop_in_place.html #[stable(feature = "rust1", since = "1.0.0")] fn drop(&mut self); } From 63d28221c62be5c63d6df4ac83043d9cacd2a226 Mon Sep 17 00:00:00 2001 From: Oliver Scherer <github35764891676564198441@oli-obk.de> Date: Mon, 23 Dec 2019 15:11:09 +0100 Subject: [PATCH 21/21] Fix typo --- src/libcore/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 544fd4fb99fa1..6481789c1dd00 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1337,7 +1337,7 @@ extern "rust-intrinsic" { /// Performs rotate right. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `rotate_right` method. For example, - /// [`std::u32::rotate_right`](../../std/primitive.u32.html#method.rotate_right + /// [`std::u32::rotate_right`](../../std/primitive.u32.html#method.rotate_right) #[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")] pub fn rotate_right<T>(x: T, y: T) -> T;