about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJonathan Brouwer <jonathantbrouwer@gmail.com>2025-06-25 09:44:52 +0200
committerJonathan Brouwer <jonathantbrouwer@gmail.com>2025-06-27 09:08:21 +0200
commitf98ea3d144208113df2e644a88a650192fad57ad (patch)
tree3c66f88d8f4cce6beb5851456747faea6e95edec
parente61dd437f33b5a640e67dc3628397689c664c17f (diff)
downloadrust-f98ea3d144208113df2e644a88a650192fad57ad.tar.gz
rust-f98ea3d144208113df2e644a88a650192fad57ad.zip
Port `#[rustc_layout_scalar_valid_range_start/end]` to the new attribute parsing infrastructure
Signed-off-by: Jonathan Brouwer <jonathantbrouwer@gmail.com>
-rw-r--r--compiler/rustc_attr_data_structures/src/attributes.rs6
-rw-r--r--compiler/rustc_attr_data_structures/src/encode_cross_crate.rs2
-rw-r--r--compiler/rustc_attr_data_structures/src/lib.rs10
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/mod.rs1
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs59
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs15
-rw-r--r--compiler/rustc_attr_parsing/src/session_diagnostics.rs4
-rw-r--r--compiler/rustc_middle/src/ty/context.rs30
-rw-r--r--compiler/rustc_passes/messages.ftl3
-rw-r--r--compiler/rustc_passes/src/check_attr.rs27
-rw-r--r--compiler/rustc_passes/src/errors.rs7
-rw-r--r--tests/ui/invalid/invalid_rustc_layout_scalar_valid_range.stderr38
-rw-r--r--tests/ui/parser/bad-lit-suffixes.rs1
-rw-r--r--tests/ui/parser/bad-lit-suffixes.stderr12
14 files changed, 146 insertions, 69 deletions
diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs
index d755afad59f..43a79d8456a 100644
--- a/compiler/rustc_attr_data_structures/src/attributes.rs
+++ b/compiler/rustc_attr_data_structures/src/attributes.rs
@@ -273,6 +273,12 @@ pub enum AttributeKind {
     /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations).
     Repr(ThinVec<(ReprAttr, Span)>),
 
+    /// Represents `#[rustc_layout_scalar_valid_range_end]`.
+    RustcLayoutScalarValidRangeEnd(Box<u128>, Span),
+
+    /// Represents `#[rustc_layout_scalar_valid_range_start]`.
+    RustcLayoutScalarValidRangeStart(Box<u128>, Span),
+
     /// Represents `#[rustc_skip_during_method_dispatch]`.
     SkipDuringMethodDispatch { array: bool, boxed_slice: bool, span: Span },
 
diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
index d4402f4e2e6..174aa5b85b5 100644
--- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
+++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
@@ -36,6 +36,8 @@ impl AttributeKind {
             NoMangle(..) => No,
             Optimize(..) => No,
             PubTransparent(..) => Yes,
+            RustcLayoutScalarValidRangeEnd(..) => Yes,
+            RustcLayoutScalarValidRangeStart(..) => Yes,
             SkipDuringMethodDispatch { .. } => No,
             TrackCaller(..) => Yes,
         }
diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs
index 86c73f0d9a0..8f8ce575a18 100644
--- a/compiler/rustc_attr_data_structures/src/lib.rs
+++ b/compiler/rustc_attr_data_structures/src/lib.rs
@@ -49,6 +49,16 @@ pub trait PrintAttribute {
     fn print_attribute(&self, p: &mut Printer);
 }
 
