From d95a7768a1c5497c6ccb0c2ded30f5968552513c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 18 Sep 2019 14:13:36 -0400 Subject: [PATCH] don't record all intermediate adjustment types That's way more than is needed, and winds up recording types that will never appear in MIR. --- .../check/generator_interior.rs | 33 +++++++++++++++---- src/test/ui/async-await/issues/issue-64477.rs | 20 +++++++++++ 2 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/async-await/issues/issue-64477.rs diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index 5cee3d63ffc..a7c307fdf89 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -181,13 +181,34 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { let scope = self.region_scope_tree.temporary_scope(expr.hir_id.local_id); - // Record the unadjusted type + // If there are adjustments, then record the final type -- + // this is the actual value that is being produced. + if let Some(adjusted_ty) = self.fcx.tables.borrow().expr_ty_adjusted_opt(expr) { + self.record(adjusted_ty, scope, Some(expr), expr.span); + } + + // Also record the unadjusted type (which is the only type if + // there are no adjustments). The reason for this is that the + // unadjusted value is sometimes a "temporary" that would wind + // up in a MIR temporary. + // + // As an example, consider an expression like `vec![].push()`. + // Here, the `vec![]` would wind up MIR stored into a + // temporary variable `t` which we can borrow to invoke + // `>::push(&mut t)`. + // + // Note that an expression can have many adjustments, and we + // are just ignoring those intermediate types. This is because + // those intermediate values are always linearly "consumed" by + // the other adjustments, and hence would never be directly + // captured in the MIR. + // + // (Note that this partly relies on the fact that the `Deref` + // traits always return references, which means their content + // can be reborrowed without needing to spill to a temporary. + // If this were not the case, then we could conceivably have + // to create intermediate temporaries.) let ty = self.fcx.tables.borrow().expr_ty(expr); self.record(ty, scope, Some(expr), expr.span); - - // Also include the adjusted types, since these can result in MIR locals - for adjustment in self.fcx.tables.borrow().expr_adjustments(expr) { - self.record(adjustment.target, scope, Some(expr), expr.span); - } } } diff --git a/src/test/ui/async-await/issues/issue-64477.rs b/src/test/ui/async-await/issues/issue-64477.rs new file mode 100644 index 00000000000..5bd52d44a58 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-64477.rs @@ -0,0 +1,20 @@ +// Regression test for #64477. +// +// We were incorrectly claiming that the `f(x).await` future captured +// a value of type `T`, and hence that `T: Send` would have to hold. +// +// check-pass +// edition:2018 + +use std::future::Future; +use std::pin::Pin; + +fn f(_: &T) -> Pin + Send>> { + unimplemented!() +} + +pub fn g(x: &'static T) -> impl Future + Send { + async move { f(x).await } +} + +fn main() { }