From 84ba2289fdd3c41ebbef53de3fdb5035f2e73e60 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 6 Aug 2022 00:17:16 +0000 Subject: [PATCH 01/13] Suggest as_ref or as_mut --- compiler/rustc_borrowck/src/diagnostics/mod.rs | 2 +- src/test/ui/borrowck/suggest-as-ref-on-mut-closure.stderr | 2 +- src/test/ui/suggestions/as-ref-2.stderr | 2 +- src/test/ui/suggestions/option-content-move.stderr | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 098e8de9420..cc5a3e16c96 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1089,7 +1089,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if is_option_or_result && maybe_reinitialized_locations_is_empty { err.span_suggestion_verbose( fn_call_span.shrink_to_lo(), - "consider calling `.as_ref()` to borrow the type's contents", + "consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents", "as_ref().", Applicability::MachineApplicable, ); diff --git a/src/test/ui/borrowck/suggest-as-ref-on-mut-closure.stderr b/src/test/ui/borrowck/suggest-as-ref-on-mut-closure.stderr index af26169c806..17546f73836 100644 --- a/src/test/ui/borrowck/suggest-as-ref-on-mut-closure.stderr +++ b/src/test/ui/borrowck/suggest-as-ref-on-mut-closure.stderr @@ -12,7 +12,7 @@ note: this function takes ownership of the receiver `self`, which moves `*cb` | LL | pub const fn map(self, f: F) -> Option | ^^^^ -help: consider calling `.as_ref()` to borrow the type's contents +help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents | LL | cb.as_ref().map(|cb| cb()); | +++++++++ diff --git a/src/test/ui/suggestions/as-ref-2.stderr b/src/test/ui/suggestions/as-ref-2.stderr index 3c9d0f72abe..08b9fb1abd7 100644 --- a/src/test/ui/suggestions/as-ref-2.stderr +++ b/src/test/ui/suggestions/as-ref-2.stderr @@ -13,7 +13,7 @@ note: this function takes ownership of the receiver `self`, which moves `foo` | LL | pub const fn map(self, f: F) -> Option | ^^^^ -help: consider calling `.as_ref()` to borrow the type's contents +help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents | LL | let _x: Option = foo.as_ref().map(|s| bar(&s)); | +++++++++ diff --git a/src/test/ui/suggestions/option-content-move.stderr b/src/test/ui/suggestions/option-content-move.stderr index fccfbe1d744..d008971e438 100644 --- a/src/test/ui/suggestions/option-content-move.stderr +++ b/src/test/ui/suggestions/option-content-move.stderr @@ -11,7 +11,7 @@ note: this function takes ownership of the receiver `self`, which moves `selecti | LL | pub const fn unwrap(self) -> T { | ^^^^ -help: consider calling `.as_ref()` to borrow the type's contents +help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents | LL | if selection.1.as_ref().unwrap().contains(selection.0) { | +++++++++ @@ -29,7 +29,7 @@ note: this function takes ownership of the receiver `self`, which moves `selecti | LL | pub fn unwrap(self) -> T | ^^^^ -help: consider calling `.as_ref()` to borrow the type's contents +help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents | LL | if selection.1.as_ref().unwrap().contains(selection.0) { | +++++++++ From 34e0d9a0bb409bb6c7fc45f1c222340b02989b8b Mon Sep 17 00:00:00 2001 From: cameron Date: Sun, 14 Aug 2022 23:07:47 +0100 Subject: [PATCH 02/13] suggest lazy-static for non-const statics --- compiler/rustc_const_eval/src/transform/check_consts/ops.rs | 5 +++++ src/test/ui/borrowck/issue-64453.stderr | 1 + src/test/ui/check-static-values-constraints.stderr | 1 + src/test/ui/consts/issue-32829-2.stderr | 2 ++ src/test/ui/consts/mir_check_nonconst.stderr | 1 + src/test/ui/issues/issue-16538.mir.stderr | 1 + src/test/ui/issues/issue-16538.thir.stderr | 1 + src/test/ui/issues/issue-25901.stderr | 1 + src/test/ui/static/static-vec-repeat-not-constant.stderr | 1 + 9 files changed, 14 insertions(+) diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 33802261644..c9cfc1f3f46 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -1,6 +1,7 @@ //! Concrete error types for all operations which may be invalid in a certain const context. use hir::def_id::LocalDefId; +use hir::ConstContext; use rustc_errors::{ error_code, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, }; @@ -331,6 +332,10 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { ccx.const_kind(), )); + if let ConstContext::Static(_) = ccx.const_kind() { + err.note("consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell"); + } + err } } diff --git a/src/test/ui/borrowck/issue-64453.stderr b/src/test/ui/borrowck/issue-64453.stderr index 1f8a1acb89f..245c3a40e05 100644 --- a/src/test/ui/borrowck/issue-64453.stderr +++ b/src/test/ui/borrowck/issue-64453.stderr @@ -14,6 +14,7 @@ LL | static settings_dir: String = format!(""); | ^^^^^^^^^^^ | = note: calls in statics are limited to constant functions, tuple structs and tuple variants + = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0507]: cannot move out of static item `settings_dir` diff --git a/src/test/ui/check-static-values-constraints.stderr b/src/test/ui/check-static-values-constraints.stderr index b28cf0d6bd0..3c193ca34ac 100644 --- a/src/test/ui/check-static-values-constraints.stderr +++ b/src/test/ui/check-static-values-constraints.stderr @@ -22,6 +22,7 @@ LL | field2: SafeEnum::Variant4("str".to_string()) | ^^^^^^^^^^^ | = note: calls in statics are limited to constant functions, tuple structs and tuple variants + = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell error[E0010]: allocations are not allowed in statics --> $DIR/check-static-values-constraints.rs:94:5 diff --git a/src/test/ui/consts/issue-32829-2.stderr b/src/test/ui/consts/issue-32829-2.stderr index b94bdc0e3df..0fec3581873 100644 --- a/src/test/ui/consts/issue-32829-2.stderr +++ b/src/test/ui/consts/issue-32829-2.stderr @@ -13,6 +13,7 @@ LL | invalid(); | ^^^^^^^^^ | = note: calls in statics are limited to constant functions, tuple structs and tuple variants + = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell error[E0015]: cannot call non-const fn `invalid` in statics --> $DIR/issue-32829-2.rs:54:9 @@ -21,6 +22,7 @@ LL | invalid(); | ^^^^^^^^^ | = note: calls in statics are limited to constant functions, tuple structs and tuple variants + = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell error: aborting due to 3 previous errors diff --git a/src/test/ui/consts/mir_check_nonconst.stderr b/src/test/ui/consts/mir_check_nonconst.stderr index 2bac995eebf..1e0652722ff 100644 --- a/src/test/ui/consts/mir_check_nonconst.stderr +++ b/src/test/ui/consts/mir_check_nonconst.stderr @@ -5,6 +5,7 @@ LL | static foo: Foo = bar(); | ^^^^^ | = note: calls in statics are limited to constant functions, tuple structs and tuple variants + = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell error: aborting due to previous error diff --git a/src/test/ui/issues/issue-16538.mir.stderr b/src/test/ui/issues/issue-16538.mir.stderr index 7dab7de7619..e320df4b7ad 100644 --- a/src/test/ui/issues/issue-16538.mir.stderr +++ b/src/test/ui/issues/issue-16538.mir.stderr @@ -5,6 +5,7 @@ LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: calls in statics are limited to constant functions, tuple structs and tuple variants + = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell error[E0133]: use of extern static is unsafe and requires unsafe function or block --> $DIR/issue-16538.rs:14:30 diff --git a/src/test/ui/issues/issue-16538.thir.stderr b/src/test/ui/issues/issue-16538.thir.stderr index a18b0197d87..4a862869274 100644 --- a/src/test/ui/issues/issue-16538.thir.stderr +++ b/src/test/ui/issues/issue-16538.thir.stderr @@ -21,6 +21,7 @@ LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: calls in statics are limited to constant functions, tuple structs and tuple variants + = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-25901.stderr b/src/test/ui/issues/issue-25901.stderr index e933745c44e..c6c80e41cf6 100644 --- a/src/test/ui/issues/issue-25901.stderr +++ b/src/test/ui/issues/issue-25901.stderr @@ -16,6 +16,7 @@ note: impl defined here, but it is not `const` LL | impl Deref for A { | ^^^^^^^^^^^^^^^^ = note: calls in statics are limited to constant functions, tuple structs and tuple variants + = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell error: aborting due to previous error diff --git a/src/test/ui/static/static-vec-repeat-not-constant.stderr b/src/test/ui/static/static-vec-repeat-not-constant.stderr index 84fc638a973..dec0123184d 100644 --- a/src/test/ui/static/static-vec-repeat-not-constant.stderr +++ b/src/test/ui/static/static-vec-repeat-not-constant.stderr @@ -5,6 +5,7 @@ LL | static a: [isize; 2] = [foo(); 2]; | ^^^^^ | = note: calls in statics are limited to constant functions, tuple structs and tuple variants + = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell error: aborting due to previous error From e37565d2db8d7cf92a6d1df535343d4b2881fc35 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 16 Aug 2022 03:02:04 +0000 Subject: [PATCH 03/13] Make as_ref suggestion a note --- .../rustc_borrowck/src/diagnostics/mod.rs | 14 +++---- .../suggest-as-ref-on-mut-closure.stderr | 5 +-- src/test/ui/suggestions/as-ref-2.fixed | 13 ------- src/test/ui/suggestions/as-ref-2.rs | 2 - src/test/ui/suggestions/as-ref-2.stderr | 10 ++--- .../ui/suggestions/option-content-move.fixed | 39 ------------------- .../ui/suggestions/option-content-move.rs | 2 - .../ui/suggestions/option-content-move.stderr | 14 ++----- 8 files changed, 15 insertions(+), 84 deletions(-) delete mode 100644 src/test/ui/suggestions/as-ref-2.fixed delete mode 100644 src/test/ui/suggestions/option-content-move.fixed diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index cc5a3e16c96..683084cf09d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1086,14 +1086,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ), ); } - if is_option_or_result && maybe_reinitialized_locations_is_empty { - err.span_suggestion_verbose( - fn_call_span.shrink_to_lo(), - "consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents", - "as_ref().", - Applicability::MachineApplicable, - ); - } // Avoid pointing to the same function in multiple different // error messages. if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) { @@ -1102,6 +1094,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &format!("this function takes ownership of the receiver `self`, which moves {}", place_name) ); } + if is_option_or_result && maybe_reinitialized_locations_is_empty { + err.span_label( + var_span, + "help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents", + ); + } } // Other desugarings takes &self, which cannot cause a move _ => {} diff --git a/src/test/ui/borrowck/suggest-as-ref-on-mut-closure.stderr b/src/test/ui/borrowck/suggest-as-ref-on-mut-closure.stderr index 17546f73836..b1af090aec2 100644 --- a/src/test/ui/borrowck/suggest-as-ref-on-mut-closure.stderr +++ b/src/test/ui/borrowck/suggest-as-ref-on-mut-closure.stderr @@ -5,6 +5,7 @@ LL | cb.map(|cb| cb()); | ^^^-------------- | | | | | `*cb` moved due to this method call + | help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents | move occurs because `*cb` has type `Option<&mut dyn FnMut()>`, which does not implement the `Copy` trait | note: this function takes ownership of the receiver `self`, which moves `*cb` @@ -12,10 +13,6 @@ note: this function takes ownership of the receiver `self`, which moves `*cb` | LL | pub const fn map(self, f: F) -> Option | ^^^^ -help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents - | -LL | cb.as_ref().map(|cb| cb()); - | +++++++++ error[E0596]: cannot borrow `*cb` as mutable, as it is behind a `&` reference --> $DIR/suggest-as-ref-on-mut-closure.rs:12:26 diff --git a/src/test/ui/suggestions/as-ref-2.fixed b/src/test/ui/suggestions/as-ref-2.fixed deleted file mode 100644 index 13bbb233f39..00000000000 --- a/src/test/ui/suggestions/as-ref-2.fixed +++ /dev/null @@ -1,13 +0,0 @@ -// run-rustfix - -struct Struct; - -fn bar(_: &Struct) -> Struct { - Struct -} - -fn main() { - let foo = Some(Struct); - let _x: Option = foo.as_ref().map(|s| bar(&s)); - let _y = foo; //~ERROR use of moved value: `foo` -} diff --git a/src/test/ui/suggestions/as-ref-2.rs b/src/test/ui/suggestions/as-ref-2.rs index 74d61cdd95f..b22f409b44a 100644 --- a/src/test/ui/suggestions/as-ref-2.rs +++ b/src/test/ui/suggestions/as-ref-2.rs @@ -1,5 +1,3 @@ -// run-rustfix - struct Struct; fn bar(_: &Struct) -> Struct { diff --git a/src/test/ui/suggestions/as-ref-2.stderr b/src/test/ui/suggestions/as-ref-2.stderr index 08b9fb1abd7..e15e45d86b9 100644 --- a/src/test/ui/suggestions/as-ref-2.stderr +++ b/src/test/ui/suggestions/as-ref-2.stderr @@ -1,10 +1,12 @@ error[E0382]: use of moved value: `foo` - --> $DIR/as-ref-2.rs:12:14 + --> $DIR/as-ref-2.rs:10:14 | LL | let foo = Some(Struct); | --- move occurs because `foo` has type `Option`, which does not implement the `Copy` trait LL | let _x: Option = foo.map(|s| bar(&s)); - | ---------------- `foo` moved due to this method call + | --- ---------------- `foo` moved due to this method call + | | + | help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents LL | let _y = foo; | ^^^ value used here after move | @@ -13,10 +15,6 @@ note: this function takes ownership of the receiver `self`, which moves `foo` | LL | pub const fn map(self, f: F) -> Option | ^^^^ -help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents - | -LL | let _x: Option = foo.as_ref().map(|s| bar(&s)); - | +++++++++ error: aborting due to previous error diff --git a/src/test/ui/suggestions/option-content-move.fixed b/src/test/ui/suggestions/option-content-move.fixed deleted file mode 100644 index ba16bcc8a33..00000000000 --- a/src/test/ui/suggestions/option-content-move.fixed +++ /dev/null @@ -1,39 +0,0 @@ -//run-rustfix - -pub struct LipogramCorpora { - selections: Vec<(char, Option)>, -} - -impl LipogramCorpora { - pub fn validate_all(&mut self) -> Result<(), char> { - for selection in &self.selections { - if selection.1.is_some() { - if selection.1.as_ref().unwrap().contains(selection.0) { - //~^ ERROR cannot move out of `selection.1` - return Err(selection.0); - } - } - } - Ok(()) - } -} - -pub struct LipogramCorpora2 { - selections: Vec<(char, Result)>, -} - -impl LipogramCorpora2 { - pub fn validate_all(&mut self) -> Result<(), char> { - for selection in &self.selections { - if selection.1.is_ok() { - if selection.1.as_ref().unwrap().contains(selection.0) { - //~^ ERROR cannot move out of `selection.1` - return Err(selection.0); - } - } - } - Ok(()) - } -} - -fn main() {} diff --git a/src/test/ui/suggestions/option-content-move.rs b/src/test/ui/suggestions/option-content-move.rs index ef38f114eca..46c895b95f5 100644 --- a/src/test/ui/suggestions/option-content-move.rs +++ b/src/test/ui/suggestions/option-content-move.rs @@ -1,5 +1,3 @@ -//run-rustfix - pub struct LipogramCorpora { selections: Vec<(char, Option)>, } diff --git a/src/test/ui/suggestions/option-content-move.stderr b/src/test/ui/suggestions/option-content-move.stderr index d008971e438..a6f1ebc975f 100644 --- a/src/test/ui/suggestions/option-content-move.stderr +++ b/src/test/ui/suggestions/option-content-move.stderr @@ -1,9 +1,10 @@ error[E0507]: cannot move out of `selection.1` which is behind a shared reference - --> $DIR/option-content-move.rs:11:20 + --> $DIR/option-content-move.rs:9:20 | LL | if selection.1.unwrap().contains(selection.0) { | ^^^^^^^^^^^ -------- `selection.1` moved due to this method call | | + | help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents | move occurs because `selection.1` has type `Option`, which does not implement the `Copy` trait | note: this function takes ownership of the receiver `self`, which moves `selection.1` @@ -11,17 +12,14 @@ note: this function takes ownership of the receiver `self`, which moves `selecti | LL | pub const fn unwrap(self) -> T { | ^^^^ -help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents - | -LL | if selection.1.as_ref().unwrap().contains(selection.0) { - | +++++++++ error[E0507]: cannot move out of `selection.1` which is behind a shared reference - --> $DIR/option-content-move.rs:29:20 + --> $DIR/option-content-move.rs:27:20 | LL | if selection.1.unwrap().contains(selection.0) { | ^^^^^^^^^^^ -------- `selection.1` moved due to this method call | | + | help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents | move occurs because `selection.1` has type `Result`, which does not implement the `Copy` trait | note: this function takes ownership of the receiver `self`, which moves `selection.1` @@ -29,10 +27,6 @@ note: this function takes ownership of the receiver `self`, which moves `selecti | LL | pub fn unwrap(self) -> T | ^^^^ -help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents - | -LL | if selection.1.as_ref().unwrap().contains(selection.0) { - | +++++++++ error: aborting due to 2 previous errors From 25de53f76842544b695f826303034fd0419a5d6a Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Wed, 10 Aug 2022 10:46:27 +0200 Subject: [PATCH 04/13] Refactor copying data to userspace --- .../std/src/sys/sgx/abi/usercalls/alloc.rs | 51 ++++++++++++------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/library/std/src/sys/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/sgx/abi/usercalls/alloc.rs index 66fa1efbf10..a3b90fc7d80 100644 --- a/library/std/src/sys/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/sgx/abi/usercalls/alloc.rs @@ -305,6 +305,34 @@ where } } +// Split a memory region ptr..ptr + len into three parts: +// +--------+ +// | small0 | Chunk smaller than 8 bytes +// +--------+ +// | big | Chunk 8-byte aligned, and size a multiple of 8 bytes +// +--------+ +// | small1 | Chunk smaller than 8 bytes +// +--------+ +fn region_as_aligned_chunks(ptr: *const u8, len: usize) -> (u8, usize, u8) { + let small0_size = (8 - ptr as usize % 8) as u8; + let small1_size = ((len - small0_size as usize) % 8) as u8; + let big_size = len - small0_size as usize - small1_size as usize; + + (small0_size, big_size, small1_size) +} + +unsafe fn copy_quadwords(src: *const u8, dst: *mut u8, len: usize) { + unsafe { + asm!( + "rep movsq (%rsi), (%rdi)", + inout("rcx") len / 8 => _, + inout("rdi") dst => _, + inout("rsi") src => _, + options(att_syntax, nostack, preserves_flags) + ); + } +} + /// Copies `len` bytes of data from enclave pointer `src` to userspace `dst` /// /// This function mitigates stale data vulnerabilities by ensuring all writes to untrusted memory are either: @@ -343,17 +371,6 @@ pub(crate) unsafe fn copy_to_userspace(src: *const u8, dst: *mut u8, len: usize) } } - unsafe fn copy_aligned_quadwords_to_userspace(src: *const u8, dst: *mut u8, len: usize) { - unsafe { - asm!( - "rep movsq (%rsi), (%rdi)", - inout("rcx") len / 8 => _, - inout("rdi") dst => _, - inout("rsi") src => _, - options(att_syntax, nostack, preserves_flags) - ); - } - } assert!(!src.is_null()); assert!(!dst.is_null()); assert!(is_enclave_range(src, len)); @@ -370,7 +387,7 @@ pub(crate) unsafe fn copy_to_userspace(src: *const u8, dst: *mut u8, len: usize) } else if len % 8 == 0 && dst as usize % 8 == 0 { // Copying 8-byte aligned quadwords: copy quad word per quad word unsafe { - copy_aligned_quadwords_to_userspace(src, dst, len); + copy_quadwords(src, dst, len); } } else { // Split copies into three parts: @@ -381,20 +398,16 @@ pub(crate) unsafe fn copy_to_userspace(src: *const u8, dst: *mut u8, len: usize) // +--------+ // | small1 | Chunk smaller than 8 bytes // +--------+ + let (small0_size, big_size, small1_size) = region_as_aligned_chunks(dst, len); unsafe { // Copy small0 - let small0_size = (8 - dst as usize % 8) as u8; - let small0_src = src; - let small0_dst = dst; - copy_bytewise_to_userspace(small0_src as _, small0_dst, small0_size as _); + copy_bytewise_to_userspace(src, dst, small0_size as _); // Copy big - let small1_size = ((len - small0_size as usize) % 8) as u8; - let big_size = len - small0_size as usize - small1_size as usize; let big_src = src.offset(small0_size as _); let big_dst = dst.offset(small0_size as _); - copy_aligned_quadwords_to_userspace(big_src as _, big_dst, big_size); + copy_quadwords(big_src as _, big_dst, big_size); // Copy small1 let small1_src = src.offset(big_size as isize + small0_size as isize); From 2a23d08aaefd60d294d63600a707575a6efcf292 Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Wed, 10 Aug 2022 15:38:53 +0200 Subject: [PATCH 05/13] Mitigate Stale Data Read for xAPIC vulnerability In order to mitigate the Stale Data Read for xAPIC vulnerability completely, reading userspace from an SGX enclave must be aligned and in 8-bytes chunks. References: - https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00657.html - https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/advisory-guidance/stale-data-read-from-xapic.html --- .../std/src/sys/sgx/abi/usercalls/alloc.rs | 114 +++++++++++++++++- .../std/src/sys/sgx/abi/usercalls/tests.rs | 30 ++++- 2 files changed, 137 insertions(+), 7 deletions(-) diff --git a/library/std/src/sys/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/sgx/abi/usercalls/alloc.rs index a3b90fc7d80..34634da44de 100644 --- a/library/std/src/sys/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/sgx/abi/usercalls/alloc.rs @@ -313,9 +313,9 @@ where // +--------+ // | small1 | Chunk smaller than 8 bytes // +--------+ -fn region_as_aligned_chunks(ptr: *const u8, len: usize) -> (u8, usize, u8) { - let small0_size = (8 - ptr as usize % 8) as u8; - let small1_size = ((len - small0_size as usize) % 8) as u8; +fn region_as_aligned_chunks(ptr: *const u8, len: usize) -> (usize, usize, usize) { + let small0_size = if ptr as usize % 8 == 0 { 0 } else { 8 - ptr as usize % 8 }; + let small1_size = (len - small0_size as usize) % 8; let big_size = len - small0_size as usize - small1_size as usize; (small0_size, big_size, small1_size) @@ -417,6 +417,106 @@ pub(crate) unsafe fn copy_to_userspace(src: *const u8, dst: *mut u8, len: usize) } } +/// Copies `len` bytes of data from userspace pointer `src` to enclave pointer `dst` +/// +/// This function mitigates AEPIC leak vulnerabilities by ensuring all reads from untrusted memory are 8-byte aligned +/// +/// # Panics +/// This function panics if: +/// +/// * The `src` pointer is null +/// * The `dst` pointer is null +/// * The `src` memory range is not in user memory +/// * The `dst` memory range is not in enclave memory +/// +/// # References +/// - https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00657.html +/// - https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/advisory-guidance/stale-data-read-from-xapic.html +pub(crate) unsafe fn copy_from_userspace(src: *const u8, dst: *mut u8, len: usize) { + // Copies memory region `src..src + len` to the enclave at `dst`. The source memory region + // is: + // - strictly less than 8 bytes in size and may be + // - located at a misaligned memory location + fn copy_misaligned_chunk_to_enclave(src: *const u8, dst: *mut u8, len: usize) { + let mut tmp_buff = [0u8; 16]; + + unsafe { + // Compute an aligned memory region to read from + // +--------+ <-- aligned_src + aligned_len (8B-aligned) + // | pad1 | + // +--------+ <-- src + len (misaligned) + // | | + // | | + // | | + // +--------+ <-- src (misaligned) + // | pad0 | + // +--------+ <-- aligned_src (8B-aligned) + let pad0_size = src as usize % 8; + let aligned_src = src.sub(pad0_size); + + let pad1_size = 8 - (src.add(len) as usize % 8); + let aligned_len = pad0_size + len + pad1_size; + + debug_assert!(len < 8); + debug_assert_eq!(aligned_src as usize % 8, 0); + debug_assert_eq!(aligned_len % 8, 0); + debug_assert!(aligned_len <= 16); + + // Copy the aligned buffer to a temporary buffer + // Note: copying from a slightly different memory location is a bit odd. In this case it + // can't lead to page faults or inadvertent copying from the enclave as we only ensured + // that the `src` pointer is aligned at an 8 byte boundary. As pages are 4096 bytes + // aligned, `aligned_src` must be on the same page as `src`. A similar argument can be made + // for `src + len` + copy_quadwords(aligned_src as _, tmp_buff.as_mut_ptr(), aligned_len); + + // Copy the correct parts of the temporary buffer to the destination + ptr::copy(tmp_buff.as_ptr().add(pad0_size), dst, len); + } + } + + assert!(!src.is_null()); + assert!(!dst.is_null()); + assert!(is_user_range(src, len)); + assert!(is_enclave_range(dst, len)); + assert!(!(src as usize).overflowing_add(len + 8).1); + assert!(!(dst as usize).overflowing_add(len + 8).1); + + if len < 8 { + copy_misaligned_chunk_to_enclave(src, dst, len); + } else if len % 8 == 0 && src as usize % 8 == 0 { + // Copying 8-byte aligned quadwords: copy quad word per quad word + unsafe { + copy_quadwords(src, dst, len); + } + } else { + // Split copies into three parts: + // +--------+ + // | small0 | Chunk smaller than 8 bytes + // +--------+ + // | big | Chunk 8-byte aligned, and size a multiple of 8 bytes + // +--------+ + // | small1 | Chunk smaller than 8 bytes + // +--------+ + let (small0_size, big_size, small1_size) = region_as_aligned_chunks(dst, len); + + unsafe { + // Copy small0 + copy_misaligned_chunk_to_enclave(src, dst, small0_size); + + // Copy big + let big_src = src.add(small0_size); + let big_dst = dst.add(small0_size); + copy_quadwords(big_src, big_dst, big_size); + + // Copy small1 + let small1_src = src.add(big_size + small0_size); + let small1_dst = dst.add(big_size + small0_size); + copy_misaligned_chunk_to_enclave(small1_src, small1_dst, small1_size); + } + } +} + #[unstable(feature = "sgx_platform", issue = "56975")] impl UserRef where @@ -481,7 +581,7 @@ where pub fn copy_to_enclave(&self, dest: &mut T) { unsafe { assert_eq!(mem::size_of_val(dest), mem::size_of_val(&*self.0.get())); - ptr::copy( + copy_from_userspace( self.0.get() as *const T as *const u8, dest as *mut T as *mut u8, mem::size_of_val(dest), @@ -507,7 +607,11 @@ where { /// Copies the value from user memory into enclave memory. pub fn to_enclave(&self) -> T { - unsafe { ptr::read(self.0.get()) } + unsafe { + let mut data: T = mem::MaybeUninit::uninit().assume_init(); + copy_from_userspace(self.0.get() as _, &mut data as *mut T as _, mem::size_of::()); + data + } } } diff --git a/library/std/src/sys/sgx/abi/usercalls/tests.rs b/library/std/src/sys/sgx/abi/usercalls/tests.rs index cbf7d7d54f7..4320f0bccd1 100644 --- a/library/std/src/sys/sgx/abi/usercalls/tests.rs +++ b/library/std/src/sys/sgx/abi/usercalls/tests.rs @@ -1,8 +1,8 @@ -use super::alloc::copy_to_userspace; use super::alloc::User; +use super::alloc::{copy_from_userspace, copy_to_userspace}; #[test] -fn test_copy_function() { +fn test_copy_to_userspace_function() { let mut src = [0u8; 100]; let mut dst = User::<[u8]>::uninitialized(100); @@ -28,3 +28,29 @@ fn test_copy_function() { } } } + +#[test] +fn test_copy_from_userspace_function() { + let mut dst = [0u8; 100]; + let mut src = User::<[u8]>::uninitialized(100); + + src.copy_from_enclave(&[0u8; 100]); + + for size in 0..48 { + // For all possible alignment + for offset in 0..8 { + // overwrite complete dst + dst = [0u8; 100]; + + // Copy src[0..size] to dst + offset + unsafe { copy_from_userspace(src.as_ptr().offset(offset), dst.as_mut_ptr(), size) }; + + // Verify copy + for byte in 0..size { + unsafe { + assert_eq!(dst[byte as usize], *src.as_ptr().offset(offset + byte as isize)); + } + } + } + } +} From e8499cfadcf17c051a33ab45a414b399f89a0a91 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Wed, 17 Aug 2022 10:06:24 +0200 Subject: [PATCH 06/13] Migrate "invalid variable declaration" errors to SessionDiagnostic --- .../locales/en-US/parser.ftl | 9 ++++++ .../rustc_parse/src/parser/diagnostics.rs | 29 +++++++++++++++++ compiler/rustc_parse/src/parser/stmt.rs | 31 +++++++------------ 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/parser.ftl b/compiler/rustc_error_messages/locales/en-US/parser.ftl index 7e583753618..2d378013dd0 100644 --- a/compiler/rustc_error_messages/locales/en-US/parser.ftl +++ b/compiler/rustc_error_messages/locales/en-US/parser.ftl @@ -32,3 +32,12 @@ parser_incorrect_use_of_await = parser_in_in_typo = expected iterable, found keyword `in` .suggestion = remove the duplicated `in` + +parser_invalid_variable_declaration = + invalid variable declaration + +parser_switch_mut_let_order = + switch the order of `mut` and `let` +parser_missing_let_before_mut = missing keyword +parser_use_let_not_auto = write `let` instead of `auto` to introduce a new variable +parser_use_let_not_var = write `let` instead of `var` to introduce a new variable diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 93e70e9abda..eeedfd157be 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -334,6 +334,35 @@ struct InInTypo { sugg_span: Span, } +#[derive(SessionDiagnostic)] +#[error(parser::invalid_variable_declaration)] +pub struct InvalidVariableDeclaration { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sub: InvalidVariableDeclarationSub, +} + +#[derive(SessionSubdiagnostic)] +pub enum InvalidVariableDeclarationSub { + #[suggestion( + parser::switch_mut_let_order, + applicability = "maybe-incorrect", + code = "let mut" + )] + SwitchMutLetOrder(#[primary_span] Span), + #[suggestion( + parser::missing_let_before_mut, + applicability = "machine-applicable", + code = "let mut" + )] + MissingLet(#[primary_span] Span), + #[suggestion(parser::use_let_not_auto, applicability = "machine-applicable", code = "let")] + UseLetNotAuto(#[primary_span] Span), + #[suggestion(parser::use_let_not_var, applicability = "machine-applicable", code = "let")] + UseLetNotVar(#[primary_span] Span), +} + // SnapshotParser is used to create a snapshot of the parser // without causing duplicate errors being emitted when the `Parser` // is dropped. diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index ade0f4fbc86..002547c6723 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -1,5 +1,7 @@ use super::attr::DEFAULT_INNER_ATTR_FORBIDDEN; -use super::diagnostics::{AttemptLocalParseRecovery, Error}; +use super::diagnostics::{ + AttemptLocalParseRecovery, Error, InvalidVariableDeclaration, InvalidVariableDeclarationSub, +}; use super::expr::LhsExpr; use super::pat::RecoverComma; use super::path::PathStyle; @@ -58,28 +60,22 @@ impl<'a> Parser<'a> { if self.token.is_keyword(kw::Mut) && self.is_keyword_ahead(1, &[kw::Let]) { self.bump(); let mut_let_span = lo.to(self.token.span); - self.struct_span_err(mut_let_span, "invalid variable declaration") - .span_suggestion( - mut_let_span, - "switch the order of `mut` and `let`", - "let mut", - Applicability::MaybeIncorrect, - ) - .emit(); + self.sess.emit_err(InvalidVariableDeclaration { + span: mut_let_span, + sub: InvalidVariableDeclarationSub::SwitchMutLetOrder(mut_let_span), + }); } Ok(Some(if self.token.is_keyword(kw::Let) { self.parse_local_mk(lo, attrs, capture_semi, force_collect)? } else if self.is_kw_followed_by_ident(kw::Mut) { - self.recover_stmt_local(lo, attrs, "missing keyword", "let mut")? + self.recover_stmt_local(lo, attrs, InvalidVariableDeclarationSub::MissingLet)? } else if self.is_kw_followed_by_ident(kw::Auto) { self.bump(); // `auto` - let msg = "write `let` instead of `auto` to introduce a new variable"; - self.recover_stmt_local(lo, attrs, msg, "let")? + self.recover_stmt_local(lo, attrs, InvalidVariableDeclarationSub::UseLetNotAuto)? } else if self.is_kw_followed_by_ident(sym::var) { self.bump(); // `var` - let msg = "write `let` instead of `var` to introduce a new variable"; - self.recover_stmt_local(lo, attrs, msg, "let")? + self.recover_stmt_local(lo, attrs, InvalidVariableDeclarationSub::UseLetNotVar)? } else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() { // We have avoided contextual keywords like `union`, items with `crate` visibility, // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something @@ -217,13 +213,10 @@ impl<'a> Parser<'a> { &mut self, lo: Span, attrs: AttrWrapper, - msg: &str, - sugg: &str, + subdiagnostic: fn(Span) -> InvalidVariableDeclarationSub, ) -> PResult<'a, Stmt> { let stmt = self.recover_local_after_let(lo, attrs)?; - self.struct_span_err(lo, "invalid variable declaration") - .span_suggestion(lo, msg, sugg, Applicability::MachineApplicable) - .emit(); + self.sess.emit_err(InvalidVariableDeclaration { span: lo, sub: subdiagnostic(lo) }); Ok(stmt) } From af4f66ef938bd21b82a81473974cb620be9a0c72 Mon Sep 17 00:00:00 2001 From: Jhonny Bill Mena Date: Thu, 18 Aug 2022 08:14:21 -0400 Subject: [PATCH 07/13] ADD - ExpectedUsedSymbol diagnostic to port used() diagnostic --- compiler/rustc_error_messages/locales/en-US/typeck.ftl | 2 ++ compiler/rustc_typeck/src/collect.rs | 7 +------ compiler/rustc_typeck/src/errors.rs | 7 +++++++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/typeck.ftl b/compiler/rustc_error_messages/locales/en-US/typeck.ftl index 0014da17c88..d937661794a 100644 --- a/compiler/rustc_error_messages/locales/en-US/typeck.ftl +++ b/compiler/rustc_error_messages/locales/en-US/typeck.ftl @@ -131,3 +131,5 @@ typeck_unused_extern_crate = typeck_extern_crate_not_idiomatic = `extern crate` is not idiomatic in the new edition .suggestion = convert it to a `{$msg_code}` + +typeck_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)` diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index e7c5ecc60ec..970b39dc845 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2836,12 +2836,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED; } Some(_) => { - tcx.sess - .struct_span_err( - attr.span, - "expected `used`, `used(compiler)` or `used(linker)`", - ) - .emit(); + tcx.sess.emit_err(errors::ExpectedUsedSymbol { span: attr.span }); } None => { // Unfortunately, unconditionally using `llvm.used` causes diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs index 76599721e58..8b1cb8d1c93 100644 --- a/compiler/rustc_typeck/src/errors.rs +++ b/compiler/rustc_typeck/src/errors.rs @@ -340,3 +340,10 @@ pub struct ExternCrateNotIdiomatic { pub msg_code: String, pub suggestion_code: String, } + +#[derive(SessionDiagnostic)] +#[error(typeck::expected_used_symbol)] +pub struct ExpectedUsedSymbol { + #[primary_span] + pub span: Span, +} From 09ea9f0a87be489250bdb8d9171c7deb20fd04b1 Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Thu, 18 Aug 2022 19:27:29 +0100 Subject: [PATCH 08/13] Add diagnostic translation lints to crates that don't emit them --- compiler/rustc_apfloat/src/lib.rs | 2 ++ compiler/rustc_arena/src/lib.rs | 2 ++ compiler/rustc_ast/src/lib.rs | 2 ++ compiler/rustc_ast_pretty/src/lib.rs | 2 ++ compiler/rustc_data_structures/src/lib.rs | 2 ++ compiler/rustc_error_codes/src/lib.rs | 2 ++ compiler/rustc_error_messages/src/lib.rs | 2 ++ compiler/rustc_feature/src/lib.rs | 2 ++ compiler/rustc_fs_util/src/lib.rs | 3 +++ compiler/rustc_graphviz/src/lib.rs | 2 ++ compiler/rustc_hir/src/lib.rs | 2 ++ compiler/rustc_hir_pretty/src/lib.rs | 2 ++ compiler/rustc_index/src/lib.rs | 2 ++ compiler/rustc_lexer/src/lib.rs | 2 ++ compiler/rustc_lint_defs/src/lib.rs | 2 ++ compiler/rustc_llvm/src/lib.rs | 2 ++ compiler/rustc_log/src/lib.rs | 3 +++ compiler/rustc_macros/src/lib.rs | 2 ++ compiler/rustc_parse_format/src/lib.rs | 2 ++ compiler/rustc_query_impl/src/lib.rs | 2 ++ compiler/rustc_serialize/src/lib.rs | 2 ++ compiler/rustc_smir/src/lib.rs | 2 ++ compiler/rustc_span/src/lib.rs | 2 ++ compiler/rustc_target/src/lib.rs | 2 ++ compiler/rustc_traits/src/lib.rs | 2 ++ 25 files changed, 52 insertions(+) diff --git a/compiler/rustc_apfloat/src/lib.rs b/compiler/rustc_apfloat/src/lib.rs index cfc3d5b15a6..dde368e7b92 100644 --- a/compiler/rustc_apfloat/src/lib.rs +++ b/compiler/rustc_apfloat/src/lib.rs @@ -33,6 +33,8 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![no_std] #![forbid(unsafe_code)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate alloc; diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 6529f11100d..98faacdc1fb 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -19,6 +19,8 @@ #![feature(rustc_attrs)] #![cfg_attr(test, feature(test))] #![feature(strict_provenance)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] use smallvec::SmallVec; diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 528fc4816e9..2426a0cb7dd 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -19,6 +19,8 @@ #![feature(slice_internals)] #![feature(stmt_expr_attributes)] #![recursion_limit = "256"] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_ast_pretty/src/lib.rs b/compiler/rustc_ast_pretty/src/lib.rs index 79178830bf9..bf094af5f7b 100644 --- a/compiler/rustc_ast_pretty/src/lib.rs +++ b/compiler/rustc_ast_pretty/src/lib.rs @@ -1,3 +1,5 @@ +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #![feature(associated_type_bounds)] #![feature(box_patterns)] #![feature(with_negative_coherence)] diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 265f45b72d1..c8b09cffe01 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -28,6 +28,8 @@ #![feature(vec_into_raw_parts)] #![allow(rustc::default_hash_types)] #![allow(rustc::potential_query_instability)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index f2432f61653..bd424dd9d06 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -1,4 +1,6 @@ #![deny(rustdoc::invalid_codeblock_attributes)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] //! This library is used to gather all error codes into one place, //! the goal being to make their maintenance easier. diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 6ae4dab3a35..ee978f04be2 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -1,6 +1,8 @@ #![feature(once_cell)] #![feature(rustc_attrs)] #![feature(type_alias_impl_trait)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] use fluent_bundle::FluentResource; use fluent_syntax::parser::ParserError; diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index efb83052768..e44c9291f84 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -12,6 +12,8 @@ //! symbol to the `accepted` or `removed` modules respectively. #![feature(once_cell)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] mod accepted; mod active; diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs index 87e97c746ef..63998bb6b00 100644 --- a/compiler/rustc_fs_util/src/lib.rs +++ b/compiler/rustc_fs_util/src/lib.rs @@ -1,3 +1,6 @@ +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] + use std::ffi::CString; use std::fs; use std::io; diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs index 6eaff5c2f74..3c1bb553266 100644 --- a/compiler/rustc_graphviz/src/lib.rs +++ b/compiler/rustc_graphviz/src/lib.rs @@ -273,6 +273,8 @@ html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(attr(allow(unused_variables), deny(warnings))) )] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] use LabelText::*; diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 0f9e6fa7b98..7097f998beb 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -11,6 +11,8 @@ #![feature(never_type)] #![feature(rustc_attrs)] #![recursion_limit = "256"] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 0f754dddbec..42663da8a3f 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1,4 +1,6 @@ #![recursion_limit = "256"] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] use rustc_ast as ast; use rustc_ast::util::parser::{self, AssocOp, Fixity}; diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index 33c3c536f11..aa34673de81 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -1,3 +1,5 @@ +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #![feature(allow_internal_unstable)] #![feature(bench_black_box)] #![feature(extend_one)] diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 6d311af9007..178366f7d80 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -18,6 +18,8 @@ //! lexeme types. //! //! [`rustc_parse::lexer`]: ../rustc_parse/lexer/index.html +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] // We want to be able to build this crate with a stable compiler, so no // `#![feature]` attributes should be added. diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 6acbe97a7a1..a826f599e9c 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -1,4 +1,6 @@ #![feature(min_specialization)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index 8eade02a408..8542dcf5bf0 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -1,3 +1,5 @@ +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] // NOTE: This crate only exists to allow linking on mingw targets. diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs index f2ec80b0c1b..458f5e87bae 100644 --- a/compiler/rustc_log/src/lib.rs +++ b/compiler/rustc_log/src/lib.rs @@ -38,6 +38,9 @@ //! debugging, you can make changes inside those crates and quickly run main.rs //! to read the debug logs. +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] + use std::env::{self, VarError}; use std::fmt::{self, Display}; use std::io; diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 2f9c13cf817..e01d035767b 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -4,6 +4,8 @@ #![feature(proc_macro_diagnostic)] #![feature(proc_macro_span)] #![allow(rustc::default_hash_types)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #![recursion_limit = "128"] use synstructure::decl_derive; diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 4890fade50f..e4842d2afb7 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -9,6 +9,8 @@ html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))) )] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] // We want to be able to build this crate with a stable compiler, so no // `#![feature]` attributes should be added. diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index eda61df7700..df187ea0c94 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -7,6 +7,8 @@ #![feature(rustc_attrs)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index e606f427335..079d44bac68 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -18,6 +18,8 @@ Core encoding and decoding interfaces. #![feature(new_uninit)] #![cfg_attr(test, feature(test))] #![allow(rustc::internal)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] pub use self::serialize::{Decodable, Decoder, Encodable, Encoder}; diff --git a/compiler/rustc_smir/src/lib.rs b/compiler/rustc_smir/src/lib.rs index 5c7aaf35b90..3e93c6bba97 100644 --- a/compiler/rustc_smir/src/lib.rs +++ b/compiler/rustc_smir/src/lib.rs @@ -11,6 +11,8 @@ test(attr(allow(unused_variables), deny(warnings))) )] #![cfg_attr(not(feature = "default"), feature(rustc_private))] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] pub mod mir; diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index cf306928151..8bd20b67c72 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -20,6 +20,8 @@ #![feature(negative_impls)] #![feature(min_specialization)] #![feature(rustc_attrs)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index 59dbea70534..9c9e297849e 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -16,6 +16,8 @@ #![feature(never_type)] #![feature(rustc_attrs)] #![feature(step_trait)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] use std::iter::FromIterator; use std::path::{Path, PathBuf}; diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs index 2bea164c051..318e76c79f1 100644 --- a/compiler/rustc_traits/src/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -1,6 +1,8 @@ //! New recursive solver modeled on Chalk's recursive solver. Most of //! the guts are broken up into modules; see the comments in those modules. +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #![feature(let_else)] #![recursion_limit = "256"] From 1b54ad0585ca25b779be93d1149930664f722dc3 Mon Sep 17 00:00:00 2001 From: akabinds Date: Thu, 18 Aug 2022 16:14:04 -0500 Subject: [PATCH 09/13] added improved diagnostic for a function defined with an invalid qualifier --- compiler/rustc_parse/src/parser/diagnostics.rs | 9 +++++++++ src/test/ui/parser/fn-defined-using-def.rs | 10 ++++++++++ src/test/ui/parser/fn-defined-using-def.stderr | 10 ++++++++++ src/test/ui/parser/fn-defined-using-fun.rs | 10 ++++++++++ src/test/ui/parser/fn-defined-using-fun.stderr | 10 ++++++++++ src/test/ui/parser/fn-defined-using-func.rs | 10 ++++++++++ src/test/ui/parser/fn-defined-using-func.stderr | 10 ++++++++++ src/test/ui/parser/fn-defined-using-function.rs | 10 ++++++++++ src/test/ui/parser/fn-defined-using-function.stderr | 10 ++++++++++ 9 files changed, 89 insertions(+) create mode 100644 src/test/ui/parser/fn-defined-using-def.rs create mode 100644 src/test/ui/parser/fn-defined-using-def.stderr create mode 100644 src/test/ui/parser/fn-defined-using-fun.rs create mode 100644 src/test/ui/parser/fn-defined-using-fun.stderr create mode 100644 src/test/ui/parser/fn-defined-using-func.rs create mode 100644 src/test/ui/parser/fn-defined-using-func.stderr create mode 100644 src/test/ui/parser/fn-defined-using-function.rs create mode 100644 src/test/ui/parser/fn-defined-using-function.stderr diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index f4c6b33a529..3bc00635013 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -611,6 +611,15 @@ impl<'a> Parser<'a> { appl, ); } + + if ["def", "fun", "func", "function"].contains(&symbol.as_str()) { + err.span_suggestion_short( + self.prev_token.span, + &format!("write `fn` instead of `{symbol}` to declare a function"), + "fn", + appl, + ); + } } // Add suggestion for a missing closing angle bracket if '>' is included in expected_tokens diff --git a/src/test/ui/parser/fn-defined-using-def.rs b/src/test/ui/parser/fn-defined-using-def.rs new file mode 100644 index 00000000000..21da34c47c9 --- /dev/null +++ b/src/test/ui/parser/fn-defined-using-def.rs @@ -0,0 +1,10 @@ +// Check what happens when `def` is used to define a function, instead of `fn` +// edition:2021 + +#![allow(dead_code)] + +def foo() {} +//~^ ERROR expected one of `!` or `::`, found `foo` +//~^^ HELP write `fn` instead of `def` to declare a function + +fn main() {} diff --git a/src/test/ui/parser/fn-defined-using-def.stderr b/src/test/ui/parser/fn-defined-using-def.stderr new file mode 100644 index 00000000000..f34329012a0 --- /dev/null +++ b/src/test/ui/parser/fn-defined-using-def.stderr @@ -0,0 +1,10 @@ +error: expected one of `!` or `::`, found `foo` + --> $DIR/fn-defined-using-def.rs:6:5 + | +LL | def foo() {} + | --- ^^^ expected one of `!` or `::` + | | + | help: write `fn` instead of `def` to declare a function + +error: aborting due to previous error + diff --git a/src/test/ui/parser/fn-defined-using-fun.rs b/src/test/ui/parser/fn-defined-using-fun.rs new file mode 100644 index 00000000000..4f74605043e --- /dev/null +++ b/src/test/ui/parser/fn-defined-using-fun.rs @@ -0,0 +1,10 @@ +// Check what happens when `fun` is used to define a function, instead of `fn` +// edition:2021 + +#![allow(dead_code)] + +fun foo() {} +//~^ ERROR expected one of `!` or `::`, found `foo` +//~^^ HELP write `fn` instead of `fun` to declare a function + +fn main() {} diff --git a/src/test/ui/parser/fn-defined-using-fun.stderr b/src/test/ui/parser/fn-defined-using-fun.stderr new file mode 100644 index 00000000000..2f6cfff350c --- /dev/null +++ b/src/test/ui/parser/fn-defined-using-fun.stderr @@ -0,0 +1,10 @@ +error: expected one of `!` or `::`, found `foo` + --> $DIR/fn-defined-using-fun.rs:6:5 + | +LL | fun foo() {} + | --- ^^^ expected one of `!` or `::` + | | + | help: write `fn` instead of `fun` to declare a function + +error: aborting due to previous error + diff --git a/src/test/ui/parser/fn-defined-using-func.rs b/src/test/ui/parser/fn-defined-using-func.rs new file mode 100644 index 00000000000..2dce96fdce0 --- /dev/null +++ b/src/test/ui/parser/fn-defined-using-func.rs @@ -0,0 +1,10 @@ +// Check what happens when `func` is used to define a function, instead of `fn` +// edition:2021 + +#![allow(dead_code)] + +func foo() {} +//~^ ERROR expected one of `!` or `::`, found `foo` +//~^^ HELP write `fn` instead of `func` to declare a function + +fn main() {} diff --git a/src/test/ui/parser/fn-defined-using-func.stderr b/src/test/ui/parser/fn-defined-using-func.stderr new file mode 100644 index 00000000000..355741e8949 --- /dev/null +++ b/src/test/ui/parser/fn-defined-using-func.stderr @@ -0,0 +1,10 @@ +error: expected one of `!` or `::`, found `foo` + --> $DIR/fn-defined-using-func.rs:6:6 + | +LL | func foo() {} + | ---- ^^^ expected one of `!` or `::` + | | + | help: write `fn` instead of `func` to declare a function + +error: aborting due to previous error + diff --git a/src/test/ui/parser/fn-defined-using-function.rs b/src/test/ui/parser/fn-defined-using-function.rs new file mode 100644 index 00000000000..fd8782728e2 --- /dev/null +++ b/src/test/ui/parser/fn-defined-using-function.rs @@ -0,0 +1,10 @@ +// Check what happens when `function` is used to define a function, instead of `fn` +// edition:2021 + +#![allow(dead_code)] + +function foo() {} +//~^ ERROR expected one of `!` or `::`, found `foo` +//~^^ HELP write `fn` instead of `function` to declare a function + +fn main() {} diff --git a/src/test/ui/parser/fn-defined-using-function.stderr b/src/test/ui/parser/fn-defined-using-function.stderr new file mode 100644 index 00000000000..43c33a2cdd7 --- /dev/null +++ b/src/test/ui/parser/fn-defined-using-function.stderr @@ -0,0 +1,10 @@ +error: expected one of `!` or `::`, found `foo` + --> $DIR/fn-defined-using-function.rs:6:10 + | +LL | function foo() {} + | -------- ^^^ expected one of `!` or `::` + | | + | help: write `fn` instead of `function` to declare a function + +error: aborting due to previous error + From f50f8782fe5d6f617d9c5b20115a7639dc7521bc Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Thu, 18 Aug 2022 14:51:10 -0700 Subject: [PATCH 10/13] Avoid zeroing a 1kb stack buffer on every call to `std::sys::windows::fill_utf16_buf` --- library/std/src/sys/windows/mod.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs index b3f6d2d0aae..3b0c612dd60 100644 --- a/library/std/src/sys/windows/mod.rs +++ b/library/std/src/sys/windows/mod.rs @@ -2,6 +2,7 @@ use crate::ffi::{CStr, OsStr, OsString}; use crate::io::ErrorKind; +use crate::mem::MaybeUninit; use crate::os::windows::ffi::{OsStrExt, OsStringExt}; use crate::path::PathBuf; use crate::time::Duration; @@ -204,8 +205,8 @@ where // This initial size also works around `GetFullPathNameW` returning // incorrect size hints for some short paths: // https://github.com/dylni/normpath/issues/5 - let mut stack_buf = [0u16; 512]; - let mut heap_buf = Vec::new(); + let mut stack_buf: [MaybeUninit; 512] = MaybeUninit::uninit_array(); + let mut heap_buf: Vec> = Vec::new(); unsafe { let mut n = stack_buf.len(); loop { @@ -214,6 +215,11 @@ where } else { let extra = n - heap_buf.len(); heap_buf.reserve(extra); + // We used `reserve` and not `reserve_exact`, so in theory we + // may have gotten more than requested. If so, we'd like to use + // it... so long as we won't cause overflow. + n = heap_buf.capacity().min(c::DWORD::MAX as usize); + // Safety: MaybeUninit does not need initialization heap_buf.set_len(n); &mut heap_buf[..] }; @@ -228,13 +234,13 @@ where // error" is still 0 then we interpret it as a 0 length buffer and // not an actual error. c::SetLastError(0); - let k = match f1(buf.as_mut_ptr(), n as c::DWORD) { + let k = match f1(buf.as_mut_ptr().cast::(), n as c::DWORD) { 0 if c::GetLastError() == 0 => 0, 0 => return Err(crate::io::Error::last_os_error()), n => n, } as usize; if k == n && c::GetLastError() == c::ERROR_INSUFFICIENT_BUFFER { - n *= 2; + n = n.saturating_mul(2).min(c::DWORD::MAX as usize); } else if k > n { n = k; } else if k == n { @@ -244,7 +250,9 @@ where // Therefore k never equals n. unreachable!(); } else { - return Ok(f2(&buf[..k])); + // Safety: First `k` bytes are initialized. + let slice: &[u16] = MaybeUninit::slice_assume_init_ref(&buf[..k]); + return Ok(f2(slice)); } } } From d4cba61099b3d0457f4ab63a2cb9ae4ae6cf324e Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Fri, 19 Aug 2022 08:45:21 -0700 Subject: [PATCH 11/13] Fix comment typo --- library/std/src/sys/windows/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs index 3b0c612dd60..a9846a48488 100644 --- a/library/std/src/sys/windows/mod.rs +++ b/library/std/src/sys/windows/mod.rs @@ -250,7 +250,7 @@ where // Therefore k never equals n. unreachable!(); } else { - // Safety: First `k` bytes are initialized. + // Safety: First `k` values are initialized. let slice: &[u16] = MaybeUninit::slice_assume_init_ref(&buf[..k]); return Ok(f2(slice)); } From d35749b0f2ba52546fd9c616f665a5132ec55384 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Fri, 19 Aug 2022 17:31:32 +0100 Subject: [PATCH 12/13] triagebot: Autolabel `A-rustdoc-json` --- triagebot.toml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index b7532e016b6..4d3f748195b 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -129,6 +129,7 @@ trigger_files = [ # Internal tooling "src/etc/htmldocck.py", + "src/etc/check_missing_items.py", "src/tools/jsondocck", "src/tools/rustdoc-gui", "src/tools/rustdoc-js", @@ -138,6 +139,15 @@ exclude_labels = [ "T-*", ] +[autolabel."A-rustdoc-json"] +trigger_files = [ + "src/etc/check_missing_items.py", + "src/librustdoc/json/", + "src/rustdoc-json-types", + "src/test/rustdoc-json", + "src/tools/jsondocck", +] + [autolabel."T-compiler"] trigger_files = [ # Source code From 3de74f7e2be7be983aaef0fe7be08e9030e4ecbb Mon Sep 17 00:00:00 2001 From: yukang Date: Sat, 20 Aug 2022 09:43:37 +0800 Subject: [PATCH 13/13] Suggest the right help message for as_ref --- .../src/infer/error_reporting/mod.rs | 3 +- src/test/ui/issues/issue-100605.rs | 9 ++++ src/test/ui/issues/issue-100605.stderr | 46 +++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/issues/issue-100605.rs create mode 100644 src/test/ui/issues/issue-100605.stderr diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 20864c657ff..529ddf03a8c 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2078,7 +2078,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { diag.span_suggestion( span, *msg, - format!("{}.as_ref()", snippet), + // HACK: fix issue# 100605, suggesting convert from &Option to Option<&T>, remove the extra `&` + format!("{}.as_ref()", snippet.trim_start_matches('&')), Applicability::MachineApplicable, ); } diff --git a/src/test/ui/issues/issue-100605.rs b/src/test/ui/issues/issue-100605.rs new file mode 100644 index 00000000000..917a45c15bb --- /dev/null +++ b/src/test/ui/issues/issue-100605.rs @@ -0,0 +1,9 @@ +fn takes_option(_arg: Option<&String>) {} + +fn main() { + takes_option(&None); //~ ERROR 4:18: 4:23: mismatched types [E0308] + + let x = String::from("x"); + let res = Some(x); + takes_option(&res); //~ ERROR 8:18: 8:22: mismatched types [E0308] +} diff --git a/src/test/ui/issues/issue-100605.stderr b/src/test/ui/issues/issue-100605.stderr new file mode 100644 index 00000000000..886e3cd6bb7 --- /dev/null +++ b/src/test/ui/issues/issue-100605.stderr @@ -0,0 +1,46 @@ +error[E0308]: mismatched types + --> $DIR/issue-100605.rs:4:18 + | +LL | takes_option(&None); + | ------------ ^^^^^ expected enum `Option`, found `&Option<_>` + | | + | arguments to this function are incorrect + | + = note: expected enum `Option<&String>` + found reference `&Option<_>` +note: function defined here + --> $DIR/issue-100605.rs:1:4 + | +LL | fn takes_option(_arg: Option<&String>) {} + | ^^^^^^^^^^^^ --------------------- +help: you can convert from `&Option` to `Option<&T>` using `.as_ref()` + | +LL | takes_option(None.as_ref()); + | ~~~~~~~~~~~~~ +help: consider removing the borrow + | +LL - takes_option(&None); +LL + takes_option(None); + | + +error[E0308]: mismatched types + --> $DIR/issue-100605.rs:8:18 + | +LL | takes_option(&res); + | ------------ ^^^^ + | | | + | | expected enum `Option`, found `&Option` + | | help: you can convert from `&Option` to `Option<&T>` using `.as_ref()`: `res.as_ref()` + | arguments to this function are incorrect + | + = note: expected enum `Option<&String>` + found reference `&Option` +note: function defined here + --> $DIR/issue-100605.rs:1:4 + | +LL | fn takes_option(_arg: Option<&String>) {} + | ^^^^^^^^^^^^ --------------------- + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`.