Skip to content
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

move async unsafe fn into #![feature(async_unsafe)] #62518

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 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
10 changes: 10 additions & 0 deletions src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,9 @@ declare_features! (
// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests
(active, cfg_doctest, "1.37.0", Some(62210), None),

// Allows `async unsafe` functions.
(active, async_unsafe, "1.38.0", Some(62501), None),

// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
Expand Down Expand Up @@ -2585,6 +2588,13 @@ pub fn check_crate(krate: &ast::Crate,
"async closures are unstable"
));

for_each_in_lock(&sess.async_unsafe_spans, |span| gate_feature!(
&ctx,
async_unsafe,
*span,
"async unsafe functions are unstable"
));

let visitor = &mut PostExpansionVisitor {
context: &ctx,
builtin_attributes: &*BUILTIN_ATTRIBUTE_MAP,
Expand Down
1 change: 1 addition & 0 deletions src/libsyntax/parse/lexer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1388,6 +1388,7 @@ mod tests {
param_attr_spans: Lock::new(Vec::new()),
let_chains_spans: Lock::new(Vec::new()),
async_closure_spans: Lock::new(Vec::new()),
async_unsafe_spans: Lock::new(Vec::new()),
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/libsyntax/parse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ pub struct ParseSess {
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>>,
// Places where `async unsafe fn` was used and should be feature gated.
pub async_unsafe_spans: Lock<Vec<Span>>,
}

impl ParseSess {
Expand Down Expand Up @@ -87,6 +89,7 @@ impl ParseSess {
param_attr_spans: Lock::new(Vec::new()),
let_chains_spans: Lock::new(Vec::new()),
async_closure_spans: Lock::new(Vec::new()),
async_unsafe_spans: Lock::new(Vec::new()),
}
}

Expand Down
13 changes: 11 additions & 2 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5690,11 +5690,16 @@ impl<'a> Parser<'a> {
let is_const_fn = self.eat_keyword(kw::Const);
let const_span = self.prev_span;
let asyncness = self.parse_asyncness();
if let IsAsync::Async { .. } = asyncness {
let async_span = self.prev_span;
if asyncness.is_async() {
self.ban_async_in_2015(self.prev_span);
}
let asyncness = respan(self.prev_span, asyncness);
let unsafety = self.parse_unsafety();
if asyncness.is_async() && unsafety == Unsafety::Unsafe {
// Feature gate `async unsafe` functions.
self.sess.async_unsafe_spans.borrow_mut().push(self.prev_span);
}
let asyncness = respan(async_span, asyncness);
let (constness, unsafety, abi) = if is_const_fn {
(respan(const_span, Constness::Const), unsafety, Abi::Rust)
} else {
Expand Down Expand Up @@ -7196,6 +7201,10 @@ impl<'a> Parser<'a> {
// ASYNC FUNCTION ITEM
self.bump(); // `async`
let unsafety = self.parse_unsafety(); // `unsafe`?
if unsafety == Unsafety::Unsafe {
// Feature gate `async unsafe` functions.
self.sess.async_unsafe_spans.borrow_mut().push(self.prev_span);
}
self.expect_keyword(kw::Fn)?; // `fn`
let fn_span = self.prev_span;
let (ident, item_, extra_attrs) =
Expand Down
1 change: 1 addition & 0 deletions src/libsyntax_pos/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ symbols! {
associated_types,
async_await,
async_closure,
async_unsafe,
attr,
attributes,
attr_literals,
Expand Down
57 changes: 4 additions & 53 deletions src/test/ui/async-await/async-await.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,23 @@

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

#![feature(async_await)]

extern crate arc_wake;
extern crate wake_once;

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

struct Counter {
pub struct Counter {
delan marked this conversation as resolved.
Show resolved Hide resolved
wakes: AtomicUsize,
}

Expand All @@ -29,23 +31,6 @@ impl ArcWake for Counter {
}
}

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_block(x: u8) -> impl Future<Output = u8> {
async move {
wake_and_yield_once().await;
Expand Down Expand Up @@ -115,29 +100,6 @@ fn async_fn_with_internal_borrow(y: u8) -> impl Future<Output = u8> {
}
}

async unsafe fn unsafe_async_fn(x: u8) -> u8 {
wake_and_yield_once().await;
x
}

struct Foo;

trait Bar {
fn foo() {}
}

impl Foo {
async fn async_assoc_item(x: u8) -> u8 {
unsafe {
unsafe_async_fn(x).await
}
}

async unsafe fn async_unsafe_assoc_item(x: u8) -> u8 {
unsafe_async_fn(x).await
}
}

fn test_future_yields_once_then_returns<F, Fut>(f: F)
where
F: FnOnce(u8) -> Fut,
Expand Down Expand Up @@ -176,17 +138,6 @@ fn main() {
async_fn,
generic_async_fn,
async_fn_with_internal_borrow,
Foo::async_assoc_item,
|x| {
async move {
unsafe { unsafe_async_fn(x).await }
}
},
|x| {
async move {
unsafe { Foo::async_unsafe_assoc_item(x).await }
}
},
}
test_with_borrow! {
async_block_with_borrow_named_lifetime,
Expand Down
92 changes: 92 additions & 0 deletions src/test/ui/async-await/async-unsafe-await.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// run-pass

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

#![feature(async_await, async_unsafe)]

extern crate arc_wake;
extern crate wake_once;

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

pub 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);
}
}

async unsafe fn unsafe_async_fn(x: u8) -> u8 {
wake_and_yield_once().await;
x
}

struct Foo;

trait Bar {
fn foo() {}
}

impl Foo {
async fn async_assoc_item(x: u8) -> u8 {
unsafe {
unsafe_async_fn(x).await
}
}

async unsafe fn async_unsafe_assoc_item(x: u8) -> u8 {
unsafe_async_fn(x).await
}
}

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! {
Foo::async_assoc_item,
|x| {
async move {
unsafe { unsafe_async_fn(x).await }
}
},
|x| {
async move {
unsafe { Foo::async_unsafe_assoc_item(x).await }
}
},
}
}
92 changes: 92 additions & 0 deletions src/test/ui/async-await/async-unsafe-macro.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// run-pass

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

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

extern crate arc_wake;
extern crate wake_once;

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

pub 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);
}
}

async unsafe fn unsafe_async_fn(x: u8) -> u8 {
await!(wake_and_yield_once());
x
}

struct Foo;

trait Bar {
fn foo() {}
}

impl Foo {
async fn async_assoc_item(x: u8) -> u8 {
unsafe {
await!(unsafe_async_fn(x))
}
}

async unsafe fn async_unsafe_assoc_item(x: u8) -> u8 {
await!(unsafe_async_fn(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! {
Foo::async_assoc_item,
|x| {
async move {
unsafe { await!(unsafe_async_fn(x)) }
}
},
|x| {
async move {
unsafe { await!(Foo::async_unsafe_assoc_item(x)) }
}
},
}
}
22 changes: 22 additions & 0 deletions src/test/ui/async-await/auxiliary/wake_once.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// edition:2018

use std::pin::Pin;
use std::future::Future;
use std::task::{Context, Poll};

pub struct WakeOnceThenComplete(bool);

pub 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
}
}
}
Loading