about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-09-23 10:01:49 +0000
committerbors <bors@rust-lang.org>2023-09-23 10:01:49 +0000
commit3050938abd423f9e37466cc4cd4129c9b8cc427c (patch)
treece55e89f07b92c7c2f71c048f5d52ed05da6403f
parent0237aa3d771f4c6152c7d46a888ea89c538b121e (diff)
parent79d685325c170f0aed483e4c50c1f2b7d5b2bdc1 (diff)
downloadrust-3050938abd423f9e37466cc4cd4129c9b8cc427c.tar.gz
rust-3050938abd423f9e37466cc4cd4129c9b8cc427c.zip
Auto merge of #116081 - compiler-errors:closure-captures-sized, r=cjgillot
Check that closure/generator's interior/capture types are sized

check that closure upvars and generator interiors are sized. this check is only necessary when `unsized_fn_params` or `unsized_locals` is enabled, so only check if those are active.

Fixes #93622
Fixes #61335
Fixes #68543
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs21
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs11
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/mod.rs14
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs15
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs18
-rw-r--r--tests/ui/async-await/awaiting-unsized-param.drop_tracking_mir.stderr21
-rw-r--r--tests/ui/async-await/awaiting-unsized-param.no_drop_tracking.stderr21
-rw-r--r--tests/ui/async-await/awaiting-unsized-param.rs15
-rw-r--r--tests/ui/async-await/unsized-across-await.drop_tracking_mir.stderr21
-rw-r--r--tests/ui/async-await/unsized-across-await.no_drop_tracking.stderr21
-rw-r--r--tests/ui/async-await/unsized-across-await.rs18
-rw-r--r--tests/ui/closures/capture-unsized-by-move.rs10
-rw-r--r--tests/ui/closures/capture-unsized-by-move.stderr14
-rw-r--r--tests/ui/closures/capture-unsized-by-ref.rs10
-rw-r--r--tests/ui/generator/unsized-across-yield.rs34
-rw-r--r--tests/ui/generator/unsized-across-yield.stderr32
17 files changed, 296 insertions, 4 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 13826264a22..116222ba56e 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -18,7 +18,7 @@ use rustc_infer::traits::{Obligation, TraitEngineExt as _};
 use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::stability::EvalResult;
-use rustc_middle::traits::DefiningAnchor;
+use rustc_middle::traits::{DefiningAnchor, ObligationCauseCode};
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
 use rustc_middle::ty::util::{Discr, IntTypeExt};
@@ -1626,6 +1626,25 @@ pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) {
         let obligation = Obligation::new(tcx, cause.clone(), param_env, *predicate);
         fulfillment_cx.register_predicate_obligation(&infcx, obligation);
     }
