From 127b6c4c18998695edfafc195c682bf3f42e203e Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 1 Aug 2022 21:50:21 +0400 Subject: [PATCH 01/16] cleanup code w/ pointers in std a little --- library/core/src/alloc/global.rs | 2 +- library/core/src/ptr/const_ptr.rs | 4 ++-- library/core/src/ptr/mut_ptr.rs | 7 ++++--- library/core/src/slice/iter.rs | 4 ++-- library/core/tests/const_ptr.rs | 6 +++--- library/core/tests/lib.rs | 2 ++ library/std/src/sys/sgx/abi/usercalls/alloc.rs | 2 +- library/std/src/sys/unsupported/alloc.rs | 7 ++++--- 8 files changed, 19 insertions(+), 15 deletions(-) diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index 887246c600144..6756eecd0e0f8 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -74,7 +74,7 @@ use crate::ptr; /// { /// return null_mut(); /// }; -/// (self.arena.get() as *mut u8).add(allocated) +/// self.arena.get().cast::().add(allocated) /// } /// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} /// } diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index e0655d68d2cfa..2f2d8329baa46 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1270,8 +1270,8 @@ impl *const T { /// # fn foo(n: usize) { /// # use std::mem::align_of; /// # unsafe { - /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; - /// let ptr = x.as_ptr().add(n) as *const u8; + /// let x = [5u8, 6, 7, 8, 9]; + /// let ptr = x.as_ptr().add(n); /// let offset = ptr.align_offset(align_of::()); /// if offset < x.len() - n - 1 { /// let u16_ptr = ptr.add(offset) as *const u16; diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index fc3dd2a9b25a9..e932c72ad9860 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1548,12 +1548,13 @@ impl *mut T { /// # fn foo(n: usize) { /// # use std::mem::align_of; /// # unsafe { - /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; - /// let ptr = x.as_ptr().add(n) as *const u8; + /// let mut x = [5u8, 6, 7, 8, 9]; + /// let ptr = x.as_mut_ptr().add(n); /// let offset = ptr.align_offset(align_of::()); /// if offset < x.len() - n - 1 { - /// let u16_ptr = ptr.add(offset) as *const u16; + /// let u16_ptr = ptr.add(offset) as *mut u16; /// assert_ne!(*u16_ptr, 500); + /// *u16_ptr = 0; /// } else { /// // while the pointer can be aligned via `offset`, it would point /// // outside the allocation diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 76b4a534e5db5..c310ffe091d2c 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -92,7 +92,7 @@ impl<'a, T> Iter<'a, T> { assume(!ptr.is_null()); let end = if mem::size_of::() == 0 { - (ptr as *const u8).wrapping_add(slice.len()) as *const T + ptr.wrapping_byte_add(slice.len()) } else { ptr.add(slice.len()) }; @@ -228,7 +228,7 @@ impl<'a, T> IterMut<'a, T> { assume(!ptr.is_null()); let end = if mem::size_of::() == 0 { - (ptr as *mut u8).wrapping_add(slice.len()) as *mut T + ptr.wrapping_byte_add(slice.len()) } else { ptr.add(slice.len()) }; diff --git a/library/core/tests/const_ptr.rs b/library/core/tests/const_ptr.rs index 152fed803ecdb..d874f08317f61 100644 --- a/library/core/tests/const_ptr.rs +++ b/library/core/tests/const_ptr.rs @@ -3,7 +3,7 @@ const DATA: [u16; 2] = [u16::from_ne_bytes([0x01, 0x23]), u16::from_ne_bytes([0x const fn unaligned_ptr() -> *const u16 { // Since DATA.as_ptr() is aligned to two bytes, adding 1 byte to that produces an unaligned *const u16 - unsafe { (DATA.as_ptr() as *const u8).add(1) as *const u16 } + unsafe { DATA.as_ptr().byte_add(1) } } #[test] @@ -67,7 +67,7 @@ fn write() { const fn write_unaligned() -> [u16; 2] { let mut two_aligned = [0u16; 2]; unsafe { - let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16; + let unaligned_ptr = two_aligned.as_mut_ptr().byte_add(1); ptr::write_unaligned(unaligned_ptr, u16::from_ne_bytes([0x23, 0x45])); } two_aligned @@ -91,7 +91,7 @@ fn mut_ptr_write() { const fn write_unaligned() -> [u16; 2] { let mut two_aligned = [0u16; 2]; unsafe { - let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16; + let unaligned_ptr = two_aligned.as_mut_ptr().byte_add(1); unaligned_ptr.write_unaligned(u16::from_ne_bytes([0x23, 0x45])); } two_aligned diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index db94368f6e0cc..df9b1073a0994 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -14,6 +14,7 @@ #![feature(const_maybe_uninit_assume_init_read)] #![feature(const_nonnull_new)] #![feature(const_num_from_num)] +#![feature(const_pointer_byte_offsets)] #![feature(const_ptr_as_ref)] #![feature(const_ptr_read)] #![feature(const_ptr_write)] @@ -74,6 +75,7 @@ #![feature(never_type)] #![feature(unwrap_infallible)] #![feature(result_into_ok_or_err)] +#![feature(pointer_byte_offsets)] #![feature(portable_simd)] #![feature(ptr_metadata)] #![feature(once_cell)] diff --git a/library/std/src/sys/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/sgx/abi/usercalls/alloc.rs index ea24fedd0eb3d..66fa1efbf103f 100644 --- a/library/std/src/sys/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/sgx/abi/usercalls/alloc.rs @@ -115,7 +115,7 @@ pub unsafe trait UserSafe { /// * the pointer is null. /// * the pointed-to range is not in user memory. unsafe fn check_ptr(ptr: *const Self) { - let is_aligned = |p| -> bool { 0 == (p as usize) & (Self::align_of() - 1) }; + let is_aligned = |p: *const u8| -> bool { 0 == p.addr() & (Self::align_of() - 1) }; assert!(is_aligned(ptr as *const u8)); assert!(is_user_range(ptr as _, mem::size_of_val(unsafe { &*ptr }))); diff --git a/library/std/src/sys/unsupported/alloc.rs b/library/std/src/sys/unsupported/alloc.rs index 8d5d0a2f5ccd1..d715ae45401e6 100644 --- a/library/std/src/sys/unsupported/alloc.rs +++ b/library/std/src/sys/unsupported/alloc.rs @@ -1,15 +1,16 @@ use crate::alloc::{GlobalAlloc, Layout, System}; +use crate::ptr::null_mut; #[stable(feature = "alloc_system_type", since = "1.28.0")] unsafe impl GlobalAlloc for System { #[inline] unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { - 0 as *mut u8 + null_mut() } #[inline] unsafe fn alloc_zeroed(&self, _layout: Layout) -> *mut u8 { - 0 as *mut u8 + null_mut() } #[inline] @@ -17,6 +18,6 @@ unsafe impl GlobalAlloc for System { #[inline] unsafe fn realloc(&self, _ptr: *mut u8, _layout: Layout, _new_size: usize) -> *mut u8 { - 0 as *mut u8 + null_mut() } } From a7c45ec867fe93bdbbb2950ad9a69d5c5cb835e0 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 2 Aug 2022 03:51:51 +0400 Subject: [PATCH 02/16] improve documentation of `pointer::align_offset` --- library/core/src/ptr/const_ptr.rs | 17 +++++++++-------- library/core/src/ptr/mut_ptr.rs | 18 ++++++++++-------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 2f2d8329baa46..716f7c6af8f34 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1267,20 +1267,21 @@ impl *const T { /// Accessing adjacent `u8` as `u16` /// /// ``` - /// # fn foo(n: usize) { - /// # use std::mem::align_of; + /// use std::mem::align_of; + /// /// # unsafe { - /// let x = [5u8, 6, 7, 8, 9]; - /// let ptr = x.as_ptr().add(n); + /// let x = [5_u8, 6, 7, 8, 9]; + /// let ptr = x.as_ptr(); /// let offset = ptr.align_offset(align_of::()); - /// if offset < x.len() - n - 1 { - /// let u16_ptr = ptr.add(offset) as *const u16; - /// assert_ne!(*u16_ptr, 500); + /// + /// if offset < x.len() - 1 { + /// let u16_ptr = ptr.add(offset).cast::(); + /// assert!(*u16_ptr == u16::from_ne_bytes([5, 6]) || *u16_ptr == u16::from_ne_bytes([6, 7])); /// } else { /// // while the pointer can be aligned via `offset`, it would point /// // outside the allocation /// } - /// # } } + /// # } /// ``` #[stable(feature = "align_offset", since = "1.36.0")] #[rustc_const_unstable(feature = "const_align_offset", issue = "90962")] diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index e932c72ad9860..b8551eeed9e0d 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1545,21 +1545,23 @@ impl *mut T { /// Accessing adjacent `u8` as `u16` /// /// ``` - /// # fn foo(n: usize) { - /// # use std::mem::align_of; + /// use std::mem::align_of; + /// /// # unsafe { - /// let mut x = [5u8, 6, 7, 8, 9]; - /// let ptr = x.as_mut_ptr().add(n); + /// let mut x = [5_u8, 6, 7, 8, 9]; + /// let ptr = x.as_mut_ptr(); /// let offset = ptr.align_offset(align_of::()); - /// if offset < x.len() - n - 1 { - /// let u16_ptr = ptr.add(offset) as *mut u16; - /// assert_ne!(*u16_ptr, 500); + /// + /// if offset < x.len() - 1 { + /// let u16_ptr = ptr.add(offset).cast::(); /// *u16_ptr = 0; /// } else { /// // while the pointer can be aligned via `offset`, it would point /// // outside the allocation /// } - /// # } } + /// + /// assert!(x == [0, 0, 7, 8, 9] || x == [5, 0, 0, 8, 9]); + /// # } /// ``` #[stable(feature = "align_offset", since = "1.36.0")] #[rustc_const_unstable(feature = "const_align_offset", issue = "90962")] From be6bb56ee0c88353a01675c4cc525020f1d3137a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 7 Aug 2022 08:30:03 -0400 Subject: [PATCH 03/16] add -Zextra-const-ub-checks to enable more UB checking in const-eval --- .../src/const_eval/machine.rs | 10 +++ .../src/interpret/validity.rs | 4 ++ compiler/rustc_session/src/options.rs | 2 + src/test/rustdoc-ui/z-help.stdout | 1 + .../consts/extra-const-ub/detect-extra-ub.rs | 43 +++++++++++ .../extra-const-ub/detect-extra-ub.stderr | 71 +++++++++++++++++++ 6 files changed, 131 insertions(+) create mode 100644 src/test/ui/consts/extra-const-ub/detect-extra-ub.rs create mode 100644 src/test/ui/consts/extra-const-ub/detect-extra-ub.stderr diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index fc2e6652a3d72..684877cae7677 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -236,6 +236,16 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error + #[inline(always)] + fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks + } + + #[inline(always)] + fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks + } + fn load_mir( ecx: &InterpCx<'mir, 'tcx, Self>, instance: ty::InstanceDef<'tcx>, diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 6f6717721fb5a..f1b1855c3ec74 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -1005,6 +1005,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// It will error if the bits at the destination do not match the ones described by the layout. #[inline(always)] pub fn validate_operand(&self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx> { + // Note that we *could* actually be in CTFE here with `-Zextra-const-ub-checks`, but it's + // still correct to not use `ctfe_mode`: that mode is for validation of the final constant + // value, it rules out things like `UnsafeCell` in awkward places. It also can make checking + // recurse through references which, for now, we don't want here, either. self.validate_operand_internal(op, vec![], None, None) } } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 1827f1c208de7..0032dd7d113f8 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1310,6 +1310,8 @@ options! { "emit the bc module with thin LTO info (default: yes)"), export_executable_symbols: bool = (false, parse_bool, [TRACKED], "export symbols from executables, as if they were dynamic libraries"), + extra_const_ub_checks: bool = (false, parse_bool, [TRACKED], + "turns on more checks to detect const UB, which can be slow (default: no)"), #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::fewer_names` instead of this field"))] fewer_names: Option = (None, parse_opt_bool, [TRACKED], "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \ diff --git a/src/test/rustdoc-ui/z-help.stdout b/src/test/rustdoc-ui/z-help.stdout index 6dc41231559c0..236469ce9797a 100644 --- a/src/test/rustdoc-ui/z-help.stdout +++ b/src/test/rustdoc-ui/z-help.stdout @@ -38,6 +38,7 @@ -Z emit-stack-sizes=val -- emit a section containing stack size metadata (default: no) -Z emit-thin-lto=val -- emit the bc module with thin LTO info (default: yes) -Z export-executable-symbols=val -- export symbols from executables, as if they were dynamic libraries + -Z extra-const-ub-checks=val -- turns on more checks to detect const UB, which can be slow (default: no) -Z fewer-names=val -- reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) (default: no) -Z force-unstable-if-unmarked=val -- force all crates to be `rustc_private` unstable (default: no) -Z fuel=val -- set the optimization fuel quota for a crate diff --git a/src/test/ui/consts/extra-const-ub/detect-extra-ub.rs b/src/test/ui/consts/extra-const-ub/detect-extra-ub.rs new file mode 100644 index 0000000000000..ebbe315b8f818 --- /dev/null +++ b/src/test/ui/consts/extra-const-ub/detect-extra-ub.rs @@ -0,0 +1,43 @@ +// compile-flags: -Zextra-const-ub-checks +#![feature(const_ptr_read)] + +use std::mem::transmute; + +const INVALID_BOOL: () = unsafe { + let _x: bool = transmute(3u8); + //~^ ERROR: evaluation of constant value failed + //~| invalid value +}; + +const INVALID_PTR_IN_INT: () = unsafe { + let _x: usize = transmute(&3u8); + //~^ ERROR: evaluation of constant value failed + //~| invalid value +}; + +const INVALID_SLICE_TO_USIZE_TRANSMUTE: () = unsafe { + let x: &[u8] = &[0; 32]; + let _x: (usize, usize) = transmute(x); + //~^ ERROR: evaluation of constant value failed + //~| invalid value +}; + +const UNALIGNED_PTR: () = unsafe { + let _x: &u32 = transmute(&[0u8; 4]); + //~^ ERROR: evaluation of constant value failed + //~| invalid value +}; + +const UNALIGNED_READ: () = { + INNER; //~ERROR any use of this value will cause an error + //~| previously accepted + // There is an error here but its span is in the standard library so we cannot match it... + // so we have this in a *nested* const, such that the *outer* const fails to use it. + const INNER: () = unsafe { + let x = &[0u8; 4]; + let ptr = x.as_ptr().cast::(); + ptr.read(); + }; +}; + +fn main() {} diff --git a/src/test/ui/consts/extra-const-ub/detect-extra-ub.stderr b/src/test/ui/consts/extra-const-ub/detect-extra-ub.stderr new file mode 100644 index 0000000000000..66634f3dd5695 --- /dev/null +++ b/src/test/ui/consts/extra-const-ub/detect-extra-ub.stderr @@ -0,0 +1,71 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/detect-extra-ub.rs:7:20 + | +LL | let _x: bool = transmute(3u8); + | ^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean + +error[E0080]: evaluation of constant value failed + --> $DIR/detect-extra-ub.rs:13:21 + | +LL | let _x: usize = transmute(&3u8); + | ^^^^^^^^^^^^^^^ constructing invalid value: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes + +error[E0080]: evaluation of constant value failed + --> $DIR/detect-extra-ub.rs:20:30 + | +LL | let _x: (usize, usize) = transmute(x); + | ^^^^^^^^^^^^ constructing invalid value at .0: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes + +error[E0080]: evaluation of constant value failed + --> $DIR/detect-extra-ub.rs:26:20 + | +LL | let _x: &u32 = transmute(&[0u8; 4]); + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 4 byte alignment but found 1) + +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | +LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | accessing memory with alignment 1, but alignment 4 is required + | inside `std::ptr::read::` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | + ::: $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | +LL | unsafe { read(self) } + | ---------- inside `ptr::const_ptr::::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | + ::: $DIR/detect-extra-ub.rs:39:9 + | +LL | ptr.read(); + | ---------- inside `INNER` at $DIR/detect-extra-ub.rs:39:9 + +error: any use of this value will cause an error + --> $DIR/detect-extra-ub.rs:32:5 + | +LL | const UNALIGNED_READ: () = { + | ------------------------ +LL | INNER; + | ^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/detect-extra-ub.rs:32:5 + | +LL | const UNALIGNED_READ: () = { + | ------------------------ +LL | INNER; + | ^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + From cc8259e4b6b1c8c390969ad24ce09ca502b55f69 Mon Sep 17 00:00:00 2001 From: Dan Vail Date: Sun, 7 Aug 2022 21:02:04 -0500 Subject: [PATCH 04/16] Adding more verbose documentation for `std::fmt::Write` --- library/core/src/fmt/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 372141e0933f5..80f37cb5fdba5 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -119,6 +119,13 @@ pub trait Write { /// /// This function will return an instance of [`Error`] on error. /// + /// Though it is possible for implementors of this trait to return an error, at the time + /// of writing these docs, no implementation of [`std::fmt::Write`] in the standard library + /// returns such an error. + /// + /// When working with external crates, it is advised to check the implementation of this + /// trait and anticipate any possible [`Error`]s. + /// /// # Examples /// /// ``` From 7b2a5f284e155775e4a2f9e34b9d474033cce6d2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 9 Aug 2022 08:23:16 -0400 Subject: [PATCH 05/16] dont rely on old macro-in-trait-impl bug --- compiler/rustc_const_eval/src/interpret/machine.rs | 12 ------------ compiler/rustc_mir_transform/src/const_prop.rs | 12 ++++++++++++ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 71ccd1799fa95..9b9919fcc2a3d 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -436,24 +436,12 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { type AllocExtra = (); type FrameExtra = (); - #[inline(always)] - fn enforce_alignment(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { - // We do not check for alignment to avoid having to carry an `Align` - // in `ConstValue::ByRef`. - false - } - #[inline(always)] fn force_int_for_alignment_check(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { // We do not support `force_int`. false } - #[inline(always)] - fn enforce_validity(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { - false // for now, we don't enforce validity - } - #[inline(always)] fn enforce_number_init(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { true diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index fbc0a767f0766..1ead691e1b331 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -183,6 +183,18 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> type MemoryKind = !; + #[inline(always)] + fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + // We do not check for alignment to avoid having to carry an `Align` + // in `ConstValue::ByRef`. + false + } + + #[inline(always)] + fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + false // for now, we don't enforce validity + } + fn load_mir( _ecx: &InterpCx<'mir, 'tcx, Self>, _instance: ty::InstanceDef<'tcx>, From 2bd947998497c0bf2dc91152528eb654bbe6091b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 9 Aug 2022 09:40:44 -0400 Subject: [PATCH 06/16] compare with-flag to without-flag --- .../consts/extra-const-ub/detect-extra-ub.rs | 24 ++++++++++--------- ...tderr => detect-extra-ub.with_flag.stderr} | 16 ++++++------- 2 files changed, 21 insertions(+), 19 deletions(-) rename src/test/ui/consts/extra-const-ub/{detect-extra-ub.stderr => detect-extra-ub.with_flag.stderr} (91%) diff --git a/src/test/ui/consts/extra-const-ub/detect-extra-ub.rs b/src/test/ui/consts/extra-const-ub/detect-extra-ub.rs index ebbe315b8f818..97c9e1505197f 100644 --- a/src/test/ui/consts/extra-const-ub/detect-extra-ub.rs +++ b/src/test/ui/consts/extra-const-ub/detect-extra-ub.rs @@ -1,36 +1,38 @@ -// compile-flags: -Zextra-const-ub-checks +// revisions: no_flag with_flag +// [no_flag] check-pass +// [with_flag] compile-flags: -Zextra-const-ub-checks #![feature(const_ptr_read)] use std::mem::transmute; const INVALID_BOOL: () = unsafe { let _x: bool = transmute(3u8); - //~^ ERROR: evaluation of constant value failed - //~| invalid value + //[with_flag]~^ ERROR: evaluation of constant value failed + //[with_flag]~| invalid value }; const INVALID_PTR_IN_INT: () = unsafe { let _x: usize = transmute(&3u8); - //~^ ERROR: evaluation of constant value failed - //~| invalid value + //[with_flag]~^ ERROR: evaluation of constant value failed + //[with_flag]~| invalid value }; const INVALID_SLICE_TO_USIZE_TRANSMUTE: () = unsafe { let x: &[u8] = &[0; 32]; let _x: (usize, usize) = transmute(x); - //~^ ERROR: evaluation of constant value failed - //~| invalid value + //[with_flag]~^ ERROR: evaluation of constant value failed + //[with_flag]~| invalid value }; const UNALIGNED_PTR: () = unsafe { let _x: &u32 = transmute(&[0u8; 4]); - //~^ ERROR: evaluation of constant value failed - //~| invalid value + //[with_flag]~^ ERROR: evaluation of constant value failed + //[with_flag]~| invalid value }; const UNALIGNED_READ: () = { - INNER; //~ERROR any use of this value will cause an error - //~| previously accepted + INNER; //[with_flag]~ERROR any use of this value will cause an error + //[with_flag]~| previously accepted // There is an error here but its span is in the standard library so we cannot match it... // so we have this in a *nested* const, such that the *outer* const fails to use it. const INNER: () = unsafe { diff --git a/src/test/ui/consts/extra-const-ub/detect-extra-ub.stderr b/src/test/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr similarity index 91% rename from src/test/ui/consts/extra-const-ub/detect-extra-ub.stderr rename to src/test/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr index 66634f3dd5695..1706db7ac43ca 100644 --- a/src/test/ui/consts/extra-const-ub/detect-extra-ub.stderr +++ b/src/test/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr @@ -1,23 +1,23 @@ error[E0080]: evaluation of constant value failed - --> $DIR/detect-extra-ub.rs:7:20 + --> $DIR/detect-extra-ub.rs:9:20 | LL | let _x: bool = transmute(3u8); | ^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean error[E0080]: evaluation of constant value failed - --> $DIR/detect-extra-ub.rs:13:21 + --> $DIR/detect-extra-ub.rs:15:21 | LL | let _x: usize = transmute(&3u8); | ^^^^^^^^^^^^^^^ constructing invalid value: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes error[E0080]: evaluation of constant value failed - --> $DIR/detect-extra-ub.rs:20:30 + --> $DIR/detect-extra-ub.rs:22:30 | LL | let _x: (usize, usize) = transmute(x); | ^^^^^^^^^^^^ constructing invalid value at .0: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes error[E0080]: evaluation of constant value failed - --> $DIR/detect-extra-ub.rs:26:20 + --> $DIR/detect-extra-ub.rs:28:20 | LL | let _x: &u32 = transmute(&[0u8; 4]); | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 4 byte alignment but found 1) @@ -36,13 +36,13 @@ LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1); LL | unsafe { read(self) } | ---------- inside `ptr::const_ptr::::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - ::: $DIR/detect-extra-ub.rs:39:9 + ::: $DIR/detect-extra-ub.rs:41:9 | LL | ptr.read(); - | ---------- inside `INNER` at $DIR/detect-extra-ub.rs:39:9 + | ---------- inside `INNER` at $DIR/detect-extra-ub.rs:41:9 error: any use of this value will cause an error - --> $DIR/detect-extra-ub.rs:32:5 + --> $DIR/detect-extra-ub.rs:34:5 | LL | const UNALIGNED_READ: () = { | ------------------------ @@ -58,7 +58,7 @@ error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0080`. Future incompatibility report: Future breakage diagnostic: error: any use of this value will cause an error - --> $DIR/detect-extra-ub.rs:32:5 + --> $DIR/detect-extra-ub.rs:34:5 | LL | const UNALIGNED_READ: () = { | ------------------------ From d52ed8234e8a9b8f3b988b63dae44e82827fcbda Mon Sep 17 00:00:00 2001 From: Waffle Maybe Date: Tue, 9 Aug 2022 21:19:19 +0400 Subject: [PATCH 07/16] move an `assert!` to the right place --- library/core/src/ptr/mut_ptr.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index b8551eeed9e0d..bd2cadef7742e 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1555,12 +1555,12 @@ impl *mut T { /// if offset < x.len() - 1 { /// let u16_ptr = ptr.add(offset).cast::(); /// *u16_ptr = 0; + /// + /// assert!(x == [0, 0, 7, 8, 9] || x == [5, 0, 0, 8, 9]); /// } else { /// // while the pointer can be aligned via `offset`, it would point /// // outside the allocation /// } - /// - /// assert!(x == [0, 0, 7, 8, 9] || x == [5, 0, 0, 8, 9]); /// # } /// ``` #[stable(feature = "align_offset", since = "1.36.0")] From ee8a01f596d7d5aeeb817565492e5534e3bd4737 Mon Sep 17 00:00:00 2001 From: Dan Vail Date: Tue, 9 Aug 2022 12:57:19 -0500 Subject: [PATCH 08/16] Switching documentation to be more clear about potential errors --- library/core/src/fmt/mod.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 80f37cb5fdba5..7ec565edb3483 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -119,12 +119,9 @@ pub trait Write { /// /// This function will return an instance of [`Error`] on error. /// - /// Though it is possible for implementors of this trait to return an error, at the time - /// of writing these docs, no implementation of [`std::fmt::Write`] in the standard library - /// returns such an error. - /// - /// When working with external crates, it is advised to check the implementation of this - /// trait and anticipate any possible [`Error`]s. + /// The purpose of std::fmt::Error is to abort the formatting operation when the underlying + /// destination encounters some error preventing it from accepting more text; it should + /// generally be propagated rather than handled, at least when implementing formatting traits. /// /// # Examples /// From 2eebd34cd50c1486024da06d24415781af3a0a54 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 10 Aug 2022 11:48:25 +0100 Subject: [PATCH 09/16] errors: don't fail on broken primary translations If a primary bundle doesn't contain a message then the fallback bundle is used. However, if the primary bundle's message is broken (e.g. it refers to a interpolated variable that the compiler isn't providing) then this would just result in a compiler panic. While there aren't any primary bundles right now, this is the type of issue that could come up once translation is further along. Signed-off-by: David Wood --- compiler/rustc_errors/src/emitter.rs | 80 ++++++++++++------- compiler/rustc_errors/src/lib.rs | 3 +- src/test/run-make/translation/Makefile | 25 ++++-- src/test/run-make/translation/broken.ftl | 3 + src/test/run-make/translation/missing.ftl | 3 + .../{basic-translation.rs => test.rs} | 0 .../{basic-translation.ftl => working.ftl} | 0 7 files changed, 76 insertions(+), 38 deletions(-) create mode 100644 src/test/run-make/translation/broken.ftl create mode 100644 src/test/run-make/translation/missing.ftl rename src/test/run-make/translation/{basic-translation.rs => test.rs} (100%) rename src/test/run-make/translation/{basic-translation.ftl => working.ftl} (100%) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 61d953cd6f1cc..753e2f07c042e 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -273,40 +273,58 @@ pub trait Emitter { DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr), }; - let bundle = match self.fluent_bundle() { - Some(bundle) if bundle.has_message(&identifier) => bundle, - _ => self.fallback_fluent_bundle(), - }; + let translate_with_bundle = |bundle: &'a FluentBundle| -> Option<(Cow<'_, str>, Vec<_>)> { + let message = bundle.get_message(&identifier)?; + let value = match attr { + Some(attr) => message.get_attribute(attr)?.value(), + None => message.value()?, + }; + debug!(?message, ?value); - let message = bundle.get_message(&identifier).expect("missing diagnostic in fluent bundle"); - let value = match attr { - Some(attr) => { - if let Some(attr) = message.get_attribute(attr) { - attr.value() - } else { - panic!("missing attribute `{attr}` in fluent message `{identifier}`") - } - } - None => { - if let Some(value) = message.value() { - value - } else { - panic!("missing value in fluent message `{identifier}`") - } - } + let mut errs = vec![]; + let translated = bundle.format_pattern(value, Some(&args), &mut errs); + debug!(?translated, ?errs); + Some((translated, errs)) }; - let mut err = vec![]; - let translated = bundle.format_pattern(value, Some(&args), &mut err); - trace!(?translated, ?err); - debug_assert!( - err.is_empty(), - "identifier: {:?}, args: {:?}, errors: {:?}", - identifier, - args, - err - ); - translated + self.fluent_bundle() + .and_then(|bundle| translate_with_bundle(bundle)) + // If `translate_with_bundle` returns `None` with the primary bundle, this is likely + // just that the primary bundle doesn't contain the message being translated, so + // proceed to the fallback bundle. + // + // However, when errors are produced from translation, then that means the translation + // is broken (e.g. `{$foo}` exists in a translation but `foo` isn't provided). + // + // In debug builds, assert so that compiler devs can spot the broken translation and + // fix it.. + .inspect(|(_, errs)| { + debug_assert!( + errs.is_empty(), + "identifier: {:?}, attr: {:?}, args: {:?}, errors: {:?}", + identifier, + attr, + args, + errs + ); + }) + // ..otherwise, for end users, an error about this wouldn't be useful or actionable, so + // just hide it and try with the fallback bundle. + .filter(|(_, errs)| errs.is_empty()) + .or_else(|| translate_with_bundle(self.fallback_fluent_bundle())) + .map(|(translated, errs)| { + // Always bail out for errors with the fallback bundle. + assert!( + errs.is_empty(), + "identifier: {:?}, attr: {:?}, args: {:?}, errors: {:?}", + identifier, + attr, + args, + errs + ); + translated + }) + .expect("failed to find message in primary or fallback fluent bundles") } /// Formats the substitutions of the primary_span diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 15c1858023de7..f83e972efd56e 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -6,9 +6,10 @@ #![feature(drain_filter)] #![feature(if_let_guard)] #![cfg_attr(bootstrap, feature(let_chains))] +#![feature(adt_const_params)] #![feature(let_else)] #![feature(never_type)] -#![feature(adt_const_params)] +#![feature(result_option_inspect)] #![feature(rustc_attrs)] #![allow(incomplete_features)] #![allow(rustc::potential_query_instability)] diff --git a/src/test/run-make/translation/Makefile b/src/test/run-make/translation/Makefile index bfff75e7acb08..20e86c7f9a072 100644 --- a/src/test/run-make/translation/Makefile +++ b/src/test/run-make/translation/Makefile @@ -9,16 +9,29 @@ FAKEROOT=$(TMPDIR)/fakeroot all: normal custom sysroot -normal: basic-translation.rs +# Check that the test works normally, using the built-in fallback bundle. +normal: test.rs $(RUSTC) $< 2>&1 | grep "struct literal body without path" -custom: basic-translation.rs basic-translation.ftl - $(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/basic-translation.ftl 2>&1 | grep "this is a test message" +# Check that a primary bundle can be loaded and will be preferentially used +# where possible. +custom: test.rs working.ftl + $(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/working.ftl 2>&1 | grep "this is a test message" + +# Check that a primary bundle with a broken message (e.g. a interpolated +# variable is missing) will use the fallback bundle. +missing: test.rs missing.ftl + $(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/missing.ftl 2>&1 | grep "struct literal body without path" + +# Check that a primary bundle without the desired message will use the fallback +# bundle. +broken: test.rs broken.ftl + $(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/broken.ftl 2>&1 | grep "struct literal body without path" # Check that a locale can be loaded from the sysroot given a language # identifier by making a local copy of the sysroot and adding the custom locale # to it. -sysroot: basic-translation.rs basic-translation.ftl +sysroot: test.rs working.ftl mkdir $(FAKEROOT) ln -s $(SYSROOT)/* $(FAKEROOT) rm -f $(FAKEROOT)/lib @@ -31,7 +44,7 @@ sysroot: basic-translation.rs basic-translation.ftl mkdir $(FAKEROOT)/lib/rustlib/src ln -s $(SYSROOT)/lib/rustlib/src/* $(FAKEROOT)/lib/rustlib/src mkdir -p $(FAKEROOT)/share/locale/zh-CN/ - ln -s $(CURDIR)/basic-translation.ftl $(FAKEROOT)/share/locale/zh-CN/basic-translation.ftl + ln -s $(CURDIR)/working.ftl $(FAKEROOT)/share/locale/zh-CN/basic-translation.ftl $(RUSTC) $< --sysroot $(FAKEROOT) -Ztranslate-lang=zh-CN 2>&1 | grep "this is a test message" # Check that the compiler errors out when the sysroot requested cannot be @@ -43,7 +56,7 @@ sysroot-missing: # Check that the compiler errors out when the sysroot requested cannot be # found. This test might start failing if there actually exists a Klingon # translation of rustc's error messages. -sysroot-invalid: basic-translation.rs basic-translation.ftl +sysroot-invalid: test.rs working.ftl mkdir $(FAKEROOT) ln -s $(SYSROOT)/* $(FAKEROOT) rm -f $(FAKEROOT)/lib diff --git a/src/test/run-make/translation/broken.ftl b/src/test/run-make/translation/broken.ftl new file mode 100644 index 0000000000000..1482dd2824aed --- /dev/null +++ b/src/test/run-make/translation/broken.ftl @@ -0,0 +1,3 @@ +# `foo` isn't provided by this diagnostic so it is expected that the fallback message is used. +parser-struct-literal-body-without-path = this is a {$foo} message + .suggestion = this is a test suggestion diff --git a/src/test/run-make/translation/missing.ftl b/src/test/run-make/translation/missing.ftl new file mode 100644 index 0000000000000..43076b1d6ae79 --- /dev/null +++ b/src/test/run-make/translation/missing.ftl @@ -0,0 +1,3 @@ +# `parser-struct-literal-body-without-path` isn't provided by this resource at all, so the +# fallback should be used. +foo = bar diff --git a/src/test/run-make/translation/basic-translation.rs b/src/test/run-make/translation/test.rs similarity index 100% rename from src/test/run-make/translation/basic-translation.rs rename to src/test/run-make/translation/test.rs diff --git a/src/test/run-make/translation/basic-translation.ftl b/src/test/run-make/translation/working.ftl similarity index 100% rename from src/test/run-make/translation/basic-translation.ftl rename to src/test/run-make/translation/working.ftl From 3d21c371effa15fcf3562b5b722c80623dbd2c43 Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 1 Aug 2022 14:32:09 +0200 Subject: [PATCH 10/16] std: optimize thread ID generation --- library/std/src/thread/mod.rs | 59 ++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 44c8a50fd860a..479669647c128 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -170,7 +170,6 @@ use crate::ptr::addr_of_mut; use crate::str; use crate::sync::Arc; use crate::sys::thread as imp; -use crate::sys_common::mutex; use crate::sys_common::thread; use crate::sys_common::thread_info; use crate::sys_common::thread_parker::Parker; @@ -1033,24 +1032,48 @@ pub struct ThreadId(NonZeroU64); impl ThreadId { // Generate a new unique thread ID. fn new() -> ThreadId { - // It is UB to attempt to acquire this mutex reentrantly! - static GUARD: mutex::StaticMutex = mutex::StaticMutex::new(); - static mut COUNTER: u64 = 1; - - unsafe { - let guard = GUARD.lock(); - - // If we somehow use up all our bits, panic so that we're not - // covering up subtle bugs of IDs being reused. - if COUNTER == u64::MAX { - drop(guard); // in case the panic handler ends up calling `ThreadId::new()`, avoid reentrant lock acquire. - panic!("failed to generate unique thread ID: bitspace exhausted"); - } - - let id = COUNTER; - COUNTER += 1; + #[cold] + fn exhausted() -> ! { + panic!("failed to generate unique thread ID: bitspace exhausted") + } - ThreadId(NonZeroU64::new(id).unwrap()) + cfg_if::cfg_if! { + if #[cfg(target_has_atomic = "64")] { + use crate::sync::atomic::{AtomicU64, Ordering::Relaxed}; + + static COUNTER: AtomicU64 = AtomicU64::new(0); + + let mut last = COUNTER.load(Relaxed); + loop { + let Some(id) = last.checked_add(1) else { + exhausted(); + }; + + match COUNTER.compare_exchange_weak(last, id, Relaxed, Relaxed) { + Ok(_) => return ThreadId(NonZeroU64::new(id).unwrap()), + Err(id) => last = id, + } + } + } else { + use crate::sys_common::mutex::StaticMutex; + + // It is UB to attempt to acquire this mutex reentrantly! + static GUARD: StaticMutex = StaticMutex::new(); + static mut COUNTER: u64 = 0; + + unsafe { + let guard = GUARD.lock(); + + let Some(id) = COUNTER.checked_add(1) else { + drop(guard); // in case the panic handler ends up calling `ThreadId::new()`, avoid reentrant lock acquire. + exhausted(); + }; + + COUNTER = id; + drop(guard); + ThreadId(NonZeroU64::new(id).unwrap()) + } + } } } From e1e25a845c2d190afad0c98029cbe368f5bad427 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 7 Aug 2022 21:03:28 +0200 Subject: [PATCH 11/16] Generalize trait object generic param check to aliases. --- compiler/rustc_typeck/src/astconv/mod.rs | 134 +++++++----------- .../ui/associated-types/issue-22560.stderr | 46 +++--- .../cycle-trait-default-type-trait.rs | 1 - .../cycle-trait-default-type-trait.stderr | 21 +-- src/test/ui/issues/issue-21950.stderr | 18 +-- .../ui/traits/alias/generic-default-in-dyn.rs | 10 ++ .../alias/generic-default-in-dyn.stderr | 39 +++++ .../unspecified-self-in-trait-ref.rs | 0 .../unspecified-self-in-trait-ref.stderr | 0 9 files changed, 136 insertions(+), 133 deletions(-) create mode 100644 src/test/ui/traits/alias/generic-default-in-dyn.rs create mode 100644 src/test/ui/traits/alias/generic-default-in-dyn.stderr rename src/test/ui/{ => traits}/unspecified-self-in-trait-ref.rs (100%) rename src/test/ui/{ => traits}/unspecified-self-in-trait-ref.stderr (100%) diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 8a5c7fee697d1..0951713e5db18 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -367,36 +367,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { return (tcx.intern_substs(&[]), arg_count); } - let is_object = self_ty.map_or(false, |ty| ty == self.tcx().types.trait_object_dummy_self); - struct SubstsForAstPathCtxt<'a, 'tcx> { astconv: &'a (dyn AstConv<'tcx> + 'a), def_id: DefId, generic_args: &'a GenericArgs<'a>, span: Span, - missing_type_params: Vec, inferred_params: Vec, infer_args: bool, - is_object: bool, - } - - impl<'tcx, 'a> SubstsForAstPathCtxt<'tcx, 'a> { - fn default_needs_object_self(&mut self, param: &ty::GenericParamDef) -> bool { - let tcx = self.astconv.tcx(); - if let GenericParamDefKind::Type { has_default, .. } = param.kind { - if self.is_object && has_default { - let default_ty = tcx.at(self.span).type_of(param.def_id); - let self_param = tcx.types.self_param; - if default_ty.walk().any(|arg| arg == self_param.into()) { - // There is no suitable inference default for a type parameter - // that references self, in an object type. - return true; - } - } - } - - false - } } impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for SubstsForAstPathCtxt<'a, 'tcx> { @@ -499,41 +476,23 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { GenericParamDefKind::Type { has_default, .. } => { if !infer_args && has_default { // No type parameter provided, but a default exists. - - // If we are converting an object type, then the - // `Self` parameter is unknown. However, some of the - // other type parameters may reference `Self` in their - // defaults. This will lead to an ICE if we are not - // careful! - if self.default_needs_object_self(param) { - self.missing_type_params.push(param.name); - tcx.ty_error().into() - } else { - // This is a default type parameter. - let substs = substs.unwrap(); - if substs.iter().any(|arg| match arg.unpack() { - GenericArgKind::Type(ty) => ty.references_error(), - _ => false, - }) { - // Avoid ICE #86756 when type error recovery goes awry. - return tcx.ty_error().into(); - } - self.astconv - .normalize_ty( - self.span, - EarlyBinder(tcx.at(self.span).type_of(param.def_id)) - .subst(tcx, substs), - ) - .into() + let substs = substs.unwrap(); + if substs.iter().any(|arg| match arg.unpack() { + GenericArgKind::Type(ty) => ty.references_error(), + _ => false, + }) { + // Avoid ICE #86756 when type error recovery goes awry. + return tcx.ty_error().into(); } + self.astconv + .normalize_ty( + self.span, + EarlyBinder(tcx.at(self.span).type_of(param.def_id)) + .subst(tcx, substs), + ) + .into() } else if infer_args { - // No type parameters were provided, we can infer all. - let param = if !self.default_needs_object_self(param) { - Some(param) - } else { - None - }; - self.astconv.ty_infer(param, self.span).into() + self.astconv.ty_infer(Some(param), self.span).into() } else { // We've already errored above about the mismatch. tcx.ty_error().into() @@ -563,10 +522,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { def_id, span, generic_args, - missing_type_params: vec![], inferred_params: vec![], infer_args, - is_object, }; let substs = Self::create_substs_for_generic_args( tcx, @@ -578,13 +535,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &mut substs_ctx, ); - self.complain_about_missing_type_params( - substs_ctx.missing_type_params, - def_id, - span, - generic_args.args.is_empty(), - ); - debug!( "create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}", generics, self_ty, substs @@ -1489,23 +1439,47 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Erase the `dummy_self` (`trait_object_dummy_self`) used above. let existential_trait_refs = regular_traits.iter().map(|i| { i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| { - if trait_ref.self_ty() != dummy_self { - // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`, - // which picks up non-supertraits where clauses - but also, the object safety - // completely ignores trait aliases, which could be object safety hazards. We - // `delay_span_bug` here to avoid an ICE in stable even when the feature is - // disabled. (#66420) - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!( - "trait_ref_to_existential called on {:?} with non-dummy Self", - trait_ref, - ), - ); - } - ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) + assert_eq!(trait_ref.self_ty(), dummy_self); + + // Verify that `dummy_self` did not leak inside default type parameters. This + // could not be done at path creation, since we need to see through trait aliases. + let mut missing_type_params = vec![]; + let generics = tcx.generics_of(trait_ref.def_id); + let substs: Vec<_> = trait_ref + .substs + .iter() + .enumerate() + .skip(1) // Remove `Self` for `ExistentialPredicate`. + .map(|(index, arg)| { + if let ty::GenericArgKind::Type(ty) = arg.unpack() + && ty == dummy_self + { + let param = &generics.params[index]; + missing_type_params.push(param.name); + tcx.ty_error().into() + } else { + arg + } + }) + .collect(); + let substs = tcx.intern_substs(&substs[..]); + + let span = i.bottom().1; + let empty_generic_args = trait_bounds.iter().any(|hir_bound| { + hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id) + && hir_bound.span.contains(span) + }); + self.complain_about_missing_type_params( + missing_type_params, + trait_ref.def_id, + span, + empty_generic_args, + ); + + ty::ExistentialTraitRef { def_id: trait_ref.def_id, substs } }) }); + let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| { bound.map_bound(|b| { if b.projection_ty.self_ty() != dummy_self { diff --git a/src/test/ui/associated-types/issue-22560.stderr b/src/test/ui/associated-types/issue-22560.stderr index 700923c1b3f58..2b88cf0b4411e 100644 --- a/src/test/ui/associated-types/issue-22560.stderr +++ b/src/test/ui/associated-types/issue-22560.stderr @@ -1,25 +1,3 @@ -error[E0393]: the type parameter `Rhs` must be explicitly specified - --> $DIR/issue-22560.rs:9:23 - | -LL | trait Sub { - | ------------------- type parameter `Rhs` must be specified for this -... -LL | type Test = dyn Add + Sub; - | ^^^ help: set the type parameter to the desired type: `Sub` - | - = note: because of the default `Self` reference, type parameters must be specified on object types - -error[E0393]: the type parameter `Rhs` must be explicitly specified - --> $DIR/issue-22560.rs:9:17 - | -LL | trait Add { - | ------------------- type parameter `Rhs` must be specified for this -... -LL | type Test = dyn Add + Sub; - | ^^^ help: set the type parameter to the desired type: `Add` - | - = note: because of the default `Self` reference, type parameters must be specified on object types - error[E0225]: only auto traits can be used as additional traits in a trait object --> $DIR/issue-22560.rs:9:23 | @@ -28,7 +6,7 @@ LL | type Test = dyn Add + Sub; | | | first non-auto trait | - = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add<[type error]> + Sub<[type error]> {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add + Sub {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0191]: the value of the associated types `Output` (from trait `Add`), `Output` (from trait `Sub`) must be specified @@ -50,6 +28,28 @@ help: specify the associated types LL | type Test = dyn Add + Sub; | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~ +error[E0393]: the type parameter `Rhs` must be explicitly specified + --> $DIR/issue-22560.rs:9:17 + | +LL | trait Add { + | ------------------- type parameter `Rhs` must be specified for this +... +LL | type Test = dyn Add + Sub; + | ^^^ help: set the type parameter to the desired type: `Add` + | + = note: because of the default `Self` reference, type parameters must be specified on object types + +error[E0393]: the type parameter `Rhs` must be explicitly specified + --> $DIR/issue-22560.rs:9:23 + | +LL | trait Sub { + | ------------------- type parameter `Rhs` must be specified for this +... +LL | type Test = dyn Add + Sub; + | ^^^ help: set the type parameter to the desired type: `Sub` + | + = note: because of the default `Self` reference, type parameters must be specified on object types + error: aborting due to 4 previous errors Some errors have detailed explanations: E0191, E0225, E0393. diff --git a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.rs b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.rs index b2edc1a1f66ca..6175b7df1107a 100644 --- a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.rs +++ b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.rs @@ -3,7 +3,6 @@ trait Foo> { //~^ ERROR cycle detected - //~| ERROR cycle detected } fn main() { } diff --git a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr index d4976a0f9c9cd..9d715f4947146 100644 --- a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr +++ b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr @@ -10,30 +10,11 @@ note: cycle used when collecting item types in top-level module | LL | / trait Foo> { LL | | -LL | | -LL | | } -LL | | -LL | | fn main() { } - | |_____________^ - -error[E0391]: cycle detected when computing type of `Foo::X` - --> $DIR/cycle-trait-default-type-trait.rs:4:23 - | -LL | trait Foo> { - | ^^^ - | - = note: ...which immediately requires computing type of `Foo::X` again -note: cycle used when collecting item types in top-level module - --> $DIR/cycle-trait-default-type-trait.rs:4:1 - | -LL | / trait Foo> { -LL | | -LL | | LL | | } LL | | LL | | fn main() { } | |_____________^ -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/issues/issue-21950.stderr b/src/test/ui/issues/issue-21950.stderr index 4909398bb848f..731615a6bd8d4 100644 --- a/src/test/ui/issues/issue-21950.stderr +++ b/src/test/ui/issues/issue-21950.stderr @@ -1,3 +1,12 @@ +error[E0191]: the value of the associated type `Output` (from trait `Add`) must be specified + --> $DIR/issue-21950.rs:10:25 + | +LL | type Output; + | ----------- `Output` defined here +... +LL | let x = &10 as &dyn Add; + | ^^^ help: specify the associated type: `Add` + error[E0393]: the type parameter `Rhs` must be explicitly specified --> $DIR/issue-21950.rs:10:25 | @@ -9,15 +18,6 @@ LL | let x = &10 as &dyn Add; | = note: because of the default `Self` reference, type parameters must be specified on object types -error[E0191]: the value of the associated type `Output` (from trait `Add`) must be specified - --> $DIR/issue-21950.rs:10:25 - | -LL | type Output; - | ----------- `Output` defined here -... -LL | let x = &10 as &dyn Add; - | ^^^ help: specify the associated type: `Add` - error: aborting due to 2 previous errors Some errors have detailed explanations: E0191, E0393. diff --git a/src/test/ui/traits/alias/generic-default-in-dyn.rs b/src/test/ui/traits/alias/generic-default-in-dyn.rs new file mode 100644 index 0000000000000..d44e1c2a97530 --- /dev/null +++ b/src/test/ui/traits/alias/generic-default-in-dyn.rs @@ -0,0 +1,10 @@ +trait SendEqAlias = PartialEq; +//~^ ERROR trait aliases are experimental + +struct Foo(dyn SendEqAlias); +//~^ ERROR the type parameter `Rhs` must be explicitly specified [E0393] + +struct Bar(dyn SendEqAlias, T); +//~^ ERROR the type parameter `Rhs` must be explicitly specified [E0393] + +fn main() {} diff --git a/src/test/ui/traits/alias/generic-default-in-dyn.stderr b/src/test/ui/traits/alias/generic-default-in-dyn.stderr new file mode 100644 index 0000000000000..76a068e864a3c --- /dev/null +++ b/src/test/ui/traits/alias/generic-default-in-dyn.stderr @@ -0,0 +1,39 @@ +error[E0658]: trait aliases are experimental + --> $DIR/generic-default-in-dyn.rs:1:1 + | +LL | trait SendEqAlias = PartialEq; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #41517 for more information + = help: add `#![feature(trait_alias)]` to the crate attributes to enable + +error[E0393]: the type parameter `Rhs` must be explicitly specified + --> $DIR/generic-default-in-dyn.rs:4:19 + | +LL | struct Foo(dyn SendEqAlias); + | ^^^^^^^^^^^^^^ missing reference to `Rhs` + | + ::: $SRC_DIR/core/src/cmp.rs:LL:COL + | +LL | pub trait PartialEq { + | --------------------------------------- type parameter `Rhs` must be specified for this + | + = note: because of the default `Self` reference, type parameters must be specified on object types + +error[E0393]: the type parameter `Rhs` must be explicitly specified + --> $DIR/generic-default-in-dyn.rs:7:19 + | +LL | struct Bar(dyn SendEqAlias, T); + | ^^^^^^^^^^^^^^ missing reference to `Rhs` + | + ::: $SRC_DIR/core/src/cmp.rs:LL:COL + | +LL | pub trait PartialEq { + | --------------------------------------- type parameter `Rhs` must be specified for this + | + = note: because of the default `Self` reference, type parameters must be specified on object types + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0393, E0658. +For more information about an error, try `rustc --explain E0393`. diff --git a/src/test/ui/unspecified-self-in-trait-ref.rs b/src/test/ui/traits/unspecified-self-in-trait-ref.rs similarity index 100% rename from src/test/ui/unspecified-self-in-trait-ref.rs rename to src/test/ui/traits/unspecified-self-in-trait-ref.rs diff --git a/src/test/ui/unspecified-self-in-trait-ref.stderr b/src/test/ui/traits/unspecified-self-in-trait-ref.stderr similarity index 100% rename from src/test/ui/unspecified-self-in-trait-ref.stderr rename to src/test/ui/traits/unspecified-self-in-trait-ref.stderr From 0df84ae67c01d44c3d6c0887333bafca1ea7f060 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 7 Aug 2022 22:02:02 +0200 Subject: [PATCH 12/16] Ban indirect references to `Self` too. --- compiler/rustc_typeck/src/astconv/mod.rs | 38 +++++++++++++++---- src/test/ui/traits/alias/self-in-generics.rs | 8 ++++ .../ui/traits/alias/self-in-generics.stderr | 11 ++++++ 3 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/traits/alias/self-in-generics.rs create mode 100644 src/test/ui/traits/alias/self-in-generics.stderr diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 0951713e5db18..9ec3002e3aaf1 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -43,7 +43,7 @@ use rustc_trait_selection::traits::error_reporting::{ }; use rustc_trait_selection::traits::wf::object_region_bounds; -use smallvec::SmallVec; +use smallvec::{smallvec, SmallVec}; use std::collections::BTreeSet; use std::slice; @@ -1444,6 +1444,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Verify that `dummy_self` did not leak inside default type parameters. This // could not be done at path creation, since we need to see through trait aliases. let mut missing_type_params = vec![]; + let mut references_self = false; let generics = tcx.generics_of(trait_ref.def_id); let substs: Vec<_> = trait_ref .substs @@ -1451,12 +1452,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .enumerate() .skip(1) // Remove `Self` for `ExistentialPredicate`. .map(|(index, arg)| { - if let ty::GenericArgKind::Type(ty) = arg.unpack() - && ty == dummy_self - { - let param = &generics.params[index]; - missing_type_params.push(param.name); - tcx.ty_error().into() + if let ty::GenericArgKind::Type(ty) = arg.unpack() { + debug!(?ty); + if ty == dummy_self { + let param = &generics.params[index]; + missing_type_params.push(param.name); + tcx.ty_error().into() + } else if ty.walk().any(|arg| arg == dummy_self.into()) { + references_self = true; + tcx.ty_error().into() + } else { + arg + } } else { arg } @@ -1476,6 +1483,23 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { empty_generic_args, ); + if references_self { + let def_id = i.bottom().0.def_id(); + let mut err = struct_span_err!( + tcx.sess, + i.bottom().1, + E0038, + "the {} `{}` cannot be made into an object", + tcx.def_kind(def_id).descr(def_id), + tcx.item_name(def_id), + ); + err.note( + rustc_middle::traits::ObjectSafetyViolation::SupertraitSelf(smallvec![]) + .error_msg(), + ); + err.emit(); + } + ty::ExistentialTraitRef { def_id: trait_ref.def_id, substs } }) }); diff --git a/src/test/ui/traits/alias/self-in-generics.rs b/src/test/ui/traits/alias/self-in-generics.rs new file mode 100644 index 0000000000000..6b99431f5bbcf --- /dev/null +++ b/src/test/ui/traits/alias/self-in-generics.rs @@ -0,0 +1,8 @@ +#![feature(trait_alias)] + +pub trait SelfInput = Fn(&mut Self); + +pub fn f(_f: &dyn SelfInput) {} +//~^ ERROR the trait alias `SelfInput` cannot be made into an object [E0038] + +fn main() {} diff --git a/src/test/ui/traits/alias/self-in-generics.stderr b/src/test/ui/traits/alias/self-in-generics.stderr new file mode 100644 index 0000000000000..a1056872ea641 --- /dev/null +++ b/src/test/ui/traits/alias/self-in-generics.stderr @@ -0,0 +1,11 @@ +error[E0038]: the trait alias `SelfInput` cannot be made into an object + --> $DIR/self-in-generics.rs:5:19 + | +LL | pub fn f(_f: &dyn SelfInput) {} + | ^^^^^^^^^ + | + = note: it cannot use `Self` as a type parameter in a supertrait or `where`-clause + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0038`. From 98518c2379d4bcf6909817758eb0bfd50557d51b Mon Sep 17 00:00:00 2001 From: chenyukang Date: Thu, 11 Aug 2022 22:26:26 +0800 Subject: [PATCH 13/16] suggest const or static for global variable --- compiler/rustc_parse/src/parser/item.rs | 7 ++++++- src/test/ui/parser/suggest-const-for-global-var.rs | 6 ++++++ src/test/ui/parser/suggest-const-for-global-var.stderr | 8 ++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/parser/suggest-const-for-global-var.rs create mode 100644 src/test/ui/parser/suggest-const-for-global-var.stderr diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 72c23776d3399..197c038489835 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -68,7 +68,12 @@ impl<'a> Parser<'a> { if !self.maybe_consume_incorrect_semicolon(&items) { let msg = &format!("expected item, found {token_str}"); let mut err = self.struct_span_err(self.token.span, msg); - err.span_label(self.token.span, "expected item"); + let label = if self.is_kw_followed_by_ident(kw::Let) { + "consider using `const` or `static` instead of `let` for global variables" + } else { + "expected item" + }; + err.span_label(self.token.span, label); return Err(err); } } diff --git a/src/test/ui/parser/suggest-const-for-global-var.rs b/src/test/ui/parser/suggest-const-for-global-var.rs new file mode 100644 index 0000000000000..d6216cb7ac275 --- /dev/null +++ b/src/test/ui/parser/suggest-const-for-global-var.rs @@ -0,0 +1,6 @@ +let X: i32 = 12; +//~^ ERROR expected item, found keyword `let` + +fn main() { + println!("{}", X); +} diff --git a/src/test/ui/parser/suggest-const-for-global-var.stderr b/src/test/ui/parser/suggest-const-for-global-var.stderr new file mode 100644 index 0000000000000..94e44ec7f6ce1 --- /dev/null +++ b/src/test/ui/parser/suggest-const-for-global-var.stderr @@ -0,0 +1,8 @@ +error: expected item, found keyword `let` + --> $DIR/suggest-const-for-global-var.rs:1:1 + | +LL | let X: i32 = 12; + | ^^^ consider using `const` or `static` instead of `let` for global variables + +error: aborting due to previous error + From dd4613cbc091860d4b56f506b195b92c87f022a1 Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Thu, 11 Aug 2022 06:59:58 -0700 Subject: [PATCH 14/16] rustdoc: don't generate DOM element for operator In our source page highlighting, we were generating `` tags for all "operators", including e.g. `<` `>` around generic parameters, `*`, `&`. This contributed significantly to DOM size, but we don't actually style `.op` except in the ayu theme. Remove the styles for `.op` in ayu, and stop generating the ``s. This reduces DOM size of an example page[1] from 265,938 HTML elements to 242,165 elements, a 9% reduction. [1]: https://doc.rust-lang.org/nightly/src/core/up/up/stdarch/crates/core_arch/src/x86/avx512f.rs.html --- src/librustdoc/html/highlight.rs | 17 +++++++--------- .../html/highlight/fixtures/decorations.html | 4 ++-- .../html/highlight/fixtures/highlight.html | 4 ++-- .../html/highlight/fixtures/sample.html | 20 +++++++++---------- .../html/highlight/fixtures/union.html | 2 +- src/librustdoc/html/static/css/themes/ayu.css | 4 ++-- src/test/rustdoc/macro_rules-matchers.rs | 5 +---- 7 files changed, 25 insertions(+), 31 deletions(-) diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 05547ea1515c3..2cef2c99930c7 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -133,7 +133,6 @@ enum Class { // Keywords that do pointer/reference stuff. RefKeyWord, Self_(Span), - Op, Macro(Span), MacroNonTerminal, String, @@ -157,7 +156,6 @@ impl Class { Class::KeyWord => "kw", Class::RefKeyWord => "kw-2", Class::Self_(_) => "self", - Class::Op => "op", Class::Macro(_) => "macro", Class::MacroNonTerminal => "macro-nonterminal", Class::String => "string", @@ -182,7 +180,6 @@ impl Class { | Self::Attribute | Self::KeyWord | Self::RefKeyWord - | Self::Op | Self::MacroNonTerminal | Self::String | Self::Number @@ -494,7 +491,7 @@ impl<'a> Classifier<'a> { // or a reference or pointer type. Unless, of course, it looks like // a logical and or a multiplication operator: `&&` or `* `. TokenKind::Star => match self.tokens.peek() { - Some((TokenKind::Whitespace, _)) => Class::Op, + Some((TokenKind::Whitespace, _)) => return no_highlight(sink), Some((TokenKind::Ident, "mut")) => { self.next(); sink(Highlight::Token { text: "*mut", class: Some(Class::RefKeyWord) }); @@ -510,15 +507,15 @@ impl<'a> Classifier<'a> { TokenKind::And => match self.tokens.peek() { Some((TokenKind::And, _)) => { self.next(); - sink(Highlight::Token { text: "&&", class: Some(Class::Op) }); + sink(Highlight::Token { text: "&&", class: None }); return; } Some((TokenKind::Eq, _)) => { self.next(); - sink(Highlight::Token { text: "&=", class: Some(Class::Op) }); + sink(Highlight::Token { text: "&=", class: None }); return; } - Some((TokenKind::Whitespace, _)) => Class::Op, + Some((TokenKind::Whitespace, _)) => return no_highlight(sink), Some((TokenKind::Ident, "mut")) => { self.next(); sink(Highlight::Token { text: "&mut", class: Some(Class::RefKeyWord) }); @@ -531,7 +528,7 @@ impl<'a> Classifier<'a> { TokenKind::Eq => match lookahead { Some(TokenKind::Eq) => { self.next(); - sink(Highlight::Token { text: "==", class: Some(Class::Op) }); + sink(Highlight::Token { text: "==", class: None }); return; } Some(TokenKind::Gt) => { @@ -539,7 +536,7 @@ impl<'a> Classifier<'a> { sink(Highlight::Token { text: "=>", class: None }); return; } - _ => Class::Op, + _ => return no_highlight(sink), }, TokenKind::Minus if lookahead == Some(TokenKind::Gt) => { self.next(); @@ -556,7 +553,7 @@ impl<'a> Classifier<'a> { | TokenKind::Percent | TokenKind::Bang | TokenKind::Lt - | TokenKind::Gt => Class::Op, + | TokenKind::Gt => return no_highlight(sink), // Miscellaneous, no highlighting. TokenKind::Dot diff --git a/src/librustdoc/html/highlight/fixtures/decorations.html b/src/librustdoc/html/highlight/fixtures/decorations.html index 45f567880c9d9..ae4dba116d637 100644 --- a/src/librustdoc/html/highlight/fixtures/decorations.html +++ b/src/librustdoc/html/highlight/fixtures/decorations.html @@ -1,2 +1,2 @@ -let x = 1; -let y = 2; \ No newline at end of file +let x = 1; +let y = 2; \ No newline at end of file diff --git a/src/librustdoc/html/highlight/fixtures/highlight.html b/src/librustdoc/html/highlight/fixtures/highlight.html index abc2db1790c53..17f23278ec1f2 100644 --- a/src/librustdoc/html/highlight/fixtures/highlight.html +++ b/src/librustdoc/html/highlight/fixtures/highlight.html @@ -1,4 +1,4 @@ use crate::a::foo; use self::whatever; -let x = super::b::foo; -let y = Self::whatever; \ No newline at end of file +let x = super::b::foo; +let y = Self::whatever; \ No newline at end of file diff --git a/src/librustdoc/html/highlight/fixtures/sample.html b/src/librustdoc/html/highlight/fixtures/sample.html index b117a12e39f4a..ea797fd99d3f4 100644 --- a/src/librustdoc/html/highlight/fixtures/sample.html +++ b/src/librustdoc/html/highlight/fixtures/sample.html @@ -8,23 +8,23 @@ .lifetime { color: #B76514; } .question-mark { color: #ff9011; } -
#![crate_type = "lib"]
+
#![crate_type = "lib"]
 
 use std::path::{Path, PathBuf};
 
