Skip to content

Rollup of 4 pull requests #124301

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

Closed
wants to merge 47 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
e243f8d
Merge commit '89f54caacf90e99fc8ba0d60a28bdadea3cfdf1e' into sync_cg_…
bjorn3 Apr 11, 2024
bf02a87
Merge branch 'sync_from_rust'
bjorn3 Apr 11, 2024
71e7414
Allow MaybeUninit in input and output of inline assembly
taiki-e Apr 14, 2024
49ad3ae
Merge pull request #1481 from taiki-e/asm-maybe-uninit
bjorn3 Apr 14, 2024
5075386
Rustup to rustc 1.79.0-nightly (0d8b3346a 2024-04-14)
bjorn3 Apr 15, 2024
9e4e444
static_mut_refs: use raw pointers to remove the remaining FIXME
RalfJung Apr 15, 2024
ceead1b
Change intrinsic types to use `u32` instead of `T` to match stable re…
WaffleLapkin Apr 16, 2024
e4a854e
Miri: adopt to new intrinsic types
WaffleLapkin Apr 16, 2024
7ce867f
Add an assertion in const eval
WaffleLapkin Apr 16, 2024
c2046c4
Add codegen tests for changed intrinsics
WaffleLapkin Apr 16, 2024
4b6bbcb
Fixup 2 ui tests using changed intrinsics
WaffleLapkin Apr 16, 2024
fbac8ef
Cranelift: Revert raw-dylib for Windows futex APIs
ChrisDenton Apr 16, 2024
f532309
ScalarInt: add methods to assert being a (u)int of given size
RalfJung Apr 18, 2024
a2a949b
Auto merge of #124113 - RalfJung:interpret-scalar-ops, r=oli-obk
bors Apr 19, 2024
2ef1552
Don't fatal when calling expect_one_of when recovering arg in parse_seq
compiler-errors Apr 19, 2024
c0b5cc9
Do intrinsic changes in `rustc_codegen_cranelift`
WaffleLapkin Apr 19, 2024
468179c
Fixup `rustc_codegen_gcc` test signature
WaffleLapkin Apr 20, 2024
4027a52
Sync from rust f9b16149208c8a8a349c32813312716f6603eb6f
bjorn3 Apr 20, 2024
82dd93f
Rustup to rustc 1.79.0-nightly (f9b161492 2024-04-19)
bjorn3 Apr 20, 2024
9ad9620
Don't create data object for zero sized allocations
bjorn3 Apr 20, 2024
be9d7ca
Rollup merge of #123967 - RalfJung:static_mut_refs, r=Nilstrieb
jieyouxu Apr 20, 2024
72e6f0c
Remove a couple of items from the crate prelude
bjorn3 Apr 21, 2024
e654877
Also handle AggregateKind::RawPtr in cg_cranelift
scottmcm Apr 12, 2024
a74d6c2
Only apply --cap-lints to the extended_sysroot test suite
bjorn3 Apr 22, 2024
8bc15fb
Sync from rust fb898629a26e4acec59c928ce3ec00a62675d1cc
bjorn3 Apr 22, 2024
d0c5141
Rustup to rustc 1.79.0-nightly (fb898629a 2024-04-21)
bjorn3 Apr 22, 2024
8bf1687
Fix neon test on non arm64 targets
bjorn3 Apr 22, 2024
569df1d
Inline CValue::pointer_from_data_and_meta
bjorn3 Apr 22, 2024
498dbbd
Fix warning in alloc_system.rs
bjorn3 Apr 22, 2024
d569c84
Update libloading
bjorn3 Apr 22, 2024
c02f6c5
Update windows-trgets to 0.52.5
bjorn3 Apr 22, 2024
cea3e7d
Update syn, quote and proc-macro2
bjorn3 Apr 22, 2024
966e269
Update data structure crates
bjorn3 Apr 22, 2024
2c6ef5a
Update a couple of crates
bjorn3 Apr 22, 2024
6ec27fe
Update to Cranelift 0.107
bjorn3 Mar 31, 2024
041666a
Update abi-cafe ui128 test expectations
bjorn3 Apr 1, 2024
b8fdf71
Modify `find_expr` from `Span` to better account for closures
estebank Apr 18, 2024
0136766
Mention when type parameter could be `Clone`
estebank Apr 18, 2024
17a27e8
Suggest cloning captured binding in `move` closure
estebank Apr 19, 2024
de5d652
Rustup to rustc 1.79.0-nightly (7f2fc33da 2024-04-22)
bjorn3 Apr 23, 2024
3d682cf
Merge commit 'de5d6523738fd44a0521b6abf3e73ae1df210741' into sync_cg_…
bjorn3 Apr 23, 2024
7c968a2
Update allowed cg_clif deps
bjorn3 Apr 23, 2024
96152c7
Fix broken subtree sync
bjorn3 Apr 23, 2024
bbda9b6
Rollup merge of #124003 - WaffleLapkin:dellvmization, r=scottmcm,Ralf…
matthiaskrgr Apr 23, 2024
ba00abe
Rollup merge of #124136 - estebank:clone-o-rama-2, r=estebank
matthiaskrgr Apr 23, 2024
bba2788
Rollup merge of #124169 - compiler-errors:parser-fatal, r=oli-obk
matthiaskrgr Apr 23, 2024
7e9174d
Rollup merge of #124286 - bjorn3:sync_cg_clif-2024-04-23, r=bjorn3
matthiaskrgr Apr 23, 2024
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
Prev Previous commit
Next Next commit
Suggest cloning captured binding in move closure
```
error[E0507]: cannot move out of `bar`, a captured variable in an `FnMut` closure
  --> $DIR/borrowck-move-by-capture.rs:9:29
   |
LL |     let bar: Box<_> = Box::new(3);
   |         --- captured outer variable
LL |     let _g = to_fn_mut(|| {
   |                        -- captured by this `FnMut` closure
LL |         let _h = to_fn_once(move || -> isize { *bar });
   |                             ^^^^^^^^^^^^^^^^   ----
   |                             |                  |
   |                             |                  variable moved due to use in closure
   |                             |                  move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait
   |                             `bar` is moved here
   |
help: clone the value before moving it into the closure
   |
LL ~         let value = bar.clone();
LL ~         let _h = to_fn_once(move || -> isize { value });
   |
```
  • Loading branch information
