diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 41966360377b3..01dee0a394337 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -320,7 +320,7 @@ impl Box { /// This conversion does not allocate on the heap and happens in place. /// /// This is also available via [`From`]. - #[unstable(feature = "box_into_pin", issue = "0")] + #[unstable(feature = "box_into_pin", issue = "62370")] pub fn into_pin(boxed: Box) -> Pin> { // It's not possible to move or replace the insides of a `Pin>` // when `T: !Unpin`, so it's safe to pin it directly without any diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index ca35600e85792..d466948a0178e 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -2032,7 +2032,7 @@ impl BTreeMap { /// assert_eq!(keys, [1, 2]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn keys<'a>(&'a self) -> Keys<'a, K, V> { + pub fn keys(&self) -> Keys<'_, K, V> { Keys { inner: self.iter() } } @@ -2053,7 +2053,7 @@ impl BTreeMap { /// assert_eq!(values, ["hello", "goodbye"]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn values<'a>(&'a self) -> Values<'a, K, V> { + pub fn values(&self) -> Values<'_, K, V> { Values { inner: self.iter() } } @@ -2557,8 +2557,8 @@ enum UnderflowResult<'a, K, V> { Stole(NodeRef, K, V, marker::Internal>), } -fn handle_underfull_node<'a, K, V>(node: NodeRef, K, V, marker::LeafOrInternal>) - -> UnderflowResult<'a, K, V> { +fn handle_underfull_node(node: NodeRef, K, V, marker::LeafOrInternal>) + -> UnderflowResult<'_, K, V> { let parent = if let Ok(parent) = node.ascend() { parent } else { diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs index 581c66c7086a5..7cf077d61d687 100644 --- a/src/liballoc/collections/btree/node.rs +++ b/src/liballoc/collections/btree/node.rs @@ -394,7 +394,7 @@ impl NodeRef { } /// Temporarily takes out another, immutable reference to the same node. - fn reborrow<'a>(&'a self) -> NodeRef, K, V, Type> { + fn reborrow(&self) -> NodeRef, K, V, Type> { NodeRef { height: self.height, node: self.node, diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 1b0d3c1969274..366191e2c85f3 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -552,7 +552,7 @@ impl String { /// assert_eq!("Hello �World", output); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn from_utf8_lossy<'a>(v: &'a [u8]) -> Cow<'a, str> { + pub fn from_utf8_lossy(v: &[u8]) -> Cow<'_, str> { let mut iter = lossy::Utf8Lossy::from_bytes(v).chunks(); let (first_valid, first_broken) = if let Some(chunk) = iter.next() { diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index b30eff8baa9c8..3afb7e2e2a015 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -36,6 +36,8 @@ issue = "0")] #![allow(missing_docs)] +use crate::mem; + #[stable(feature = "drop_in_place", since = "1.8.0")] #[rustc_deprecated(reason = "no longer an intrinsic - use `ptr::drop_in_place` directly", since = "1.18.0")] @@ -700,17 +702,15 @@ extern "rust-intrinsic" { /// which is unsafe unless `T` is `Copy`. Also, even if T is /// `Copy`, an all-zero value may not correspond to any legitimate /// state for the type in question. + #[unstable(feature = "core_intrinsics", + reason = "intrinsics are unlikely to ever be stabilized, instead \ + they should be used through stabilized interfaces \ + in the rest of the standard library", + issue = "0")] + #[rustc_deprecated(reason = "no longer used by rustc, will be removed - use MaybeUnint instead", + since = "1.38.0")] pub fn init() -> T; - /// Creates an uninitialized value. - /// - /// `uninit` is unsafe because there is no guarantee of what its - /// contents are. In particular its drop-flag may be set to any - /// state, which means it may claim either dropped or - /// undropped. In the general case one must use `ptr::write` to - /// initialize memory previous set to the result of `uninit`. - pub fn uninit() -> T; - /// Moves a value out of scope without running drop glue. pub fn forget(_: T); @@ -1331,6 +1331,26 @@ extern "rust-intrinsic" { // (`transmute` also falls into this category, but it cannot be wrapped due to the // check that `T` and `U` have the same size.) +/// Checks whether `ptr` is properly aligned with respect to +/// `align_of::()`. +pub(crate) fn is_aligned_and_not_null(ptr: *const T) -> bool { + !ptr.is_null() && ptr as usize % mem::align_of::() == 0 +} + +/// Checks whether the regions of memory starting at `src` and `dst` of size +/// `count * size_of::()` overlap. +fn overlaps(src: *const T, dst: *const T, count: usize) -> bool { + let src_usize = src as usize; + let dst_usize = dst as usize; + let size = mem::size_of::().checked_mul(count).unwrap(); + let diff = if src_usize > dst_usize { + src_usize - dst_usize + } else { + dst_usize - src_usize + }; + size > diff +} + /// Copies `count * size_of::()` bytes from `src` to `dst`. The source /// and destination must *not* overlap. /// @@ -1420,7 +1440,11 @@ pub unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { extern "rust-intrinsic" { fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); } - copy_nonoverlapping(src, dst, count); + + debug_assert!(is_aligned_and_not_null(src), "attempt to copy from unaligned or null pointer"); + debug_assert!(is_aligned_and_not_null(dst), "attempt to copy to unaligned or null pointer"); + debug_assert!(!overlaps(src, dst, count), "attempt to copy to overlapping memory"); + copy_nonoverlapping(src, dst, count) } /// Copies `count * size_of::()` bytes from `src` to `dst`. The source @@ -1480,6 +1504,9 @@ pub unsafe fn copy(src: *const T, dst: *mut T, count: usize) { extern "rust-intrinsic" { fn copy(src: *const T, dst: *mut T, count: usize); } + + debug_assert!(is_aligned_and_not_null(src), "attempt to copy from unaligned or null pointer"); + debug_assert!(is_aligned_and_not_null(dst), "attempt to copy to unaligned or null pointer"); copy(src, dst, count) } @@ -1561,6 +1588,8 @@ pub unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { extern "rust-intrinsic" { fn write_bytes(dst: *mut T, val: u8, count: usize); } + + debug_assert!(is_aligned_and_not_null(dst), "attempt to write to unaligned or null pointer"); write_bytes(dst, val, count) } diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index d2d08a075b92c..8d9062d546c7d 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -74,6 +74,7 @@ #![feature(concat_idents)] #![feature(const_fn)] #![feature(const_fn_union)] +#![feature(custom_inner_attributes)] #![feature(doc_cfg)] #![feature(doc_spotlight)] #![feature(extern_types)] diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index d9757d78dcebb..39c390b4df6d3 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -498,7 +498,7 @@ macro_rules! impls{ /// # end: *const T, /// # phantom: PhantomData<&'a T>, /// # } -/// fn borrow_vec<'a, T>(vec: &'a Vec) -> Slice<'a, T> { +/// fn borrow_vec(vec: &Vec) -> Slice<'_, T> { /// let ptr = vec.as_ptr(); /// Slice { /// start: ptr, diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs index b31522db474b7..b62d81affddbd 100644 --- a/src/libcore/mem/mod.rs +++ b/src/libcore/mem/mod.rs @@ -450,8 +450,7 @@ pub const fn needs_drop() -> bool { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn zeroed() -> T { - intrinsics::panic_if_uninhabited::(); - intrinsics::init() + MaybeUninit::zeroed().assume_init() } /// Bypasses Rust's normal memory-initialization checks by pretending to @@ -476,8 +475,7 @@ pub unsafe fn zeroed() -> T { #[rustc_deprecated(since = "1.38.0", reason = "use `mem::MaybeUninit` instead")] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn uninitialized() -> T { - intrinsics::panic_if_uninhabited::(); - intrinsics::uninit() + MaybeUninit::uninit().assume_init() } /// Swaps the values at two mutable locations, without deinitializing either one. diff --git a/src/libcore/ops/index.rs b/src/libcore/ops/index.rs index 3158f58e95806..9cff474a76030 100644 --- a/src/libcore/ops/index.rs +++ b/src/libcore/ops/index.rs @@ -105,7 +105,7 @@ pub trait Index { /// impl Index for Balance { /// type Output = Weight; /// -/// fn index<'a>(&'a self, index: Side) -> &'a Self::Output { +/// fn index(&self, index: Side) -> &Self::Output { /// println!("Accessing {:?}-side of balance immutably", index); /// match index { /// Side::Left => &self.left, @@ -115,7 +115,7 @@ pub trait Index { /// } /// /// impl IndexMut for Balance { -/// fn index_mut<'a>(&'a mut self, index: Side) -> &'a mut Self::Output { +/// fn index_mut(&mut self, index: Side) -> &mut Self::Output { /// println!("Accessing {:?}-side of balance mutably", index); /// match index { /// Side::Left => &mut self.left, diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs index da781d7e9feee..2a6c2b1331e5c 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -625,42 +625,50 @@ pub unsafe fn read(src: *const T) -> T { /// [read-ownership]: ./fn.read.html#ownership-of-the-returned-value /// [valid]: ../ptr/index.html#safety /// -/// # Examples +/// ## On `packed` structs /// -/// Access members of a packed struct by reference: +/// It is currently impossible to create raw pointers to unaligned fields +/// of a packed struct. /// -/// ``` -/// use std::ptr; +/// Attempting to create a raw pointer to an `unaligned` struct field with +/// an expression such as `&packed.unaligned as *const FieldType` creates an +/// intermediate unaligned reference before converting that to a raw pointer. +/// That this reference is temporary and immediately cast is inconsequential +/// as the compiler always expects references to be properly aligned. +/// As a result, using `&packed.unaligned as *const FieldType` causes immediate +/// *undefined behavior* in your program. /// +/// An example of what not to do and how this relates to `read_unaligned` is: +/// +/// ```no_run /// #[repr(packed, C)] /// struct Packed { /// _padding: u8, /// unaligned: u32, /// } /// -/// let x = Packed { +/// let packed = Packed { /// _padding: 0x00, /// unaligned: 0x01020304, /// }; /// /// let v = unsafe { -/// // Take the address of a 32-bit integer which is not aligned. -/// // This must be done as a raw pointer; unaligned references are invalid. -/// let unaligned = &x.unaligned as *const u32; -/// -/// // Dereferencing normally will emit an aligned load instruction, -/// // causing undefined behavior. -/// // let v = *unaligned; // ERROR +/// // Here we attempt to take the address of a 32-bit integer which is not aligned. +/// let unaligned = +/// // A temporary unaligned reference is created here which results in +/// // undefined behavior regardless of whether the reference is used or not. +/// &packed.unaligned +/// // Casting to a raw pointer doesn't help; the mistake already happened. +/// as *const u32; /// -/// // Instead, use `read_unaligned` to read improperly aligned values. -/// let v = ptr::read_unaligned(unaligned); +/// let v = std::ptr::read_unaligned(unaligned); /// /// v /// }; -/// -/// // Accessing unaligned values directly is safe. -/// assert!(x.unaligned == v); /// ``` +/// +/// Accessing unaligned fields directly with e.g. `packed.unaligned` is safe however. +// FIXME: Update docs based on outcome of RFC #2582 and friends. #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] pub unsafe fn read_unaligned(src: *const T) -> T { @@ -789,38 +797,48 @@ pub unsafe fn write(dst: *mut T, src: T) { /// /// [valid]: ../ptr/index.html#safety /// -/// # Examples +/// ## On `packed` structs /// -/// Access fields in a packed struct: +/// It is currently impossible to create raw pointers to unaligned fields +/// of a packed struct. /// -/// ``` -/// use std::{mem, ptr}; +/// Attempting to create a raw pointer to an `unaligned` struct field with +/// an expression such as `&packed.unaligned as *const FieldType` creates an +/// intermediate unaligned reference before converting that to a raw pointer. +/// That this reference is temporary and immediately cast is inconsequential +/// as the compiler always expects references to be properly aligned. +/// As a result, using `&packed.unaligned as *const FieldType` causes immediate +/// *undefined behavior* in your program. /// +/// An example of what not to do and how this relates to `write_unaligned` is: +/// +/// ```no_run /// #[repr(packed, C)] -/// #[derive(Default)] /// struct Packed { /// _padding: u8, /// unaligned: u32, /// } /// /// let v = 0x01020304; -/// let mut x: Packed = unsafe { mem::zeroed() }; -/// -/// unsafe { -/// // Take a reference to a 32-bit integer which is not aligned. -/// let unaligned = &mut x.unaligned as *mut u32; +/// let mut packed: Packed = unsafe { std::mem::zeroed() }; /// -/// // Dereferencing normally will emit an aligned store instruction, -/// // causing undefined behavior because the pointer is not aligned. -/// // *unaligned = v; // ERROR +/// let v = unsafe { +/// // Here we attempt to take the address of a 32-bit integer which is not aligned. +/// let unaligned = +/// // A temporary unaligned reference is created here which results in +/// // undefined behavior regardless of whether the reference is used or not. +/// &mut packed.unaligned +/// // Casting to a raw pointer doesn't help; the mistake already happened. +/// as *mut u32; /// -/// // Instead, use `write_unaligned` to write improperly aligned values. -/// ptr::write_unaligned(unaligned, v); -/// } +/// std::ptr::write_unaligned(unaligned, v); /// -/// // Accessing unaligned values directly is safe. -/// assert!(x.unaligned == v); +/// v +/// }; /// ``` +/// +/// Accessing unaligned fields directly with e.g. `packed.unaligned` is safe however. +// FIXME: Update docs based on outcome of RFC #2582 and friends. #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] pub unsafe fn write_unaligned(dst: *mut T, src: T) { diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index fe48e2458cd16..4757ab26cdf0b 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -25,7 +25,7 @@ use crate::cmp::Ordering::{self, Less, Equal, Greater}; use crate::cmp; use crate::fmt; -use crate::intrinsics::{assume, exact_div, unchecked_sub}; +use crate::intrinsics::{assume, exact_div, unchecked_sub, is_aligned_and_not_null}; use crate::isize; use crate::iter::*; use crate::ops::{FnMut, Try, self}; @@ -5228,7 +5228,7 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { - debug_assert!(data as usize % mem::align_of::() == 0, "attempt to create unaligned slice"); + debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice"); debug_assert!(mem::size_of::().saturating_mul(len) <= isize::MAX as usize, "attempt to create slice covering half the address space"); &*ptr::slice_from_raw_parts(data, len) @@ -5249,7 +5249,7 @@ pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] { - debug_assert!(data as usize % mem::align_of::() == 0, "attempt to create unaligned slice"); + debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice"); debug_assert!(mem::size_of::().saturating_mul(len) <= isize::MAX as usize, "attempt to create slice covering half the address space"); &mut *ptr::slice_from_raw_parts_mut(data, len) diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index d2082ab87e738..442a90ab3f845 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -422,11 +422,6 @@ rustc_queries! { "const-evaluating `{}`", tcx.def_path_str(key.value.instance.def.def_id()) } - cache_on_disk_if(_, opt_result) { - // Only store results without errors - // FIXME: We never store these - opt_result.map_or(true, |r| r.is_ok()) - } } /// Results of evaluating const items or constants embedded in diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 4710d611d99df..88236a79421f3 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1,5 +1,3 @@ -// ignore-tidy-filelength - //! Type context book-keeping. use crate::arena::Arena; @@ -67,7 +65,6 @@ use std::ops::{Deref, Bound}; use std::iter; use std::sync::mpsc; use std::sync::Arc; -use std::marker::PhantomData; use rustc_target::spec::abi; use rustc_macros::HashStable; use syntax::ast; @@ -81,14 +78,12 @@ use crate::hir; pub struct AllArenas { pub interner: SyncDroplessArena, - pub local_interner: SyncDroplessArena, } impl AllArenas { pub fn new() -> Self { AllArenas { interner: SyncDroplessArena::default(), - local_interner: SyncDroplessArena::default(), } } } @@ -136,57 +131,21 @@ impl<'tcx> CtxtInterners<'tcx> { /// Intern a type #[inline(never)] - fn intern_ty( - local: &CtxtInterners<'tcx>, - global: &CtxtInterners<'tcx>, - st: TyKind<'tcx>, + fn intern_ty(&self, + st: TyKind<'tcx> ) -> Ty<'tcx> { - let flags = super::flags::FlagComputation::for_sty(&st); - - // HACK(eddyb) Depend on flags being accurate to - // determine that all contents are in the global tcx. - // See comments on Lift for why we can't use that. - if flags.flags.intersects(ty::TypeFlags::KEEP_IN_LOCAL_TCX) { - local.type_.borrow_mut().intern(st, |st| { - let ty_struct = TyS { - sty: st, - flags: flags.flags, - outer_exclusive_binder: flags.outer_exclusive_binder, - }; + self.type_.borrow_mut().intern(st, |st| { + let flags = super::flags::FlagComputation::for_sty(&st); - // Make sure we don't end up with inference - // types/regions in the global interner - if ptr_eq(local, global) { - bug!("Attempted to intern `{:?}` which contains \ - inference types/regions in the global type context", - &ty_struct); - } - - // This is safe because all the types the ty_struct can point to - // already is in the local arena or the global arena - let ty_struct: TyS<'tcx> = unsafe { - mem::transmute(ty_struct) - }; - - Interned(local.arena.alloc(ty_struct)) - }).0 - } else { - global.type_.borrow_mut().intern(st, |st| { - let ty_struct = TyS { - sty: st, - flags: flags.flags, - outer_exclusive_binder: flags.outer_exclusive_binder, - }; + let ty_struct = TyS { + sty: st, + flags: flags.flags, + outer_exclusive_binder: flags.outer_exclusive_binder, + }; - // This is safe because all the types the ty_struct can point to - // already is in the global arena - let ty_struct: TyS<'tcx> = unsafe { - mem::transmute(ty_struct) - }; - Interned(global.arena.alloc(ty_struct)) - }).0 - } + Interned(self.arena.alloc(ty_struct)) + }).0 } } @@ -933,7 +892,7 @@ EnumLiftImpl! { impl<'tcx> CommonTypes<'tcx> { fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> { - let mk = |sty| CtxtInterners::intern_ty(interners, interners, sty); + let mk = |sty| interners.intern_ty(sty); CommonTypes { unit: mk(Tuple(List::empty())), @@ -1015,8 +974,6 @@ pub struct FreeRegionInfo { #[derive(Copy, Clone)] pub struct TyCtxt<'tcx> { gcx: &'tcx GlobalCtxt<'tcx>, - interners: &'tcx CtxtInterners<'tcx>, - dummy: PhantomData<&'tcx ()>, } impl<'tcx> Deref for TyCtxt<'tcx> { @@ -1030,8 +987,7 @@ impl<'tcx> Deref for TyCtxt<'tcx> { pub struct GlobalCtxt<'tcx> { pub arena: WorkerLocal>, - global_interners: CtxtInterners<'tcx>, - local_interners: CtxtInterners<'tcx>, + interners: CtxtInterners<'tcx>, cstore: &'tcx CrateStoreDyn, @@ -1122,8 +1078,6 @@ impl<'tcx> TyCtxt<'tcx> { pub fn global_tcx(self) -> TyCtxt<'tcx> { TyCtxt { gcx: self.gcx, - interners: &self.gcx.global_interners, - dummy: PhantomData, } } @@ -1203,11 +1157,6 @@ impl<'tcx> TyCtxt<'tcx> { value.lift_to_tcx(self.global_tcx()) } - /// Returns `true` if self is the same as self.global_tcx(). - fn is_global(self) -> bool { - ptr_eq(self.interners, &self.global_interners) - } - /// Creates a type context and call the closure with a `TyCtxt` reference /// to the context. The closure enforces that the type context and any interned /// value (types, substs, etc.) can only be used while `ty::tls` has a valid @@ -1229,7 +1178,6 @@ impl<'tcx> TyCtxt<'tcx> { s.fatal(&err); }); let interners = CtxtInterners::new(&arenas.interner); - let local_interners = CtxtInterners::new(&arenas.local_interner); let common = Common { empty_predicates: ty::GenericPredicates { parent: None, @@ -1287,8 +1235,7 @@ impl<'tcx> TyCtxt<'tcx> { sess: s, cstore, arena: WorkerLocal::new(|_| Arena::default()), - global_interners: interners, - local_interners: local_interners, + interners, dep_graph, common, types: common_types, @@ -1682,8 +1629,6 @@ impl<'tcx> GlobalCtxt<'tcx> { { let tcx = TyCtxt { gcx: self, - interners: &self.local_interners, - dummy: PhantomData, }; ty::tls::with_related_context(tcx.global_tcx(), |icx| { let new_icx = ty::tls::ImplicitCtxt { @@ -1729,11 +1674,7 @@ macro_rules! nop_lift { type Lifted = $lifted; fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { if tcx.interners.arena.in_arena(*self as *const _) { - return Some(unsafe { mem::transmute(*self) }); - } - // Also try in the global tcx if we're not that. - if !tcx.is_global() { - self.lift_to_tcx(tcx.global_tcx()) + Some(unsafe { mem::transmute(*self) }) } else { None } @@ -1751,11 +1692,7 @@ macro_rules! nop_list_lift { return Some(List::empty()); } if tcx.interners.arena.in_arena(*self as *const _) { - return Some(unsafe { mem::transmute(*self) }); - } - // Also try in the global tcx if we're not that. - if !tcx.is_global() { - self.lift_to_tcx(tcx.global_tcx()) + Some(unsafe { mem::transmute(*self) }) } else { None } @@ -1785,7 +1722,6 @@ pub mod tls { use std::fmt; use std::mem; - use std::marker::PhantomData; use syntax_pos; use crate::ty::query; use errors::{Diagnostic, TRACK_DIAGNOSTICS}; @@ -1949,8 +1885,6 @@ pub mod tls { let tcx = TyCtxt { gcx, - interners: &gcx.global_interners, - dummy: PhantomData, }; let icx = ImplicitCtxt { tcx, @@ -1981,8 +1915,6 @@ pub mod tls { let gcx = &*(gcx as *const GlobalCtxt<'_>); let tcx = TyCtxt { gcx, - interners: &gcx.global_interners, - dummy: PhantomData, }; let icx = ImplicitCtxt { query: None, @@ -2041,26 +1973,6 @@ pub mod tls { }) } - /// Allows access to the current ImplicitCtxt whose tcx field has the same global - /// interner and local interner as the tcx argument passed in. This means the closure - /// is given an ImplicitCtxt with the same 'tcx and 'tcx lifetimes as the TyCtxt passed in. - /// This will panic if you pass it a TyCtxt which has a different global interner or - /// a different local interner from the current ImplicitCtxt's tcx field. - #[inline] - pub fn with_fully_related_context<'tcx, F, R>(tcx: TyCtxt<'tcx>, f: F) -> R - where - F: for<'b> FnOnce(&ImplicitCtxt<'b, 'tcx>) -> R, - { - with_context(|context| { - unsafe { - assert!(ptr_eq(context.tcx.gcx, tcx.gcx)); - assert!(ptr_eq(context.tcx.interners, tcx.interners)); - let context: &ImplicitCtxt<'_, '_> = mem::transmute(context); - f(context) - } - }) - } - /// Allows access to the TyCtxt in the current ImplicitCtxt. /// Panics if there is no ImplicitCtxt available #[inline] @@ -2288,39 +2200,22 @@ impl<'tcx> Borrow<[Goal<'tcx>]> for Interned<'tcx, List>> { macro_rules! intern_method { ($lt_tcx:tt, $name:ident: $method:ident($alloc:ty, $alloc_method:expr, - $alloc_to_key:expr, - $keep_in_local_tcx:expr) -> $ty:ty) => { + $alloc_to_key:expr) -> $ty:ty) => { impl<$lt_tcx> TyCtxt<$lt_tcx> { pub fn $method(self, v: $alloc) -> &$lt_tcx $ty { let key = ($alloc_to_key)(&v); - // HACK(eddyb) Depend on flags being accurate to - // determine that all contents are in the global tcx. - // See comments on Lift for why we can't use that. - if ($keep_in_local_tcx)(&v) { - self.interners.$name.borrow_mut().intern_ref(key, || { - // Make sure we don't end up with inference - // types/regions in the global tcx. - if self.is_global() { - bug!("Attempted to intern `{:?}` which contains \ - inference types/regions in the global type context", - v); - } + self.interners.$name.borrow_mut().intern_ref(key, || { + Interned($alloc_method(&self.interners.arena, v)) - Interned($alloc_method(&self.interners.arena, v)) - }).0 - } else { - self.global_interners.$name.borrow_mut().intern_ref(key, || { - Interned($alloc_method(&self.global_interners.arena, v)) - }).0 - } + }).0 } } } } macro_rules! direct_interners { - ($lt_tcx:tt, $($name:ident: $method:ident($keep_in_local_tcx:expr) -> $ty:ty),+) => { + ($lt_tcx:tt, $($name:ident: $method:ident($ty:ty)),+) => { $(impl<$lt_tcx> PartialEq for Interned<$lt_tcx, $ty> { fn eq(&self, other: &Self) -> bool { self.0 == other.0 @@ -2339,8 +2234,7 @@ macro_rules! direct_interners { $lt_tcx, $name: $method($ty, |a: &$lt_tcx SyncDroplessArena, v| -> &$lt_tcx $ty { a.alloc(v) }, - |x| x, - $keep_in_local_tcx) -> $ty);)+ + |x| x) -> $ty);)+ } } @@ -2349,9 +2243,9 @@ pub fn keep_local<'tcx, T: ty::TypeFoldable<'tcx>>(x: &T) -> bool { } direct_interners!('tcx, - region: mk_region(|r: &RegionKind| r.keep_in_local_tcx()) -> RegionKind, - goal: mk_goal(|c: &GoalKind<'_>| keep_local(c)) -> GoalKind<'tcx>, - const_: mk_const(|c: &Const<'_>| keep_local(&c)) -> Const<'tcx> + region: mk_region(RegionKind), + goal: mk_goal(GoalKind<'tcx>), + const_: mk_const(Const<'tcx>) ); macro_rules! slice_interners { @@ -2359,8 +2253,7 @@ macro_rules! slice_interners { $(intern_method!( 'tcx, $field: $method( &[$ty], |a, v| List::from_arena(a, v), - Deref::deref, - |xs: &[$ty]| xs.iter().any(keep_local)) -> List<$ty>);)+ + Deref::deref) -> List<$ty>);)+ ); } @@ -2384,8 +2277,7 @@ intern_method! { canonical_var_infos: _intern_canonical_var_infos( &[CanonicalVarInfo], |a, v| List::from_arena(a, v), - Deref::deref, - |_xs: &[CanonicalVarInfo]| -> bool { false } + Deref::deref ) -> List } @@ -2431,7 +2323,7 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn mk_ty(&self, st: TyKind<'tcx>) -> Ty<'tcx> { - CtxtInterners::intern_ty(&self.interners, &self.global_interners, st) + self.interners.intern_ty(st) } pub fn mk_mach_int(self, tm: ast::IntTy) -> Ty<'tcx> { diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs index 85153f99b1917..56c9474170cad 100644 --- a/src/librustc/ty/query/on_disk_cache.rs +++ b/src/librustc/ty/query/on_disk_cache.rs @@ -201,28 +201,22 @@ impl<'sess> OnDiskCache<'sess> { let mut query_result_index = EncodedQueryResultIndex::new(); time(tcx.sess, "encode query results", || { - use crate::ty::query::queries::*; let enc = &mut encoder; let qri = &mut query_result_index; - encode_query_results::, _>(tcx, enc, qri)?; - encode_query_results::, _>(tcx, enc, qri)?; - encode_query_results::, _>(tcx, enc, qri)?; - encode_query_results::, _>(tcx, enc, qri)?; - encode_query_results::, _>(tcx, enc, qri)?; - encode_query_results::, _>(tcx, enc, qri)?; - encode_query_results::, _>(tcx, enc, qri)?; - encode_query_results::, _>(tcx, enc, qri)?; - encode_query_results::, _>(tcx, enc, qri)?; - encode_query_results::, _>(tcx, enc, qri)?; - encode_query_results::, _>(tcx, enc, qri)?; - encode_query_results::, _>(tcx, enc, qri)?; - encode_query_results::, _>(tcx, enc, qri)?; - encode_query_results::, _>(tcx, enc, qri)?; - encode_query_results::, _>(tcx, enc, qri)?; - encode_query_results::, _>(tcx, enc, qri)?; - encode_query_results::, _>(tcx, enc, qri)?; - // FIXME: Include const_eval_raw? + macro_rules! encode_queries { + ($($query:ident,)*) => { + $( + encode_query_results::, _>( + tcx, + enc, + qri + )?; + )* + } + } + + rustc_cached_queries!(encode_queries!); Ok(()) })?; diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 7831c200114a5..69f8356f66920 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -234,7 +234,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { return; } // Effectively no-ops - "uninit" | "forget" => { + "forget" => { return; } "needs_drop" => { diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index a5c295cd4525c..708ba79ec3ab2 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -1736,7 +1736,9 @@ extern "C" { pub fn LLVMRustArchiveIteratorFree(AIR: &'a mut ArchiveIterator<'a>); pub fn LLVMRustDestroyArchive(AR: &'static mut Archive); - pub fn LLVMRustGetSectionName(SI: &SectionIterator<'_>, data: &mut *const c_char) -> size_t; + #[allow(improper_ctypes)] + pub fn LLVMRustGetSectionName(SI: &SectionIterator<'_>, + data: &mut Option>) -> size_t; #[allow(improper_ctypes)] pub fn LLVMRustWriteTwineToString(T: &Twine, s: &RustString); diff --git a/src/librustc_codegen_llvm/metadata.rs b/src/librustc_codegen_llvm/metadata.rs index 7cf497cb5d036..cd7255888118c 100644 --- a/src/librustc_codegen_llvm/metadata.rs +++ b/src/librustc_codegen_llvm/metadata.rs @@ -8,7 +8,6 @@ use rustc_data_structures::owning_ref::OwningRef; use rustc_codegen_ssa::METADATA_FILENAME; use std::path::Path; -use std::ptr; use std::slice; use rustc_fs_util::path_to_c_string; @@ -67,10 +66,16 @@ fn search_meta_section<'a>(of: &'a ObjectFile, unsafe { let si = mk_section_iter(of.llof); while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False { - let mut name_buf = ptr::null(); + let mut name_buf = None; let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf); - let name = slice::from_raw_parts(name_buf as *const u8, name_len as usize).to_vec(); - let name = String::from_utf8(name).unwrap(); + let name = name_buf.map_or( + String::new(), // We got a NULL ptr, ignore `name_len`. + |buf| String::from_utf8( + slice::from_raw_parts(buf.as_ptr() as *const u8, + name_len as usize) + .to_vec() + ).unwrap() + ); debug!("get_metadata_section: name {}", name); if read_metadata_section_name(target) == name { let cbuf = llvm::LLVMGetSectionContents(si.llsi); diff --git a/src/librustc_macros/src/query.rs b/src/librustc_macros/src/query.rs index d47bd0580d6ca..a8df7e197a8c9 100644 --- a/src/librustc_macros/src/query.rs +++ b/src/librustc_macros/src/query.rs @@ -414,6 +414,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { let mut dep_node_force_stream = quote! {}; let mut try_load_from_on_disk_cache_stream = quote! {}; let mut no_force_queries = Vec::new(); + let mut cached_queries = quote! {}; for group in groups.0 { let mut group_stream = quote! {}; @@ -427,6 +428,12 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { _ => quote! { #result_full }, }; + if modifiers.cache.is_some() { + cached_queries.extend(quote! { + #name, + }); + } + if modifiers.cache.is_some() && !modifiers.no_force { try_load_from_on_disk_cache_stream.extend(quote! { DepKind::#name => { @@ -549,6 +556,12 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { } } } + macro_rules! rustc_cached_queries { + ($($macro:tt)*) => { + $($macro)*(#cached_queries); + } + } + #query_description_stream impl DepNode { diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index d8d08107b826a..dd0beee2104e8 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -19,9 +19,8 @@ use syntax::ext::base::{MacroKind, SyntaxExtension}; use syntax::ext::expand::{AstFragment, Invocation, InvocationKind}; use syntax::ext::hygiene::Mark; use syntax::ext::tt::macro_rules; -use syntax::feature_gate::{ - feature_err, is_builtin_attr_name, AttributeGate, GateIssue, Stability, BUILTIN_ATTRIBUTES, -}; +use syntax::feature_gate::{feature_err, emit_feature_err, is_builtin_attr_name}; +use syntax::feature_gate::{AttributeGate, GateIssue, Stability, BUILTIN_ATTRIBUTES}; use syntax::symbol::{Symbol, kw, sym}; use syntax::visit::Visitor; use syntax::util::lev_distance::find_best_match_for_name; @@ -298,12 +297,25 @@ impl<'a> Resolver<'a> { let res = self.resolve_macro_to_res_inner(path, kind, parent_scope, trace, force); // Report errors and enforce feature gates for the resolved macro. + let features = self.session.features_untracked(); if res != Err(Determinacy::Undetermined) { // Do not report duplicated errors on every undetermined resolution. for segment in &path.segments { if let Some(args) = &segment.args { self.session.span_err(args.span(), "generic arguments in macro path"); } + if kind == MacroKind::Attr && !features.rustc_attrs && + segment.ident.as_str().starts_with("rustc") { + let msg = "attributes starting with `rustc` are \ + reserved for use by the `rustc` compiler"; + emit_feature_err( + &self.session.parse_sess, + sym::rustc_attrs, + segment.ident.span, + GateIssue::Language, + msg, + ); + } } } @@ -320,24 +332,15 @@ impl<'a> Resolver<'a> { } Res::NonMacroAttr(attr_kind) => { if kind == MacroKind::Attr { - let features = self.session.features_untracked(); if attr_kind == NonMacroAttrKind::Custom { assert!(path.segments.len() == 1); - let name = path.segments[0].ident.as_str(); - if name.starts_with("rustc_") { - if !features.rustc_attrs { - let msg = "unless otherwise specified, attributes with the prefix \ - `rustc_` are reserved for internal compiler diagnostics"; - self.report_unknown_attribute(path.span, &name, msg, - sym::rustc_attrs); - } - } else if !features.custom_attribute { + if !features.custom_attribute { let msg = format!("The attribute `{}` is currently unknown to the \ compiler and may have meaning added to it in the \ future", path); self.report_unknown_attribute( path.span, - &name, + &path.segments[0].ident.as_str(), &msg, sym::custom_attribute, ); diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 9b1a891382209..82a736bf9c5f2 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -145,7 +145,6 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem) { "rustc_peek" => (1, vec![param(0)], param(0)), "panic_if_uninhabited" => (1, Vec::new(), tcx.mk_unit()), "init" => (1, Vec::new(), param(0)), - "uninit" => (1, Vec::new(), param(0)), "forget" => (1, vec![param(0)], tcx.mk_unit()), "transmute" => (2, vec![ param(0) ], param(1)), "move_val_init" => { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 8ae96d8665718..2fe40f4e10b64 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -392,7 +392,7 @@ impl fmt::Debug for Item { impl Item { /// Finds the `doc` attribute as a NameValue and returns the corresponding /// value found. - pub fn doc_value<'a>(&'a self) -> Option<&'a str> { + pub fn doc_value(&self) -> Option<&str> { self.attrs.doc_value() } /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined @@ -699,11 +699,11 @@ impl<'a> Iterator for ListAttributesIter<'a> { pub trait AttributesExt { /// Finds an attribute as List and returns the list of attributes nested inside. - fn lists<'a>(&'a self, name: Symbol) -> ListAttributesIter<'a>; + fn lists(&self, name: Symbol) -> ListAttributesIter<'_>; } impl AttributesExt for [ast::Attribute] { - fn lists<'a>(&'a self, name: Symbol) -> ListAttributesIter<'a> { + fn lists(&self, name: Symbol) -> ListAttributesIter<'_> { ListAttributesIter { attrs: self.iter(), current_list: Vec::new().into_iter(), @@ -952,7 +952,7 @@ impl Attributes { /// Finds the `doc` attribute as a NameValue and returns the corresponding /// value found. - pub fn doc_value<'a>(&'a self) -> Option<&'a str> { + pub fn doc_value(&self) -> Option<&str> { self.doc_strings.first().map(|s| s.as_str()) } @@ -1037,7 +1037,7 @@ impl Hash for Attributes { } impl AttributesExt for Attributes { - fn lists<'a>(&'a self, name: Symbol) -> ListAttributesIter<'a> { + fn lists(&self, name: Symbol) -> ListAttributesIter<'_> { self.other_attrs.lists(name) } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 2d6503c944560..2d69c29dfae3c 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2541,7 +2541,7 @@ fn full_path(cx: &Context, item: &clean::Item) -> String { s } -fn shorter<'a>(s: Option<&'a str>) -> String { +fn shorter(s: Option<&str>) -> String { match s { Some(s) => s.lines() .skip_while(|s| s.chars().all(|c| c.is_whitespace())) diff --git a/src/librustdoc/html/toc.rs b/src/librustdoc/html/toc.rs index 2564c611e54e5..2da7aceae8bf4 100644 --- a/src/librustdoc/html/toc.rs +++ b/src/librustdoc/html/toc.rs @@ -119,7 +119,7 @@ impl TocBuilder { /// Push a level `level` heading into the appropriate place in the /// hierarchy, returning a string containing the section number in /// `..` format. - pub fn push<'a>(&'a mut self, level: u32, name: String, id: String) -> &'a str { + pub fn push(&mut self, level: u32, name: String, id: String) -> &str { assert!(level >= 1); // collapse all previous sections into their parents until we diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index b0a37ea9c8081..50a647f244db5 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -17,7 +17,7 @@ use crate::html::markdown::{ErrorCodes, IdMap, Markdown, MarkdownWithToc, find_t use crate::test::{TestOptions, Collector}; /// Separate any lines at the start of the file that begin with `# ` or `%`. -fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) { +fn extract_leading_metadata(s: &str) -> (Vec<&str>, &str) { let mut metadata = Vec::new(); let mut count = 0; diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index a7e7c09f9ae44..726306d60ce1e 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -1031,7 +1031,7 @@ impl Json { /// If the Json value is an Object, returns the value associated with the provided key. /// Otherwise, returns None. - pub fn find<'a>(&'a self, key: &str) -> Option<&'a Json>{ + pub fn find(&self, key: &str) -> Option<&Json> { match *self { Json::Object(ref map) => map.get(key), _ => None @@ -1052,7 +1052,7 @@ impl Json { /// If the Json value is an Object, performs a depth-first search until /// a value associated with the provided key is found. If no value is found /// or the Json value is not an Object, returns `None`. - pub fn search<'a>(&'a self, key: &str) -> Option<&'a Json> { + pub fn search(&self, key: &str) -> Option<&Json> { match self { &Json::Object(ref map) => { match map.get(key) { diff --git a/src/libstd/sync/mpsc/sync.rs b/src/libstd/sync/mpsc/sync.rs index f8fcd3ff5a5bc..fbe36d10517eb 100644 --- a/src/libstd/sync/mpsc/sync.rs +++ b/src/libstd/sync/mpsc/sync.rs @@ -140,7 +140,7 @@ fn wait_timeout_receiver<'a, 'b, T>(lock: &'a Mutex>, new_guard } -fn abort_selection<'a, T>(guard: &mut MutexGuard<'a , State>) -> bool { +fn abort_selection(guard: &mut MutexGuard<'_, State>) -> bool { match mem::replace(&mut guard.blocker, NoneBlocked) { NoneBlocked => true, BlockedSender(token) => { diff --git a/src/libstd/sys/redox/ext/net.rs b/src/libstd/sys/redox/ext/net.rs index b3ef5f3064c16..1f5c785f41907 100644 --- a/src/libstd/sys/redox/ext/net.rs +++ b/src/libstd/sys/redox/ext/net.rs @@ -673,7 +673,7 @@ impl UnixListener { /// } /// ``` #[stable(feature = "unix_socket_redox", since = "1.29.0")] - pub fn incoming<'a>(&'a self) -> Incoming<'a> { + pub fn incoming(&self) -> Incoming<'_> { Incoming { listener: self } } } diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index 41090caee8459..42edd5dbbea7c 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -198,7 +198,7 @@ impl SocketAddr { } } - fn address<'a>(&'a self) -> AddressKind<'a> { + fn address(&self) -> AddressKind<'_> { let len = self.len as usize - sun_path_offset(&self.addr); let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; @@ -894,7 +894,7 @@ impl UnixListener { /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn incoming<'a>(&'a self) -> Incoming<'a> { + pub fn incoming(&self) -> Incoming<'_> { Incoming { listener: self } } } diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 1cb5553912981..36fb1fb5ff68d 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -195,7 +195,7 @@ fn wide_char_to_multi_byte(code_page: u32, } } -pub fn truncate_utf16_at_nul<'a>(v: &'a [u16]) -> &'a [u16] { +pub fn truncate_utf16_at_nul(v: &[u16]) -> &[u16] { match v.iter().position(|c| *c == 0) { // don't include the 0 Some(i) => &v[..i], diff --git a/src/libstd/sys/windows/path.rs b/src/libstd/sys/windows/path.rs index f3178a5e9e690..7eae28cb14fbc 100644 --- a/src/libstd/sys/windows/path.rs +++ b/src/libstd/sys/windows/path.rs @@ -19,7 +19,7 @@ pub fn is_verbatim_sep(b: u8) -> bool { b == b'\\' } -pub fn parse_prefix<'a>(path: &'a OsStr) -> Option> { +pub fn parse_prefix(path: &OsStr) -> Option> { use crate::path::Prefix::*; unsafe { // The unsafety here stems from converting between &OsStr and &[u8] diff --git a/src/libstd/sys_common/io.rs b/src/libstd/sys_common/io.rs index 44b0963302ddf..8789abe55c3d0 100644 --- a/src/libstd/sys_common/io.rs +++ b/src/libstd/sys_common/io.rs @@ -16,7 +16,7 @@ pub mod test { p.join(path) } - pub fn path<'a>(&'a self) -> &'a Path { + pub fn path(&self) -> &Path { let TempDir(ref p) = *self; p } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index c71fa61443c43..6fbd2ab7c43f2 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1504,9 +1504,7 @@ impl<'feat> ExpansionConfig<'feat> { } fn enable_custom_inner_attributes(&self) -> bool { - self.features.map_or(false, |features| { - features.custom_inner_attributes || features.custom_attribute || features.rustc_attrs - }) + self.features.map_or(false, |features| features.custom_inner_attributes) } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 4a0c957333bca..e1e39faaad4ad 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -31,6 +31,7 @@ use crate::tokenstream::TokenTree; use errors::{Applicability, DiagnosticBuilder, Handler}; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sync::Lock; use rustc_target::spec::abi::Abi; use syntax_pos::{Span, DUMMY_SP, MultiSpan}; use log::debug; @@ -573,6 +574,9 @@ declare_features! ( // Allows `impl Trait` with multiple unrelated lifetimes. (active, member_constraints, "1.37.0", Some(61977), None), + // Allows `async || body` closures. + (active, async_closure, "1.37.0", Some(62290), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- @@ -1292,6 +1296,18 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ attribute is just used for rustc unit \ tests and will never be stable", cfg_fn!(rustc_attrs))), + (sym::rustc_dump_env_program_clauses, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_dump_env_program_clauses]` \ + attribute is just used for rustc unit \ + tests and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_object_lifetime_default, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_object_lifetime_default]` \ + attribute is just used for rustc unit \ + tests and will never be stable", + cfg_fn!(rustc_attrs))), (sym::rustc_test_marker, Normal, template!(Word), Gated(Stability::Unstable, sym::rustc_attrs, "the `#[rustc_test_marker]` attribute \ @@ -1353,6 +1369,26 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ "internal implementation detail", cfg_fn!(rustc_attrs))), + (sym::rustc_allocator_nounwind, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "internal implementation detail", + cfg_fn!(rustc_attrs))), + + (sym::rustc_doc_only_macro, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "internal implementation detail", + cfg_fn!(rustc_attrs))), + + (sym::rustc_promotable, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "internal implementation detail", + cfg_fn!(rustc_attrs))), + + (sym::rustc_allow_const_fn_ptr, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "internal implementation detail", + cfg_fn!(rustc_attrs))), + (sym::rustc_dummy, Normal, template!(Word /* doesn't matter*/), Gated(Stability::Unstable, sym::rustc_attrs, "used by the test suite", @@ -1639,6 +1675,14 @@ impl<'a> Context<'a> { } debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage); return; + } else { + for segment in &attr.path.segments { + if segment.ident.as_str().starts_with("rustc") { + let msg = "attributes starting with `rustc` are \ + reserved for use by the `rustc` compiler"; + gate_feature!(self, rustc_attrs, segment.ident.span, msg); + } + } } for &(n, ty) in self.plugin_attributes { if attr.path == n { @@ -1649,19 +1693,13 @@ impl<'a> Context<'a> { return; } } - if !attr::is_known(attr) { - if attr.name_or_empty().as_str().starts_with("rustc_") { - let msg = "unless otherwise specified, attributes with the prefix `rustc_` \ - are reserved for internal compiler diagnostics"; - gate_feature!(self, rustc_attrs, attr.span, msg); - } else if !is_macro { - // Only run the custom attribute lint during regular feature gate - // checking. Macro gating runs before the plugin attributes are - // registered, so we skip this in that case. - let msg = format!("The attribute `{}` is currently unknown to the compiler and \ - may have meaning added to it in the future", attr.path); - gate_feature!(self, custom_attribute, attr.span, &msg); - } + if !is_macro && !attr::is_known(attr) { + // Only run the custom attribute lint during regular feature gate + // checking. Macro gating runs before the plugin attributes are + // registered, so we skip this in that case. + let msg = format!("The attribute `{}` is currently unknown to the compiler and \ + may have meaning added to it in the future", attr.path); + gate_feature!(self, custom_attribute, attr.span, &msg); } } } @@ -2191,9 +2229,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { "labels on blocks are unstable"); } } - ast::ExprKind::Closure(_, ast::IsAsync::Async { .. }, ..) => { - gate_feature_post!(&self, async_await, e.span, "async closures are unstable"); - } ast::ExprKind::Async(..) => { gate_feature_post!(&self, async_await, e.span, "async blocks are unstable"); } @@ -2527,6 +2562,10 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], features } +fn for_each_in_lock(vec: &Lock>, f: impl Fn(&T)) { + vec.borrow().iter().for_each(f); +} + pub fn check_crate(krate: &ast::Crate, sess: &ParseSess, features: &Features, @@ -2539,27 +2578,26 @@ pub fn check_crate(krate: &ast::Crate, plugin_attributes, }; - sess - .param_attr_spans - .borrow() - .iter() - .for_each(|span| gate_feature!( - &ctx, - param_attrs, - *span, - "attributes on function parameters are unstable" - )); - - sess - .let_chains_spans - .borrow() - .iter() - .for_each(|span| gate_feature!( - &ctx, - let_chains, - *span, - "`let` expressions in this position are experimental" - )); + for_each_in_lock(&sess.param_attr_spans, |span| gate_feature!( + &ctx, + param_attrs, + *span, + "attributes on function parameters are unstable" + )); + + for_each_in_lock(&sess.let_chains_spans, |span| gate_feature!( + &ctx, + let_chains, + *span, + "`let` expressions in this position are experimental" + )); + + for_each_in_lock(&sess.async_closure_spans, |span| gate_feature!( + &ctx, + async_closure, + *span, + "async closures are unstable" + )); let visitor = &mut PostExpansionVisitor { context: &ctx, diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 49f714e4e4654..3717bb435f69d 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1452,6 +1452,7 @@ mod tests { ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), param_attr_spans: Lock::new(Vec::new()), let_chains_spans: Lock::new(Vec::new()), + async_closure_spans: Lock::new(Vec::new()), } } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index e19eab371f44e..4056905d5dd01 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -57,6 +57,8 @@ pub struct ParseSess { pub param_attr_spans: Lock>, // Places where `let` exprs were used and should be feature gated according to `let_chains`. pub let_chains_spans: Lock>, + // Places where `async || ..` exprs were used and should be feature gated. + pub async_closure_spans: Lock>, } impl ParseSess { @@ -84,6 +86,7 @@ impl ParseSess { ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), param_attr_spans: Lock::new(Vec::new()), let_chains_spans: Lock::new(Vec::new()), + async_closure_spans: Lock::new(Vec::new()), } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9c1796000938f..efd1443ae4c03 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3221,21 +3221,24 @@ impl<'a> Parser<'a> { -> PResult<'a, P> { let lo = self.token.span; + let movability = if self.eat_keyword(kw::Static) { Movability::Static } else { Movability::Movable }; + let asyncness = if self.token.span.rust_2018() { self.parse_asyncness() } else { IsAsync::NotAsync }; - let capture_clause = if self.eat_keyword(kw::Move) { - CaptureBy::Value - } else { - CaptureBy::Ref - }; + if asyncness.is_async() { + // Feature gate `async ||` closures. + self.sess.async_closure_spans.borrow_mut().push(self.prev_span); + } + + let capture_clause = self.parse_capture_clause(); let decl = self.parse_fn_block_decl()?; let decl_hi = self.prev_span; let body = match decl.output { @@ -3257,7 +3260,7 @@ impl<'a> Parser<'a> { attrs)) } - // `else` token already eaten + /// `else` token already eaten fn parse_else_expr(&mut self) -> PResult<'a, P> { if self.eat_keyword(kw::If) { return self.parse_if_expr(ThinVec::new()); @@ -3306,7 +3309,7 @@ impl<'a> Parser<'a> { Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_label), attrs)) } - // parse `loop {...}`, `loop` token already eaten + /// Parse `loop {...}`, `loop` token already eaten. fn parse_loop_expr(&mut self, opt_label: Option