Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add size tests for moved locals in generators
- Loading branch information
Showing
2 changed files
with
146 additions
and
0 deletions.
There are no files selected for viewing
98 changes: 98 additions & 0 deletions
98
src/test/run-pass/async-await/async-fn-size-moved-locals.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
// Test that we don't duplicate storage for futures moved around in .await, and | ||
// for futures moved into other futures. | ||
// | ||
// The exact sizes can change by a few bytes (we'd like to know when they do). | ||
// What we don't want to see is the wrong multiple of 1024 (the size of BigFut) | ||
// being reflected in the size. | ||
// | ||
// See issue #59123 for a full explanation. | ||
|
||
// edition:2018 | ||
|
||
#![feature(async_await)] | ||
|
||
use std::future::Future; | ||
use std::pin::Pin; | ||
use std::task::{Context, Poll}; | ||
|
||
const BIG_FUT_SIZE: usize = 1024; | ||
struct BigFut([u8; BIG_FUT_SIZE]); | ||
|
||
impl BigFut { | ||
fn new() -> Self { | ||
BigFut([0; BIG_FUT_SIZE]) | ||
} } | ||
|
||
impl Drop for BigFut { | ||
fn drop(&mut self) {} | ||
} | ||
|
||
impl Future for BigFut { | ||
type Output = (); | ||
|
||
fn poll(self: Pin<&mut Self>, _ctx: &mut Context<'_>) -> Poll<Self::Output> { | ||
Poll::Ready(()) | ||
} | ||
} | ||
|
||
#[allow(dead_code)] | ||
struct Joiner { | ||
a: Option<BigFut>, | ||
b: Option<BigFut>, | ||
c: Option<BigFut>, | ||
} | ||
|
||
impl Future for Joiner { | ||
type Output = (); | ||
|
||
fn poll(self: Pin<&mut Self>, _ctx: &mut Context<'_>) -> Poll<Self::Output> { | ||
Poll::Ready(()) | ||
} | ||
} | ||
|
||
fn noop() {} | ||
|
||
async fn single() { | ||
let x = BigFut::new(); | ||
x.await; | ||
} | ||
|
||
async fn single_with_noop() { | ||
let x = BigFut::new(); | ||
noop(); | ||
x.await; | ||
} | ||
|
||
async fn joined() { | ||
let a = BigFut::new(); | ||
let b = BigFut::new(); | ||
let c = BigFut::new(); | ||
|
||
let joiner = Joiner { | ||
a: Some(a), | ||
b: Some(b), | ||
c: Some(c), | ||
}; | ||
joiner.await | ||
} | ||
|
||
async fn joined_with_noop() { | ||
let a = BigFut::new(); | ||
let b = BigFut::new(); | ||
let c = BigFut::new(); | ||
|
||
let joiner = Joiner { | ||
a: Some(a), | ||
b: Some(b), | ||
c: Some(c), | ||
}; | ||
noop(); | ||
joiner.await | ||
} | ||
|
||
fn main() { | ||
assert_eq!(1028, std::mem::size_of_val(&single())); | ||
assert_eq!(1032, std::mem::size_of_val(&single_with_noop())); | ||
assert_eq!(3084, std::mem::size_of_val(&joined())); | ||
assert_eq!(3084, std::mem::size_of_val(&joined_with_noop())); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// Test that we don't duplicate storage for a variable that is moved to another | ||
// binding. This used to happen in the presence of unwind and drop edges (see | ||
// `complex` below.) | ||
// | ||
// The exact sizes here can change (we'd like to know when they do). What we | ||
// don't want to see is the `complex` generator size being upwards of 2048 bytes | ||
// (which would indicate it is reserving space for two copies of Foo.) | ||
// | ||
// See issue #59123 for a full explanation. | ||
|
||
// edition:2018 | ||
|
||
#![feature(generators, generator_trait)] | ||
|
||
use std::ops::Generator; | ||
|
||
const FOO_SIZE: usize = 1024; | ||
struct Foo([u8; FOO_SIZE]); | ||
|
||
impl Drop for Foo { | ||
fn drop(&mut self) {} | ||
} | ||
|
||
fn simple() -> impl Generator<Yield = (), Return = ()> { | ||
static || { | ||
let first = Foo([0; FOO_SIZE]); | ||
let _second = first; | ||
yield; | ||
// _second dropped here | ||
} | ||
} | ||
|
||
fn noop() {} | ||
|
||
fn complex() -> impl Generator<Yield = (), Return = ()> { | ||
static || { | ||
let first = Foo([0; FOO_SIZE]); | ||
noop(); | ||
let _second = first; | ||
yield; | ||
// _second dropped here | ||
} | ||
} | ||
|
||
fn main() { | ||
assert_eq!(1028, std::mem::size_of_val(&simple())); | ||
assert_eq!(1032, std::mem::size_of_val(&complex())); | ||
} |