+impl PrintAttribute for u128 {
+    fn should_render(&self) -> bool {
+        true
+    }
+
+    fn print_attribute(&self, p: &mut Printer) {
+        p.word(self.to_string())
+    }
+}
+
 impl<T: PrintAttribute> PrintAttribute for &T {
     fn should_render(&self) -> bool {
         T::should_render(self)
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index d407669cb41..a7c17009653 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -35,6 +35,7 @@ pub(crate) mod lint_helpers;
 pub(crate) mod loop_match;
 pub(crate) mod must_use;
 pub(crate) mod repr;
+pub(crate) mod rustc_internal;
 pub(crate) mod semantics;
 pub(crate) mod stability;
 pub(crate) mod traits;
diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
new file mode 100644
index 00000000000..7364a3f20e2
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
@@ -0,0 +1,59 @@
+use rustc_ast::LitKind;
+use rustc_attr_data_structures::AttributeKind;
+use rustc_feature::{AttributeTemplate, template};
+use rustc_span::{Symbol, sym};
+
+use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
+use crate::context::{AcceptContext, Stage};
+use crate::parser::ArgParser;
+
+pub(crate) struct RustcLayoutScalarValidRangeStart;
+
+impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeStart {
+    const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_start];
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const TEMPLATE: AttributeTemplate = template!(List: "start");
+
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+        parse_rustc_layout_scalar_valid_range(cx, args)
+            .map(|n| AttributeKind::RustcLayoutScalarValidRangeStart(n, cx.attr_span))
+    }
+}
+
+pub(crate) struct RustcLayoutScalarValidRangeEnd;
+
+impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeEnd {
+    const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_end];
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const TEMPLATE: AttributeTemplate = template!(List: "end");
+
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+        parse_rustc_layout_scalar_valid_range(cx, args)
+            .map(|n| AttributeKind::RustcLayoutScalarValidRangeEnd(n, cx.attr_span))
+    }
+}
+
+fn parse_rustc_layout_scalar_valid_range<S: Stage>(
+    cx: &mut AcceptContext<'_, '_, S>,
+    args: &ArgParser<'_>,
+) -> Option<Box<u128>> {
+    let Some(list) = args.list() else {
+        cx.expected_list(cx.attr_span);
+        return None;
+    };
+    let Some(single) = list.single() else {
+        cx.expected_single_argument(list.span);
+        return None;
+    };
+    let Some(lit) = single.lit() else {
+        cx.expected_integer_literal(single.span());
+        return None;
+    };
+    let LitKind::Int(num, _ty) = lit.kind else {
+        cx.expected_integer_literal(single.span());
+        return None;
+    };
+    Some(Box::new(num.0))
+}
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index 83e3c75dedb..659e21c97bc 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -25,6 +25,9 @@ use crate::attributes::lint_helpers::{AsPtrParser, PubTransparentParser};
 use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
 use crate::attributes::must_use::MustUseParser;
 use crate::attributes::repr::{AlignParser, ReprParser};
+use crate::attributes::rustc_internal::{
+    RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart,
+};
 use crate::attributes::semantics::MayDangleParser;
 use crate::attributes::stability::{
     BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
@@ -126,6 +129,8 @@ attribute_parsers!(
         Single<OptimizeParser>,
         Single<PubTransparentParser>,
         Single<RustcForceInlineParser>,
+        Single<RustcLayoutScalarValidRangeEnd>,
+        Single<RustcLayoutScalarValidRangeStart>,
         Single<SkipDuringMethodDispatchParser>,
         Single<TrackCallerParser>,
         Single<TransparencyParser>,
@@ -269,6 +274,16 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
         })
     }
 