estebank committed Apr 22, 2024
commit 17a27e85a9f591901dfcddb94133531119a35c6f
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1241,7 +1241,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}

fn implements_clone(&self, ty: Ty<'tcx>) -> bool {
pub(crate) fn implements_clone(&self, ty: Ty<'tcx>) -> bool {
let Some(clone_trait_def) = self.infcx.tcx.lang_items().clone_trait() else { return false };
self.infcx
.type_implements_trait(clone_trait_def, [ty], self.param_env)
Expand Down
142 changes: 135 additions & 7 deletions compiler/rustc_borrowck/src/diagnostics/move_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
#![allow(rustc::untranslatable_diagnostic)]

use rustc_errors::{Applicability, Diag};
use rustc_hir::intravisit::Visitor;
use rustc_hir::{CaptureBy, ExprKind, HirId, Node};
use rustc_middle::mir::*;
use rustc_middle::ty::{self, Ty};
use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex};
use rustc_span::{BytePos, ExpnKind, MacroKind, Span};
use rustc_trait_selection::traits::error_reporting::FindExprBySpan;

use crate::diagnostics::CapturedMessageOpt;
use crate::diagnostics::{DescribePlaceOpt, UseSpans};
Expand Down Expand Up @@ -303,17 +306,133 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
self.cannot_move_out_of(span, &description)
}

