mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 07:14:28 +00:00
Fix drop-tracking ICE when a struct containing a field with a Drop
impl is used across an await
Previously, drop-tracking would incorrectly assume the struct would be dropped immediately, which was not true: when the field had a type with a manual `Drop` impl, the drop becomes observable and has to be dropped after the await instead. For reasons I don't understand, this also fixes another error crater popped up related to type parameters. #98476
This commit is contained in:
parent
17355a3b9f
commit
b30315d64f
@ -14,7 +14,7 @@ use rustc_hir::hir_id::HirIdSet;
|
|||||||
use rustc_hir::intravisit::{self, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
|
use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
|
||||||
use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData};
|
use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData};
|
||||||
use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt};
|
use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt, TypeVisitable};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
@ -376,6 +376,17 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
|
|||||||
|
|
||||||
debug!("is_borrowed_temporary: {:?}", self.drop_ranges.is_borrowed_temporary(expr));
|
debug!("is_borrowed_temporary: {:?}", self.drop_ranges.is_borrowed_temporary(expr));
|
||||||
|
|
||||||
|
let ty = self.fcx.typeck_results.borrow().expr_ty_adjusted_opt(expr);
|
||||||
|
let may_need_drop = |ty: Ty<'tcx>| {
|
||||||
|
// Avoid ICEs in needs_drop.
|
||||||
|
let ty = self.fcx.resolve_vars_if_possible(ty);
|
||||||
|
let ty = self.fcx.tcx.erase_regions(ty);
|
||||||
|
if ty.needs_infer() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
ty.needs_drop(self.fcx.tcx, self.fcx.param_env)
|
||||||
|
};
|
||||||
|
|
||||||
// Typically, the value produced by an expression is consumed by its parent in some way,
|
// Typically, the value produced by an expression is consumed by its parent in some way,
|
||||||
// so we only have to check if the parent contains a yield (note that the parent may, for
|
// so we only have to check if the parent contains a yield (note that the parent may, for
|
||||||
// example, store the value into a local variable, but then we already consider local
|
// example, store the value into a local variable, but then we already consider local
|
||||||
@ -384,7 +395,18 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
|
|||||||
// However, in the case of temporary values, we are going to store the value into a
|
// However, in the case of temporary values, we are going to store the value into a
|
||||||
// temporary on the stack that is live for the current temporary scope and then return a
|
// temporary on the stack that is live for the current temporary scope and then return a
|
||||||
// reference to it. That value may be live across the entire temporary scope.
|
// reference to it. That value may be live across the entire temporary scope.
|
||||||
let scope = if self.drop_ranges.is_borrowed_temporary(expr) {
|
//
|
||||||
|
// There's another subtlety: if the type has an observable drop, it must be dropped after
|
||||||
|
// the yield, even if it's not borrowed or referenced after the yield. Ideally this would
|
||||||
|
// *only* happen for types with observable drop, not all types which wrap them, but that
|
||||||
|
// doesn't match the behavior of MIR borrowck and causes ICEs. See the FIXME comment in
|
||||||
|
// src/test/ui/generator/drop-tracking-parent-expression.rs.
|
||||||
|
let scope = if self.drop_ranges.is_borrowed_temporary(expr)
|
||||||
|
|| ty.map_or(true, |ty| {
|
||||||
|
let needs_drop = may_need_drop(ty);
|
||||||
|
debug!(?needs_drop, ?ty);
|
||||||
|
needs_drop
|
||||||
|
}) {
|
||||||
self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id)
|
self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id)
|
||||||
} else {
|
} else {
|
||||||
debug!("parent_node: {:?}", self.fcx.tcx.hir().find_parent_node(expr.hir_id));
|
debug!("parent_node: {:?}", self.fcx.tcx.hir().find_parent_node(expr.hir_id));
|
||||||
@ -398,7 +420,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
|
|||||||
|
|
||||||
// If there are adjustments, then record the final type --
|
// If there are adjustments, then record the final type --
|
||||||
// this is the actual value that is being produced.
|
// this is the actual value that is being produced.
|
||||||
if let Some(adjusted_ty) = self.fcx.typeck_results.borrow().expr_ty_adjusted_opt(expr) {
|
if let Some(adjusted_ty) = ty {
|
||||||
self.record(adjusted_ty, expr.hir_id, scope, Some(expr), expr.span);
|
self.record(adjusted_ty, expr.hir_id, scope, Some(expr), expr.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
22
src/test/ui/async-await/default-struct-update.rs
Normal file
22
src/test/ui/async-await/default-struct-update.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// build-pass
|
||||||
|
// edition:2018
|
||||||
|
// compile-flags: -Zdrop-tracking=y
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _ = foo();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn from_config(_: Config) {}
|
||||||
|
|
||||||
|
async fn foo() {
|
||||||
|
from_config(Config {
|
||||||
|
nickname: None,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct Config {
|
||||||
|
nickname: Option<Box<u8>>,
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
error[E0277]: `Sender<i32>` cannot be shared between threads safely
|
error[E0277]: `Sender<i32>` cannot be shared between threads safely
|
||||||
--> $DIR/issue-70935-complex-spans.rs:13:45
|
--> $DIR/issue-70935-complex-spans.rs:12:45
|
||||||
|
|
|
|
||||||
LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
|
LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
|
||||||
| ^^^^^^^^^^^^^^^^^^ `Sender<i32>` cannot be shared between threads safely
|
| ^^^^^^^^^^^^^^^^^^ `Sender<i32>` cannot be shared between threads safely
|
||||||
@ -7,7 +7,7 @@ LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
|
|||||||
= help: the trait `Sync` is not implemented for `Sender<i32>`
|
= help: the trait `Sync` is not implemented for `Sender<i32>`
|
||||||
= note: required because of the requirements on the impl of `Send` for `&Sender<i32>`
|
= note: required because of the requirements on the impl of `Send` for `&Sender<i32>`
|
||||||
note: required because it's used within this closure
|
note: required because it's used within this closure
|
||||||
--> $DIR/issue-70935-complex-spans.rs:25:13
|
--> $DIR/issue-70935-complex-spans.rs:16:13
|
||||||
|
|
|
|
||||||
LL | baz(|| async{
|
LL | baz(|| async{
|
||||||
| ^^
|
| ^^
|
||||||
@ -16,16 +16,14 @@ note: required because it's used within this `async fn` body
|
|||||||
|
|
|
|
||||||
LL | async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
|
LL | async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
|
||||||
| ___________________________________________________________________^
|
| ___________________________________________________________________^
|
||||||
LL | |
|
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
= note: required because it captures the following types: `ResumeTy`, `impl for<'r, 's, 't0> Future<Output = ()>`, `()`
|
= note: required because it captures the following types: `ResumeTy`, `impl for<'r, 's, 't0> Future<Output = ()>`, `()`
|
||||||
note: required because it's used within this `async` block
|
note: required because it's used within this `async` block
|
||||||
--> $DIR/issue-70935-complex-spans.rs:23:16
|
--> $DIR/issue-70935-complex-spans.rs:15:16
|
||||||
|
|
|
|
||||||
LL | async move {
|
LL | async move {
|
||||||
| ________________^
|
| ________________^
|
||||||
LL | |
|
|
||||||
LL | | baz(|| async{
|
LL | | baz(|| async{
|
||||||
LL | | foo(tx.clone());
|
LL | | foo(tx.clone());
|
||||||
LL | | }).await;
|
LL | | }).await;
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
error: future cannot be sent between threads safely
|
error: future cannot be sent between threads safely
|
||||||
--> $DIR/issue-70935-complex-spans.rs:13:45
|
--> $DIR/issue-70935-complex-spans.rs:12:45
|
||||||
|
|
|
|
||||||
LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
|
LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
|
||||||
| ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
|
| ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
|
||||||
|
|
|
|
||||||
= help: the trait `Sync` is not implemented for `Sender<i32>`
|
= help: the trait `Sync` is not implemented for `Sender<i32>`
|
||||||
note: future is not `Send` as this value is used across an await
|
note: future is not `Send` as this value is used across an await
|
||||||
--> $DIR/issue-70935-complex-spans.rs:27:11
|
--> $DIR/issue-70935-complex-spans.rs:18:11
|
||||||
|
|
|
|
||||||
LL | baz(|| async{
|
LL | baz(|| async{
|
||||||
| _____________-
|
| _____________-
|
||||||
@ -14,9 +14,9 @@ LL | | foo(tx.clone());
|
|||||||
LL | | }).await;
|
LL | | }).await;
|
||||||
| | - ^^^^^^ await occurs here, with the value maybe used later
|
| | - ^^^^^^ await occurs here, with the value maybe used later
|
||||||
| |_________|
|
| |_________|
|
||||||
| has type `[closure@$DIR/issue-70935-complex-spans.rs:25:13: 25:15]` which is not `Send`
|
| has type `[closure@$DIR/issue-70935-complex-spans.rs:16:13: 16:15]` which is not `Send`
|
||||||
note: the value is later dropped here
|
note: the value is later dropped here
|
||||||
--> $DIR/issue-70935-complex-spans.rs:27:17
|
--> $DIR/issue-70935-complex-spans.rs:18:17
|
||||||
|
|
|
|
||||||
LL | }).await;
|
LL | }).await;
|
||||||
| ^
|
| ^
|
||||||
|
@ -7,22 +7,13 @@
|
|||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|
||||||
async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
|
async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
|
||||||
//[drop_tracking]~^ within this `async fn` body
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
|
fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
|
||||||
//[normal]~^ ERROR: future cannot be sent between threads safely
|
//[normal]~^ ERROR future cannot be sent between threads safely
|
||||||
//[drop_tracking]~^^ ERROR: `Sender<i32>` cannot be shared
|
//[drop_tracking]~^^ ERROR `Sender<i32>` cannot be shared between threads
|
||||||
//[drop_tracking]~| NOTE: cannot be shared
|
|
||||||
//[drop_tracking]~| NOTE: requirements on the impl of `Send`
|
|
||||||
//[drop_tracking]~| NOTE: captures the following types
|
|
||||||
//[drop_tracking]~| NOTE: in this expansion
|
|
||||||
//[drop_tracking]~| NOTE: in this expansion
|
|
||||||
//[drop_tracking]~| NOTE: in this expansion
|
|
||||||
//[drop_tracking]~| NOTE: in this expansion
|
|
||||||
async move {
|
async move {
|
||||||
//[drop_tracking]~^ within this `async` block
|
baz(|| async{
|
||||||
baz(|| async{ //[drop_tracking]~ NOTE: used within this closure
|
|
||||||
foo(tx.clone());
|
foo(tx.clone());
|
||||||
}).await;
|
}).await;
|
||||||
}
|
}
|
||||||
|
36
src/test/ui/async-await/non-trivial-drop.rs
Normal file
36
src/test/ui/async-await/non-trivial-drop.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// build-pass
|
||||||
|
// edition:2018
|
||||||
|
// compile-flags: -Zdrop-tracking=y
|
||||||
|
|
||||||
|
#![feature(generators)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _ = foo();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
|| {
|
||||||
|
yield drop(Config {
|
||||||
|
nickname: NonCopy,
|
||||||
|
b: NonCopy2,
|
||||||
|
}.nickname);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct NonCopy;
|
||||||
|
impl Drop for NonCopy {
|
||||||
|
fn drop(&mut self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct NonCopy2;
|
||||||
|
impl Drop for NonCopy2 {
|
||||||
|
fn drop(&mut self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct Config {
|
||||||
|
nickname: NonCopy,
|
||||||
|
b: NonCopy2,
|
||||||
|
}
|
18
src/test/ui/async-await/type-parameter-send.rs
Normal file
18
src/test/ui/async-await/type-parameter-send.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// check-pass
|
||||||
|
// compile-flags: --crate-type lib
|
||||||
|
// edition:2018
|
||||||
|
|
||||||
|
fn assert_send<F: Send>(_: F) {}
|
||||||
|
|
||||||
|
async fn __post<T>() -> T {
|
||||||
|
if false {
|
||||||
|
todo!()
|
||||||
|
} else {
|
||||||
|
async {}.await;
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo<T>() {
|
||||||
|
assert_send(__post::<T>());
|
||||||
|
}
|
17
src/test/ui/generator/derived-drop-parent-expr.rs
Normal file
17
src/test/ui/generator/derived-drop-parent-expr.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// build-pass
|
||||||
|
// compile-flags:-Zdrop-tracking
|
||||||
|
|
||||||
|
//! Like drop-tracking-parent-expression, but also tests that this doesn't ICE when building MIR
|
||||||
|
#![feature(generators)]
|
||||||
|
|
||||||
|
fn assert_send<T: Send>(_thing: T) {}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Client { pub nickname: String }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let g = move || match drop(Client { ..Client::default() }) {
|
||||||
|
_status => yield,
|
||||||
|
};
|
||||||
|
assert_send(g);
|
||||||
|
}
|
69
src/test/ui/generator/drop-tracking-parent-expression.rs
Normal file
69
src/test/ui/generator/drop-tracking-parent-expression.rs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
// compile-flags: -Zdrop-tracking
|
||||||
|
#![feature(generators, negative_impls, rustc_attrs)]
|
||||||
|
|
||||||
|
macro_rules! type_combinations {
|
||||||
|
(
|
||||||
|
$( $name:ident => { $( $tt:tt )* } );* $(;)?
|
||||||
|
) => { $(
|
||||||
|
mod $name {
|
||||||
|
$( $tt )*
|
||||||
|
|
||||||
|
impl !Sync for Client {}
|
||||||
|
impl !Send for Client {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Struct update syntax. This fails because the Client used in the update is considered
|
||||||
|
// dropped *after* the yield.
|
||||||
|
{
|
||||||
|
let g = move || match drop($name::Client { ..$name::Client::default() }) {
|
||||||
|
//~^ `significant_drop::Client` which is not `Send`
|
||||||
|
//~| `insignificant_dtor::Client` which is not `Send`
|
||||||
|
//~| `derived_drop::Client` which is not `Send`
|
||||||
|
_ => yield,
|
||||||
|
};
|
||||||
|
assert_send(g);
|
||||||
|
//~^ ERROR cannot be sent between threads
|
||||||
|
//~| ERROR cannot be sent between threads
|
||||||
|
//~| ERROR cannot be sent between threads
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple owned value. This works because the Client is considered moved into `drop`,
|
||||||
|
// even though the temporary expression doesn't end until after the yield.
|
||||||
|
{
|
||||||
|
let g = move || match drop($name::Client::default()) {
|
||||||
|
_ => yield,
|
||||||
|
};
|
||||||
|
assert_send(g);
|
||||||
|
}
|
||||||
|
)* }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_send<T: Send>(_thing: T) {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
type_combinations!(
|
||||||
|
// OK
|
||||||
|
copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
|
||||||
|
// NOT OK: MIR borrowck thinks that this is used after the yield, even though
|
||||||
|
// this has no `Drop` impl and only the drops of the fields are observable.
|
||||||
|
// FIXME: this should compile.
|
||||||
|
derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } };
|
||||||
|
// NOT OK
|
||||||
|
significant_drop => {
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Client;
|
||||||
|
impl Drop for Client {
|
||||||
|
fn drop(&mut self) {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// NOT OK (we need to agree with MIR borrowck)
|
||||||
|
insignificant_dtor => {
|
||||||
|
#[derive(Default)]
|
||||||
|
#[rustc_insignificant_dtor]
|
||||||
|
pub struct Client;
|
||||||
|
impl Drop for Client {
|
||||||
|
fn drop(&mut self) {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
);
|
||||||
|
}
|
128
src/test/ui/generator/drop-tracking-parent-expression.stderr
Normal file
128
src/test/ui/generator/drop-tracking-parent-expression.stderr
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
error: generator cannot be sent between threads safely
|
||||||
|
--> $DIR/drop-tracking-parent-expression.rs:24:13
|
||||||
|
|
|
||||||
|
LL | assert_send(g);
|
||||||
|
| ^^^^^^^^^^^ generator is not `Send`
|
||||||
|
...
|
||||||
|
LL | / type_combinations!(
|
||||||
|
LL | | // OK
|
||||||
|
LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
|
||||||
|
LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though
|
||||||
|
... |
|
||||||
|
LL | | };
|
||||||
|
LL | | );
|
||||||
|
| |_____- in this macro invocation
|
||||||
|
|
|
||||||
|
= help: within `[generator@$DIR/drop-tracking-parent-expression.rs:18:21: 18:28]`, the trait `Send` is not implemented for `derived_drop::Client`
|
||||||
|
note: generator is not `Send` as this value is used across a yield
|
||||||
|
--> $DIR/drop-tracking-parent-expression.rs:22:22
|
||||||
|
|
|
||||||
|
LL | let g = move || match drop($name::Client { ..$name::Client::default() }) {
|
||||||
|
| ------------------------ has type `derived_drop::Client` which is not `Send`
|
||||||
|
...
|
||||||
|
LL | _ => yield,
|
||||||
|
| ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
|
||||||
|
LL | };
|
||||||
|
| - `$name::Client::default()` is later dropped here
|
||||||
|
...
|
||||||
|
LL | / type_combinations!(
|
||||||
|
LL | | // OK
|
||||||
|
LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
|
||||||
|
LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though
|
||||||
|
... |
|
||||||
|
LL | | };
|
||||||
|
LL | | );
|
||||||
|
| |_____- in this macro invocation
|
||||||
|
note: required by a bound in `assert_send`
|
||||||
|
--> $DIR/drop-tracking-parent-expression.rs:41:19
|
||||||
|
|
|
||||||
|
LL | fn assert_send<T: Send>(_thing: T) {}
|
||||||
|
| ^^^^ required by this bound in `assert_send`
|
||||||
|
= note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: generator cannot be sent between threads safely
|
||||||
|
--> $DIR/drop-tracking-parent-expression.rs:24:13
|
||||||
|
|
|
||||||
|
LL | assert_send(g);
|
||||||
|
| ^^^^^^^^^^^ generator is not `Send`
|
||||||
|
...
|
||||||
|
LL | / type_combinations!(
|
||||||
|
LL | | // OK
|
||||||
|
LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
|
||||||
|
LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though
|
||||||
|
... |
|
||||||
|
LL | | };
|
||||||
|
LL | | );
|
||||||
|
| |_____- in this macro invocation
|
||||||
|
|
|
||||||
|
= help: within `[generator@$DIR/drop-tracking-parent-expression.rs:18:21: 18:28]`, the trait `Send` is not implemented for `significant_drop::Client`
|
||||||
|
note: generator is not `Send` as this value is used across a yield
|
||||||
|
--> $DIR/drop-tracking-parent-expression.rs:22:22
|
||||||
|
|
|
||||||
|
LL | let g = move || match drop($name::Client { ..$name::Client::default() }) {
|
||||||
|
| ------------------------ has type `significant_drop::Client` which is not `Send`
|
||||||
|
...
|
||||||
|
LL | _ => yield,
|
||||||
|
| ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
|
||||||
|
LL | };
|
||||||
|
| - `$name::Client::default()` is later dropped here
|
||||||
|
...
|
||||||
|
LL | / type_combinations!(
|
||||||
|
LL | | // OK
|
||||||
|
LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
|
||||||
|
LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though
|
||||||
|
... |
|
||||||
|
LL | | };
|
||||||
|
LL | | );
|
||||||
|
| |_____- in this macro invocation
|
||||||
|
note: required by a bound in `assert_send`
|
||||||
|
--> $DIR/drop-tracking-parent-expression.rs:41:19
|
||||||
|
|
|
||||||
|
LL | fn assert_send<T: Send>(_thing: T) {}
|
||||||
|
| ^^^^ required by this bound in `assert_send`
|
||||||
|
= note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: generator cannot be sent between threads safely
|
||||||
|
--> $DIR/drop-tracking-parent-expression.rs:24:13
|
||||||
|
|
|
||||||
|
LL | assert_send(g);
|
||||||
|
| ^^^^^^^^^^^ generator is not `Send`
|
||||||
|
...
|
||||||
|
LL | / type_combinations!(
|
||||||
|
LL | | // OK
|
||||||
|
LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
|
||||||
|
LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though
|
||||||
|
... |
|
||||||
|
LL | | };
|
||||||
|
LL | | );
|
||||||
|
| |_____- in this macro invocation
|
||||||
|
|
|
||||||
|
= help: within `[generator@$DIR/drop-tracking-parent-expression.rs:18:21: 18:28]`, the trait `Send` is not implemented for `insignificant_dtor::Client`
|
||||||
|
note: generator is not `Send` as this value is used across a yield
|
||||||
|
--> $DIR/drop-tracking-parent-expression.rs:22:22
|
||||||
|
|
|
||||||
|
LL | let g = move || match drop($name::Client { ..$name::Client::default() }) {
|
||||||
|
| ------------------------ has type `insignificant_dtor::Client` which is not `Send`
|
||||||
|
...
|
||||||
|
LL | _ => yield,
|
||||||
|
| ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
|
||||||
|
LL | };
|
||||||
|
| - `$name::Client::default()` is later dropped here
|
||||||
|
...
|
||||||
|
LL | / type_combinations!(
|
||||||
|
LL | | // OK
|
||||||
|
LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
|
||||||
|
LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though
|
||||||
|
... |
|
||||||
|
LL | | };
|
||||||
|
LL | | );
|
||||||
|
| |_____- in this macro invocation
|
||||||
|
note: required by a bound in `assert_send`
|
||||||
|
--> $DIR/drop-tracking-parent-expression.rs:41:19
|
||||||
|
|
|
||||||
|
LL | fn assert_send<T: Send>(_thing: T) {}
|
||||||
|
| ^^^^ required by this bound in `assert_send`
|
||||||
|
= note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
@ -1,22 +1,55 @@
|
|||||||
// check-pass
|
// build-pass
|
||||||
// compile-flags: -Zdrop-tracking
|
// compile-flags: -Zdrop-tracking
|
||||||
#![feature(generators, negative_impls)]
|
#![feature(generators, negative_impls)]
|
||||||
|
|
||||||
struct Client;
|
macro_rules! type_combinations {
|
||||||
|
(
|
||||||
|
$( $name:ident => { $( $tt:tt )* } );*
|
||||||
|
) => { $(
|
||||||
|
mod $name {
|
||||||
|
pub mod unsync {
|
||||||
|
$( $tt )*
|
||||||
|
|
||||||
impl !Sync for Client {}
|
impl !Sync for Client {}
|
||||||
|
}
|
||||||
|
pub mod unsend {
|
||||||
|
$( $tt )*
|
||||||
|
|
||||||
fn status(_client_status: &Client) -> i16 {
|
impl !Send for Client {}
|
||||||
200
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the same bug as issue 57017, but using yield instead of await
|
||||||
|
{
|
||||||
|
let g = move || match drop(&$name::unsync::Client::default()) {
|
||||||
|
_status => yield,
|
||||||
|
};
|
||||||
|
assert_send(g);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This tests that `Client` is properly considered to be dropped after moving it into the
|
||||||
|
// function.
|
||||||
|
{
|
||||||
|
let g = move || match drop($name::unsend::Client::default()) {
|
||||||
|
_status => yield,
|
||||||
|
};
|
||||||
|
assert_send(g);
|
||||||
|
}
|
||||||
|
)* }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assert_send<T: Send>(_thing: T) {}
|
fn assert_send<T: Send>(_thing: T) {}
|
||||||
|
|
||||||
// This is the same bug as issue 57017, but using yield instead of await
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let client = Client;
|
type_combinations!(
|
||||||
let g = move || match status(&client) {
|
copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
|
||||||
_status => yield,
|
derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } };
|
||||||
};
|
significant_drop => {
|
||||||
assert_send(g);
|
#[derive(Default)]
|
||||||
|
pub struct Client;
|
||||||
|
impl Drop for Client {
|
||||||
|
fn drop(&mut self) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user