+    pub(crate) fn expected_integer_literal(&self, span: Span) -> ErrorGuaranteed {
+        self.emit_err(AttributeParseError {
+            span,
+            attr_span: self.attr_span,
+            template: self.template.clone(),
+            attribute: self.attr_path.clone(),
+            reason: AttributeParseErrorReason::ExpectedIntegerLiteral,
+        })
+    }
+
     pub(crate) fn expected_list(&self, span: Span) -> ErrorGuaranteed {
         self.emit_err(AttributeParseError {
             span,
diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
index 7cfce579979..0a5a42ce32e 100644
--- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs
+++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
@@ -503,6 +503,7 @@ pub(crate) struct NakedFunctionIncompatibleAttribute {
 pub(crate) enum AttributeParseErrorReason {
     ExpectedNoArgs,
     ExpectedStringLiteral { byte_string: Option<Span> },
+    ExpectedIntegerLiteral,
     ExpectedAtLeastOneArgument,
     ExpectedSingleArgument,
     ExpectedList,
@@ -543,6 +544,9 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
                     diag.span_label(self.span, "expected a string literal here");
                 }
             }
+            AttributeParseErrorReason::ExpectedIntegerLiteral => {
+                diag.span_label(self.span, "expected an integer literal here");
+            }
             AttributeParseErrorReason::ExpectedSingleArgument => {
                 diag.span_label(self.span, "expected a single argument here");
                 diag.code(E0805);
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 457a4f4d502..72810491214 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -17,6 +17,7 @@ use std::{fmt, iter, mem};
 
 use rustc_abi::{ExternAbi, FieldIdx, Layout, LayoutData, TargetDataLayout, VariantIdx};
 use rustc_ast as ast;
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_data_structures::defer;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
@@ -1648,32 +1649,9 @@ impl<'tcx> TyCtxt<'tcx> {
     /// `rustc_layout_scalar_valid_range` attribute.
     // FIXME(eddyb) this is an awkward spot for this method, maybe move it?
     pub fn layout_scalar_valid_range(self, def_id: DefId) -> (Bound<u128>, Bound<u128>) {
-        let get = |name| {
-            let Some(attr) = self.get_attr(def_id, name) else {
-                return Bound::Unbounded;
-            };
-            debug!("layout_scalar_valid_range: attr={:?}", attr);
-            if let Some(
-                &[
-                    ast::MetaItemInner::Lit(ast::MetaItemLit {
-                        kind: ast::LitKind::Int(a, _), ..
-                    }),
-                ],
-            ) = attr.meta_item_list().as_deref()
-            {
-                Bound::Included(a.get())
-            } else {
-                self.dcx().span_delayed_bug(
-                    attr.span(),
-                    "invalid rustc_layout_scalar_valid_range attribute",
-                );
-                Bound::Unbounded
-            }
-        };
-        (
-            get(sym::rustc_layout_scalar_valid_range_start),
-            get(sym::rustc_layout_scalar_valid_range_end),
-        )
+        let start = find_attr!(self.get_all_attrs(def_id), AttributeKind::RustcLayoutScalarValidRangeStart(n, _) => Bound::Included(**n)).unwrap_or(Bound::Unbounded);
+        let end = find_attr!(self.get_all_attrs(def_id), AttributeKind::RustcLayoutScalarValidRangeEnd(n, _) => Bound::Included(**n)).unwrap_or(Bound::Unbounded);
+        (start, end)
     }
 
     pub fn lift<T: Lift<TyCtxt<'tcx>>>(self, value: T) -> Option<T::Lifted> {
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index e2995daadfe..2a2948f78bd 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -618,9 +618,6 @@ passes_rustc_force_inline_coro =
     attribute cannot be applied to a `async`, `gen` or `async gen` function
     .label = `async`, `gen` or `async gen` function
 
-passes_rustc_layout_scalar_valid_range_arg =
-    expected exactly one integer literal argument
-
 passes_rustc_layout_scalar_valid_range_not_struct =
     attribute should be applied to a struct
     .label = not a struct
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 491b3699f4c..b5b297eaf85 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -9,7 +9,7 @@ use std::cell::Cell;
 use std::collections::hash_map::Entry;
 
 use rustc_abi::{Align, ExternAbi, Size};
-use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, MetaItemLit, ast};
+use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, ast};
 use rustc_attr_data_structures::{AttributeKind, InlineAttr, ReprAttr, find_attr};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey};
@@ -184,6 +184,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     self.check_track_caller(hir_id, *attr_span, attrs, span, target)
                 }
                 Attribute::Parsed(
+                    AttributeKind::RustcLayoutScalarValidRangeStart(_num, attr_span)
+                    | AttributeKind::RustcLayoutScalarValidRangeEnd(_num, attr_span),
+                ) => self.check_rustc_layout_scalar_valid_range(*attr_span, span, target),
+                Attribute::Parsed(
                     AttributeKind::BodyStability { .. }
                     | AttributeKind::ConstStabilityIndirect
                     | AttributeKind::MacroTransparency(_),
@@ -228,10 +232,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                             &mut doc_aliases,
                         ),
                         [sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target),
-                        [sym::rustc_layout_scalar_valid_range_start, ..]
-                        | [sym::rustc_layout_scalar_valid_range_end, ..] => {
-                            self.check_rustc_layout_scalar_valid_range(attr, span, target)
-                        }
                         [sym::debugger_visualizer, ..] => self.check_debugger_visualizer(attr, target),
                         [sym::rustc_std_internal_symbol, ..] => {
                             self.check_rustc_std_internal_symbol(attr, span, target)
@@ -1675,24 +1675,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         }
     }
 
