From c5975e9b6c5781b3b7300b7921c14b060086e1c1 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Tue, 4 Aug 2020 16:10:11 +0800 Subject: [PATCH 01/28] Reduce duplicate in liballoc reserve error handling --- library/alloc/src/raw_vec.rs | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 99ac027bf0b9f..59e8bb087217d 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -303,11 +303,7 @@ impl RawVec { /// # } /// ``` pub fn reserve(&mut self, len: usize, additional: usize) { - match self.try_reserve(len, additional) { - Err(CapacityOverflow) => capacity_overflow(), - Err(AllocError { layout, .. }) => handle_alloc_error(layout), - Ok(()) => { /* yay */ } - } + handle_reserve(self.try_reserve(len, additional)); } /// The same as `reserve`, but returns on errors instead of panicking or aborting. @@ -337,11 +333,7 @@ impl RawVec { /// /// Aborts on OOM. pub fn reserve_exact(&mut self, len: usize, additional: usize) { - match self.try_reserve_exact(len, additional) { - Err(CapacityOverflow) => capacity_overflow(), - Err(AllocError { layout, .. }) => handle_alloc_error(layout), - Ok(()) => { /* yay */ } - } + handle_reserve(self.try_reserve_exact(len, additional)); } /// The same as `reserve_exact`, but returns on errors instead of panicking or aborting. @@ -364,11 +356,7 @@ impl RawVec { /// /// Aborts on OOM. pub fn shrink_to_fit(&mut self, amount: usize) { - match self.shrink(amount) { - Err(CapacityOverflow) => capacity_overflow(), - Err(AllocError { layout, .. }) => handle_alloc_error(layout), - Ok(()) => { /* yay */ } - } + handle_reserve(self.shrink(amount)); } } @@ -510,6 +498,16 @@ unsafe impl<#[may_dangle] T, A: AllocRef> Drop for RawVec { } } +// Central function for reserve error handling. +#[inline] +fn handle_reserve(result: Result<(), TryReserveError>) { + match result { + Err(CapacityOverflow) => capacity_overflow(), + Err(AllocError { layout, .. }) => handle_alloc_error(layout), + Ok(()) => { /* yay */ } + } +} + // We need to guarantee the following: // * We don't ever allocate `> isize::MAX` byte-size objects. // * We don't overflow `usize::MAX` and actually allocate too little. From 28db5214d2c48e7a58cf79b9e272097260910a33 Mon Sep 17 00:00:00 2001 From: Federico Ponzi Date: Wed, 2 Sep 2020 23:25:09 +0200 Subject: [PATCH 02/28] More implementations of Write for immutable refs Fixes #73836 --- library/std/src/io/stdio.rs | 54 +++++++++++++++++++++++++++++++++++++ library/std/src/io/util.rs | 24 +++++++++++++++++ library/std/src/process.rs | 19 +++++++++++++ 3 files changed, 97 insertions(+) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 3943c66aad53a..f320cf907c365 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -606,6 +606,33 @@ impl Write for Stdout { self.lock().write_fmt(args) } } + +#[stable(feature = "write_mt", since = "1.47.0")] +impl Write for &Stdout { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.lock().write(buf) + } + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + self.lock().write_vectored(bufs) + } + #[inline] + fn is_write_vectored(&self) -> bool { + self.lock().is_write_vectored() + } + fn flush(&mut self) -> io::Result<()> { + self.lock().flush() + } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + self.lock().write_all(buf) + } + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + self.lock().write_all_vectored(bufs) + } + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { + self.lock().write_fmt(args) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Write for StdoutLock<'_> { fn write(&mut self, buf: &[u8]) -> io::Result { @@ -782,6 +809,33 @@ impl Write for Stderr { self.lock().write_fmt(args) } } + +#[stable(feature = "write_mt", since = "1.47.0")] +impl Write for &Stderr { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.lock().write(buf) + } + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + self.lock().write_vectored(bufs) + } + #[inline] + fn is_write_vectored(&self) -> bool { + self.lock().is_write_vectored() + } + fn flush(&mut self) -> io::Result<()> { + self.lock().flush() + } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + self.lock().write_all(buf) + } + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + self.lock().write_all_vectored(bufs) + } + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { + self.lock().write_fmt(args) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Write for StderrLock<'_> { fn write(&mut self, buf: &[u8]) -> io::Result { diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index a093b745b0c13..ce4dd1dcd493d 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -248,6 +248,30 @@ impl Write for Sink { } } +#[stable(feature = "write_mt", since = "1.47.0")] +impl Write for &Sink { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + Ok(buf.len()) + } + + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + let total_len = bufs.iter().map(|b| b.len()).sum(); + Ok(total_len) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Sink { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/library/std/src/process.rs b/library/std/src/process.rs index c42bc1096528b..36521fdaec00f 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -262,6 +262,25 @@ impl Write for ChildStdin { } } +#[stable(feature = "write_mt", since = "1.47.0")] +impl Write for &ChildStdin { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.inner.write(buf) + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + self.inner.write_vectored(bufs) + } + + fn is_write_vectored(&self) -> bool { + self.inner.is_write_vectored() + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + impl AsInner for ChildStdin { fn as_inner(&self) -> &AnonPipe { &self.inner From ec7f9b927f1896c7f29c602d6b0f961c891d0941 Mon Sep 17 00:00:00 2001 From: Federico Ponzi Date: Fri, 11 Sep 2020 11:11:34 +0200 Subject: [PATCH 03/28] Deduplicates io::Write implementations --- library/std/src/io/stdio.rs | 28 ++++++++++++++-------------- library/std/src/process.rs | 8 ++++---- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index f320cf907c365..cccc0aadf9989 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -584,26 +584,26 @@ impl fmt::Debug for Stdout { #[stable(feature = "rust1", since = "1.0.0")] impl Write for Stdout { fn write(&mut self, buf: &[u8]) -> io::Result { - self.lock().write(buf) + (&*self).write(buf) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.lock().write_vectored(bufs) + (&*self).write_vectored(bufs) } #[inline] fn is_write_vectored(&self) -> bool { - self.lock().is_write_vectored() + io::Write::is_write_vectored(&&*self) } fn flush(&mut self) -> io::Result<()> { - self.lock().flush() + (&*self).flush() } fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.lock().write_all(buf) + (&*self).write_all(buf) } fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - self.lock().write_all_vectored(bufs) + (&*self).write_all_vectored(bufs) } fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { - self.lock().write_fmt(args) + (&*self).write_fmt(args) } } @@ -787,26 +787,26 @@ impl fmt::Debug for Stderr { #[stable(feature = "rust1", since = "1.0.0")] impl Write for Stderr { fn write(&mut self, buf: &[u8]) -> io::Result { - self.lock().write(buf) + (&*self).write(buf) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.lock().write_vectored(bufs) + (&*self).write_vectored(bufs) } #[inline] fn is_write_vectored(&self) -> bool { - self.lock().is_write_vectored() + io::Write::is_write_vectored(&&*self) } fn flush(&mut self) -> io::Result<()> { - self.lock().flush() + (&*self).flush() } fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.lock().write_all(buf) + (&*self).write_all(buf) } fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - self.lock().write_all_vectored(bufs) + (&*self).write_all_vectored(bufs) } fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { - self.lock().write_fmt(args) + (&*self).write_fmt(args) } } diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 36521fdaec00f..d620a720be3ab 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -246,19 +246,19 @@ pub struct ChildStdin { #[stable(feature = "process", since = "1.0.0")] impl Write for ChildStdin { fn write(&mut self, buf: &[u8]) -> io::Result { - self.inner.write(buf) + (&*self).write(buf) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.inner.write_vectored(bufs) + (&*self).write_vectored(bufs) } fn is_write_vectored(&self) -> bool { - self.inner.is_write_vectored() + io::Write::is_write_vectored(&&*self) } fn flush(&mut self) -> io::Result<()> { - Ok(()) + (&*self).flush() } } From 8f27e3cb1b4140d9124d60df0850ef734e73b884 Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Sun, 13 Sep 2020 01:55:34 +0200 Subject: [PATCH 04/28] Make some methods of `Pin` unstable const Make the following methods unstable const under the `const_pin` feature: - `new` - `new_unchecked` - `into_inner` - `into_inner_unchecked` - `get_ref` - `into_ref` Also adds tests for these methods in a const context. Tracking issue: #76654 --- library/core/src/lib.rs | 1 + library/core/src/pin.rs | 27 ++++++++++++++++----------- library/core/tests/lib.rs | 2 ++ library/core/tests/pin.rs | 21 +++++++++++++++++++++ 4 files changed, 40 insertions(+), 11 deletions(-) create mode 100644 library/core/tests/pin.rs diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index c3cadcbb01e31..696b6a64a9fec 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -80,6 +80,7 @@ #![feature(const_int_pow)] #![feature(constctlz)] #![feature(const_panic)] +#![feature(const_pin)] #![feature(const_fn_union)] #![feature(const_generics)] #![feature(const_option)] diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 1cc1dfb014335..fa5b37edc36e6 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -471,9 +471,10 @@ impl> Pin

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

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

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

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

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

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

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

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

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

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

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

) -> P { pin.pointer } } @@ -693,17 +697,18 @@ impl<'a, T: ?Sized> Pin<&'a T> { /// with the same lifetime as the original `Pin`. /// /// ["pinning projections"]: self#projections-and-structural-pinning - #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn get_ref(self) -> &'a T { + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + #[stable(feature = "pin", since = "1.33.0")] + pub const fn get_ref(self) -> &'a T { self.pointer } } impl<'a, T: ?Sized> Pin<&'a mut T> { /// Converts this `Pin<&mut T>` into a `Pin<&T>` with the same lifetime. - #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] + #[stable(feature = "pin", since = "1.33.0")] pub fn into_ref(self) -> Pin<&'a T> { Pin { pointer: self.pointer } } diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index a2e294ace1860..b8d67d7266543 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -39,6 +39,7 @@ #![feature(iter_order_by)] #![feature(cmp_min_max_by)] #![feature(iter_map_while)] +#![feature(const_pin)] #![feature(const_slice_from_raw_parts)] #![feature(const_raw_ptr_deref)] #![feature(never_type)] @@ -74,6 +75,7 @@ mod num; mod ops; mod option; mod pattern; +mod pin; mod ptr; mod result; mod slice; diff --git a/library/core/tests/pin.rs b/library/core/tests/pin.rs new file mode 100644 index 0000000000000..1363353163829 --- /dev/null +++ b/library/core/tests/pin.rs @@ -0,0 +1,21 @@ +use core::pin::Pin; + +#[test] +fn pin_const() { + // test that the methods of `Pin` are usable in a const context + + const POINTER: &'static usize = &2; + + const PINNED: Pin<&'static usize> = Pin::new(POINTER); + const PINNED_UNCHECKED: Pin<&'static usize> = unsafe { Pin::new_unchecked(POINTER) }; + assert_eq!(PINNED_UNCHECKED, PINNED); + + const INNER: &'static usize = Pin::into_inner(PINNED); + assert_eq!(INNER, POINTER); + + const INNER_UNCHECKED: &'static usize = unsafe { Pin::into_inner_unchecked(PINNED) }; + assert_eq!(INNER_UNCHECKED, POINTER); + + const REF: &'static usize = PINNED.get_ref(); + assert_eq!(REF, POINTER) +} From eede953c283c7bbe903a0e8abb44c923baf5cfac Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Thu, 10 Sep 2020 03:10:36 +0000 Subject: [PATCH 05/28] Only get ImplKind::Impl once --- src/librustdoc/clean/inline.rs | 41 ++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index f8987c6beca33..931355b82f503 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -350,14 +350,22 @@ pub fn build_impl( } } - let for_ = if let Some(did) = did.as_local() { - let hir_id = tcx.hir().local_def_id_to_hir_id(did); - match tcx.hir().expect_item(hir_id).kind { - hir::ItemKind::Impl { self_ty, .. } => self_ty.clean(cx), - _ => panic!("did given to build_impl was not an impl"), + let impl_item = match did.as_local() { + Some(did) => { + let hir_id = tcx.hir().local_def_id_to_hir_id(did); + match tcx.hir().expect_item(hir_id).kind { + hir::ItemKind::Impl { self_ty, ref generics, ref items, .. } => { + Some((self_ty, generics, items)) + } + _ => panic!("`DefID` passed to `build_impl` is not an `impl"), + } } - } else { - tcx.type_of(did).clean(cx) + None => None, + }; + + let for_ = match impl_item { + Some((self_ty, _, _)) => self_ty.clean(cx), + None => tcx.type_of(did).clean(cx), }; // Only inline impl if the implementing type is @@ -377,17 +385,12 @@ pub fn build_impl( } let predicates = tcx.explicit_predicates_of(did); - let (trait_items, generics) = if let Some(did) = did.as_local() { - let hir_id = tcx.hir().local_def_id_to_hir_id(did); - match tcx.hir().expect_item(hir_id).kind { - hir::ItemKind::Impl { ref generics, ref items, .. } => ( - items.iter().map(|item| tcx.hir().impl_item(item.id).clean(cx)).collect::>(), - generics.clean(cx), - ), - _ => panic!("did given to build_impl was not an impl"), - } - } else { - ( + let (trait_items, generics) = match impl_item { + Some((_, generics, items)) => ( + items.iter().map(|item| tcx.hir().impl_item(item.id).clean(cx)).collect::>(), + generics.clean(cx), + ), + None => ( tcx.associated_items(did) .in_definition_order() .filter_map(|item| { @@ -399,7 +402,7 @@ pub fn build_impl( }) .collect::>(), clean::enter_impl_trait(cx, || (tcx.generics_of(did), predicates).clean(cx)), - ) + ), }; let polarity = tcx.impl_polarity(did); let trait_ = associated_trait.clean(cx).map(|bound| match bound { From ed6c7efd87f17a7d9282f4bc7341cb5cbda8db4d Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 2 Sep 2020 13:25:19 -0700 Subject: [PATCH 06/28] Use enum for status of non-const ops --- .../src/transform/check_consts/ops.rs | 112 ++++++++++-------- 1 file changed, 61 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index ea025f208e49d..ff27d0c3a9211 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -14,35 +14,32 @@ use super::ConstCx; pub fn non_const(ccx: &ConstCx<'_, '_>, op: O, span: Span) { debug!("illegal_op: op={:?}", op); - if op.is_allowed_in_item(ccx) { - return; - } + let gate = match op.status_in_item(ccx) { + Status::Allowed => return, + Status::Unstable(gate) if ccx.tcx.features().enabled(gate) => return, + Status::Unstable(gate) => Some(gate), + Status::Forbidden => None, + }; if ccx.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you { - ccx.tcx.sess.miri_unleashed_feature(span, O::feature_gate()); + ccx.tcx.sess.miri_unleashed_feature(span, gate); return; } op.emit_error(ccx, span); } +pub enum Status { + Allowed, + Unstable(Symbol), + Forbidden, +} + /// An operation that is not *always* allowed in a const context. pub trait NonConstOp: std::fmt::Debug { - /// Returns the `Symbol` corresponding to the feature gate that would enable this operation, - /// or `None` if such a feature gate does not exist. - fn feature_gate() -> Option { - None - } - - /// Returns `true` if this operation is allowed in the given item. - /// - /// This check should assume that we are not in a non-const `fn`, where all operations are - /// legal. - /// - /// By default, it returns `true` if and only if this operation has a corresponding feature - /// gate and that gate is enabled. - fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool { - Self::feature_gate().map_or(false, |gate| ccx.tcx.features().enabled(gate)) + /// Returns an enum indicating whether this operation is allowed within the given item. + fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status { + Status::Forbidden } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { @@ -53,9 +50,13 @@ pub trait NonConstOp: std::fmt::Debug { "{} contains unimplemented expression type", ccx.const_kind() ); - if let Some(feat) = Self::feature_gate() { - err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feat)); + + if let Status::Unstable(gate) = self.status_in_item(ccx) { + if !ccx.tcx.features().enabled(gate) && nightly_options::is_nightly_build() { + err.help(&format!("add `#![feature({})]` to the crate attributes to enable", gate)); + } } + if ccx.tcx.sess.teach(&err.get_code().unwrap()) { err.note( "A function call isn't allowed in the const's initialization expression \ @@ -182,14 +183,13 @@ impl NonConstOp for CellBorrow { #[derive(Debug)] pub struct MutBorrow; impl NonConstOp for MutBorrow { - fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool { - // Forbid everywhere except in const fn - ccx.const_kind() == hir::ConstContext::ConstFn - && ccx.tcx.features().enabled(Self::feature_gate().unwrap()) - } - - fn feature_gate() -> Option { - Some(sym::const_mut_refs) + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + // Forbid everywhere except in const fn with a feature gate + if ccx.const_kind() == hir::ConstContext::ConstFn { + Status::Unstable(sym::const_mut_refs) + } else { + Status::Forbidden + } } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { @@ -201,15 +201,16 @@ impl NonConstOp for MutBorrow { &format!("mutable references are not allowed in {}s", ccx.const_kind()), ) } else { - struct_span_err!( + let mut err = struct_span_err!( ccx.tcx.sess, span, E0764, "mutable references are not allowed in {}s", ccx.const_kind(), - ) + ); + err.span_label(span, format!("`&mut` is only allowed in `const fn`")); + err }; - err.span_label(span, "`&mut` is only allowed in `const fn`".to_string()); if ccx.tcx.sess.teach(&err.get_code().unwrap()) { err.note( "References in statics and constants may only refer \ @@ -226,11 +227,17 @@ impl NonConstOp for MutBorrow { } } +// FIXME(ecstaticmorse): Unify this with `MutBorrow`. It has basically the same issues. #[derive(Debug)] pub struct MutAddressOf; impl NonConstOp for MutAddressOf { - fn feature_gate() -> Option { - Some(sym::const_mut_refs) + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + // Forbid everywhere except in const fn with a feature gate + if ccx.const_kind() == hir::ConstContext::ConstFn { + Status::Unstable(sym::const_mut_refs) + } else { + Status::Forbidden + } } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { @@ -247,16 +254,16 @@ impl NonConstOp for MutAddressOf { #[derive(Debug)] pub struct MutDeref; impl NonConstOp for MutDeref { - fn feature_gate() -> Option { - Some(sym::const_mut_refs) + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_mut_refs) } } #[derive(Debug)] pub struct Panic; impl NonConstOp for Panic { - fn feature_gate() -> Option { - Some(sym::const_panic) + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_panic) } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { @@ -289,8 +296,8 @@ impl NonConstOp for RawPtrComparison { #[derive(Debug)] pub struct RawPtrDeref; impl NonConstOp for RawPtrDeref { - fn feature_gate() -> Option { - Some(sym::const_raw_ptr_deref) + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_raw_ptr_deref) } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { @@ -307,8 +314,8 @@ impl NonConstOp for RawPtrDeref { #[derive(Debug)] pub struct RawPtrToIntCast; impl NonConstOp for RawPtrToIntCast { - fn feature_gate() -> Option { - Some(sym::const_raw_ptr_to_usize_cast) + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_raw_ptr_to_usize_cast) } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { @@ -326,8 +333,12 @@ impl NonConstOp for RawPtrToIntCast { #[derive(Debug)] pub struct StaticAccess; impl NonConstOp for StaticAccess { - fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool { - matches!(ccx.const_kind(), hir::ConstContext::Static(_)) + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + if let hir::ConstContext::Static(_) = ccx.const_kind() { + Status::Allowed + } else { + Status::Forbidden + } } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { @@ -371,14 +382,13 @@ impl NonConstOp for ThreadLocalAccess { #[derive(Debug)] pub struct UnionAccess; impl NonConstOp for UnionAccess { - fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool { + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { // Union accesses are stable in all contexts except `const fn`. - ccx.const_kind() != hir::ConstContext::ConstFn - || ccx.tcx.features().enabled(Self::feature_gate().unwrap()) - } - - fn feature_gate() -> Option { - Some(sym::const_fn_union) + if ccx.const_kind() != hir::ConstContext::ConstFn { + Status::Allowed + } else { + Status::Unstable(sym::const_fn_union) + } } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { From c3607bd7dd323a898b8cc9d2c603dfd14172c73c Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 2 Sep 2020 14:35:02 -0700 Subject: [PATCH 07/28] Use helper function for searching `allow_internal_unstable` --- compiler/rustc_mir/src/transform/check_consts/mod.rs | 8 ++++++++ compiler/rustc_mir/src/transform/qualify_min_const_fn.rs | 7 ++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/mod.rs b/compiler/rustc_mir/src/transform/check_consts/mod.rs index 81c1b0b5bd49f..c1b4cb5f1a8d5 100644 --- a/compiler/rustc_mir/src/transform/check_consts/mod.rs +++ b/compiler/rustc_mir/src/transform/check_consts/mod.rs @@ -4,10 +4,12 @@ //! has interior mutability or needs to be dropped, as well as the visitor that emits errors when //! it finds operations that are invalid in a certain context. +use rustc_attr as attr; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::mir; use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::Symbol; pub use self::qualifs::Qualif; @@ -55,3 +57,9 @@ impl ConstCx<'mir, 'tcx> { pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { Some(def_id) == tcx.lang_items().panic_fn() || Some(def_id) == tcx.lang_items().begin_panic_fn() } + +pub fn allow_internal_unstable(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool { + let attrs = tcx.get_attrs(def_id); + attr::allow_internal_unstable(&tcx.sess, attrs) + .map_or(false, |mut features| features.any(|name| name == feature_gate)) +} diff --git a/compiler/rustc_mir/src/transform/qualify_min_const_fn.rs b/compiler/rustc_mir/src/transform/qualify_min_const_fn.rs index 5e102f5151d0c..f15a7f7c2c889 100644 --- a/compiler/rustc_mir/src/transform/qualify_min_const_fn.rs +++ b/compiler/rustc_mir/src/transform/qualify_min_const_fn.rs @@ -1,4 +1,3 @@ -use rustc_attr as attr; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::mir::*; @@ -344,8 +343,7 @@ fn feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bo // However, we cannot allow stable `const fn`s to use unstable features without an explicit // opt-in via `allow_internal_unstable`. - attr::allow_internal_unstable(&tcx.sess, &tcx.get_attrs(def_id)) - .map_or(false, |mut features| features.any(|name| name == feature_gate)) + super::check_consts::allow_internal_unstable(tcx, def_id, feature_gate) } /// Returns `true` if the given library feature gate is allowed within the function with the given `DefId`. @@ -364,8 +362,7 @@ pub fn lib_feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbo // However, we cannot allow stable `const fn`s to use unstable features without an explicit // opt-in via `allow_internal_unstable`. - attr::allow_internal_unstable(&tcx.sess, &tcx.get_attrs(def_id)) - .map_or(false, |mut features| features.any(|name| name == feature_gate)) + super::check_consts::allow_internal_unstable(tcx, def_id, feature_gate) } fn check_terminator( From e4edc161f20ccbc77fffb7ceb60ebb6102cbd747 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 2 Sep 2020 14:54:55 -0700 Subject: [PATCH 08/28] Give name to extra `Span` in `LiveDrop` error --- compiler/rustc_mir/src/transform/check_consts/ops.rs | 6 ++++-- .../src/transform/check_consts/post_drop_elaboration.rs | 2 +- compiler/rustc_mir/src/transform/check_consts/validation.rs | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index ff27d0c3a9211..4af355310ae25 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -148,7 +148,9 @@ pub struct InlineAsm; impl NonConstOp for InlineAsm {} #[derive(Debug)] -pub struct LiveDrop(pub Option); +pub struct LiveDrop { + pub dropped_at: Option, +} impl NonConstOp for LiveDrop { fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { let mut diagnostic = struct_span_err!( @@ -158,7 +160,7 @@ impl NonConstOp for LiveDrop { "destructors cannot be evaluated at compile-time" ); diagnostic.span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind())); - if let Some(span) = self.0 { + if let Some(span) = self.dropped_at { diagnostic.span_label(span, "value is dropped here"); } diagnostic.emit(); diff --git a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs index 55075b3ab5e99..a2e5c905612aa 100644 --- a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs +++ b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs @@ -52,7 +52,7 @@ impl std::ops::Deref for CheckLiveDrops<'mir, 'tcx> { impl CheckLiveDrops<'mir, 'tcx> { fn check_live_drop(&self, span: Span) { - ops::non_const(self.ccx, ops::LiveDrop(None), span); + ops::non_const(self.ccx, ops::LiveDrop { dropped_at: None }, span); } } diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index e8411b121e394..ebba7f29663ed 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -576,7 +576,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { if needs_drop { self.check_op_spanned( - ops::LiveDrop(Some(terminator.source_info.span)), + ops::LiveDrop { dropped_at: Some(terminator.source_info.span) }, err_span, ); } From 81b3b66487c7001a0dbadf7f9af41ad714702533 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 2 Sep 2020 17:11:55 -0700 Subject: [PATCH 09/28] Error if an unstable const eval feature is used in a stable const fn --- .../src/transform/check_consts/ops.rs | 26 +++++++++++++++++-- .../check_consts/post_drop_elaboration.rs | 11 +++++--- .../src/transform/check_consts/validation.rs | 2 +- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index 4af355310ae25..032cbc23a3f52 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -1,6 +1,6 @@ //! Concrete error types for all operations which may be invalid in a certain const context. -use rustc_errors::struct_span_err; +use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_session::config::nightly_options; @@ -16,7 +16,29 @@ pub fn non_const(ccx: &ConstCx<'_, '_>, op: O, span: Span) { let gate = match op.status_in_item(ccx) { Status::Allowed => return, - Status::Unstable(gate) if ccx.tcx.features().enabled(gate) => return, + + Status::Unstable(gate) if ccx.tcx.features().enabled(gate) => { + let unstable_in_stable = ccx.const_kind() == hir::ConstContext::ConstFn + && ccx.tcx.features().enabled(sym::staged_api) + && !ccx.tcx.has_attr(ccx.def_id.to_def_id(), sym::rustc_const_unstable) + && !super::allow_internal_unstable(ccx.tcx, ccx.def_id.to_def_id(), gate); + + if unstable_in_stable { + ccx.tcx.sess + .struct_span_err(span, &format!("`#[feature({})]` cannot be depended on in a const-stable function", gate.as_str())) + .span_suggestion( + ccx.body.span, + "if it is not part of the public API, make this function unstably const", + concat!(r#"#[rustc_const_unstable(feature = "...", issue = "...")]"#, '\n').to_owned(), + Applicability::HasPlaceholders, + ) + .help("otherwise `#[allow_internal_unstable]` can be used to bypass stability checks") + .emit(); + } + + return; + } + Status::Unstable(gate) => Some(gate), Status::Forbidden => None, }; diff --git a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs index a2e5c905612aa..0228f2d7de023 100644 --- a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs +++ b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs @@ -2,7 +2,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::{self, BasicBlock, Location}; use rustc_middle::ty::TyCtxt; -use rustc_span::Span; +use rustc_span::{sym, Span}; use super::ops; use super::qualifs::{NeedsDrop, Qualif}; @@ -11,7 +11,12 @@ use super::ConstCx; /// Returns `true` if we should use the more precise live drop checker that runs after drop /// elaboration. -pub fn checking_enabled(tcx: TyCtxt<'tcx>) -> bool { +pub fn checking_enabled(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool { + // Const-stable functions must always use the stable live drop checker. + if tcx.features().staged_api && !tcx.has_attr(def_id.to_def_id(), sym::rustc_const_unstable) { + return false; + } + tcx.features().const_precise_live_drops } @@ -25,7 +30,7 @@ pub fn check_live_drops(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &mir::Body< return; } - if !checking_enabled(tcx) { + if !checking_enabled(tcx, def_id) { return; } diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index ebba7f29663ed..0501302b7610a 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -551,7 +551,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { | TerminatorKind::DropAndReplace { place: dropped_place, .. } => { // If we are checking live drops after drop-elaboration, don't emit duplicate // errors here. - if super::post_drop_elaboration::checking_enabled(self.tcx) { + if super::post_drop_elaboration::checking_enabled(self.tcx, self.def_id) { return; } From 1e1257b8f87d1e3073020df27765dc57fcf2c0cd Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 16 Sep 2020 13:09:46 -0700 Subject: [PATCH 10/28] Bless `miri-unleashed` tests `const_mut_refs` doesn't actually work in a `const` or `static` --- src/test/ui/consts/miri_unleashed/box.stderr | 2 +- .../ui/consts/miri_unleashed/mutable_references.stderr | 8 ++++---- .../consts/miri_unleashed/mutable_references_err.stderr | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/ui/consts/miri_unleashed/box.stderr b/src/test/ui/consts/miri_unleashed/box.stderr index 768b795ca5b39..66ea9d5924dfb 100644 --- a/src/test/ui/consts/miri_unleashed/box.stderr +++ b/src/test/ui/consts/miri_unleashed/box.stderr @@ -21,7 +21,7 @@ help: skipping check for `const_mut_refs` feature | LL | &mut *(box 0) | ^^^^^^^^^^^^^ -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/box.rs:10:5 | LL | &mut *(box 0) diff --git a/src/test/ui/consts/miri_unleashed/mutable_references.stderr b/src/test/ui/consts/miri_unleashed/mutable_references.stderr index 7109ffd8b61d7..c6180c1e0041c 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references.stderr @@ -6,17 +6,17 @@ LL | *OH_YES = 99; warning: skipping const checks | -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/mutable_references.rs:9:26 | LL | static FOO: &&mut u32 = &&mut 42; | ^^^^^^^ -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/mutable_references.rs:13:23 | LL | static BAR: &mut () = &mut (); | ^^^^^^^ -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/mutable_references.rs:18:28 | LL | static BOO: &mut Foo<()> = &mut Foo(()); @@ -26,7 +26,7 @@ help: skipping check that does not even have a feature gate | LL | x: &UnsafeCell::new(42), | ^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/mutable_references.rs:30:27 | LL | static OH_YES: &mut i32 = &mut 42; diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr b/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr index 45e7d5a2cc3b3..7647a9ff4f6e4 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr @@ -30,7 +30,7 @@ help: skipping check that does not even have a feature gate | LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/mutable_references_err.rs:30:25 | LL | const BLUNT: &mut i32 = &mut 42; From abc71677da866fd36c70790e768f36d2f809c493 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 16 Sep 2020 13:19:45 -0700 Subject: [PATCH 11/28] Test that `const_precise_live_drops` can't be depended upon stably --- .../stable-precise-live-drops-in-libcore.rs | 22 ++++++++++++++++++ ...table-precise-live-drops-in-libcore.stderr | 12 ++++++++++ .../unstable-precise-live-drops-in-libcore.rs | 23 +++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 src/test/ui/consts/stable-precise-live-drops-in-libcore.rs create mode 100644 src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr create mode 100644 src/test/ui/consts/unstable-precise-live-drops-in-libcore.rs diff --git a/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs b/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs new file mode 100644 index 0000000000000..651462d7ef19c --- /dev/null +++ b/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs @@ -0,0 +1,22 @@ +#![stable(feature = "core", since = "1.6.0")] +#![feature(staged_api)] +#![feature(const_precise_live_drops, const_fn)] + +enum Either { + Left(T), + Right(S), +} + +impl Either { + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "foo", since = "1.0.0")] + pub const fn unwrap(self) -> T { + //~^ ERROR destructors cannot be evaluated at compile-time + match self { + Self::Left(t) => t, + Self::Right(t) => t, + } + } +} + +fn main() {} diff --git a/src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr b/src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr new file mode 100644 index 0000000000000..a3f513541dd6a --- /dev/null +++ b/src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr @@ -0,0 +1,12 @@ +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/stable-precise-live-drops-in-libcore.rs:13:25 + | +LL | pub const fn unwrap(self) -> T { + | ^^^^ constant functions cannot evaluate destructors +... +LL | } + | - value is dropped here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0493`. diff --git a/src/test/ui/consts/unstable-precise-live-drops-in-libcore.rs b/src/test/ui/consts/unstable-precise-live-drops-in-libcore.rs new file mode 100644 index 0000000000000..619084eaa517a --- /dev/null +++ b/src/test/ui/consts/unstable-precise-live-drops-in-libcore.rs @@ -0,0 +1,23 @@ +// check-pass + +#![stable(feature = "core", since = "1.6.0")] +#![feature(staged_api)] +#![feature(const_precise_live_drops)] + +enum Either { + Left(T), + Right(S), +} + +impl Either { + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "foo", issue = "none")] + pub const fn unwrap(self) -> T { + match self { + Self::Left(t) => t, + Self::Right(t) => t, + } + } +} + +fn main() {} From e3c6e46168758642f0bab64da374f93ed21b1cd0 Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Fri, 18 Sep 2020 19:23:50 +0200 Subject: [PATCH 12/28] Make some methods of `Pin<&mut T>` unstable const Make the following methods unstable const under the `const_pin` feature: - `into_ref` - `get_mut` - `get_unchecked_mut` --- library/core/src/pin.rs | 13 ++++++++----- library/core/tests/lib.rs | 1 + library/core/tests/pin.rs | 12 +++++++++++- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index fa5b37edc36e6..9f0284d5d9542 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -708,8 +708,9 @@ impl<'a, T: ?Sized> Pin<&'a T> { impl<'a, T: ?Sized> Pin<&'a mut T> { /// Converts this `Pin<&mut T>` into a `Pin<&T>` with the same lifetime. #[inline(always)] + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] #[stable(feature = "pin", since = "1.33.0")] - pub fn into_ref(self) -> Pin<&'a T> { + pub const fn into_ref(self) -> Pin<&'a T> { Pin { pointer: self.pointer } } @@ -722,9 +723,10 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { /// that lives for as long as the borrow of the `Pin`, not the lifetime of /// the `Pin` itself. This method allows turning the `Pin` into a reference /// with the same lifetime as the original `Pin`. - #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn get_mut(self) -> &'a mut T + #[stable(feature = "pin", since = "1.33.0")] + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + pub const fn get_mut(self) -> &'a mut T where T: Unpin, { @@ -741,9 +743,10 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { /// /// If the underlying data is `Unpin`, `Pin::get_mut` should be used /// instead. - #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub unsafe fn get_unchecked_mut(self) -> &'a mut T { + #[stable(feature = "pin", since = "1.33.0")] + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + pub const unsafe fn get_unchecked_mut(self) -> &'a mut T { self.pointer } diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index b8d67d7266543..490f016ab8b2e 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -39,6 +39,7 @@ #![feature(iter_order_by)] #![feature(cmp_min_max_by)] #![feature(iter_map_while)] +#![feature(const_mut_refs)] #![feature(const_pin)] #![feature(const_slice_from_raw_parts)] #![feature(const_raw_ptr_deref)] diff --git a/library/core/tests/pin.rs b/library/core/tests/pin.rs index 1363353163829..6f617c8d0c297 100644 --- a/library/core/tests/pin.rs +++ b/library/core/tests/pin.rs @@ -17,5 +17,15 @@ fn pin_const() { assert_eq!(INNER_UNCHECKED, POINTER); const REF: &'static usize = PINNED.get_ref(); - assert_eq!(REF, POINTER) + assert_eq!(REF, POINTER); + + // Note: `pin_mut_const` tests that the methods of `Pin<&mut T>` are usable in a const context. + // A const fn is used because `&mut` is not (yet) usable in constants. + const fn pin_mut_const() { + let _ = Pin::new(&mut 2).into_ref(); + let _ = Pin::new(&mut 2).get_mut(); + let _ = unsafe { Pin::new(&mut 2).get_unchecked_mut() }; + } + + pin_mut_const(); } From f7d5080ec3c21c5418649a1c5b3f830ff37734f1 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Fri, 18 Sep 2020 20:49:25 +0200 Subject: [PATCH 13/28] don't take `TyCtxt` by reference --- compiler/rustc_middle/src/middle/lang_items.rs | 6 +++--- compiler/rustc_middle/src/mir/interpret/mod.rs | 18 +++++++++--------- compiler/rustc_middle/src/ty/context.rs | 18 +++++++++--------- compiler/rustc_middle/src/ty/error.rs | 12 ++++++------ compiler/rustc_middle/src/ty/fold.rs | 8 ++++---- compiler/rustc_middle/src/ty/util.rs | 10 ++++------ 6 files changed, 35 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs index 7194a035e89f6..cc9706f2d867c 100644 --- a/compiler/rustc_middle/src/middle/lang_items.rs +++ b/compiler/rustc_middle/src/middle/lang_items.rs @@ -17,7 +17,7 @@ use rustc_target::spec::PanicStrategy; impl<'tcx> TyCtxt<'tcx> { /// Returns the `DefId` for a given `LangItem`. /// If not found, fatally aborts compilation. - pub fn require_lang_item(&self, lang_item: LangItem, span: Option) -> DefId { + pub fn require_lang_item(self, lang_item: LangItem, span: Option) -> DefId { self.lang_items().require(lang_item).unwrap_or_else(|msg| { if let Some(span) = span { self.sess.span_fatal(span, &msg) @@ -27,7 +27,7 @@ impl<'tcx> TyCtxt<'tcx> { }) } - pub fn fn_trait_kind_from_lang_item(&self, id: DefId) -> Option { + pub fn fn_trait_kind_from_lang_item(self, id: DefId) -> Option { let items = self.lang_items(); match Some(id) { x if x == items.fn_trait() => Some(ty::ClosureKind::Fn), @@ -37,7 +37,7 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub fn is_weak_lang_item(&self, item_def_id: DefId) -> bool { + pub fn is_weak_lang_item(self, item_def_id: DefId) -> bool { self.lang_items().is_weak_lang_item(item_def_id) } } diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index cbc362d934ff8..51642fceb1d93 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -447,14 +447,14 @@ impl<'tcx> TyCtxt<'tcx> { /// /// Make sure to call `set_alloc_id_memory` or `set_alloc_id_same_memory` before returning such /// an `AllocId` from a query. - pub fn reserve_alloc_id(&self) -> AllocId { + pub fn reserve_alloc_id(self) -> AllocId { self.alloc_map.lock().reserve() } /// Reserves a new ID *if* this allocation has not been dedup-reserved before. /// Should only be used for function pointers and statics, we don't want /// to dedup IDs for "real" memory! - fn reserve_and_set_dedup(&self, alloc: GlobalAlloc<'tcx>) -> AllocId { + fn reserve_and_set_dedup(self, alloc: GlobalAlloc<'tcx>) -> AllocId { let mut alloc_map = self.alloc_map.lock(); match alloc { GlobalAlloc::Function(..) | GlobalAlloc::Static(..) => {} @@ -472,13 +472,13 @@ impl<'tcx> TyCtxt<'tcx> { /// Generates an `AllocId` for a static or return a cached one in case this function has been /// called on the same static before. - pub fn create_static_alloc(&self, static_id: DefId) -> AllocId { + pub fn create_static_alloc(self, static_id: DefId) -> AllocId { self.reserve_and_set_dedup(GlobalAlloc::Static(static_id)) } /// Generates an `AllocId` for a function. Depending on the function type, /// this might get deduplicated or assigned a new ID each time. - pub fn create_fn_alloc(&self, instance: Instance<'tcx>) -> AllocId { + pub fn create_fn_alloc(self, instance: Instance<'tcx>) -> AllocId { // Functions cannot be identified by pointers, as asm-equal functions can get deduplicated // by the linker (we set the "unnamed_addr" attribute for LLVM) and functions can be // duplicated across crates. @@ -507,7 +507,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Statics with identical content will still point to the same `Allocation`, i.e., /// their data will be deduplicated through `Allocation` interning -- but they /// are different places in memory and as such need different IDs. - pub fn create_memory_alloc(&self, mem: &'tcx Allocation) -> AllocId { + pub fn create_memory_alloc(self, mem: &'tcx Allocation) -> AllocId { let id = self.reserve_alloc_id(); self.set_alloc_id_memory(id, mem); id @@ -519,7 +519,7 @@ impl<'tcx> TyCtxt<'tcx> { /// This function exists to allow const eval to detect the difference between evaluation- /// local dangling pointers and allocations in constants/statics. #[inline] - pub fn get_global_alloc(&self, id: AllocId) -> Option> { + pub fn get_global_alloc(self, id: AllocId) -> Option> { self.alloc_map.lock().alloc_map.get(&id).cloned() } @@ -529,7 +529,7 @@ impl<'tcx> TyCtxt<'tcx> { /// constants (as all constants must pass interning and validation that check for dangling /// ids), this function is frequently used throughout rustc, but should not be used within /// the miri engine. - pub fn global_alloc(&self, id: AllocId) -> GlobalAlloc<'tcx> { + pub fn global_alloc(self, id: AllocId) -> GlobalAlloc<'tcx> { match self.get_global_alloc(id) { Some(alloc) => alloc, None => bug!("could not find allocation for {}", id), @@ -538,7 +538,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. Trying to /// call this function twice, even with the same `Allocation` will ICE the compiler. - pub fn set_alloc_id_memory(&self, id: AllocId, mem: &'tcx Allocation) { + pub fn set_alloc_id_memory(self, id: AllocId, mem: &'tcx Allocation) { if let Some(old) = self.alloc_map.lock().alloc_map.insert(id, GlobalAlloc::Memory(mem)) { bug!("tried to set allocation ID {}, but it was already existing as {:#?}", id, old); } @@ -546,7 +546,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. May be called /// twice for the same `(AllocId, Allocation)` pair. - fn set_alloc_id_same_memory(&self, id: AllocId, mem: &'tcx Allocation) { + fn set_alloc_id_same_memory(self, id: AllocId, mem: &'tcx Allocation) { self.alloc_map.lock().alloc_map.insert_same(id, GlobalAlloc::Memory(mem)); } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 56746666e2f1f..39bf5472b76f8 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1403,7 +1403,7 @@ impl<'tcx> TyCtxt<'tcx> { } // Returns the `DefId` and the `BoundRegion` corresponding to the given region. - pub fn is_suitable_region(&self, region: Region<'tcx>) -> Option { + pub fn is_suitable_region(self, region: Region<'tcx>) -> Option { let (suitable_region_binding_scope, bound_region) = match *region { ty::ReFree(ref free_region) => { (free_region.scope.expect_local(), free_region.bound_region) @@ -1433,7 +1433,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Given a `DefId` for an `fn`, return all the `dyn` and `impl` traits in its return type. pub fn return_type_impl_or_dyn_traits( - &self, + self, scope_def_id: LocalDefId, ) -> Vec<&'tcx hir::Ty<'tcx>> { let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id); @@ -1479,7 +1479,7 @@ impl<'tcx> TyCtxt<'tcx> { v.0 } - pub fn return_type_impl_trait(&self, scope_def_id: LocalDefId) -> Option<(Ty<'tcx>, Span)> { + pub fn return_type_impl_trait(self, scope_def_id: LocalDefId) -> Option<(Ty<'tcx>, Span)> { // HACK: `type_of_def_id()` will fail on these (#55796), so return `None`. let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id); match self.hir().get(hir_id) { @@ -1497,7 +1497,7 @@ impl<'tcx> TyCtxt<'tcx> { let ret_ty = self.type_of(scope_def_id); match ret_ty.kind() { ty::FnDef(_, _) => { - let sig = ret_ty.fn_sig(*self); + let sig = ret_ty.fn_sig(self); let output = self.erase_late_bound_regions(&sig.output()); if output.is_impl_trait() { let fn_decl = self.hir().fn_decl_by_hir_id(hir_id).unwrap(); @@ -1511,7 +1511,7 @@ impl<'tcx> TyCtxt<'tcx> { } // Checks if the bound region is in Impl Item. - pub fn is_bound_region_in_impl_item(&self, suitable_region_binding_scope: LocalDefId) -> bool { + pub fn is_bound_region_in_impl_item(self, suitable_region_binding_scope: LocalDefId) -> bool { let container_id = self.associated_item(suitable_region_binding_scope.to_def_id()).container.id(); if self.impl_trait_ref(container_id).is_some() { @@ -1528,21 +1528,21 @@ impl<'tcx> TyCtxt<'tcx> { /// Determines whether identifiers in the assembly have strict naming rules. /// Currently, only NVPTX* targets need it. - pub fn has_strict_asm_symbol_naming(&self) -> bool { + pub fn has_strict_asm_symbol_naming(self) -> bool { self.sess.target.target.arch.contains("nvptx") } /// Returns `&'static core::panic::Location<'static>`. - pub fn caller_location_ty(&self) -> Ty<'tcx> { + pub fn caller_location_ty(self) -> Ty<'tcx> { self.mk_imm_ref( self.lifetimes.re_static, self.type_of(self.require_lang_item(LangItem::PanicLocation, None)) - .subst(*self, self.mk_substs([self.lifetimes.re_static.into()].iter())), + .subst(self, self.mk_substs([self.lifetimes.re_static.into()].iter())), ) } /// Returns a displayable description and article for the given `def_id` (e.g. `("a", "struct")`). - pub fn article_and_description(&self, def_id: DefId) -> (&'static str, &'static str) { + pub fn article_and_description(self, def_id: DefId) -> (&'static str, &'static str) { match self.def_kind(def_id) { DefKind::Generator => match self.generator_kind(def_id).unwrap() { rustc_hir::GeneratorKind::Async(..) => ("an", "async closure"), diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 7226a906e5c97..475c3101c1e98 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -546,7 +546,7 @@ impl Trait for X { } fn suggest_constraint( - &self, + self, db: &mut DiagnosticBuilder<'_>, msg: &str, body_owner_def_id: DefId, @@ -554,14 +554,14 @@ impl Trait for X { ty: Ty<'tcx>, ) -> bool { let assoc = self.associated_item(proj_ty.item_def_id); - let trait_ref = proj_ty.trait_ref(*self); + let trait_ref = proj_ty.trait_ref(self); if let Some(item) = self.hir().get_if_local(body_owner_def_id) { if let Some(hir_generics) = item.generics() { // Get the `DefId` for the type parameter corresponding to `A` in `::Foo`. // This will also work for `impl Trait`. let def_id = if let ty::Param(param_ty) = proj_ty.self_ty().kind() { let generics = self.generics_of(body_owner_def_id); - generics.type_param(¶m_ty, *self).def_id + generics.type_param(param_ty, self).def_id } else { return false; }; @@ -629,7 +629,7 @@ impl Trait for X { /// and the `impl`, we provide a generic `help` to constrain the assoc type or call an assoc /// fn that returns the type. fn expected_projection( - &self, + self, db: &mut DiagnosticBuilder<'_>, proj_ty: &ty::ProjectionTy<'tcx>, values: &ExpectedFound>, @@ -734,7 +734,7 @@ fn foo(&self) -> Self::T { String::new() } } fn point_at_methods_that_satisfy_associated_type( - &self, + self, db: &mut DiagnosticBuilder<'_>, assoc_container_id: DefId, current_method_ident: Option, @@ -789,7 +789,7 @@ fn foo(&self) -> Self::T { String::new() } } fn point_at_associated_type( - &self, + self, db: &mut DiagnosticBuilder<'_>, body_owner_def_id: DefId, found: Ty<'tcx>, diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 5e8fb95dc2985..84134bedef0bc 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -623,7 +623,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Replaces any late-bound regions bound in `value` with /// free variants attached to `all_outlive_scope`. pub fn liberate_late_bound_regions( - &self, + self, all_outlive_scope: DefId, value: &ty::Binder, ) -> T @@ -644,7 +644,7 @@ impl<'tcx> TyCtxt<'tcx> { /// variables and equate `value` with something else, those /// variables will also be equated. pub fn collect_constrained_late_bound_regions( - &self, + self, value: &Binder, ) -> FxHashSet where @@ -655,7 +655,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns a set of all late-bound regions that appear in `value` anywhere. pub fn collect_referenced_late_bound_regions( - &self, + self, value: &Binder, ) -> FxHashSet where @@ -665,7 +665,7 @@ impl<'tcx> TyCtxt<'tcx> { } fn collect_late_bound_regions( - &self, + self, value: &Binder, just_constraint: bool, ) -> FxHashSet diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index f3eb7c35f0494..4127b6535bca6 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -170,9 +170,7 @@ impl<'tcx> TyCtxt<'tcx> { }); hasher.finish() } -} -impl<'tcx> TyCtxt<'tcx> { pub fn has_error_field(self, ty: Ty<'tcx>) -> bool { if let ty::Adt(def, substs) = *ty.kind() { for field in def.all_fields() { @@ -526,22 +524,22 @@ impl<'tcx> TyCtxt<'tcx> { } /// Returns `true` if the node pointed to by `def_id` is a `static` item. - pub fn is_static(&self, def_id: DefId) -> bool { + pub fn is_static(self, def_id: DefId) -> bool { self.static_mutability(def_id).is_some() } /// Returns `true` if this is a `static` item with the `#[thread_local]` attribute. - pub fn is_thread_local_static(&self, def_id: DefId) -> bool { + pub fn is_thread_local_static(self, def_id: DefId) -> bool { self.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) } /// Returns `true` if the node pointed to by `def_id` is a mutable `static` item. - pub fn is_mutable_static(&self, def_id: DefId) -> bool { + pub fn is_mutable_static(self, def_id: DefId) -> bool { self.static_mutability(def_id) == Some(hir::Mutability::Mut) } /// Get the type of the pointer to the static that we use in MIR. - pub fn static_ptr_ty(&self, def_id: DefId) -> Ty<'tcx> { + pub fn static_ptr_ty(self, def_id: DefId) -> Ty<'tcx> { // Make sure that any constants in the static's type are evaluated. let static_ty = self.normalize_erasing_regions(ty::ParamEnv::empty(), self.type_of(def_id)); From a219ad64a6ee025b9a5c83de390280f818cd81c6 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 19 Sep 2020 12:34:31 +0200 Subject: [PATCH 14/28] extend `is_ty_or_ty_ctxt` to self types --- compiler/rustc_lint/src/internal.rs | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 100e555f299ae..2bac4517409b4 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -5,7 +5,9 @@ use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext} use rustc_ast::{Item, ItemKind}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; +use rustc_hir::def::Res; use rustc_hir::{GenericArg, HirId, MutTy, Mutability, Path, PathSegment, QPath, Ty, TyKind}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::symbol::{sym, Ident, Symbol}; @@ -177,11 +179,25 @@ fn lint_ty_kind_usage(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> bool { fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, ty: &Ty<'_>) -> Option { if let TyKind::Path(qpath) = &ty.kind { if let QPath::Resolved(_, path) = qpath { - let did = path.res.opt_def_id()?; - if cx.tcx.is_diagnostic_item(sym::Ty, did) { - return Some(format!("Ty{}", gen_args(path.segments.last().unwrap()))); - } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, did) { - return Some(format!("TyCtxt{}", gen_args(path.segments.last().unwrap()))); + match path.res { + Res::Def(_, did) => { + if cx.tcx.is_diagnostic_item(sym::Ty, did) { + return Some(format!("Ty{}", gen_args(path.segments.last().unwrap()))); + } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, did) { + return Some(format!("TyCtxt{}", gen_args(path.segments.last().unwrap()))); + } + } + // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait. + Res::SelfTy(None, Some((did, _))) => { + if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() { + if cx.tcx.is_diagnostic_item(sym::Ty, adt.did) { + return Some(format!("Ty<{}>", substs[0])); + } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, adt.did) { + return Some(format!("TyCtxt<{}>", substs[0])); + } + } + } + _ => (), } } } From 67f319c30bed5c83ae3b4872109999a8a574f29e Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 19 Sep 2020 12:38:24 +0200 Subject: [PATCH 15/28] take `TyCtxt` by value --- compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_middle/src/ty/error.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 39bf5472b76f8..5a575677f9e4a 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1179,7 +1179,7 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_const(ty::Const { val: ty::ConstKind::Error(DelaySpanBugEmitted(())), ty }) } - pub fn consider_optimizing String>(&self, msg: T) -> bool { + pub fn consider_optimizing String>(self, msg: T) -> bool { let cname = self.crate_name(LOCAL_CRATE).as_str(); self.sess.consider_optimizing(&cname, msg) } diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 475c3101c1e98..82d2e9b987472 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -851,7 +851,7 @@ fn foo(&self) -> Self::T { String::new() } /// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref` /// requirement, provide a strucuted suggestion to constrain it to a given type `ty`. fn constrain_generic_bound_associated_type_structured_suggestion( - &self, + self, db: &mut DiagnosticBuilder<'_>, trait_ref: &ty::TraitRef<'tcx>, bounds: hir::GenericBounds<'_>, @@ -875,7 +875,7 @@ fn foo(&self) -> Self::T { String::new() } /// Given a span corresponding to a bound, provide a structured suggestion to set an /// associated type to a given type `ty`. fn constrain_associated_type_structured_suggestion( - &self, + self, db: &mut DiagnosticBuilder<'_>, span: Span, assoc: &ty::AssocItem, From 2a00dda90258576e3adf5ecae0437a8fe6fadbcf Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 10 Sep 2020 19:43:53 +0200 Subject: [PATCH 16/28] miri: correctly deal with `ConstKind::Bound` --- compiler/rustc_mir/src/interpret/operand.rs | 6 ++-- .../ui/const-generics/issues/issue-73260.rs | 20 +++++++++++++ .../const-generics/issues/issue-73260.stderr | 29 +++++++++++++++++++ .../ui/const-generics/issues/issue-74634.rs | 27 +++++++++++++++++ .../const-generics/issues/issue-74634.stderr | 10 +++++++ 5 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/const-generics/issues/issue-73260.rs create mode 100644 src/test/ui/const-generics/issues/issue-73260.stderr create mode 100644 src/test/ui/const-generics/issues/issue-74634.rs create mode 100644 src/test/ui/const-generics/issues/issue-74634.stderr diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs index 57245696e576e..136a2699d20b2 100644 --- a/compiler/rustc_mir/src/interpret/operand.rs +++ b/compiler/rustc_mir/src/interpret/operand.rs @@ -549,7 +549,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; // Early-return cases. let val_val = match val.val { - ty::ConstKind::Param(_) => throw_inval!(TooGeneric), + ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric), ty::ConstKind::Error(_) => throw_inval!(TypeckError(ErrorReported)), ty::ConstKind::Unevaluated(def, substs, promoted) => { let instance = self.resolve(def.did, substs)?; @@ -561,9 +561,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // happening. return Ok(self.const_eval(GlobalId { instance, promoted }, val.ty)?); } - ty::ConstKind::Infer(..) - | ty::ConstKind::Bound(..) - | ty::ConstKind::Placeholder(..) => { + ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => { span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", val) } ty::ConstKind::Value(val_val) => val_val, diff --git a/src/test/ui/const-generics/issues/issue-73260.rs b/src/test/ui/const-generics/issues/issue-73260.rs new file mode 100644 index 0000000000000..351d6849af5db --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-73260.rs @@ -0,0 +1,20 @@ +// compile-flags: -Zsave-analysis + +#![feature(const_generics)] +#![allow(incomplete_features)] +struct Arr +where Assert::<{N < usize::max_value() / 2}>: IsTrue, //~ ERROR constant expression +{ +} + +enum Assert {} + +trait IsTrue {} + +impl IsTrue for Assert {} + +fn main() { + let x: Arr<{usize::max_value()}> = Arr {}; + //~^ ERROR mismatched types + //~| ERROR mismatched types +} diff --git a/src/test/ui/const-generics/issues/issue-73260.stderr b/src/test/ui/const-generics/issues/issue-73260.stderr new file mode 100644 index 0000000000000..e22612ed5ea63 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-73260.stderr @@ -0,0 +1,29 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-73260.rs:6:47 + | +LL | where Assert::<{N < usize::max_value() / 2}>: IsTrue, + | ^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error[E0308]: mismatched types + --> $DIR/issue-73260.rs:17:12 + | +LL | let x: Arr<{usize::max_value()}> = Arr {}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `false`, found `true` + | + = note: expected type `false` + found type `true` + +error[E0308]: mismatched types + --> $DIR/issue-73260.rs:17:40 + | +LL | let x: Arr<{usize::max_value()}> = Arr {}; + | ^^^ expected `false`, found `true` + | + = note: expected type `false` + found type `true` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/issues/issue-74634.rs b/src/test/ui/const-generics/issues/issue-74634.rs new file mode 100644 index 0000000000000..0f23fa92c3679 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-74634.rs @@ -0,0 +1,27 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +trait If {} +impl If for () {} + +trait IsZero { + type Answer; +} + +struct True; +struct False; + +impl IsZero for () +where (): If<{N == 0}> { //~ERROR constant expression + type Answer = True; +} + +trait Foobar {} + +impl Foobar for () +where (): IsZero {} + +impl Foobar for () +where (): IsZero {} + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-74634.stderr b/src/test/ui/const-generics/issues/issue-74634.stderr new file mode 100644 index 0000000000000..091a1ac7b9981 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-74634.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-74634.rs:15:11 + | +LL | where (): If<{N == 0}> { + | ^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + From 67342304253d8af47fe4453fbe2396b627620431 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Fri, 11 Sep 2020 18:39:26 +0200 Subject: [PATCH 17/28] do not ICE on `ty::Bound` in Layout::compute --- compiler/rustc_middle/src/ty/layout.rs | 4 ++-- .../ui/const-generics/issues/issue-76595.rs | 18 ++++++++++++++++ .../const-generics/issues/issue-76595.stderr | 21 +++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/const-generics/issues/issue-76595.rs create mode 100644 src/test/ui/const-generics/issues/issue-76595.stderr diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index b0a1413a9d62f..cb79b089d94a0 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1259,11 +1259,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { tcx.layout_raw(param_env.and(normalized))? } - ty::Bound(..) | ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Infer(_) => { + ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Infer(_) => { bug!("Layout::compute: unexpected type `{}`", ty) } - ty::Param(_) | ty::Error(_) => { + ty::Bound(..) | ty::Param(_) | ty::Error(_) => { return Err(LayoutError::Unknown(ty)); } }) diff --git a/src/test/ui/const-generics/issues/issue-76595.rs b/src/test/ui/const-generics/issues/issue-76595.rs new file mode 100644 index 0000000000000..0a16ca181f557 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-76595.rs @@ -0,0 +1,18 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +struct Bool; + +trait True {} + +impl True for Bool {} + +fn test() where Bool<{core::mem::size_of::() > 4}>: True { + todo!() +} + +fn main() { + test::<2>(); + //~^ ERROR wrong number of type + //~| ERROR constant expression depends +} diff --git a/src/test/ui/const-generics/issues/issue-76595.stderr b/src/test/ui/const-generics/issues/issue-76595.stderr new file mode 100644 index 0000000000000..4235bdc9b893c --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-76595.stderr @@ -0,0 +1,21 @@ +error[E0107]: wrong number of type arguments: expected 1, found 0 + --> $DIR/issue-76595.rs:15:5 + | +LL | test::<2>(); + | ^^^^^^^^^ expected 1 type argument + +error: constant expression depends on a generic parameter + --> $DIR/issue-76595.rs:15:5 + | +LL | fn test() where Bool<{core::mem::size_of::() > 4}>: True { + | ---- required by a bound in this +... +LL | test::<2>(); + | ^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + = note: required by this bound in `test` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0107`. From 65b3419ca04fdf921309e7fc03010d9d2cc9b8f0 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 20 Sep 2020 09:32:59 +0200 Subject: [PATCH 18/28] update stderr file --- src/test/ui/const-generics/issues/issue-76595.stderr | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/ui/const-generics/issues/issue-76595.stderr b/src/test/ui/const-generics/issues/issue-76595.stderr index 4235bdc9b893c..2e457595393ca 100644 --- a/src/test/ui/const-generics/issues/issue-76595.stderr +++ b/src/test/ui/const-generics/issues/issue-76595.stderr @@ -8,13 +8,12 @@ error: constant expression depends on a generic parameter --> $DIR/issue-76595.rs:15:5 | LL | fn test() where Bool<{core::mem::size_of::() > 4}>: True { - | ---- required by a bound in this + | ---- required by this bound in `test` ... LL | test::<2>(); | ^^^^^^^^^ | = note: this may fail depending on what value the parameter takes - = note: required by this bound in `test` error: aborting due to 2 previous errors From c690c82ad42a15417996a087ef072fd2d8c2fe3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Fri, 18 Sep 2020 18:33:37 +0200 Subject: [PATCH 19/28] use if let instead of single match arm expressions to compact code and reduce nesting (clippy::single_match) --- .../nice_region_error/static_impl_trait.rs | 18 ++++++++---------- compiler/rustc_middle/src/ty/error.rs | 11 ++++------- compiler/rustc_middle/src/ty/print/pretty.rs | 9 +-------- .../rustc_mir/src/transform/promote_consts.rs | 16 +++++----------- compiler/rustc_parse/src/lexer/tokentrees.rs | 9 +++------ compiler/rustc_parse_format/src/lib.rs | 9 +++------ compiler/rustc_resolve/src/lib.rs | 7 ++----- compiler/rustc_symbol_mangling/src/v0.rs | 7 ++----- 8 files changed, 28 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 975b9d4f08631..441cfeea20a48 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -488,18 +488,16 @@ impl<'tcx> Visitor<'tcx> for HirTraitObjectVisitor { } fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) { - match t.kind { - TyKind::TraitObject( - poly_trait_refs, - Lifetime { name: LifetimeName::ImplicitObjectLifetimeDefault, .. }, - ) => { - for ptr in poly_trait_refs { - if Some(self.1) == ptr.trait_ref.trait_def_id() { - self.0.push(ptr.span); - } + if let TyKind::TraitObject( + poly_trait_refs, + Lifetime { name: LifetimeName::ImplicitObjectLifetimeDefault, .. }, + ) = t.kind + { + for ptr in poly_trait_refs { + if Some(self.1) == ptr.trait_ref.trait_def_id() { + self.0.push(ptr.span); } } - _ => {} } walk_ty(self, t); } diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 7226a906e5c97..2a950dcdf23fe 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -832,14 +832,11 @@ fn foo(&self) -> Self::T { String::new() } kind: hir::ItemKind::Impl { items, .. }, .. })) => { for item in &items[..] { - match item.kind { - hir::AssocItemKind::Type => { - if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found { - db.span_label(item.span, "expected this associated type"); - return true; - } + if let hir::AssocItemKind::Type = item.kind { + if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found { + db.span_label(item.span, "expected this associated type"); + return true; } - _ => {} } } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index f0bae48cc1221..c9cc9bfc9fa26 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2125,17 +2125,10 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N // Iterate all local crate items no matter where they are defined. let hir = tcx.hir(); for item in hir.krate().items.values() { - if item.ident.name.as_str().is_empty() { + if item.ident.name.as_str().is_empty() || matches!(item.kind, ItemKind::Use(_, _)) { continue; } - match item.kind { - ItemKind::Use(_, _) => { - continue; - } - _ => {} - } - if let Some(local_def_id) = hir.definitions().opt_hir_id_to_local_def_id(item.hir_id) { let def_id = local_def_id.to_def_id(); let ns = tcx.def_kind(def_id).ns().unwrap_or(Namespace::TypeNS); diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index 37202276161c7..7510c43243b1d 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -242,11 +242,8 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { } TerminatorKind::InlineAsm { ref operands, .. } => { for (index, op) in operands.iter().enumerate() { - match op { - InlineAsmOperand::Const { .. } => { - self.candidates.push(Candidate::InlineAsm { bb: location.block, index }) - } - _ => {} + if let InlineAsmOperand::Const { .. } = op { + self.candidates.push(Candidate::InlineAsm { bb: location.block, index }) } } } @@ -612,12 +609,9 @@ impl<'tcx> Validator<'_, 'tcx> { let operand_ty = operand.ty(self.body, self.tcx); let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); - match (cast_in, cast_out) { - (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => { - // ptr-to-int casts are not possible in consts and thus not promotable - return Err(Unpromotable); - } - _ => {} + if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) { + // ptr-to-int casts are not possible in consts and thus not promotable + return Err(Unpromotable); } } diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index 0f364bffb134e..6233549dc8579 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -149,12 +149,9 @@ impl<'a> TokenTreesReader<'a> { } } - match (open_brace, delim) { - //only add braces - (DelimToken::Brace, DelimToken::Brace) => { - self.matching_block_spans.push((open_brace_span, close_brace_span)); - } - _ => {} + //only add braces + if let (DelimToken::Brace, DelimToken::Brace) = (open_brace, delim) { + self.matching_block_spans.push((open_brace_span, close_brace_span)); } if self.open_braces.is_empty() { diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index e07b8b86aef8e..556bf69c9315e 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -527,12 +527,9 @@ impl<'a> Parser<'a> { // fill character if let Some(&(_, c)) = self.cur.peek() { - match self.cur.clone().nth(1) { - Some((_, '>' | '<' | '^')) => { - spec.fill = Some(c); - self.cur.next(); - } - _ => {} + if let Some((_, '>' | '<' | '^')) = self.cur.clone().nth(1) { + spec.fill = Some(c); + self.cur.next(); } } // Alignment diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 85ddc5f55d110..677cf27cde71c 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -534,11 +534,8 @@ impl<'a> ModuleData<'a> { if ns != TypeNS { return; } - match binding.res() { - Res::Def(DefKind::Trait | DefKind::TraitAlias, _) => { - collected_traits.push((name, binding)) - } - _ => (), + if let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = binding.res() { + collected_traits.push((name, binding)) } }); *traits = Some(collected_traits.into_boxed_slice()); diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 619edf06aa6e6..091d488138e46 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -152,11 +152,8 @@ impl SymbolMangler<'tcx> { let _ = write!(self.out, "{}", ident.len()); // Write a separating `_` if necessary (leading digit or `_`). - match ident.chars().next() { - Some('_' | '0'..='9') => { - self.push("_"); - } - _ => {} + if let Some('_' | '0'..='9') = ident.chars().next() { + self.push("_"); } self.push(ident); From 88a29e630c1ce05fa28ec927e26cbf8a19d6efc4 Mon Sep 17 00:00:00 2001 From: Federico Ponzi Date: Mon, 21 Sep 2020 08:52:59 +0200 Subject: [PATCH 20/28] Updates stability attributes to the current nightly version --- library/std/src/io/stdio.rs | 4 ++-- library/std/src/io/util.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index cccc0aadf9989..b1033636a4536 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -607,7 +607,7 @@ impl Write for Stdout { } } -#[stable(feature = "write_mt", since = "1.47.0")] +#[stable(feature = "write_mt", since = "1.48.0")] impl Write for &Stdout { fn write(&mut self, buf: &[u8]) -> io::Result { self.lock().write(buf) @@ -810,7 +810,7 @@ impl Write for Stderr { } } -#[stable(feature = "write_mt", since = "1.47.0")] +#[stable(feature = "write_mt", since = "1.48.0")] impl Write for &Stderr { fn write(&mut self, buf: &[u8]) -> io::Result { self.lock().write(buf) diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index ce4dd1dcd493d..482378a6aba25 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -248,7 +248,7 @@ impl Write for Sink { } } -#[stable(feature = "write_mt", since = "1.47.0")] +#[stable(feature = "write_mt", since = "1.48.0")] impl Write for &Sink { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { From 0acb0ed1841d362a1119ba2ad293683660bdfaaf Mon Sep 17 00:00:00 2001 From: Federico Ponzi Date: Mon, 21 Sep 2020 08:12:40 +0100 Subject: [PATCH 21/28] Update library/std/src/process.rs Co-authored-by: David Tolnay --- library/std/src/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/process.rs b/library/std/src/process.rs index d620a720be3ab..b2815ba32c4f4 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -262,7 +262,7 @@ impl Write for ChildStdin { } } -#[stable(feature = "write_mt", since = "1.47.0")] +#[stable(feature = "write_mt", since = "1.48.0")] impl Write for &ChildStdin { fn write(&mut self, buf: &[u8]) -> io::Result { self.inner.write(buf) From 60b102de06f52102aa6c343de1f1ef31ff08f8df Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 31 Aug 2020 12:32:37 +0200 Subject: [PATCH 22/28] Don't recommend ManuallyDrop to customize drop order See https://internals.rust-lang.org/t/need-for-controlling-drop-order-of-fields/12914/21 for the discussion. TL;DR: ManuallyDrop is unsafe and footguny, but you can just ask the compiler to do all the work for you by re-ordering declarations. --- library/core/src/mem/manually_drop.rs | 55 +++++++++------------------ 1 file changed, 19 insertions(+), 36 deletions(-) diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index aab0e96d83ab9..d86939454be5b 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -15,50 +15,33 @@ use crate::ptr; /// be exposed through a public safe API. /// Correspondingly, `ManuallyDrop::drop` is unsafe. /// -/// # Examples +/// # `ManuallyDrop` and drop order. /// -/// This wrapper can be used to enforce a particular drop order on fields, regardless -/// of how they are defined in the struct: +/// Rust has a well-defined [drop order] of values. To make sure that fields or +/// locals are dropped in a specific order, reorder the declarations such that +/// the implicit drop order is the correct one. /// -/// ```rust -/// use std::mem::ManuallyDrop; -/// struct Peach; -/// struct Banana; -/// struct Melon; -/// struct FruitBox { -/// // Immediately clear there’s something non-trivial going on with these fields. -/// peach: ManuallyDrop, -/// melon: Melon, // Field that’s independent of the other two. -/// banana: ManuallyDrop, -/// } +/// It is possible to use `ManuallyDrop` to control the drop order, but this +/// requires unsafe code and is hard to do correctly in the presence of +/// unwinding. /// -/// impl Drop for FruitBox { -/// fn drop(&mut self) { -/// unsafe { -/// // Explicit ordering in which field destructors are run specified in the intuitive -/// // location – the destructor of the structure containing the fields. -/// // Moreover, one can now reorder fields within the struct however much they want. -/// ManuallyDrop::drop(&mut self.peach); -/// ManuallyDrop::drop(&mut self.banana); -/// } -/// // After destructor for `FruitBox` runs (this function), the destructor for Melon gets -/// // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`. -/// } -/// } -/// ``` +/// For example, if you want to make sure that a specific field is dropped after +/// the others, make it the last field of a struct: /// -/// However, care should be taken when using this pattern as it can lead to *leak amplification*. -/// In this example, if the `Drop` implementation for `Peach` were to panic, the `banana` field -/// would also be leaked. +/// ``` +/// struct Context; /// -/// In contrast, the automatically-generated compiler drop implementation would have ensured -/// that all fields are dropped even in the presence of panics. This is especially important when -/// working with [pinned] data, where reusing the memory without calling the destructor could lead -/// to Undefined Behaviour. +/// struct Widget { +/// children: Vec, +/// // `context` will be dropped after `children`. +/// // Rust guarantees that fields are dropped in the order of declaration. +/// context: Context, +/// } +/// ``` /// +/// [drop order]: https://doc.rust-lang.org/reference/destructors.html /// [`mem::zeroed`]: crate::mem::zeroed /// [`MaybeUninit`]: crate::mem::MaybeUninit -/// [pinned]: crate::pin #[stable(feature = "manually_drop", since = "1.20.0")] #[lang = "manually_drop"] #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] From b4b4a2f0927d2d1d838da1e128472ff8bf64e98b Mon Sep 17 00:00:00 2001 From: James Whaley Date: Mon, 21 Sep 2020 18:27:43 +0100 Subject: [PATCH 23/28] Reduce boilerplate for BytePos and CharPos --- compiler/rustc_span/src/lib.rs | 137 +++++++++++++-------------------- 1 file changed, 55 insertions(+), 82 deletions(-) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index a730c30378827..ad3a866463d45 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1558,58 +1558,71 @@ pub trait Pos { fn to_u32(&self) -> u32; } -/// A byte offset. Keep this small (currently 32-bits), as AST contains -/// a lot of them. -#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] -pub struct BytePos(pub u32); - -/// A character offset. Because of multibyte UTF-8 characters, a byte offset -/// is not equivalent to a character offset. The `SourceMap` will convert `BytePos` -/// values to `CharPos` values as necessary. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] -pub struct CharPos(pub usize); +macro_rules! impl_pos { + ( + $( + $(#[$attr:meta])* + $vis:vis struct $ident:ident($inner_vis:vis $inner_ty:ty); + )* + ) => { + $( + $(#[$attr])* + $vis struct $ident($inner_vis $inner_ty); + + impl Pos for $ident { + #[inline(always)] + fn from_usize(n: usize) -> $ident { + $ident(n as $inner_ty) + } -// FIXME: lots of boilerplate in these impls, but so far my attempts to fix -// have been unsuccessful. + #[inline(always)] + fn to_usize(&self) -> usize { + self.0 as usize + } -impl Pos for BytePos { - #[inline(always)] - fn from_usize(n: usize) -> BytePos { - BytePos(n as u32) - } + #[inline(always)] + fn from_u32(n: u32) -> $ident { + $ident(n as $inner_ty) + } - #[inline(always)] - fn to_usize(&self) -> usize { - self.0 as usize - } + #[inline(always)] + fn to_u32(&self) -> u32 { + self.0 as u32 + } + } - #[inline(always)] - fn from_u32(n: u32) -> BytePos { - BytePos(n) - } + impl Add for $ident { + type Output = $ident; - #[inline(always)] - fn to_u32(&self) -> u32 { - self.0 - } -} + #[inline(always)] + fn add(self, rhs: $ident) -> $ident { + $ident((self.to_usize() + rhs.to_usize()) as $inner_ty) + } + } -impl Add for BytePos { - type Output = BytePos; + impl Sub for $ident { + type Output = $ident; - #[inline(always)] - fn add(self, rhs: BytePos) -> BytePos { - BytePos((self.to_usize() + rhs.to_usize()) as u32) - } + #[inline(always)] + fn sub(self, rhs: $ident) -> $ident { + $ident((self.to_usize() - rhs.to_usize()) as $inner_ty) + } + } + )* + }; } -impl Sub for BytePos { - type Output = BytePos; +impl_pos! { + /// A byte offset. Keep this small (currently 32-bits), as AST contains + /// a lot of them. + #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] + pub struct BytePos(pub u32); - #[inline(always)] - fn sub(self, rhs: BytePos) -> BytePos { - BytePos((self.to_usize() - rhs.to_usize()) as u32) - } + /// A character offset. Because of multibyte UTF-8 characters, a byte offset + /// is not equivalent to a character offset. The `SourceMap` will convert `BytePos` + /// values to `CharPos` values as necessary. + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] + pub struct CharPos(pub usize); } impl Encodable for BytePos { @@ -1624,46 +1637,6 @@ impl Decodable for BytePos { } } -impl Pos for CharPos { - #[inline(always)] - fn from_usize(n: usize) -> CharPos { - CharPos(n) - } - - #[inline(always)] - fn to_usize(&self) -> usize { - self.0 - } - - #[inline(always)] - fn from_u32(n: u32) -> CharPos { - CharPos(n as usize) - } - - #[inline(always)] - fn to_u32(&self) -> u32 { - self.0 as u32 - } -} - -impl Add for CharPos { - type Output = CharPos; - - #[inline(always)] - fn add(self, rhs: CharPos) -> CharPos { - CharPos(self.to_usize() + rhs.to_usize()) - } -} - -impl Sub for CharPos { - type Output = CharPos; - - #[inline(always)] - fn sub(self, rhs: CharPos) -> CharPos { - CharPos(self.to_usize() - rhs.to_usize()) - } -} - // _____________________________________________________________________________ // Loc, SourceFileAndLine, SourceFileAndBytePos // From 8fc782afc204adf1d2d6c1e0f13b1242aef396d4 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 21 Sep 2020 20:28:52 +0200 Subject: [PATCH 24/28] add test --- compiler/rustc_lint/src/internal.rs | 6 ++++ .../internal-lints/pass_ty_by_ref_self.rs | 33 +++++++++++++++++++ .../internal-lints/pass_ty_by_ref_self.stderr | 20 +++++++++++ 3 files changed, 59 insertions(+) create mode 100644 src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs create mode 100644 src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 2bac4517409b4..c2d98b8e4ad37 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -191,6 +191,12 @@ fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, ty: &Ty<'_>) -> Option { Res::SelfTy(None, Some((did, _))) => { if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() { if cx.tcx.is_diagnostic_item(sym::Ty, adt.did) { + // NOTE: This path is currently unreachable as `Ty<'tcx>` is + // defined as a type alias meaning that `impl<'tcx> Ty<'tcx>` + // is not actually allowed. + // + // I(@lcnr) still kept this branch in so we don't miss this + // if we ever change it in the future. return Some(format!("Ty<{}>", substs[0])); } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, adt.did) { return Some(format!("TyCtxt<{}>", substs[0])); diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs new file mode 100644 index 0000000000000..f58446d559222 --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs @@ -0,0 +1,33 @@ +// NOTE: This test doesn't actually require `fulldeps` +// so we could instead use it as an `ui` test. +// +// Considering that all other `internal-lints` are tested here +// this seems like the cleaner solution though. +#![feature(rustc_attrs)] +#![deny(rustc::ty_pass_by_reference)] +#![allow(unused)] + +#[rustc_diagnostic_item = "TyCtxt"] +struct TyCtxt<'tcx> { + inner: &'tcx (), +} + +impl<'tcx> TyCtxt<'tcx> { + fn by_value(self) {} // OK + fn by_ref(&self) {} //~ ERROR passing `TyCtxt<'tcx>` by reference +} + + +struct TyS<'tcx> { + inner: &'tcx (), +} + +#[rustc_diagnostic_item = "Ty"] +type Ty<'tcx> = &'tcx TyS<'tcx>; + +impl<'tcx> TyS<'tcx> { + fn by_value(self: Ty<'tcx>) {} + fn by_ref(self: &Ty<'tcx>) {} //~ ERROR passing `Ty<'tcx>` by reference +} + +fn main() {} diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr new file mode 100644 index 0000000000000..b846b30f4ed37 --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr @@ -0,0 +1,20 @@ +error: passing `TyCtxt<'tcx>` by reference + --> $DIR/pass_ty_by_ref_self.rs:17:15 + | +LL | fn by_ref(&self) {} + | ^^^^^ help: try passing by value: `TyCtxt<'tcx>` + | +note: the lint level is defined here + --> $DIR/pass_ty_by_ref_self.rs:7:9 + | +LL | #![deny(rustc::ty_pass_by_reference)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: passing `Ty<'tcx>` by reference + --> $DIR/pass_ty_by_ref_self.rs:30:21 + | +LL | fn by_ref(self: &Ty<'tcx>) {} + | ^^^^^^^^^ help: try passing by value: `Ty<'tcx>` + +error: aborting due to 2 previous errors + From 9a1f1777d3602b267c78229e1d5de68fe7eab57a Mon Sep 17 00:00:00 2001 From: James Whaley Date: Mon, 21 Sep 2020 19:42:43 +0100 Subject: [PATCH 25/28] Remove cast to usize for BytePos and CharPos The case shouldn't be necessary and implicitly truncating BytePos is not desirable. --- compiler/rustc_span/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index ad3a866463d45..4b02a2d4076d7 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1596,7 +1596,7 @@ macro_rules! impl_pos { #[inline(always)] fn add(self, rhs: $ident) -> $ident { - $ident((self.to_usize() + rhs.to_usize()) as $inner_ty) + $ident(self.0 + rhs.0) } } @@ -1605,7 +1605,7 @@ macro_rules! impl_pos { #[inline(always)] fn sub(self, rhs: $ident) -> $ident { - $ident((self.to_usize() - rhs.to_usize()) as $inner_ty) + $ident(self.0 - rhs.0) } } )* From 63195ecb458bba01f36f407b6df69aa03828243e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 8 Sep 2020 21:02:18 +0200 Subject: [PATCH 26/28] Add explanation for E0756 --- compiler/rustc_error_codes/src/error_codes.rs | 2 +- .../src/error_codes/E0756.md | 29 +++++++++++++++++++ src/test/ui/ffi_const.stderr | 1 + 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0756.md diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 23a7b08016e50..a202736ea6cbe 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -441,6 +441,7 @@ E0752: include_str!("./error_codes/E0752.md"), E0753: include_str!("./error_codes/E0753.md"), E0754: include_str!("./error_codes/E0754.md"), E0755: include_str!("./error_codes/E0755.md"), +E0756: include_str!("./error_codes/E0756.md"), E0758: include_str!("./error_codes/E0758.md"), E0759: include_str!("./error_codes/E0759.md"), E0760: include_str!("./error_codes/E0760.md"), @@ -633,7 +634,6 @@ E0774: include_str!("./error_codes/E0774.md"), E0722, // Malformed `#[optimize]` attribute E0726, // non-explicit (not `'_`) elided lifetime in unsupported position // E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. - E0756, // `#[ffi_const]` is only allowed on foreign functions E0757, // `#[ffi_const]` functions cannot be `#[ffi_pure]` E0772, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`. } diff --git a/compiler/rustc_error_codes/src/error_codes/E0756.md b/compiler/rustc_error_codes/src/error_codes/E0756.md new file mode 100644 index 0000000000000..ffdc421aab584 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0756.md @@ -0,0 +1,29 @@ +The `ffi_const` attribute was used on something other than a foreign function +declaration. + +Erroneous code example: + +```compile_fail,E0756 +#![feature(ffi_const)] + +#[ffi_const] // error! +pub fn foo() {} +# fn main() {} +``` + +The `ffi_const` attribute can only be used on foreign function declarations +which have no side effects except for their return value: + +``` +#![feature(ffi_const)] + +extern "C" { + #[ffi_const] // ok! + pub fn strlen(s: *const i8) -> i32; +} +# fn main() {} +``` + +You can get more information about it in the [unstable Rust Book]. + +[unstable Rust Book]: https://doc.rust-lang.org/nightly/unstable-book/language-features/ffi-const.html diff --git a/src/test/ui/ffi_const.stderr b/src/test/ui/ffi_const.stderr index 623551cc07bbb..bc3c12eaf981b 100644 --- a/src/test/ui/ffi_const.stderr +++ b/src/test/ui/ffi_const.stderr @@ -6,3 +6,4 @@ LL | #[ffi_const] error: aborting due to previous error +For more information about this error, try `rustc --explain E0756`. From f5d71a9b3cf3018ec646acb6f8fa731fb8ca902e Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 30 Aug 2020 18:08:16 -0400 Subject: [PATCH 27/28] Don't use `zip` to compare iterators during pretty-print hack If the right-hand iterator has exactly one more element than the left-hand iterator, then both iterators will be fully consumed, but the extra element will never be compared. --- compiler/rustc_parse/src/lib.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 72a34b86ae20b..21bbdc9ba8dce 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -3,6 +3,7 @@ #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(bindings_after_at)] +#![feature(iter_order_by)] #![feature(or_patterns)] use rustc_ast as ast; @@ -459,14 +460,10 @@ pub fn tokenstream_probably_equal_for_proc_macro( // Break tokens after we expand any nonterminals, so that we break tokens // that are produced as a result of nonterminal expansion. - let mut t1 = first.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens); - let mut t2 = other.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens); - for (t1, t2) in t1.by_ref().zip(t2.by_ref()) { - if !tokentree_probably_equal_for_proc_macro(&t1, &t2, sess) { - return false; - } - } - t1.next().is_none() && t2.next().is_none() + let t1 = first.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens); + let t2 = other.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens); + + t1.eq_by(t2, |t1, t2| tokentree_probably_equal_for_proc_macro(&t1, &t2, sess)) } // See comments in `Nonterminal::to_tokenstream` for why we care about From d452744100203c9f75202079ce7c8ad8aa1bdf02 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 21 Sep 2020 23:48:39 +0200 Subject: [PATCH 28/28] lint missing docs for extern items --- compiler/rustc_lint/src/builtin.rs | 13 +++++++++++++ src/test/ui/lint/lint-missing-doc.rs | 19 ++++++++++++++++++- src/test/ui/lint/lint-missing-doc.stderr | 20 +++++++++++++++++++- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index c35b6a9aaf4e9..abd899e8db4d3 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -613,6 +613,19 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { ); } + fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'_>) { + let def_id = cx.tcx.hir().local_def_id(foreign_item.hir_id); + let (article, desc) = cx.tcx.article_and_description(def_id.to_def_id()); + self.check_missing_docs_attrs( + cx, + Some(foreign_item.hir_id), + &foreign_item.attrs, + foreign_item.span, + article, + desc, + ); + } + fn check_struct_field(&mut self, cx: &LateContext<'_>, sf: &hir::StructField<'_>) { if !sf.is_positional() { self.check_missing_docs_attrs( diff --git a/src/test/ui/lint/lint-missing-doc.rs b/src/test/ui/lint/lint-missing-doc.rs index bab6f4e9e5e15..2297257919ee1 100644 --- a/src/test/ui/lint/lint-missing-doc.rs +++ b/src/test/ui/lint/lint-missing-doc.rs @@ -2,7 +2,7 @@ // injected intrinsics by the compiler. #![deny(missing_docs)] #![allow(dead_code)] -#![feature(associated_type_defaults)] +#![feature(associated_type_defaults, extern_types)] //! Some garbage docs for the crate here #![doc="More garbage"] @@ -183,4 +183,21 @@ pub mod public_interface { pub use internal_impl::globbed::*; } +extern "C" { + /// dox + pub fn extern_fn_documented(f: f32) -> f32; + pub fn extern_fn_undocumented(f: f32) -> f32; + //~^ ERROR: missing documentation for a function + + /// dox + pub static EXTERN_STATIC_DOCUMENTED: u8; + pub static EXTERN_STATIC_UNDOCUMENTED: u8; + //~^ ERROR: missing documentation for a static + + /// dox + pub type ExternTyDocumented; + pub type ExternTyUndocumented; + //~^ ERROR: missing documentation for a foreign type +} + fn main() {} diff --git a/src/test/ui/lint/lint-missing-doc.stderr b/src/test/ui/lint/lint-missing-doc.stderr index 21da4fae4c161..56f8fc10e8623 100644 --- a/src/test/ui/lint/lint-missing-doc.stderr +++ b/src/test/ui/lint/lint-missing-doc.stderr @@ -118,5 +118,23 @@ error: missing documentation for a function LL | pub fn also_undocumented1() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 19 previous errors +error: missing documentation for a function + --> $DIR/lint-missing-doc.rs:189:5 + | +LL | pub fn extern_fn_undocumented(f: f32) -> f32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: missing documentation for a static + --> $DIR/lint-missing-doc.rs:194:5 + | +LL | pub static EXTERN_STATIC_UNDOCUMENTED: u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: missing documentation for a foreign type + --> $DIR/lint-missing-doc.rs:199:5 + | +LL | pub type ExternTyUndocumented; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 22 previous errors