Skip to content

Rollup of 4 pull requests #62365

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 14 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion src/libcore/intrinsics.rs
Original file line number Diff line number Diff line change
@@ -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")]
@@ -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::<T>()`.
pub(crate) fn is_aligned_and_not_null<T>(ptr: *const T) -> bool {
!ptr.is_null() && ptr as usize % mem::align_of::<T>() == 0
}

/// Checks whether the regions of memory starting at `src` and `dst` of size
/// `count * size_of::<T>()` overlap.
fn overlaps<T>(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::<T>().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::<T>()` bytes from `src` to `dst`. The source
/// and destination must *not* overlap.
///
@@ -1420,7 +1442,11 @@ pub unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
extern "rust-intrinsic" {
fn copy_nonoverlapping<T>(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::<T>()` bytes from `src` to `dst`. The source
@@ -1480,6 +1506,9 @@ pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
extern "rust-intrinsic" {
fn copy<T>(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<T>(dst: *mut T, val: u8, count: usize) {
extern "rust-intrinsic" {
fn write_bytes<T>(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)
}

6 changes: 3 additions & 3 deletions src/libcore/slice/mod.rs
Original file line number Diff line number Diff line change
@@ -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::<T>() == 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::<T>().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::<T>() == 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::<T>().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)
164 changes: 28 additions & 136 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
@@ -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<Arena<'tcx>>,

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<Self::Lifted> {
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<Goal<'tcx>>> {
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,18 +2243,17 @@ 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 {
($($field:ident: $method:ident($ty:ty)),+) => (
$(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<CanonicalVarInfo>
}

@@ -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> {
4 changes: 3 additions & 1 deletion src/librustc_codegen_llvm/llvm/ffi.rs
Original file line number Diff line number Diff line change
@@ -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<std::ptr::NonNull<c_char>>) -> size_t;

#[allow(improper_ctypes)]
pub fn LLVMRustWriteTwineToString(T: &Twine, s: &RustString);
13 changes: 9 additions & 4 deletions src/librustc_codegen_llvm/metadata.rs
Original file line number Diff line number Diff line change
@@ -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);
52 changes: 28 additions & 24 deletions src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
@@ -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<T>(vec: &Lock<Vec<T>>, 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,
1 change: 1 addition & 0 deletions src/libsyntax/parse/lexer/mod.rs
Original file line number Diff line number Diff line change
@@ -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()),
}
}

3 changes: 3 additions & 0 deletions src/libsyntax/parse/mod.rs
Original file line number Diff line number Diff line change
@@ -57,6 +57,8 @@ pub struct ParseSess {
pub param_attr_spans: Lock<Vec<Span>>,
// Places where `let` exprs were used and should be feature gated according to `let_chains`.
pub let_chains_spans: Lock<Vec<Span>>,
// Places where `async || ..` exprs were used and should be feature gated.
pub async_closure_spans: Lock<Vec<Span>>,
}

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()),
}
}

36 changes: 21 additions & 15 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
@@ -3221,21 +3221,24 @@ impl<'a> Parser<'a> {
-> PResult<'a, P<Expr>>
{
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<Expr>> {
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<Label>,
span_lo: Span,
mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
@@ -3316,17 +3319,20 @@ impl<'a> Parser<'a> {
Ok(self.mk_expr(span, ExprKind::Loop(body, opt_label), attrs))
}

/// Parses an `async move {...}` expression.
pub fn parse_async_block(&mut self, mut attrs: ThinVec<Attribute>)
-> PResult<'a, P<Expr>>
{
let span_lo = self.token.span;
self.expect_keyword(kw::Async)?;
let capture_clause = if self.eat_keyword(kw::Move) {
/// Parse an optional `move` prefix to a closure lke construct.
fn parse_capture_clause(&mut self) -> CaptureBy {
if self.eat_keyword(kw::Move) {
CaptureBy::Value
} else {
CaptureBy::Ref
};
}
}

/// Parses an `async move? {...}` expression.
pub fn parse_async_block(&mut self, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
let span_lo = self.token.span;
self.expect_keyword(kw::Async)?;
let capture_clause = self.parse_capture_clause();
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
attrs.extend(iattrs);
Ok(self.mk_expr(
1 change: 1 addition & 0 deletions src/libsyntax_pos/symbol.rs
Original file line number Diff line number Diff line change
@@ -146,6 +146,7 @@ symbols! {
associated_type_defaults,
associated_types,
async_await,
async_closure,
attr,
attributes,
attr_literals,
1 change: 1 addition & 0 deletions src/test/codegen/issue-45222.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// compile-flags: -O
// ignore-debug: the debug assertions get in the way

#![crate_type = "lib"]

1 change: 1 addition & 0 deletions src/test/codegen/issue-45466.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// compile-flags: -O
// ignore-debug: the debug assertions get in the way

#![crate_type="rlib"]

1 change: 1 addition & 0 deletions src/test/codegen/swap-small-types.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// compile-flags: -O
// only-x86_64
// ignore-debug: the debug assertions get in the way

#![crate_type = "lib"]

16 changes: 8 additions & 8 deletions src/test/run-pass/async-await/async-fn-size.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// edition:2018

#![feature(async_await, await_macro)]
#![feature(async_await)]

#[path = "../auxiliary/arc_wake.rs"]
mod arc_wake;
@@ -58,31 +58,31 @@ fn wait(fut: impl Future<Output = u8>) -> u8 {
fn base() -> WakeOnceThenComplete { WakeOnceThenComplete(false, 1) }

async fn await1_level1() -> u8 {
await!(base())
base().await
}

async fn await2_level1() -> u8 {
await!(base()) + await!(base())
base().await + base().await
}

async fn await3_level1() -> u8 {
await!(base()) + await!(base()) + await!(base())
base().await + base().await + base().await
}

async fn await3_level2() -> u8 {
await!(await3_level1()) + await!(await3_level1()) + await!(await3_level1())
await3_level1().await + await3_level1().await + await3_level1().await
}

async fn await3_level3() -> u8 {
await!(await3_level2()) + await!(await3_level2()) + await!(await3_level2())
await3_level2().await + await3_level2().await + await3_level2().await
}

async fn await3_level4() -> u8 {
await!(await3_level3()) + await!(await3_level3()) + await!(await3_level3())
await3_level3().await + await3_level3().await + await3_level3().await
}

async fn await3_level5() -> u8 {
await!(await3_level4()) + await!(await3_level4()) + await!(await3_level4())
await3_level4().await + await3_level4().await + await3_level4().await
}

fn main() {
4 changes: 2 additions & 2 deletions src/test/run-pass/async-await/issue-60709.rs
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
// handled incorrectly in generators.
// compile-flags: -Copt-level=z -Cdebuginfo=2 --edition=2018

#![feature(async_await, await_macro)]
#![feature(async_await)]
#![allow(unused)]

use std::future::Future;
@@ -22,7 +22,7 @@ impl Future for Never {
fn main() {
let fut = async {
let _rc = Rc::new(()); // Also crashes with Arc
await!(Never());
Never().await;
};
let _bla = fut; // Moving the future is required.
}
8 changes: 0 additions & 8 deletions src/test/ui/async-await/async-await.rs
Original file line number Diff line number Diff line change
@@ -70,13 +70,6 @@ fn async_nonmove_block(x: u8) -> impl Future<Output = u8> {
}
}

fn async_closure(x: u8) -> impl Future<Output = u8> {
(async move |x: u8| -> u8 {
wake_and_yield_once().await;
x
})(x)
}

async fn async_fn(x: u8) -> u8 {
wake_and_yield_once().await;
x
@@ -180,7 +173,6 @@ fn main() {
test! {
async_block,
async_nonmove_block,
async_closure,
async_fn,
generic_async_fn,
async_fn_with_internal_borrow,
12 changes: 12 additions & 0 deletions src/test/ui/async-await/async-closure-matches-expr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// compile-pass
// edition:2018

#![feature(async_await, async_closure)]

macro_rules! match_expr {
($x:expr) => {}
}

fn main() {
match_expr!(async || {});
}
81 changes: 81 additions & 0 deletions src/test/ui/async-await/async-closure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// run-pass

// edition:2018
// aux-build:arc_wake.rs

#![feature(async_await, async_closure)]

extern crate arc_wake;

use std::pin::Pin;
use std::future::Future;
use std::sync::{
Arc,
atomic::{self, AtomicUsize},
};
use std::task::{Context, Poll};
use arc_wake::ArcWake;

struct Counter {
wakes: AtomicUsize,
}

impl ArcWake for Counter {
fn wake(self: Arc<Self>) {
Self::wake_by_ref(&self)
}
fn wake_by_ref(arc_self: &Arc<Self>) {
arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst);
}
}

struct WakeOnceThenComplete(bool);

fn wake_and_yield_once() -> WakeOnceThenComplete { WakeOnceThenComplete(false) }

impl Future for WakeOnceThenComplete {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
if self.0 {
Poll::Ready(())
} else {
cx.waker().wake_by_ref();
self.0 = true;
Poll::Pending
}
}
}

fn async_closure(x: u8) -> impl Future<Output = u8> {
(async move |x: u8| -> u8 {
wake_and_yield_once().await;
x
})(x)
}

fn test_future_yields_once_then_returns<F, Fut>(f: F)
where
F: FnOnce(u8) -> Fut,
Fut: Future<Output = u8>,
{
let mut fut = Box::pin(f(9));
let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) });
let waker = ArcWake::into_waker(counter.clone());
let mut cx = Context::from_waker(&waker);
assert_eq!(0, counter.wakes.load(atomic::Ordering::SeqCst));
assert_eq!(Poll::Pending, fut.as_mut().poll(&mut cx));
assert_eq!(1, counter.wakes.load(atomic::Ordering::SeqCst));
assert_eq!(Poll::Ready(9), fut.as_mut().poll(&mut cx));
}

fn main() {
macro_rules! test {
($($fn_name:expr,)*) => { $(
test_future_yields_once_then_returns($fn_name);
)* }
}

test! {
async_closure,
}
}
2 changes: 1 addition & 1 deletion src/test/ui/async-await/async-fn-path-elision.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// edition:2018

#![feature(async_await, await_macro)]
#![feature(async_await)]
#![allow(dead_code)]

struct HasLifetime<'a>(&'a bool);
3 changes: 1 addition & 2 deletions src/test/ui/async-await/async-matches-expr.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
// build-pass (FIXME(62277): could be check-pass?)
// edition:2018

#![feature(async_await, await_macro)]
#![feature(async_await)]

macro_rules! match_expr {
($x:expr) => {}
}

fn main() {
match_expr!(async {});
match_expr!(async || {});
}
4 changes: 2 additions & 2 deletions src/test/ui/async-await/async-with-closure.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// build-pass (FIXME(62277): could be check-pass?)
// edition:2018

#![feature(async_await, await_macro)]
#![feature(async_await)]

trait MyClosure {
type Args;
@@ -20,7 +20,7 @@ async fn get_future<C: ?Sized + MyClosure>(_stream: MyStream<C>) {}

async fn f() {
let messages: MyStream<dyn FnMut()> = unimplemented!();
await!(get_future(messages));
get_future(messages).await;
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// edition:2018

#![allow(non_camel_case_types)]
#![feature(async_await, await_macro)]
#![feature(async_await)]

mod outer_mod {
pub mod await { //~ ERROR expected identifier, found reserved keyword `await`
2 changes: 1 addition & 1 deletion src/test/ui/async-await/await-macro.rs
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@
// edition:2018
// aux-build:arc_wake.rs

#![feature(async_await, await_macro)]
#![feature(async_await, async_closure, await_macro)]

extern crate arc_wake;

Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@
// run-pass

#![allow(unused_variables)]
#![feature(async_await, await_macro)]
#![feature(async_await)]

// Test that the drop order for parameters in a fn and async fn matches up. Also test that
// parameters (used or unused) are not dropped until the async fn completes execution.
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@
// run-pass

#![allow(unused_variables)]
#![feature(async_await, await_macro)]
#![feature(async_await)]

// Test that the drop order for parameters in a fn and async fn matches up. Also test that
// parameters (used or unused) are not dropped until the async fn completes execution.
8 changes: 8 additions & 0 deletions src/test/ui/async-await/feature-async-closure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// edition:2018
// gate-test-async_closure

fn f() {
let _ = async || {}; //~ ERROR async closures are unstable
}

fn main() {}
12 changes: 12 additions & 0 deletions src/test/ui/async-await/feature-async-closure.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0658]: async closures are unstable
--> $DIR/feature-async-closure.rs:5:13
|
LL | let _ = async || {};
| ^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/62290
= help: add #![feature(async_closure)] to the crate attributes to enable

error: aborting due to previous error

For more information about this error, try `rustc --explain E0658`.
6 changes: 3 additions & 3 deletions src/test/ui/async-await/issues/issue-53249.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// build-pass (FIXME(62277): could be check-pass?)
// edition:2018

#![feature(arbitrary_self_types, async_await, await_macro)]
#![feature(arbitrary_self_types, async_await)]

use std::task::{self, Poll};
use std::future::Future;
@@ -37,11 +37,11 @@ impl<R, F> Future for Lazy<F>
async fn __receive<WantFn, Fut>(want: WantFn) -> ()
where Fut: Future<Output = ()>, WantFn: Fn(&Box<dyn Send + 'static>) -> Fut,
{
await!(lazy(|_| ()));
lazy(|_| ()).await;
}

pub fn basic_spawn_receive() {
async { await!(__receive(|_| async { () })) };
async { __receive(|_| async { () }).await };
}

fn main() {}
2 changes: 1 addition & 1 deletion src/test/ui/async-await/issues/issue-54974.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// build-pass (FIXME(62277): could be check-pass?)
// edition:2018

#![feature(async_await, await_macro)]
#![feature(async_await)]

use std::sync::Arc;

4 changes: 2 additions & 2 deletions src/test/ui/async-await/issues/issue-55324.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// build-pass (FIXME(62277): could be check-pass?)
// edition:2018

#![feature(async_await, await_macro)]
#![feature(async_await)]

use std::future::Future;

#[allow(unused)]
async fn foo<F: Future<Output = i32>>(x: &i32, future: F) -> i32 {
let y = await!(future);
let y = future.await;
*x + y
}

2 changes: 1 addition & 1 deletion src/test/ui/async-await/issues/issue-58885.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// build-pass (FIXME(62277): could be check-pass?)
// edition:2018

#![feature(async_await, await_macro)]
#![feature(async_await)]

struct Xyz {
a: u64,
2 changes: 1 addition & 1 deletion src/test/ui/async-await/issues/issue-59001.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// build-pass (FIXME(62277): could be check-pass?)
// edition:2018

#![feature(async_await, await_macro)]
#![feature(async_await)]

use std::future::Future;

4 changes: 2 additions & 2 deletions src/test/ui/async-await/issues/issue-59972.rs
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@

// compile-flags: --edition=2018

#![feature(async_await, await_macro)]
#![feature(async_await)]

pub enum Uninhabited { }

@@ -15,7 +15,7 @@ async fn noop() { }
#[allow(unused)]
async fn contains_never() {
let error = uninhabited_async();
await!(noop());
noop().await;
let error2 = error;
}

Original file line number Diff line number Diff line change
@@ -11,8 +11,6 @@ fn main() {
//~^ ERROR `await` is only allowed inside `async` functions and blocks
let task1 = print_dur().await;
}.await;
(async || 2333)().await;
//~^ ERROR `await` is only allowed inside `async` functions and blocks
(|_| 2333).await;
//~^ ERROR `await` is only allowed inside `async` functions and blocks
//~^^ ERROR
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/issue-62009.rs:8:5
--> $DIR/issue-62009-1.rs:8:5
|
LL | fn main() {
| ---- this is not `async`
LL | async { let (); }.await;
| ^^^^^^^^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks

error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/issue-62009.rs:10:5
--> $DIR/issue-62009-1.rs:10:5
|
LL | fn main() {
| ---- this is not `async`
@@ -19,31 +19,22 @@ LL | | }.await;
| |___________^ only allowed inside `async` functions and blocks

error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/issue-62009.rs:14:5
|
LL | fn main() {
| ---- this is not `async`
...
LL | (async || 2333)().await;
| ^^^^^^^^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks

error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/issue-62009.rs:16:5
--> $DIR/issue-62009-1.rs:14:5
|
LL | fn main() {
| ---- this is not `async`
...
LL | (|_| 2333).await;
| ^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks

error[E0277]: the trait bound `[closure@$DIR/issue-62009.rs:16:5: 16:15]: std::future::Future` is not satisfied
--> $DIR/issue-62009.rs:16:5
error[E0277]: the trait bound `[closure@$DIR/issue-62009-1.rs:14:5: 14:15]: std::future::Future` is not satisfied
--> $DIR/issue-62009-1.rs:14:5
|
LL | (|_| 2333).await;
| ^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `[closure@$DIR/issue-62009.rs:16:5: 16:15]`
| ^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:14:5: 14:15]`
|
= note: required by `std::future::poll_with_tls_context`

error: aborting due to 5 previous errors
error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0277`.
10 changes: 10 additions & 0 deletions src/test/ui/async-await/issues/issue-62009-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// edition:2018

#![feature(async_await, async_closure)]

async fn print_dur() {}

fn main() {
(async || 2333)().await;
//~^ ERROR `await` is only allowed inside `async` functions and blocks
}
10 changes: 10 additions & 0 deletions src/test/ui/async-await/issues/issue-62009-2.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/issue-62009-2.rs:8:5
|
LL | fn main() {
| ---- this is not `async`
LL | (async || 2333)().await;
| ^^^^^^^^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks

error: aborting due to previous error

2 changes: 1 addition & 1 deletion src/test/ui/async-await/multiple-lifetimes/hrtb.rs
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@

// Test that we can use async fns with multiple arbitrary lifetimes.

#![feature(arbitrary_self_types, async_await, await_macro)]
#![feature(async_await)]
#![allow(dead_code)]

use std::ops::Add;
2 changes: 1 addition & 1 deletion src/test/ui/async-await/no-args-non-move-async-closure.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// edition:2018

#![feature(async_await, await_macro)]
#![feature(async_await, async_closure)]

fn main() {
let _ = async |x: u8| {};
4 changes: 2 additions & 2 deletions src/test/ui/async-await/recursive-async-impl-trait-type.rs
Original file line number Diff line number Diff line change
@@ -2,10 +2,10 @@
// Test that impl trait does not allow creating recursive types that are
// otherwise forbidden when using `async` and `await`.

#![feature(await_macro, async_await, generators)]
#![feature(async_await)]

async fn recursive_async_function() -> () { //~ ERROR
await!(recursive_async_function());
recursive_async_function().await;
}

fn main() {}
23 changes: 23 additions & 0 deletions src/test/ui/async-await/suggest-missing-await-closure.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// edition:2018
// run-rustfix

#![feature(async_await, async_closure)]

fn take_u32(_x: u32) {}

async fn make_u32() -> u32 {
22
}

#[allow(unused)]
async fn suggest_await_in_async_closure() {
async || {
let x = make_u32();
take_u32(x.await)
//~^ ERROR mismatched types [E0308]
//~| HELP consider using `.await` here
//~| SUGGESTION x.await
};
}

fn main() {}
23 changes: 23 additions & 0 deletions src/test/ui/async-await/suggest-missing-await-closure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// edition:2018
// run-rustfix

#![feature(async_await, async_closure)]

fn take_u32(_x: u32) {}

async fn make_u32() -> u32 {
22
}

#[allow(unused)]
async fn suggest_await_in_async_closure() {
async || {
let x = make_u32();
take_u32(x)
//~^ ERROR mismatched types [E0308]
//~| HELP consider using `.await` here
//~| SUGGESTION x.await
};
}

fn main() {}
15 changes: 15 additions & 0 deletions src/test/ui/async-await/suggest-missing-await-closure.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
error[E0308]: mismatched types
--> $DIR/suggest-missing-await-closure.rs:16:18
|
LL | take_u32(x)
| ^
| |
| expected u32, found opaque type
| help: consider using `.await` here: `x.await`
|
= note: expected type `u32`
found type `impl std::future::Future`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
11 changes: 0 additions & 11 deletions src/test/ui/async-await/suggest-missing-await.fixed
Original file line number Diff line number Diff line change
@@ -18,15 +18,4 @@ async fn suggest_await_in_async_fn() {
//~| SUGGESTION x.await
}

#[allow(unused)]
async fn suggest_await_in_async_closure() {
async || {
let x = make_u32();
take_u32(x.await)
//~^ ERROR mismatched types [E0308]
//~| HELP consider using `.await` here
//~| SUGGESTION x.await
};
}

fn main() {}
11 changes: 0 additions & 11 deletions src/test/ui/async-await/suggest-missing-await.rs
Original file line number Diff line number Diff line change
@@ -18,15 +18,4 @@ async fn suggest_await_in_async_fn() {
//~| SUGGESTION x.await
}

#[allow(unused)]
async fn suggest_await_in_async_closure() {
async || {
let x = make_u32();
take_u32(x)
//~^ ERROR mismatched types [E0308]
//~| HELP consider using `.await` here
//~| SUGGESTION x.await
};
}

fn main() {}
14 changes: 1 addition & 13 deletions src/test/ui/async-await/suggest-missing-await.stderr
Original file line number Diff line number Diff line change
@@ -10,18 +10,6 @@ LL | take_u32(x)
= note: expected type `u32`
found type `impl std::future::Future`

error[E0308]: mismatched types
--> $DIR/suggest-missing-await.rs:25:18
|
LL | take_u32(x)
| ^
| |
| expected u32, found opaque type
| help: consider using `.await` here: `x.await`
|
= note: expected type `u32`
found type `impl std::future::Future`

error: aborting due to 2 previous errors
error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
1 change: 0 additions & 1 deletion src/test/ui/feature-gates/feature-gate-async-await.rs
Original file line number Diff line number Diff line change
@@ -15,5 +15,4 @@ async fn foo() {} //~ ERROR async fn is unstable

fn main() {
let _ = async {}; //~ ERROR async blocks are unstable
let _ = async || {}; //~ ERROR async closures are unstable
}
11 changes: 1 addition & 10 deletions src/test/ui/feature-gates/feature-gate-async-await.stderr
Original file line number Diff line number Diff line change
@@ -40,15 +40,6 @@ LL | let _ = async {};
= note: for more information, see https://github.com/rust-lang/rust/issues/50547
= help: add #![feature(async_await)] to the crate attributes to enable

error[E0658]: async closures are unstable
--> $DIR/feature-gate-async-await.rs:18:13
|
LL | let _ = async || {};
| ^^^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/50547
= help: add #![feature(async_await)] to the crate attributes to enable

error: aborting due to 6 previous errors
error: aborting due to 5 previous errors

For more information about this error, try `rustc --explain E0658`.