Skip to content

Commit 1256217

Browse files
Rollup merge of rust-lang#81291 - sexxi-goose:fix-struct-update-functional-record-update-syntax-error, r=nikomatsakis
Support FRU pattern with `[feature(capture_disjoint_fields)]` In case of a functional record update syntax for creating a structure, `ExprUseVisitor` to only detect the precise use of some of the field in the `..x` part of the syntax. However, when we start building MIR, we 1. First, build the place for `x` 2. and then, add precise field projections so that only some parts of `x` end up getting read. When `capture_disjoint_fields` is enabled, and FRU is used within a closure `x` won't be completely captured, and therefore the first step will fail. This PR updates `mir_build` to create a place builder in the first step and then create place from the builder only after applying the field projection. Closes rust-lang/project-rfc-2229#32 r? `@nikomatsakis`
2 parents 352fd3c + 5e983d7 commit 1256217

File tree

4 files changed

+67
-5
lines changed

4 files changed

+67
-5
lines changed

compiler/rustc_mir_build/src/build/expr/as_place.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ impl<'tcx> PlaceBuilder<'tcx> {
304304
self.base
305305
}
306306

307-
fn field(self, f: Field, ty: Ty<'tcx>) -> Self {
307+
crate fn field(self, f: Field, ty: Ty<'tcx>) -> Self {
308308
self.project(PlaceElem::Field(f, ty))
309309
}
310310

compiler/rustc_mir_build/src/build/expr/into.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
302302
let field_names = this.hir.all_fields(adt_def, variant_index);
303303

304304
let fields: Vec<_> = if let Some(FruInfo { base, field_types }) = base {
305-
let base = unpack!(block = this.as_place(block, base));
305+
let place_builder = unpack!(block = this.as_place_builder(block, base));
306306

307307
// MIR does not natively support FRU, so for each
308308
// base-supplied field, generate an operand that
@@ -312,9 +312,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
312312
.zip(field_types.into_iter())
313313
.map(|(n, ty)| match fields_map.get(&n) {
314314
Some(v) => v.clone(),
315-
None => this.consume_by_copy_or_move(
316-
this.hir.tcx().mk_place_field(base, n, ty),
317-
),
315+
None => {
316+
let place_builder = place_builder.clone();
317+
this.consume_by_copy_or_move(
318+
place_builder
319+
.field(n, ty)
320+
.into_place(this.hir.tcx(), this.hir.typeck_results()),
321+
)
322+
},
318323
})
319324
.collect()
320325
} else {
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// run-pass
2+
3+
// Test that functional record update/struct update syntax works inside
4+
// a closure when the feature `capture_disjoint_fields` is enabled.
5+
6+
#![feature(capture_disjoint_fields)]
7+
//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
8+
//~| NOTE: `#[warn(incomplete_features)]` on by default
9+
//~| NOTE: see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
10+
11+
#[derive(Clone)]
12+
struct S {
13+
a: String,
14+
b: String,
15+
}
16+
17+
struct T {
18+
a: String,
19+
s: S,
20+
}
21+
22+
fn main() {
23+
let a = String::new();
24+
let b = String::new();
25+
let c = String::new();
26+
let s = S {a, b};
27+
let t = T {
28+
a: c,
29+
s: s.clone()
30+
};
31+
32+
let c = || {
33+
let s2 = S {
34+
a: format!("New s2"),
35+
..s
36+
};
37+
let s3 = S {
38+
a: format!("New s3"),
39+
..t.s
40+
};
41+
println!("{} {}", s2.a, s2.b);
42+
println!("{} {} {}", s3.a, s3.b, t.a);
43+
};
44+
45+
c();
46+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/fru_syntax.rs:6:12
3+
|
4+
LL | #![feature(capture_disjoint_fields)]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `#[warn(incomplete_features)]` on by default
8+
= note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
9+
10+
warning: 1 warning emitted
11+

0 commit comments

Comments
 (0)