-    fn check_rustc_layout_scalar_valid_range(&self, attr: &Attribute, span: Span, target: Target) {
+    fn check_rustc_layout_scalar_valid_range(&self, attr_span: Span, span: Span, target: Target) {
         if target != Target::Struct {
-            self.dcx().emit_err(errors::RustcLayoutScalarValidRangeNotStruct {
-                attr_span: attr.span(),
-                span,
-            });
+            self.dcx().emit_err(errors::RustcLayoutScalarValidRangeNotStruct { attr_span, span });
             return;
         }
-
-        let Some(list) = attr.meta_item_list() else {
-            return;
-        };
-
-        if !matches!(&list[..], &[MetaItemInner::Lit(MetaItemLit { kind: LitKind::Int(..), .. })]) {
-            self.tcx
-                .dcx()
-                .emit_err(errors::RustcLayoutScalarValidRangeArg { attr_span: attr.span() });
-        }
     }
 
     /// Checks if `#[rustc_legacy_const_generics]` is applied to a function and has a valid argument.
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 3286ccc94f2..107fc17b536 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -536,13 +536,6 @@ pub(crate) struct RustcLayoutScalarValidRangeNotStruct {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_rustc_layout_scalar_valid_range_arg)]
-pub(crate) struct RustcLayoutScalarValidRangeArg {
-    #[primary_span]
-    pub attr_span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(passes_rustc_legacy_const_generics_only)]
 pub(crate) struct RustcLegacyConstGenericsOnly {
     #[primary_span]
diff --git a/tests/ui/invalid/invalid_rustc_layout_scalar_valid_range.stderr b/tests/ui/invalid/invalid_rustc_layout_scalar_valid_range.stderr
index 7879e7358c0..8b9ad78db37 100644
--- a/tests/ui/invalid/invalid_rustc_layout_scalar_valid_range.stderr
+++ b/tests/ui/invalid/invalid_rustc_layout_scalar_valid_range.stderr
@@ -1,20 +1,38 @@
-error: expected exactly one integer literal argument
+error[E0539]: malformed `rustc_layout_scalar_valid_range_start` attribute input
   --> $DIR/invalid_rustc_layout_scalar_valid_range.rs:3:1
    |
 LL | #[rustc_layout_scalar_valid_range_start(u32::MAX)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------^^
+   | |                                       |
+   | |                                       expected an integer literal here
+   | help: must be of the form: `#[rustc_layout_scalar_valid_range_start(start)]`
 
-error: expected exactly one integer literal argument
+error[E0805]: malformed `rustc_layout_scalar_valid_range_end` attribute input
   --> $DIR/invalid_rustc_layout_scalar_valid_range.rs:6:1
    |
 LL | #[rustc_layout_scalar_valid_range_end(1, 2)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------^
+   | |                                    |
+   | |                                    expected a single argument here
+   | help: must be of the form: `#[rustc_layout_scalar_valid_range_end(end)]`
 
-error: expected exactly one integer literal argument
+error[E0539]: malformed `rustc_layout_scalar_valid_range_end` attribute input
   --> $DIR/invalid_rustc_layout_scalar_valid_range.rs:9:1
    |
 LL | #[rustc_layout_scalar_valid_range_end(a = "a")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------^^
+   | |                                     |
+   | |                                     expected an integer literal here
+   | help: must be of the form: `#[rustc_layout_scalar_valid_range_end(end)]`
+
+error[E0539]: malformed `rustc_layout_scalar_valid_range_start` attribute input
+  --> $DIR/invalid_rustc_layout_scalar_valid_range.rs:18:1
+   |
+LL | #[rustc_layout_scalar_valid_range_start(rustc_layout_scalar_valid_range_start)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------------------------------^^
+   | |                                       |
+   | |                                       expected an integer literal here
+   | help: must be of the form: `#[rustc_layout_scalar_valid_range_start(start)]`
 
 error: attribute should be applied to a struct
   --> $DIR/invalid_rustc_layout_scalar_valid_range.rs:12:1
@@ -27,11 +45,7 @@ LL | |     Y = 14,
 LL | | }
    | |_- not a struct
 
-error: expected exactly one integer literal argument
-  --> $DIR/invalid_rustc_layout_scalar_valid_range.rs:18:1
-   |
-LL | #[rustc_layout_scalar_valid_range_start(rustc_layout_scalar_valid_range_start)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 error: aborting due to 5 previous errors
 
+Some errors have detailed explanations: E0539, E0805.
+For more information about an error, try `rustc --explain E0539`.
diff --git a/tests/ui/parser/bad-lit-suffixes.rs b/tests/ui/parser/bad-lit-suffixes.rs
index 4e8edf4d46e..13287aabb1d 100644
--- a/tests/ui/parser/bad-lit-suffixes.rs
+++ b/tests/ui/parser/bad-lit-suffixes.rs
@@ -41,4 +41,5 @@ extern "C" {}
 
 #[rustc_layout_scalar_valid_range_start(0suffix)]
 //~^ ERROR invalid suffix `suffix` for number literal
+//~| ERROR malformed `rustc_layout_scalar_valid_range_start` attribute input
 struct S;
diff --git a/tests/ui/parser/bad-lit-suffixes.stderr b/tests/ui/parser/bad-lit-suffixes.stderr
index 416143e496a..295e3112ec0 100644
--- a/tests/ui/parser/bad-lit-suffixes.stderr
+++ b/tests/ui/parser/bad-lit-suffixes.stderr
@@ -150,5 +150,15 @@ LL |     1.0e10suffix;
    |
    = help: valid suffixes are `f32` and `f64`
 
-error: aborting due to 20 previous errors; 2 warnings emitted
+error[E0805]: malformed `rustc_layout_scalar_valid_range_start` attribute input
+  --> $DIR/bad-lit-suffixes.rs:42:1
+   |
+LL | #[rustc_layout_scalar_valid_range_start(0suffix)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------^
+   | |                                      |
+   | |                                      expected a single argument here
+   | help: must be of the form: `#[rustc_layout_scalar_valid_range_start(start)]`
+
+error: aborting due to 21 previous errors; 2 warnings emitted
 
+For more information about this error, try `rustc --explain E0805`.