about summary refs log tree commit diff
diff options
context:
space:
mode:
authorYuki Okushi <huyuumi.dev@gmail.com>2021-01-30 13:36:46 +0900
committerGitHub <noreply@github.com>2021-01-30 13:36:46 +0900
commit7fa991fb8545d8b03f0ab953770cb4fa08921abc (patch)
tree54c0955ab34bca2303c2807adf8738be0dfa1586
parent91ea1cbc177e3ed460c5435092d1cc07e4423428 (diff)
parent5e983d7b3f03e9243d905e0579f32be00170c9af (diff)
downloadrust-7fa991fb8545d8b03f0ab953770cb4fa08921abc.tar.gz
rust-7fa991fb8545d8b03f0ab953770cb4fa08921abc.zip
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 https://github.com/rust-lang/project-rfc-2229/issues/32
r? ``````@nikomatsakis``````
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs13
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/fru_syntax.rs46
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/fru_syntax.stderr11
4 files changed, 67 insertions, 5 deletions
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index c11b8f74593..2503360b1e4 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -303,7 +303,7 @@ impl<'tcx> PlaceBuilder<'tcx> {
         self.base
     }
 
-    fn field(self, f: Field, ty: Ty<'tcx>) -> Self {
+    crate fn field(self, f: Field, ty: Ty<'tcx>) -> Self {
         self.project(PlaceElem::Field(f, ty))
     }
 
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index 639f2bbc6e0..32c01f2c733 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -296,7 +296,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let field_names = this.hir.all_fields(adt_def, variant_index);
 
                 let fields: Vec<_> = if let Some(FruInfo { base, field_types }) = base {
-                    let base = unpack!(block = this.as_place(block, base));
+                    let place_builder = unpack!(block = this.as_place_builder(block, base));
 
                     // MIR does not natively support FRU, so for each
                     // base-supplied field, generate an operand that
@@ -306,9 +306,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         .zip(field_types.into_iter())
                         .map(|(n, ty)| match fields_map.get(&n) {
                             Some(v) => v.clone(),
-                            None => this.consume_by_copy_or_move(
-                                this.hir.tcx().mk_place_field(base, n, ty),
-                            ),
+                            None => {
+                                let place_builder = place_builder.clone();
+                                this.consume_by_copy_or_move(
+                                    place_builder
+                                        .field(n, ty)
+                                        .into_place(this.hir.tcx(), this.hir.typeck_results()),
+                                )
+                            },
                         })
                         .collect()
                 } else {
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/fru_syntax.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/fru_syntax.rs
new file mode 100644
index 00000000000..e89cf4550c1
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/fru_syntax.rs
@@ -0,0 +1,46 @@
+// run-pass
+
+// Test that functional record update/struct update syntax works inside
+// a closure when the feature `capture_disjoint_fields` is enabled.
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| NOTE: `#[warn(incomplete_features)]` on by default
+//~| NOTE: see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+
+#[derive(Clone)]
+struct S {
+    a: String,
+    b: String,
+}
+
+struct T {
+    a: String,
+    s: S,
+}
+
+fn main() {
+    let a = String::new();
+    let b = String::new();
+    let c = String::new();
+    let s = S {a, b};
+    let t = T {
+        a: c,
+        s: s.clone()
+    };
+
+    let c = || {
+        let s2 = S {
+            a: format!("New s2"),
+            ..s
+        };
+        let s3 = S {
+            a: format!("New s3"),
+            ..t.s
+        };
+        println!("{} {}", s2.a, s2.b);
+        println!("{} {} {}", s3.a, s3.b, t.a);
+    };
+
+    c();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/fru_syntax.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/fru_syntax.stderr
new file mode 100644
index 00000000000..7ed73abba86
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/fru_syntax.stderr
@@ -0,0 +1,11 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/fru_syntax.rs:6:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+warning: 1 warning emitted
+