fn suggest_clone_of_captured_var_in_move_closure(
&self,
err: &mut Diag<'_>,
upvar_hir_id: HirId,
upvar_name: &str,
use_spans: Option<UseSpans<'tcx>>,
) {
let tcx = self.infcx.tcx;
let typeck_results = tcx.typeck(self.mir_def_id());
let Some(use_spans) = use_spans else { return };
// We only care about the case where a closure captured a binding.
let UseSpans::ClosureUse { args_span, .. } = use_spans else { return };
let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { return };
// Fetch the type of the expression corresponding to the closure-captured binding.
let Some(captured_ty) = typeck_results.node_type_opt(upvar_hir_id) else { return };
if !self.implements_clone(captured_ty) {
// We only suggest cloning the captured binding if the type can actually be cloned.
return;
};
// Find the closure that captured the binding.
let mut expr_finder = FindExprBySpan::new(args_span, tcx);
expr_finder.include_closures = true;
expr_finder.visit_expr(tcx.hir().body(body_id).value);
let Some(closure_expr) = expr_finder.result else { return };
let ExprKind::Closure(closure) = closure_expr.kind else { return };
// We'll only suggest cloning the binding if it's a `move` closure.
let CaptureBy::Value { .. } = closure.capture_clause else { return };
// Find the expression within the closure where the binding is consumed.
let mut suggested = false;
let use_span = use_spans.var_or_use();
let mut expr_finder = FindExprBySpan::new(use_span, tcx);
expr_finder.include_closures = true;
expr_finder.visit_expr(tcx.hir().body(body_id).value);
let Some(use_expr) = expr_finder.result else { return };
let parent = tcx.parent_hir_node(use_expr.hir_id);
if let Node::Expr(expr) = parent
&& let ExprKind::Assign(lhs, ..) = expr.kind
&& lhs.hir_id == use_expr.hir_id
{
// Cloning the value being assigned makes no sense:
//
// error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure
// --> $DIR/option-content-move2.rs:11:9
// |
// LL | let mut var = None;
// | ------- captured outer variable
// LL | func(|| {
// | -- captured by this `FnMut` closure
// LL | // Shouldn't suggest `move ||.as_ref()` here
// LL | move || {
// | ^^^^^^^ `var` is moved here
// LL |
// LL | var = Some(NotCopyable);
// | ---
// | |
// | variable moved due to use in closure
// | move occurs because `var` has type `Option<NotCopyable>`, which does not implement the `Copy` trait
// |
return;
}

// Search for an appropriate place for the structured `.clone()` suggestion to be applied.
// If we encounter a statement before the borrow error, we insert a statement there.
for (_, node) in tcx.hir().parent_iter(closure_expr.hir_id) {
if let Node::Stmt(stmt) = node {
let padding = tcx
.sess
.source_map()
.indentation_before(stmt.span)
.unwrap_or_else(|| " ".to_string());
err.multipart_suggestion_verbose(
"clone the value before moving it into the closure",
vec![
(
stmt.span.shrink_to_lo(),
format!("let value = {upvar_name}.clone();\n{padding}"),
),
(use_span, "value".to_string()),
],
Applicability::MachineApplicable,
);
suggested = true;
break;
} else if let Node::Expr(expr) = node
&& let ExprKind::Closure(_) = expr.kind
{
// We want to suggest cloning only on the first closure, not
// subsequent ones (like `ui/suggestions/option-content-move2.rs`).
break;
}
}
if !suggested {
// If we couldn't find a statement for us to insert a new `.clone()` statement before,
// we have a bare expression, so we suggest the creation of a new block inline to go
// from `move || val` to `{ let value = val.clone(); move || value }`.
let padding = tcx
.sess
.source_map()
.indentation_before(closure_expr.span)
.unwrap_or_else(|| " ".to_string());
err.multipart_suggestion_verbose(
"clone the value before moving it into the closure",
vec![
(
closure_expr.span.shrink_to_lo(),
format!("{{\n{padding}let value = {upvar_name}.clone();\n{padding}"),
),
(use_spans.var_or_use(), "value".to_string()),
(closure_expr.span.shrink_to_hi(), format!("\n{padding}}}")),
],
Applicability::MachineApplicable,
);
}
}

fn report_cannot_move_from_borrowed_content(
&mut self,
move_place: Place<'tcx>,
deref_target_place: Place<'tcx>,
span: Span,
use_spans: Option<UseSpans<'tcx>>,
) -> Diag<'tcx> {
let tcx = self.infcx.tcx;
// Inspect the type of the content behind the
// borrow to provide feedback about why this
// was a move rather than a copy.
let ty = deref_target_place.ty(self.body, self.infcx.tcx).ty;
let ty = deref_target_place.ty(self.body, tcx).ty;
let upvar_field = self
.prefixes(move_place.as_ref(), PrefixSet::All)
.find_map(|p| self.is_upvar_field_projection(p));
Expand Down Expand Up @@ -363,8 +482,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {

let upvar = &self.upvars[upvar_field.unwrap().index()];
let upvar_hir_id = upvar.get_root_variable();
let upvar_name = upvar.to_string(self.infcx.tcx);
let upvar_span = self.infcx.tcx.hir().span(upvar_hir_id);
let upvar_name = upvar.to_string(tcx);
let upvar_span = tcx.hir().span(upvar_hir_id);

let place_name = self.describe_any_place(move_place.as_ref());

Expand All @@ -380,12 +499,21 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
closure_kind_ty, closure_kind, place_description,
);

