about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2023-12-13 18:03:33 +0100
committerGitHub <noreply@github.com>2023-12-13 18:03:33 +0100
commit1dd36119d062d8a19cde620a85e5891066c2cf67 (patch)
tree2c40d58703146a9f4abbfef90771e35ff4f97f86
parentdbc6ec66368d8e15bfde166d7b505d66b9bd031f (diff)
parenta48cebc4b833bc0df9242ae9845a79299b4cf079 (diff)
downloadrust-1dd36119d062d8a19cde620a85e5891066c2cf67.tar.gz
rust-1dd36119d062d8a19cde620a85e5891066c2cf67.zip
Rollup merge of #118871 - tmiasko:coroutine-maybe-uninit-fields, r=compiler-errors
Coroutine variant fields can be uninitialized

Wrap coroutine variant fields in MaybeUninit to indicate that they might be uninitialized. Otherwise an uninhabited field will make the entire variant uninhabited and introduce undefined behaviour.

The analogous issue in the prefix of coroutine layout was addressed by 6fae7f807146e400fa2bbd1c44768d9bcaa57c4c.
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs5
-rw-r--r--tests/ui/async-await/future-sizes/async-awaiting-fut.stdout6
-rw-r--r--tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr8
-rw-r--r--tests/ui/coroutine/uninhabited-field.rs37
-rw-r--r--tests/ui/print_type_sizes/coroutine_discr_placement.stdout6
5 files changed, 58 insertions, 4 deletions
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index d896873fadd..7918965e04b 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -831,7 +831,10 @@ fn coroutine_layout<'tcx>(
                     Assigned(_) => bug!("assignment does not match variant"),
                     Ineligible(_) => false,
                 })
-                .map(|local| subst_field(info.field_tys[*local].ty));
+                .map(|local| {
+                    let field_ty = subst_field(info.field_tys[*local].ty);
+                    Ty::new_maybe_uninit(tcx, field_ty)
+                });
 
             let mut variant = univariant_uninterned(
                 cx,
diff --git a/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout b/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout
index b0447a58261..47b39e5246d 100644
--- a/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout
+++ b/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout
@@ -52,10 +52,16 @@ print-type-size     variant `Panicked`: 1024 bytes
 print-type-size         upvar `.arg`: 1024 bytes
 print-type-size type: `std::mem::ManuallyDrop<bool>`: 1 bytes, alignment: 1 bytes
 print-type-size     field `.value`: 1 bytes
+print-type-size type: `std::mem::ManuallyDrop<{async fn body@$DIR/async-awaiting-fut.rs:6:17: 6:19}>`: 1 bytes, alignment: 1 bytes
+print-type-size     field `.value`: 1 bytes
 print-type-size type: `std::mem::MaybeUninit<bool>`: 1 bytes, alignment: 1 bytes
 print-type-size     variant `MaybeUninit`: 1 bytes
 print-type-size         field `.uninit`: 0 bytes
 print-type-size         field `.value`: 1 bytes
+print-type-size type: `std::mem::MaybeUninit<{async fn body@$DIR/async-awaiting-fut.rs:6:17: 6:19}>`: 1 bytes, alignment: 1 bytes
+print-type-size     variant `MaybeUninit`: 1 bytes
+print-type-size         field `.uninit`: 0 bytes
+print-type-size         field `.value`: 1 bytes
 print-type-size type: `std::task::Poll<()>`: 1 bytes, alignment: 1 bytes
 print-type-size     discriminant: 1 bytes
 print-type-size     variant `Ready`: 0 bytes
diff --git a/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr b/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr
index 95731b67ccf..8e573b512ad 100644
--- a/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr
+++ b/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr
@@ -1,7 +1,9 @@
-error[E0391]: cycle detected when computing layout of `{async fn body@$DIR/indirect-recursion-issue-112047.rs:33:27: 35:6}`
+error[E0391]: cycle detected when computing layout of `core::mem::maybe_uninit::MaybeUninit<{async fn body@$DIR/indirect-recursion-issue-112047.rs:33:27: 35:6}>`
    |
-   = note: ...which requires computing layout of `<<A as First>::Second as Second>::{opaque#0}`...
-   = note: ...which again requires computing layout of `{async fn body@$DIR/indirect-recursion-issue-112047.rs:33:27: 35:6}`, completing the cycle
+   = note: ...which requires computing layout of `core::mem::manually_drop::ManuallyDrop<{async fn body@$DIR/indirect-recursion-issue-112047.rs:33:27: 35:6}>`...
+   = note: ...which requires computing layout of `{async fn body@$DIR/indirect-recursion-issue-112047.rs:33:27: 35:6}`...
+   = note: ...which requires computing layout of `core::mem::maybe_uninit::MaybeUninit<<<A as First>::Second as Second>::{opaque#0}>`...
+   = note: ...which again requires computing layout of `core::mem::maybe_uninit::MaybeUninit<{async fn body@$DIR/indirect-recursion-issue-112047.rs:33:27: 35:6}>`, completing the cycle
    = note: cycle used when computing layout of `{async block@$DIR/indirect-recursion-issue-112047.rs:6:13: 8:6}`
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
diff --git a/tests/ui/coroutine/uninhabited-field.rs b/tests/ui/coroutine/uninhabited-field.rs
new file mode 100644
index 00000000000..d9570c2fed8
--- /dev/null
+++ b/tests/ui/coroutine/uninhabited-field.rs
@@ -0,0 +1,37 @@
+// Test that uninhabited saved local doesn't make the entire variant uninhabited.
+// run-pass
+#![allow(unused)]
+#![feature(assert_matches)]
+#![feature(coroutine_trait)]
+#![feature(coroutines)]
+#![feature(never_type)]
+use std::assert_matches::assert_matches;
+use std::ops::Coroutine;
+use std::ops::CoroutineState;
+use std::pin::Pin;
+
+fn conjure<T>() -> T { loop {} }
+
+fn run<T>(x: bool, y: bool) {
+    let mut c = || {
+        if x {
+            let a : T;
+            if y {
+                a = conjure::<T>();
+            }
+            yield ();
+        } else {
+            let a : T;
+            if y {
+                a = conjure::<T>();
+            }
+            yield ();
+        }
+    };
+    assert_matches!(Pin::new(&mut c).resume(()), CoroutineState::Yielded(()));
+    assert_matches!(Pin::new(&mut c).resume(()), CoroutineState::Complete(()));
+}
+
+fn main() {
+    run::<!>(false, false);
+}
diff --git a/tests/ui/print_type_sizes/coroutine_discr_placement.stdout b/tests/ui/print_type_sizes/coroutine_discr_placement.stdout
index f34a8e9a706..71a7f3c6381 100644
--- a/tests/ui/print_type_sizes/coroutine_discr_placement.stdout
+++ b/tests/ui/print_type_sizes/coroutine_discr_placement.stdout
@@ -9,3 +9,9 @@ print-type-size         padding: 3 bytes
 print-type-size         local `.z`: 4 bytes, alignment: 4 bytes
 print-type-size     variant `Returned`: 0 bytes
 print-type-size     variant `Panicked`: 0 bytes
+print-type-size type: `std::mem::ManuallyDrop<i32>`: 4 bytes, alignment: 4 bytes
+print-type-size     field `.value`: 4 bytes
+print-type-size type: `std::mem::MaybeUninit<i32>`: 4 bytes, alignment: 4 bytes
+print-type-size     variant `MaybeUninit`: 4 bytes
+print-type-size         field `.uninit`: 0 bytes
+print-type-size         field `.value`: 4 bytes