Skip to content

Commit 7fa991f

Browse files
authored
Rollup merge of #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 91ea1cb + 5e983d7 commit 7fa991f

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ impl<'tcx> PlaceBuilder<'tcx> {
303303
self.base
304304
}
305305

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

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

+9-4
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
296296
let field_names = this.hir.all_fields(adt_def, variant_index);
297297

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

301301
// MIR does not natively support FRU, so for each
302302
// base-supplied field, generate an operand that
@@ -306,9 +306,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
306306
.zip(field_types.into_iter())
307307
.map(|(n, ty)| match fields_map.get(&n) {
308308
Some(v) => v.clone(),
309-
None => this.consume_by_copy_or_move(
310-
this.hir.tcx().mk_place_field(base, n, ty),
311-
),
309+
None => {
310+
let place_builder = place_builder.clone();
311+
this.consume_by_copy_or_move(
312+
place_builder
313+
.field(n, ty)
314+
.into_place(this.hir.tcx(), this.hir.typeck_results()),
315+
)
316+
},
312317
})
313318
.collect()
314319
} else {
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+
}
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)