-#[cfg(target_os = "linux")]
+#[cfg(target_os = "linux")]
 fn main() -> () {
-    let foo = true && false || true;
-    let _: *const () = 0;
-    let _ = &foo;
-    let _ = &&foo;
-    let _ = *foo;
+    let foo = true && false || true;
+    let _: *const () = 0;
+    let _ = &foo;
+    let _ = &&foo;
+    let _ = *foo;
     mac!(foo, &mut bar);
-    assert!(self.length < N && index <= self.length);
+    assert!(self.length < N && index <= self.length);
     ::std::env::var("gateau").is_ok();
     #[rustfmt::skip]
-    let s:std::path::PathBuf = std::path::PathBuf::new();
-    let mut s = String::new();
+    let s:std::path::PathBuf = std::path::PathBuf::new();
+    let mut s = String::new();
 
     match &s {
         ref mut x => {}
diff --git a/src/librustdoc/html/highlight/fixtures/union.html b/src/librustdoc/html/highlight/fixtures/union.html
index c0acf31a05d08..ac8bd28f6c362 100644
--- a/src/librustdoc/html/highlight/fixtures/union.html
+++ b/src/librustdoc/html/highlight/fixtures/union.html
@@ -4,5 +4,5 @@
 }
 
 fn main() {
-    let union = 0;
+    let union = 0;
 }
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index c42cac59bd6fa..14a61f72c34ba 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -239,7 +239,7 @@ details.rustdoc-toggle > summary::before {
 pre.rust .number, pre.rust .string { color: #b8cc52; }
 pre.rust .kw, pre.rust .kw-2, pre.rust .prelude-ty,
 pre.rust .bool-val, pre.rust .prelude-val,
-pre.rust .op, pre.rust .lifetime { color: #ff7733; }
+pre.rust .lifetime { color: #ff7733; }
 pre.rust .macro, pre.rust .macro-nonterminal { color: #a37acc; }
 pre.rust .question-mark {
 	color: #ff9011;
@@ -251,7 +251,7 @@ pre.rust .self {
 pre.rust .attribute {
 	color: #e6e1cf;
 }
-pre.rust .attribute .ident, pre.rust .attribute .op {
+pre.rust .attribute .ident {
 	color: #e6e1cf;
 }
 
diff --git a/src/test/rustdoc/macro_rules-matchers.rs b/src/test/rustdoc/macro_rules-matchers.rs
index efc3b21e6da99..131c53ec24bc4 100644
--- a/src/test/rustdoc/macro_rules-matchers.rs
+++ b/src/test/rustdoc/macro_rules-matchers.rs
@@ -6,16 +6,13 @@
 // @has 'foo/macro.todo.html'
 // @has - '//span[@class="macro"]' 'macro_rules!'
 // @has - '//span[@class="ident"]' 'todo'
-// Note: the only op is the `+`
-// @count - '//pre[@class="rust macro"]//span[@class="op"]' 1
 
 // @has - '{ () => { ... }; ($('
 // @has - '//span[@class="macro-nonterminal"]' '$'
 // @has - '//span[@class="macro-nonterminal"]' 'arg'
 // @has - ':'
 // @has - '//span[@class="ident"]' 'tt'
-// @has - '),'
-// @has - '//span[@class="op"]' '+'
+// @has - ')+'
 // @has - ') => { ... }; }'
 pub use std::todo;
 

From e3c5bd617d040b5ee0bc79e6e7f01772adce791b Mon Sep 17 00:00:00 2001
From: Cormac Relf 
Date: Tue, 15 Feb 2022 17:42:50 +1100
Subject: [PATCH 15/16] let-else: add a test for warnings on let-else with
 diverging tail

---
 src/test/ui/let-else/let-else-then-diverge.rs | 19 +++++++++++++++++++
 .../ui/let-else/let-else-then-diverge.stderr  | 14 ++++++++++++++
 2 files changed, 33 insertions(+)
 create mode 100644 src/test/ui/let-else/let-else-then-diverge.rs
 create mode 100644 src/test/ui/let-else/let-else-then-diverge.stderr

diff --git a/src/test/ui/let-else/let-else-then-diverge.rs b/src/test/ui/let-else/let-else-then-diverge.rs
new file mode 100644
index 0000000000000..49633d943beea
--- /dev/null
+++ b/src/test/ui/let-else/let-else-then-diverge.rs
@@ -0,0 +1,19 @@
+//
+// popped up in in #94012, where an alternative desugaring was
+// causing unreachable code errors
+
+#![feature(let_else)]
+#![deny(unused_variables)]
+#![deny(unreachable_code)]
+
+fn let_else_diverge() -> bool {
+    let Some(_) = Some("test") else {
+        let x = 5; //~ ERROR unused variable: `x`
+        return false;
+    };
+    return true;
+}
+
+fn main() {
+    let_else_diverge();
+}
diff --git a/src/test/ui/let-else/let-else-then-diverge.stderr b/src/test/ui/let-else/let-else-then-diverge.stderr
new file mode 100644
index 0000000000000..ceb61029d3863
--- /dev/null
+++ b/src/test/ui/let-else/let-else-then-diverge.stderr
@@ -0,0 +1,14 @@
+error: unused variable: `x`
+  --> $DIR/let-else-then-diverge.rs:11:13
+   |
+LL |         let x = 5;
+   |             ^ help: if this is intentional, prefix it with an underscore: `_x`
+   |
+note: the lint level is defined here
+  --> $DIR/let-else-then-diverge.rs:6:9
+   |
+LL | #![deny(unused_variables)]
+   |         ^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+

From 981852677c531d52f701b870bb27b45668a44d52 Mon Sep 17 00:00:00 2001
From: est31 
Date: Fri, 15 Jul 2022 18:53:23 +0200
Subject: [PATCH 16/16] Add regression test for #94176

---
 src/test/ui/let-else/issue-94176.rs     | 10 ++++++++++
 src/test/ui/let-else/issue-94176.stderr | 19 +++++++++++++++++++
 2 files changed, 29 insertions(+)
 create mode 100644 src/test/ui/let-else/issue-94176.rs
 create mode 100644 src/test/ui/let-else/issue-94176.stderr

diff --git a/src/test/ui/let-else/issue-94176.rs b/src/test/ui/let-else/issue-94176.rs
new file mode 100644
index 0000000000000..e35bbd8883062
--- /dev/null
+++ b/src/test/ui/let-else/issue-94176.rs
@@ -0,0 +1,10 @@
+// Issue #94176: wrong span for the error message of a mismatched type error,
+// if the function uses a `let else` construct.
+#![feature(let_else)]
+
+pub fn test(a: Option) -> Option { //~ ERROR mismatched types
+    let Some(_) = a else { return None; };
+    println!("Foo");
+}
+
+fn main() {}
diff --git a/src/test/ui/let-else/issue-94176.stderr b/src/test/ui/let-else/issue-94176.stderr
new file mode 100644
index 0000000000000..0cb97aceebfd5
--- /dev/null
+++ b/src/test/ui/let-else/issue-94176.stderr
@@ -0,0 +1,19 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-94176.rs:5:32
+   |
+LL | pub fn test(a: Option) -> Option {
+   |        ----                    ^^^^^^^^^^^ expected enum `Option`, found `()`
+   |        |
+   |        implicitly returns `()` as its body has no tail or `return` expression
+   |
+   = note:   expected enum `Option`
+           found unit type `()`
+help: consider returning the local binding `a`
+   |
+LL ~     println!("Foo");
+LL +     a
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.