diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs index 6ee989070b429..a1e743d7997d5 100644 --- a/compiler/rustc_typeck/src/check/generator_interior.rs +++ b/compiler/rustc_typeck/src/check/generator_interior.rs @@ -17,6 +17,7 @@ use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData}; use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_trait_selection::infer::InferCtxtExt; use tracing::debug; mod drop_ranges; @@ -51,6 +52,19 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { ty, hir_id, scope, expr, source_span, self.expr_count, ); + if self.fcx.type_is_copy_modulo_regions(self.fcx.param_env, ty, source_span) { + // This is only used because it's dropped after the yield. + // But it's a Copy type, so it's not possible for the drop to read or write the value. + // Ignore it instead of giving an error. + if matches!( + scope, + Some(region::Scope { data: region::ScopeData::Remainder { .. }, .. }) + ) { + debug!("ignoring Copy type only used in drop"); + return; + } + } + let live_across_yield = scope .map(|s| { self.region_scope_tree.yield_in_scope(s).and_then(|yield_data| { diff --git a/src/test/ui/async-await/trivial-drop.rs b/src/test/ui/async-await/trivial-drop.rs new file mode 100644 index 0000000000000..4d70f4661da8e --- /dev/null +++ b/src/test/ui/async-await/trivial-drop.rs @@ -0,0 +1,12 @@ +// edition:2018 +// build-pass +async fn trivial_drop() { + let x: *const usize = &0; + async {}.await; +} + +fn assert_send(_: T) {} + +fn main() { + assert_send(trivial_drop()); +} diff --git a/src/test/ui/generator/trivial-drop-non-copy.rs b/src/test/ui/generator/trivial-drop-non-copy.rs new file mode 100644 index 0000000000000..c2224eaad0697 --- /dev/null +++ b/src/test/ui/generator/trivial-drop-non-copy.rs @@ -0,0 +1,15 @@ +#![feature(generators, negative_impls)] + +fn assert_send(_: T) {} + +struct S; +impl !Send for S {} + +fn main() { + println!("{}", std::mem::needs_drop::()); + let g = || { + let x = S; //~ type `S` + yield; //~ `x` maybe used later + }; + assert_send(g); //~ ERROR generator cannot be sent between threads +} diff --git a/src/test/ui/generator/trivial-drop-non-copy.stderr b/src/test/ui/generator/trivial-drop-non-copy.stderr new file mode 100644 index 0000000000000..483f561752e1d --- /dev/null +++ b/src/test/ui/generator/trivial-drop-non-copy.stderr @@ -0,0 +1,24 @@ +error: generator cannot be sent between threads safely + --> $DIR/trivial-drop-non-copy.rs:14:5 + | +LL | assert_send(g); + | ^^^^^^^^^^^ generator is not `Send` + | + = help: within `[generator@$DIR/trivial-drop-non-copy.rs:10:13: 10:15]`, the trait `Send` is not implemented for `S` +note: generator is not `Send` as this value is used across a yield + --> $DIR/trivial-drop-non-copy.rs:12:9 + | +LL | let x = S; + | - has type `S` which is not `Send` +LL | yield; + | ^^^^^ yield occurs here, with `x` maybe used later +LL | }; + | - `x` is later dropped here +note: required by a bound in `assert_send` + --> $DIR/trivial-drop-non-copy.rs:3:19 + | +LL | fn assert_send(_: T) {} + | ^^^^ required by this bound in `assert_send` + +error: aborting due to previous error + diff --git a/src/test/ui/generator/trivial-drop.rs b/src/test/ui/generator/trivial-drop.rs new file mode 100644 index 0000000000000..f4b38258655cc --- /dev/null +++ b/src/test/ui/generator/trivial-drop.rs @@ -0,0 +1,12 @@ +// build-pass +#![feature(generators)] + +fn assert_send(_: T) {} + +fn main() { + let g = || { + let x: *const usize = &0; + yield; + }; + assert_send(g); +}