From bb26e07dd59088fc3a308ad7a56283ba4e53b5f8 Mon Sep 17 00:00:00 2001 From: Valentin Tolmer Date: Wed, 27 Feb 2019 17:10:59 +0100 Subject: [PATCH 01/10] Add debug assertions to write_bytes and copy* --- src/libcore/intrinsics.rs | 33 ++++++++++++++++++++++++++++++++- src/libcore/slice/mod.rs | 6 +++--- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index b30eff8baa9c8..93450cb4798a7 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -41,6 +41,8 @@ since = "1.18.0")] pub use crate::ptr::drop_in_place; +use crate::mem; + extern "rust-intrinsic" { // N.B., these intrinsics take raw pointers because they mutate aliased // memory, which is not valid for either `&` or `&mut`. @@ -1331,6 +1333,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 { + return !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 +1442,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 +1506,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 +1590,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/slice/mod.rs b/src/libcore/slice/mod.rs index c6d44324ef5ee..dba9a1445e84c 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}; @@ -5213,7 +5213,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) @@ -5234,7 +5234,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) From 0533f129ecfb54ecae7e329949d7b1572368d0ae Mon Sep 17 00:00:00 2001 From: Valentin Tolmer Date: Wed, 27 Mar 2019 15:57:14 +0100 Subject: [PATCH 02/10] Handle null from LLVMRustGetSectionName --- src/librustc_codegen_llvm/llvm/ffi.rs | 4 +++- src/librustc_codegen_llvm/metadata.rs | 11 +++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) 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..9bddd29d2e88f 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,14 @@ 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( + "".to_string(), + |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); From 8a4573f841f219df32c97d25f400effee94e2474 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Jun 2019 23:15:37 +0200 Subject: [PATCH 03/10] format a bit --- src/librustc_codegen_llvm/metadata.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_codegen_llvm/metadata.rs b/src/librustc_codegen_llvm/metadata.rs index 9bddd29d2e88f..42e91ef408f9d 100644 --- a/src/librustc_codegen_llvm/metadata.rs +++ b/src/librustc_codegen_llvm/metadata.rs @@ -69,11 +69,13 @@ fn search_meta_section<'a>(of: &'a ObjectFile, let mut name_buf = None; let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf); let name = name_buf.map_or( - "".to_string(), + 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()); + .to_vec() + ).unwrap() + ); debug!("get_metadata_section: name {}", name); if read_metadata_section_name(target) == name { let cbuf = llvm::LLVMGetSectionContents(si.llsi); From 4159b27c61e991c0abe7e87ad381bd0c07077dfc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Jun 2019 23:19:04 +0200 Subject: [PATCH 04/10] order things more traditionally --- src/libcore/intrinsics.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 93450cb4798a7..2d47f08d70154 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -36,13 +36,13 @@ 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")] pub use crate::ptr::drop_in_place; -use crate::mem; - extern "rust-intrinsic" { // N.B., these intrinsics take raw pointers because they mutate aliased // memory, which is not valid for either `&` or `&mut`. From a68afc56bdf61b2ddd4f38ba4e3cabd7a4399c9b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 25 Jun 2019 09:40:50 +0200 Subject: [PATCH 05/10] ignore some codegen tests in debug mode --- src/test/codegen/issue-45222.rs | 1 + src/test/codegen/issue-45466.rs | 1 + src/test/codegen/swap-small-types.rs | 1 + 3 files changed, 3 insertions(+) diff --git a/src/test/codegen/issue-45222.rs b/src/test/codegen/issue-45222.rs index da65f2dfca5d1..7f99ca724cf73 100644 --- a/src/test/codegen/issue-45222.rs +++ b/src/test/codegen/issue-45222.rs @@ -1,4 +1,5 @@ // compile-flags: -O +// ignore-debug: the debug assertions get in the way #![crate_type = "lib"] diff --git a/src/test/codegen/issue-45466.rs b/src/test/codegen/issue-45466.rs index 7d6e31cc740f5..c79542767774a 100644 --- a/src/test/codegen/issue-45466.rs +++ b/src/test/codegen/issue-45466.rs @@ -1,4 +1,5 @@ // compile-flags: -O +// ignore-debug: the debug assertions get in the way #![crate_type="rlib"] diff --git a/src/test/codegen/swap-small-types.rs b/src/test/codegen/swap-small-types.rs index c8466fed7d1bd..6205e6a6559c9 100644 --- a/src/test/codegen/swap-small-types.rs +++ b/src/test/codegen/swap-small-types.rs @@ -1,5 +1,6 @@ // compile-flags: -O // only-x86_64 +// ignore-debug: the debug assertions get in the way #![crate_type = "lib"] From d3e1bf96dacab3e5c7c86321eb79fc916b28db87 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 25 Jun 2019 09:42:25 +0200 Subject: [PATCH 06/10] nits --- src/libcore/intrinsics.rs | 2 +- src/librustc_codegen_llvm/metadata.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 2d47f08d70154..d9b68612785e9 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1336,7 +1336,7 @@ extern "rust-intrinsic" { /// Checks whether `ptr` is properly aligned with respect to /// `align_of::()`. pub(crate) fn is_aligned_and_not_null(ptr: *const T) -> bool { - return !ptr.is_null() && ptr as usize % mem::align_of::() == 0; + !ptr.is_null() && ptr as usize % mem::align_of::() == 0 } /// Checks whether the regions of memory starting at `src` and `dst` of size diff --git a/src/librustc_codegen_llvm/metadata.rs b/src/librustc_codegen_llvm/metadata.rs index 42e91ef408f9d..cd7255888118c 100644 --- a/src/librustc_codegen_llvm/metadata.rs +++ b/src/librustc_codegen_llvm/metadata.rs @@ -69,7 +69,7 @@ fn search_meta_section<'a>(of: &'a ObjectFile, let mut name_buf = None; let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf); let name = name_buf.map_or( - String::new(), // we got a NULL ptr, ignore `name_len` + 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) From ec8c2e1ab9bd47c0184a0cbd77f35e9089c9dc0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 31 May 2019 10:23:22 +0200 Subject: [PATCH 07/10] Use a single CtxtInterners --- src/librustc/ty/context.rs | 164 +++++++------------------------------ 1 file changed, 28 insertions(+), 136 deletions(-) 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> { From bb7fbb99a293e39793a2d6497a472cce107baf56 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 2 Jul 2019 04:10:19 +0200 Subject: [PATCH 08/10] Add separate 'async_closure' feature gate. --- src/libsyntax/feature_gate.rs | 52 +++++++++++++++++--------------- src/libsyntax/parse/lexer/mod.rs | 1 + src/libsyntax/parse/mod.rs | 3 ++ src/libsyntax/parse/parser.rs | 36 +++++++++++++--------- src/libsyntax_pos/symbol.rs | 1 + 5 files changed, 54 insertions(+), 39 deletions(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 4a0c957333bca..ab61f77f5cb36 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 // ------------------------------------------------------------------------- @@ -2191,9 +2195,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 +2528,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 +2544,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 4e4fe4256c9b0..0a28eb38a58bc 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1474,6 +1474,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 696b5f48385e7..f82751c670b58 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