self.cannot_move_out_of(span, &place_description)
let closure_span = tcx.def_span(def_id);
let mut err = self
.cannot_move_out_of(span, &place_description)
.with_span_label(upvar_span, "captured outer variable")
.with_span_label(
self.infcx.tcx.def_span(def_id),
closure_span,
format!("captured by this `{closure_kind}` closure"),
)
);
self.suggest_clone_of_captured_var_in_move_closure(
&mut err,
upvar_hir_id,
&upvar_name,
use_spans,
);
err
}
_ => {
let source = self.borrowed_content_source(deref_base);
Expand Down Expand Up @@ -415,7 +543,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
),
(_, _, _) => self.cannot_move_out_of(
span,
&source.describe_for_unnamed_place(self.infcx.tcx),
&source.describe_for_unnamed_place(tcx),
),
}
}
Expand Down
11 changes: 10 additions & 1 deletion compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,13 @@ pub struct FindExprBySpan<'hir> {
pub span: Span,
pub result: Option<&'hir hir::Expr<'hir>>,
pub ty_result: Option<&'hir hir::Ty<'hir>>,
pub include_closures: bool,
pub tcx: TyCtxt<'hir>,
}

impl<'hir> FindExprBySpan<'hir> {
pub fn new(span: Span, tcx: TyCtxt<'hir>) -> Self {
Self { span, result: None, ty_result: None, tcx }
Self { span, result: None, ty_result: None, tcx, include_closures: false }
}
}

Expand All @@ -70,9 +71,17 @@ impl<'v> Visitor<'v> for FindExprBySpan<'v> {
if self.span == ex.span {
self.result = Some(ex);
} else {
if let hir::ExprKind::Closure(..) = ex.kind
&& self.include_closures
&& let closure_header_sp = self.span.with_hi(ex.span.hi())
&& closure_header_sp == ex.span
{
self.result = Some(ex);
}
hir::intravisit::walk_expr(self, ex);
}
}

fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
if self.span == ty.span {
self.ty_result = Some(ty);
Expand Down
6 changes: 6 additions & 0 deletions tests/ui/borrowck/borrowck-move-by-capture.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ LL | let _h = to_fn_once(move || -> isize { *bar });
| | variable moved due to use in closure
| | move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait
| `bar` is moved here
|
help: clone the value before moving it into the closure
|
LL ~ let value = bar.clone();
LL ~ let _h = to_fn_once(move || -> isize { value });
|

error: aborting due to 1 previous error

Expand Down
14 changes: 13 additions & 1 deletion tests/ui/suggestions/option-content-move2.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
struct NotCopyable;
#[derive(Clone)]
struct NotCopyableButCloneable;

fn func<F: FnMut() -> H, H: FnMut()>(_: F) {}

fn parse() {
fn foo() {
let mut var = None;
func(|| {
// Shouldn't suggest `move ||.as_ref()` here
Expand All @@ -12,5 +14,15 @@ fn parse() {
}
});
}
fn bar() {
let mut var = None;
func(|| {
// Shouldn't suggest `move ||.as_ref()` nor to `clone()` here
move || {
//~^ ERROR: cannot move out of `var`
var = Some(NotCopyableButCloneable);
}
});
}

fn main() {}
21 changes: 19 additions & 2 deletions tests/ui/suggestions/option-content-move2.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure
--> $DIR/option-content-move2.rs:9:9
--> $DIR/option-content-move2.rs:11:9
|
LL | let mut var = None;
| ------- captured outer variable
Expand All @@ -15,6 +15,23 @@ LL | var = Some(NotCopyable);
| variable moved due to use in closure
| move occurs because `var` has type `Option<NotCopyable>`, which does not implement the `Copy` trait

error: aborting due to 1 previous error
error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure
--> $DIR/option-content-move2.rs:21:9
|
LL | let mut var = None;
| ------- captured outer variable
LL | func(|| {
| -- captured by this `FnMut` closure
LL | // Shouldn't suggest `move ||.as_ref()` nor to `clone()` here
LL | move || {
| ^^^^^^^ `var` is moved here
LL |
LL | var = Some(NotCopyableButCloneable);
| ---
| |
| variable moved due to use in closure
| move occurs because `var` has type `Option<NotCopyableButCloneable>`, which does not implement the `Copy` trait

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0507`.
19 changes: 16 additions & 3 deletions tests/ui/suggestions/option-content-move3.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
#[derive(Debug, Clone)]
#[derive(Debug)]
struct NotCopyable;
#[derive(Debug, Clone)]
struct NotCopyableButCloneable;

fn func<F: FnMut() -> H, H: FnMut()>(_: F) {}

fn parse() {
let mut var = NotCopyable;
fn foo() {
let var = NotCopyable;
func(|| {
// Shouldn't suggest `move ||.as_ref()` here
move || { //~ ERROR cannot move out of `var`
let x = var; //~ ERROR cannot move out of `var`
println!("{x:?}");
}
});
}

fn bar() {
let var = NotCopyableButCloneable;
func(|| {
// Shouldn't suggest `move ||.as_ref()` here
move || { //~ ERROR cannot move out of `var`
Expand Down
Loading