+
+    if (tcx.features().unsized_locals || tcx.features().unsized_fn_params)
+        && let Some(generator) = tcx.mir_generator_witnesses(def_id)
+    {
+        for field_ty in generator.field_tys.iter() {
+            fulfillment_cx.register_bound(
+                &infcx,
+                param_env,
+                field_ty.ty,
+                tcx.require_lang_item(hir::LangItem::Sized, Some(field_ty.source_info.span)),
+                ObligationCause::new(
+                    field_ty.source_info.span,
+                    def_id,
+                    ObligationCauseCode::SizedGeneratorInterior(def_id),
+                ),
+            );
+        }
+    }
+
     let errors = fulfillment_cx.select_all_or_error(&infcx);
     debug!(?errors);
     if !errors.is_empty() {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index c94cfde0670..fea726ff8ca 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -518,8 +518,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.select_obligations_where_possible(|_| {});
 
         let mut generators = self.deferred_generator_interiors.borrow_mut();
-        for (_, body_id, interior, kind) in generators.drain(..) {
-            crate::generator_interior::resolve_interior(self, def_id, body_id, interior, kind);
+        for (generator_def_id, body_id, interior, kind) in generators.drain(..) {
+            crate::generator_interior::resolve_interior(
+                self,
+                def_id,
+                generator_def_id,
+                body_id,
+                interior,
+                kind,
+            );
             self.select_obligations_where_possible(|_| {});
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
index 566dc09cdd2..d2ab5aa6bae 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
@@ -9,12 +9,13 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_errors::{pluralize, DelayDm};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::hir_id::HirIdSet;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
 use rustc_infer::infer::{DefineOpaqueTypes, RegionVariableOrigin};
 use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData};
+use rustc_middle::traits::ObligationCauseCode;
 use rustc_middle::ty::fold::FnMutDelegate;
 use rustc_middle::ty::{self, BoundVariableKind, RvalueScopes, Ty, TyCtxt, TypeVisitableExt};
 use rustc_span::symbol::sym;
@@ -188,6 +189,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
 pub fn resolve_interior<'a, 'tcx>(
     fcx: &'a FnCtxt<'a, 'tcx>,
     def_id: DefId,
+    generator_def_id: LocalDefId,
     body_id: hir::BodyId,
     interior: Ty<'tcx>,
     kind: hir::GeneratorKind,
@@ -214,6 +216,16 @@ pub fn resolve_interior<'a, 'tcx>(
     // The types are already kept in insertion order.
     let types = visitor.types;
 
+    if fcx.tcx.features().unsized_locals || fcx.tcx.features().unsized_fn_params {
+        for interior_ty in &types {
+            fcx.require_type_is_sized(
+                interior_ty.ty,
+                interior_ty.span,
+                ObligationCauseCode::SizedGeneratorInterior(generator_def_id),
+            );
+        }
+    }
+
     // The types in the generator interior contain lifetimes local to the generator itself,
     // which should not be exposed outside of the generator. Therefore, we replace these
     // lifetimes with existentially-bound lifetimes, which reflect the exact value of the
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index ba469bd029d..4d641390368 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -41,6 +41,7 @@ use rustc_hir::intravisit::{self, Visitor};
 use rustc_infer::infer::UpvarRegion;
 use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, ProjectionKind};
 use rustc_middle::mir::FakeReadCause;
+use rustc_middle::traits::ObligationCauseCode;
 use rustc_middle::ty::{
     self, ClosureSizeProfileData, Ty, TyCtxt, TypeckResults, UpvarArgs, UpvarCapture,
 };
@@ -295,6 +296,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let final_upvar_tys = self.final_upvar_tys(closure_def_id);
         debug!(?closure_hir_id, ?args, ?final_upvar_tys);
 
+        if self.tcx.features().unsized_locals || self.tcx.features().unsized_fn_params {
+            for capture in
+                self.typeck_results.borrow().closure_min_captures_flattened(closure_def_id)
+            {
+                if let UpvarCapture::ByValue = capture.info.capture_kind {
+                    self.require_type_is_sized(
+                        capture.place.ty(),
+                        capture.get_path_span(self.tcx),
+                        ObligationCauseCode::SizedClosureCapture(closure_def_id),
+                    );
+                }
+            }
+        }
+
         // Build a tuple (U0..Un) of the final upvar types U0..Un
         // and unify the upvar tuple type in the closure with it:
         let final_tupled_upvars_type = Ty::new_tup(self.tcx, &final_upvar_tys);
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index eef193a657d..99b750c9afc 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -299,6 +299,10 @@ pub enum ObligationCauseCode<'tcx> {
     SizedYieldType,
     /// Inline asm operand type must be `Sized`.
     InlineAsmSized,
+    /// Captured closure type must be `Sized`.
+    SizedClosureCapture(LocalDefId),
+    /// Types live across generator yields must be `Sized`.
+    SizedGeneratorInterior(LocalDefId),
     /// `[expr; N]` requires `type_of(expr): Copy`.
     RepeatElementCopy {
         /// If element is a `const fn` we display a help message suggesting to move the
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index cd1dadde1ba..bb96e135741 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -3007,6 +3007,24 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             ObligationCauseCode::InlineAsmSized => {
                 err.note("all inline asm arguments must have a statically known size");
             }
+            ObligationCauseCode::SizedClosureCapture(closure_def_id) => {
+                err.note("all values captured by value by a closure must have a statically known size");
+                let hir::ExprKind::Closure(closure) = self.tcx.hir().get_by_def_id(closure_def_id).expect_expr().kind else {
+                    bug!("expected closure in SizedClosureCapture obligation");
+                };
+                if let hir::CaptureBy::Value = closure.capture_clause
+                    && let Some(span) = closure.fn_arg_span
+                {
+                    err.span_label(span, "this closure captures all values by move");
+                }
+            }
+            ObligationCauseCode::SizedGeneratorInterior(generator_def_id) => {
+                let what = match self.tcx.generator_kind(generator_def_id) {
+                    None | Some(hir::GeneratorKind::Gen) => "yield",
+                    Some(hir::GeneratorKind::Async(..)) => "await",
+                };
+                err.note(format!("all values live across `{what}` must have a statically known size"));
+            }
             ObligationCauseCode::ConstPatternStructural => {
                 err.note("constants used for pattern-matching must derive `PartialEq` and `Eq`");
             }
diff --git a/tests/ui/async-await/awaiting-unsized-param.drop_tracking_mir.stderr b/tests/ui/async-await/awaiting-unsized-param.drop_tracking_mir.stderr
new file mode 100644
index 00000000000..02cf8310a50
--- /dev/null
+++ b/tests/ui/async-await/awaiting-unsized-param.drop_tracking_mir.stderr
@@ -0,0 +1,21 @@
+warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/awaiting-unsized-param.rs:5:31
+   |
+LL | #![feature(unsized_fn_params, unsized_locals)]
+   |                               ^^^^^^^^^^^^^^
+   |
+   = note: see issue #48055 <https://github.com/rust-lang/rust/issues/48055> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0277]: the size for values of type `(dyn Future<Output = T> + Unpin + 'static)` cannot be known at compilation time
+  --> $DIR/awaiting-unsized-param.rs:10:17
+   |
+LL | async fn bug<T>(mut f: dyn Future<Output = T> + Unpin) -> T {
+   |                 ^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `(dyn Future<Output = T> + Unpin + 'static)`
+   = note: all values captured by value by a closure must have a statically known size
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/async-await/awaiting-unsized-param.no_drop_tracking.stderr b/tests/ui/async-await/awaiting-unsized-param.no_drop_tracking.stderr
new file mode 100644
index 00000000000..02cf8310a50
--- /dev/null
+++ b/tests/ui/async-await/awaiting-unsized-param.no_drop_tracking.stderr
@@ -0,0 +1,21 @@
+warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/awaiting-unsized-param.rs:5:31
+   |
+LL | #![feature(unsized_fn_params, unsized_locals)]
+   |                               ^^^^^^^^^^^^^^
+   |
+   = note: see issue #48055 <https://github.com/rust-lang/rust/issues/48055> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0277]: the size for values of type `(dyn Future<Output = T> + Unpin + 'static)` cannot be known at compilation time
+  --> $DIR/awaiting-unsized-param.rs:10:17
+   |
+LL | async fn bug<T>(mut f: dyn Future<Output = T> + Unpin) -> T {
+   |                 ^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `(dyn Future<Output = T> + Unpin + 'static)`
+   = note: all values captured by value by a closure must have a statically known size
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/async-await/awaiting-unsized-param.rs b/tests/ui/async-await/awaiting-unsized-param.rs
new file mode 100644
index 00000000000..2af8723b312
--- /dev/null
+++ b/tests/ui/async-await/awaiting-unsized-param.rs
@@ -0,0 +1,15 @@
+// edition: 2021
+// revisions: no_drop_tracking drop_tracking_mir
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
+
+#![feature(unsized_fn_params, unsized_locals)]
+//~^ WARN the feature `unsized_locals` is incomplete
+
+use std::future::Future;
+
+async fn bug<T>(mut f: dyn Future<Output = T> + Unpin) -> T {
+    //~^ ERROR the size for values of type `(dyn Future<Output = T> + Unpin + 'static)` cannot be known at compilation time
+    (&mut f).await
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/unsized-across-await.drop_tracking_mir.stderr b/tests/ui/async-await/unsized-across-await.drop_tracking_mir.stderr
new file mode 100644
index 00000000000..c606df8e031
--- /dev/null
+++ b/tests/ui/async-await/unsized-across-await.drop_tracking_mir.stderr
@@ -0,0 +1,21 @@
+warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/unsized-across-await.rs:5:12
+   |
+LL | #![feature(unsized_locals)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: see issue #48055 <https://github.com/rust-lang/rust/issues/48055> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0277]: the size for values of type `dyn std::fmt::Display` cannot be known at compilation time
+  --> $DIR/unsized-across-await.rs:11:9
+   |
+LL |     let _x = *x;
+   |         ^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `dyn std::fmt::Display`
+   = note: all values live across `await` must have a statically known size
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/async-await/unsized-across-await.no_drop_tracking.stderr b/tests/ui/async-await/unsized-across-await.no_drop_tracking.stderr
new file mode 100644
index 00000000000..c606df8e031
--- /dev/null
+++ b/tests/ui/async-await/unsized-across-await.no_drop_tracking.stderr
@@ -0,0 +1,21 @@
+warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/unsized-across-await.rs:5:12
+   |
+LL | #![feature(unsized_locals)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: see issue #48055 <https://github.com/rust-lang/rust/issues/48055> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0277]: the size for values of type `dyn std::fmt::Display` cannot be known at compilation time
+  --> $DIR/unsized-across-await.rs:11:9
+   |
+LL |     let _x = *x;
+   |         ^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `dyn std::fmt::Display`
+   = note: all values live across `await` must have a statically known size
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/async-await/unsized-across-await.rs b/tests/ui/async-await/unsized-across-await.rs
new file mode 100644
index 00000000000..9934e9db6d2
--- /dev/null
+++ b/tests/ui/async-await/unsized-across-await.rs
@@ -0,0 +1,18 @@
+// edition: 2021
+// revisions: no_drop_tracking drop_tracking_mir
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
+
+#![feature(unsized_locals)]
+//~^ WARN the feature `unsized_locals` is incomplete
+
+async fn f() {}
+
+async fn g(x: Box<dyn std::fmt::Display>) {
+    let _x = *x;
+    //~^ ERROR the size for values of type `dyn std::fmt::Display` cannot be known at compilation time
+    f().await;
+}
+
+fn main() {
+    let _a = g(Box::new(5));
+}
diff --git a/tests/ui/closures/capture-unsized-by-move.rs b/tests/ui/closures/capture-unsized-by-move.rs
new file mode 100644
index 00000000000..1148e34ac67
--- /dev/null
+++ b/tests/ui/closures/capture-unsized-by-move.rs
@@ -0,0 +1,10 @@
+// compile-flags: --crate-type=lib
+
+#![feature(unsized_fn_params)]
+
+pub fn f(k: dyn std::fmt::Display) {
+    let k2 = move || {
+        k.to_string();
+        //~^ ERROR the size for values of type `(dyn std::fmt::Display + 'static)` cannot be known at compilation time
+    };
+}
diff --git a/tests/ui/closures/capture-unsized-by-move.stderr b/tests/ui/closures/capture-unsized-by-move.stderr
new file mode 100644
index 00000000000..d7fafc8cadd
--- /dev/null
+++ b/tests/ui/closures/capture-unsized-by-move.stderr
@@ -0,0 +1,14 @@
+error[E0277]: the size for values of type `(dyn std::fmt::Display + 'static)` cannot be known at compilation time
+  --> $DIR/capture-unsized-by-move.rs:7:9
+   |
+LL |     let k2 = move || {
+   |                   -- this closure captures all values by move
+LL |         k.to_string();
+   |         ^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `(dyn std::fmt::Display + 'static)`
+   = note: all values captured by value by a closure must have a statically known size
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/closures/capture-unsized-by-ref.rs b/tests/ui/closures/capture-unsized-by-ref.rs
new file mode 100644
index 00000000000..c9e4a5903d9
--- /dev/null
+++ b/tests/ui/closures/capture-unsized-by-ref.rs
@@ -0,0 +1,10 @@
+// build-pass
+// compile-flags: --crate-type=lib
+
+#![feature(unsized_fn_params)]
+
+pub fn f(k: dyn std::fmt::Display) {
+    let k2 = || {
+        k.to_string();
+    };
+}
diff --git a/tests/ui/generator/unsized-across-yield.rs b/tests/ui/generator/unsized-across-yield.rs
new file mode 100644
index 00000000000..876d08ac1f0
--- /dev/null
+++ b/tests/ui/generator/unsized-across-yield.rs
@@ -0,0 +1,34 @@
+#![feature(generator_trait)]
+#![feature(generators)]
+#![feature(unsized_locals)]
+//~^ WARN the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes
+
+use std::ops::Generator;
+
+fn across() -> impl Generator {
+    move || {
+        let b: [u8] = *(Box::new([]) as Box<[u8]>);
+        //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+
+        yield;
+
+        for elem in b.iter() {}
+    }
+}
+
+fn capture() -> impl Generator {
+    let b: [u8] = *(Box::new([]) as Box<[u8]>);
+    move || {
+        println!("{:?}", &b);
+        //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+
+        yield;
+
+        for elem in b.iter() {}
+    }
+}
+
+fn main() {
+    across();
+    capture();
+}
diff --git a/tests/ui/generator/unsized-across-yield.stderr b/tests/ui/generator/unsized-across-yield.stderr
new file mode 100644
index 00000000000..82375a0ec2d
--- /dev/null
+++ b/tests/ui/generator/unsized-across-yield.stderr
@@ -0,0 +1,32 @@
+warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/unsized-across-yield.rs:3:12
+   |
+LL | #![feature(unsized_locals)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: see issue #48055 <https://github.com/rust-lang/rust/issues/48055> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/unsized-across-yield.rs:10:13
+   |
+LL |         let b: [u8] = *(Box::new([]) as Box<[u8]>);
+   |             ^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all values live across `yield` must have a statically known size
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/unsized-across-yield.rs:22:27
+   |
+LL |     move || {
+   |          -- this closure captures all values by move
+LL |         println!("{:?}", &b);
+   |                           ^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all values captured by value by a closure must have a statically known size
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.