diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md index fbb40f1d2f3d4..a941bc9348f2c 100644 --- a/src/doc/unstable-book/src/library-features/asm.md +++ b/src/doc/unstable-book/src/library-features/asm.md @@ -68,10 +68,13 @@ Let us see another example that also uses an input: let i: u64 = 3; let o: u64; unsafe { - asm!(" - mov {0}, {1} - add {0}, {number} - ", out(reg) o, in(reg) i, number = const 5); + asm!( + "mov {0}, {1}", + "add {0}, {number}", + out(reg) o, + in(reg) i, + number = const 5, + ); } assert_eq!(o, 8); ``` @@ -82,13 +85,18 @@ and then adding `5` to it. The example shows a few things: -First we can see that inputs are declared by writing `in` instead of `out`. +First, we can see that `asm!` allows multiple template string arguments; each +one is treated as a separate line of assembly code, as if they were all joined +together with newlines between them. This makes it easy to format assembly +code. + +Second, we can see that inputs are declared by writing `in` instead of `out`. -Second one of our operands has a type we haven't seen yet, `const`. +Third, one of our operands has a type we haven't seen yet, `const`. This tells the compiler to expand this argument to value directly inside the assembly template. This is only possible for constants and literals. -Third we can see that we can specify an argument number, or name as in any format string. +Fourth, we can see that we can specify an argument number, or name as in any format string. For inline assembly templates this is particularly useful as arguments are often used more than once. For more complex inline assembly using this facility is generally recommended, as it improves readability, and allows reordering instructions without changing the argument order. @@ -137,10 +145,13 @@ let mut a: u64 = 4; let b: u64 = 4; let c: u64 = 4; unsafe { - asm!(" - add {0}, {1} - add {0}, {2} - ", inout(reg) a, in(reg) b, in(reg) c); + asm!( + "add {0}, {1}", + "add {0}, {2}", + inout(reg) a, + in(reg) b, + in(reg) c, + ); } assert_eq!(a, 12); ``` @@ -233,7 +244,7 @@ unsafe { // ECX 0 selects the L0 cache information. inout("ecx") 0 => ecx, lateout("ebx") ebx, - lateout("edx") _ + lateout("edx") _, ); } @@ -255,12 +266,14 @@ This can also be used with a general register class (e.g. `reg`) to obtain a scr // Multiply x by 6 using shifts and adds let mut x: u64 = 4; unsafe { - asm!(" - mov {tmp}, {x} - shl {tmp}, 1 - shl {x}, 2 - add {x}, {tmp} - ", x = inout(reg) x, tmp = out(reg) _); + asm!( + "mov {tmp}, {x}", + "shl {tmp}, 1", + "shl {x}, 2", + "add {x}, {tmp}", + x = inout(reg) x, + tmp = out(reg) _, + ); } assert_eq!(x, 4 * 6); ``` @@ -338,7 +351,7 @@ unsafe { asm!( "add {0}, {1}", inlateout(reg) a, in(reg) b, - options(pure, nomem, nostack) + options(pure, nomem, nostack), ); } assert_eq!(a, 8); @@ -371,24 +384,26 @@ reg_operand := dir_spec "(" reg_spec ")" operand_expr operand := reg_operand / "const" const_expr / "sym" path option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "att_syntax" options := "options(" option *["," option] [","] ")" -asm := "asm!(" format_string *("," [ident "="] operand) ["," options] [","] ")" +asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) ["," options] [","] ")" ``` -The macro will initially be supported only on ARM, AArch64, x86, x86-64 and RISC-V targets. Support for more targets may be added in the future. The compiler will emit an error if `asm!` is used on an unsupported target. +The macro will initially be supported only on ARM, AArch64, Hexagon, x86, x86-64 and RISC-V targets. Support for more targets may be added in the future. The compiler will emit an error if `asm!` is used on an unsupported target. [format-syntax]: https://doc.rust-lang.org/std/fmt/#syntax -## Template string +## Template string arguments The assembler template uses the same syntax as [format strings][format-syntax] (i.e. placeholders are specified by curly braces). The corresponding arguments are accessed in order, by index, or by name. However, implicit named arguments (introduced by [RFC #2795][rfc-2795]) are not supported. +An `asm!` invocation may have one or more template string arguments; an `asm!` with multiple template string arguments is treated as if all the strings were concatenated with a `\n` between them. The expected usage is for each template string argument to correspond to a line of assembly code. All template string arguments must appear before any other arguments. + As with format strings, named arguments must appear after positional arguments. Explicit register operands must appear at the end of the operand list, after named arguments if any. Explicit register operands cannot be used by placeholders in the template string. All other named and positional operands must appear at least once in the template string, otherwise a compiler error is generated. The exact assembly code syntax is target-specific and opaque to the compiler except for the way operands are substituted into the template string to form the code passed to the assembler. -The 4 targets specified in this RFC (x86, ARM, AArch64, RISC-V) all use the assembly code syntax of the GNU assembler (GAS). On x86, the `.intel_syntax noprefix` mode of GAS is used by default. On ARM, the `.syntax unified` mode is used. These targets impose an additional restriction on the assembly code: any assembler state (e.g. the current section which can be changed with `.section`) must be restored to its original value at the end of the asm string. Assembly code that does not conform to the GAS syntax will result in assembler-specific behavior. +The 5 targets specified in this RFC (x86, ARM, AArch64, RISC-V, Hexagon) all use the assembly code syntax of the GNU assembler (GAS). On x86, the `.intel_syntax noprefix` mode of GAS is used by default. On ARM, the `.syntax unified` mode is used. These targets impose an additional restriction on the assembly code: any assembler state (e.g. the current section which can be changed with `.section`) must be restored to its original value at the end of the asm string. Assembly code that does not conform to the GAS syntax will result in assembler-specific behavior. [rfc-2795]: https://github.com/rust-lang/rfcs/pull/2795 @@ -475,6 +490,7 @@ Here is the list of currently supported register classes: | NVPTX | `reg64` | None\* | `l` | | RISC-V | `reg` | `x1`, `x[5-7]`, `x[9-15]`, `x[16-31]` (non-RV32E) | `r` | | RISC-V | `freg` | `f[0-31]` | `f` | +| Hexagon | `reg` | `r[0-28]` | `r` | > **Note**: On x86 we treat `reg_byte` differently from `reg` because the compiler can allocate `al` and `ah` separately whereas `reg` reserves the whole register. > @@ -509,6 +525,7 @@ Each register class has constraints on which value types they can be used with. | RISC-V64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` | | RISC-V | `freg` | `f` | `f32` | | RISC-V | `freg` | `d` | `f64` | +| Hexagon | `reg` | None | `i8`, `i16`, `i32`, `f32` | > **Note**: For the purposes of the above table pointers, function pointers and `isize`/`usize` are treated as the equivalent integer type (`i16`/`i32`/`i64` depending on the target). @@ -565,13 +582,16 @@ Some registers have multiple names. These are all treated by the compiler as ide | RISC-V | `f[10-17]` | `fa[0-7]` | | RISC-V | `f[18-27]` | `fs[2-11]` | | RISC-V | `f[28-31]` | `ft[8-11]` | +| Hexagon | `r29` | `sp` | +| Hexagon | `r30` | `fr` | +| Hexagon | `r31` | `lr` | Some registers cannot be used for input or output operands: | Architecture | Unsupported register | Reason | | ------------ | -------------------- | ------ | | All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. | -| All | `bp` (x86), `r11` (ARM), `x29` (AArch64), `x8` (RISC-V) | The frame pointer cannot be used as an input or output. | +| All | `bp` (x86), `r11` (ARM), `x29` (AArch64), `x8` (RISC-V), `fr` (Hexagon) | The frame pointer cannot be used as an input or output. | | x86 | `k0` | This is a constant zero register which can't be modified. | | x86 | `ip` | This is the program counter, not a real register. | | x86 | `mm[0-7]` | MMX registers are not currently supported (but may be in the future). | @@ -580,6 +600,7 @@ Some registers cannot be used for input or output operands: | ARM | `pc` | This is the program counter, not a real register. | | RISC-V | `x0` | This is a constant zero register which can't be modified. | | RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. | +| Hexagon | `lr` | This is the link register which cannot be used as an input or output. | ## Template modifiers @@ -625,6 +646,7 @@ The supported modifiers are a subset of LLVM's (and GCC's) [asm template argumen | NVPTX | `reg64` | None | `rd0` | None | | RISC-V | `reg` | None | `x1` | None | | RISC-V | `freg` | None | `f0` | None | +| Hexagon | `reg` | None | `r0` | None | > Notes: > - on ARM `e` / `f`: this prints the low or high doubleword register name of a NEON quad (128-bit) register. diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index d31c73cc1bd8d..98c7ac3f2ef17 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -77,7 +77,7 @@ pub struct Global; #[stable(feature = "global_alloc", since = "1.28.0")] #[inline] pub unsafe fn alloc(layout: Layout) -> *mut u8 { - __rust_alloc(layout.size(), layout.align()) + unsafe { __rust_alloc(layout.size(), layout.align()) } } /// Deallocate memory with the global allocator. @@ -99,7 +99,7 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 { #[stable(feature = "global_alloc", since = "1.28.0")] #[inline] pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) { - __rust_dealloc(ptr, layout.size(), layout.align()) + unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } } /// Reallocate memory with the global allocator. @@ -121,7 +121,7 @@ pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) { #[stable(feature = "global_alloc", since = "1.28.0")] #[inline] pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { - __rust_realloc(ptr, layout.size(), layout.align(), new_size) + unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) } } /// Allocate zero-initialized memory with the global allocator. @@ -158,7 +158,7 @@ pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 #[stable(feature = "global_alloc", since = "1.28.0")] #[inline] pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { - __rust_alloc_zeroed(layout.size(), layout.align()) + unsafe { __rust_alloc_zeroed(layout.size(), layout.align()) } } #[unstable(feature = "allocator_api", issue = "32838")] @@ -183,7 +183,7 @@ unsafe impl AllocRef for Global { #[inline] unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { if layout.size() != 0 { - dealloc(ptr.as_ptr(), layout) + unsafe { dealloc(ptr.as_ptr(), layout) } } } @@ -209,16 +209,21 @@ unsafe impl AllocRef for Global { match placement { ReallocPlacement::InPlace => Err(AllocErr), ReallocPlacement::MayMove if layout.size() == 0 => { - let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); + let new_layout = + unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) }; self.alloc(new_layout, init) } ReallocPlacement::MayMove => { // `realloc` probably checks for `new_size > size` or something similar. - intrinsics::assume(new_size > size); - let ptr = realloc(ptr.as_ptr(), layout, new_size); + let ptr = unsafe { + intrinsics::assume(new_size > size); + realloc(ptr.as_ptr(), layout, new_size) + }; let memory = MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size }; - init.init_offset(memory, size); + unsafe { + init.init_offset(memory, size); + } Ok(memory) } } @@ -245,13 +250,17 @@ unsafe impl AllocRef for Global { match placement { ReallocPlacement::InPlace => Err(AllocErr), ReallocPlacement::MayMove if new_size == 0 => { - self.dealloc(ptr, layout); + unsafe { + self.dealloc(ptr, layout); + } Ok(MemoryBlock { ptr: layout.dangling(), size: 0 }) } ReallocPlacement::MayMove => { // `realloc` probably checks for `new_size < size` or something similar. - intrinsics::assume(new_size < size); - let ptr = realloc(ptr.as_ptr(), layout, new_size); + let ptr = unsafe { + intrinsics::assume(new_size < size); + realloc(ptr.as_ptr(), layout, new_size) + }; Ok(MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size }) } } @@ -264,7 +273,7 @@ unsafe impl AllocRef for Global { #[lang = "exchange_malloc"] #[inline] unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { - let layout = Layout::from_size_align_unchecked(size, align); + let layout = unsafe { Layout::from_size_align_unchecked(size, align) }; match Global.alloc(layout, AllocInit::Uninitialized) { Ok(memory) => memory.ptr.as_ptr(), Err(_) => handle_alloc_error(layout), @@ -279,10 +288,12 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { // For example if `Box` is changed to `struct Box(Unique, A)`, // this function has to be changed to `fn box_free(Unique, A)` as well. pub(crate) unsafe fn box_free(ptr: Unique) { - let size = size_of_val(ptr.as_ref()); - let align = min_align_of_val(ptr.as_ref()); - let layout = Layout::from_size_align_unchecked(size, align); - Global.dealloc(ptr.cast().into(), layout) + unsafe { + let size = size_of_val(ptr.as_ref()); + let align = min_align_of_val(ptr.as_ref()); + let layout = Layout::from_size_align_unchecked(size, align); + Global.dealloc(ptr.cast().into(), layout) + } } /// Abort on memory allocation error or failure. diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index ab0dde0ada660..d10cbf1afab30 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -311,7 +311,7 @@ impl Box> { #[unstable(feature = "new_uninit", issue = "63291")] #[inline] pub unsafe fn assume_init(self) -> Box { - Box::from_raw(Box::into_raw(self) as *mut T) + unsafe { Box::from_raw(Box::into_raw(self) as *mut T) } } } @@ -349,7 +349,7 @@ impl Box<[mem::MaybeUninit]> { #[unstable(feature = "new_uninit", issue = "63291")] #[inline] pub unsafe fn assume_init(self) -> Box<[T]> { - Box::from_raw(Box::into_raw(self) as *mut [T]) + unsafe { Box::from_raw(Box::into_raw(self) as *mut [T]) } } } @@ -393,7 +393,7 @@ impl Box { #[stable(feature = "box_raw", since = "1.4.0")] #[inline] pub unsafe fn from_raw(raw: *mut T) -> Self { - Box(Unique::new_unchecked(raw)) + Box(unsafe { Unique::new_unchecked(raw) }) } /// Consumes the `Box`, returning a wrapped raw pointer. diff --git a/src/liballoc/collections/binary_heap.rs b/src/liballoc/collections/binary_heap.rs index c2fe4691b34c0..15313e333ce73 100644 --- a/src/liballoc/collections/binary_heap.rs +++ b/src/liballoc/collections/binary_heap.rs @@ -1003,7 +1003,7 @@ impl<'a, T> Hole<'a, T> { unsafe fn new(data: &'a mut [T], pos: usize) -> Self { debug_assert!(pos < data.len()); // SAFE: pos should be inside the slice - let elt = ptr::read(data.get_unchecked(pos)); + let elt = unsafe { ptr::read(data.get_unchecked(pos)) }; Hole { data, elt: ManuallyDrop::new(elt), pos } } @@ -1025,7 +1025,7 @@ impl<'a, T> Hole<'a, T> { unsafe fn get(&self, index: usize) -> &T { debug_assert!(index != self.pos); debug_assert!(index < self.data.len()); - self.data.get_unchecked(index) + unsafe { self.data.get_unchecked(index) } } /// Move hole to new location @@ -1035,9 +1035,11 @@ impl<'a, T> Hole<'a, T> { unsafe fn move_to(&mut self, index: usize) { debug_assert!(index != self.pos); debug_assert!(index < self.data.len()); - let index_ptr: *const _ = self.data.get_unchecked(index); - let hole_ptr = self.data.get_unchecked_mut(self.pos); - ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1); + unsafe { + let index_ptr: *const _ = self.data.get_unchecked(index); + let hole_ptr = self.data.get_unchecked_mut(self.pos); + ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1); + } self.pos = index; } } diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index fa1c09d9ece87..2fcc8cc98737d 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -1725,7 +1725,7 @@ impl<'a, K: 'a, V: 'a> DrainFilterInner<'a, K, V> { &mut self, ) -> Option, K, V, marker::LeafOrInternal>, marker::KV>> { let edge = self.cur_leaf_edge.as_ref()?; - ptr::read(edge).next_kv().ok() + unsafe { ptr::read(edge).next_kv().ok() } } /// Implementation of a typical `DrainFilter::next` method, given the predicate. @@ -1808,7 +1808,7 @@ impl<'a, K, V> Range<'a, K, V> { } unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) { - unwrap_unchecked(self.front.as_mut()).next_unchecked() + unsafe { unwrap_unchecked(self.front.as_mut()).next_unchecked() } } } @@ -1821,7 +1821,7 @@ impl<'a, K, V> DoubleEndedIterator for Range<'a, K, V> { impl<'a, K, V> Range<'a, K, V> { unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) { - unwrap_unchecked(self.back.as_mut()).next_back_unchecked() + unsafe { unwrap_unchecked(self.back.as_mut()).next_back_unchecked() } } } @@ -1859,7 +1859,7 @@ impl<'a, K, V> RangeMut<'a, K, V> { } unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) { - unwrap_unchecked(self.front.as_mut()).next_unchecked() + unsafe { unwrap_unchecked(self.front.as_mut()).next_unchecked() } } } @@ -1880,7 +1880,7 @@ impl FusedIterator for RangeMut<'_, K, V> {} impl<'a, K, V> RangeMut<'a, K, V> { unsafe fn next_back_unchecked(&mut self) -> (&'a mut K, &'a mut V) { - unwrap_unchecked(self.back.as_mut()).next_back_unchecked() + unsafe { unwrap_unchecked(self.back.as_mut()).next_back_unchecked() } } } diff --git a/src/liballoc/collections/btree/mod.rs b/src/liballoc/collections/btree/mod.rs index fb5825ee21a9e..543ff41a4d48d 100644 --- a/src/liballoc/collections/btree/mod.rs +++ b/src/liballoc/collections/btree/mod.rs @@ -19,7 +19,9 @@ pub unsafe fn unwrap_unchecked(val: Option) -> T { if cfg!(debug_assertions) { panic!("'unchecked' unwrap on None in BTreeMap"); } else { - core::intrinsics::unreachable(); + unsafe { + core::intrinsics::unreachable(); + } } }) } diff --git a/src/liballoc/collections/btree/navigate.rs b/src/liballoc/collections/btree/navigate.rs index 5e8dcf247ae59..5478d822438b1 100644 --- a/src/liballoc/collections/btree/navigate.rs +++ b/src/liballoc/collections/btree/navigate.rs @@ -64,8 +64,10 @@ macro_rules! def_next_kv_uncheched_dealloc { edge = match edge.$adjacent_kv() { Ok(internal_kv) => return internal_kv, Err(last_edge) => { - let parent_edge = last_edge.into_node().deallocate_and_ascend(); - unwrap_unchecked(parent_edge).forget_node_type() + unsafe { + let parent_edge = last_edge.into_node().deallocate_and_ascend(); + unwrap_unchecked(parent_edge).forget_node_type() + } } } } @@ -82,9 +84,11 @@ def_next_kv_uncheched_dealloc! {unsafe fn next_back_kv_unchecked_dealloc: left_k /// Safety: The change closure must not panic. #[inline] unsafe fn replace(v: &mut T, change: impl FnOnce(T) -> (T, R)) -> R { - let value = ptr::read(v); + let value = unsafe { ptr::read(v) }; let (new_value, ret) = change(value); - ptr::write(v, new_value); + unsafe { + ptr::write(v, new_value); + } ret } @@ -93,22 +97,26 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Ed /// key and value in between. /// Unsafe because the caller must ensure that the leaf edge is not the last one in the tree. pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) { - replace(self, |leaf_edge| { - let kv = leaf_edge.next_kv(); - let kv = unwrap_unchecked(kv.ok()); - (kv.next_leaf_edge(), kv.into_kv()) - }) + unsafe { + replace(self, |leaf_edge| { + let kv = leaf_edge.next_kv(); + let kv = unwrap_unchecked(kv.ok()); + (kv.next_leaf_edge(), kv.into_kv()) + }) + } } /// Moves the leaf edge handle to the previous leaf edge and returns references to the /// key and value in between. /// Unsafe because the caller must ensure that the leaf edge is not the first one in the tree. pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) { - replace(self, |leaf_edge| { - let kv = leaf_edge.next_back_kv(); - let kv = unwrap_unchecked(kv.ok()); - (kv.next_back_leaf_edge(), kv.into_kv()) - }) + unsafe { + replace(self, |leaf_edge| { + let kv = leaf_edge.next_back_kv(); + let kv = unwrap_unchecked(kv.ok()); + (kv.next_back_leaf_edge(), kv.into_kv()) + }) + } } } @@ -119,14 +127,16 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge /// - The caller must ensure that the leaf edge is not the last one in the tree. /// - Using the updated handle may well invalidate the returned references. pub unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) { - let kv = replace(self, |leaf_edge| { - let kv = leaf_edge.next_kv(); - let kv = unwrap_unchecked(kv.ok()); - (ptr::read(&kv).next_leaf_edge(), kv) - }); - // Doing the descend (and perhaps another move) invalidates the references - // returned by `into_kv_mut`, so we have to do this last. - kv.into_kv_mut() + unsafe { + let kv = replace(self, |leaf_edge| { + let kv = leaf_edge.next_kv(); + let kv = unwrap_unchecked(kv.ok()); + (ptr::read(&kv).next_leaf_edge(), kv) + }); + // Doing the descend (and perhaps another move) invalidates the references + // returned by `into_kv_mut`, so we have to do this last. + kv.into_kv_mut() + } } /// Moves the leaf edge handle to the previous leaf and returns references to the @@ -135,14 +145,16 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge /// - The caller must ensure that the leaf edge is not the first one in the tree. /// - Using the updated handle may well invalidate the returned references. pub unsafe fn next_back_unchecked(&mut self) -> (&'a mut K, &'a mut V) { - let kv = replace(self, |leaf_edge| { - let kv = leaf_edge.next_back_kv(); - let kv = unwrap_unchecked(kv.ok()); - (ptr::read(&kv).next_back_leaf_edge(), kv) - }); - // Doing the descend (and perhaps another move) invalidates the references - // returned by `into_kv_mut`, so we have to do this last. - kv.into_kv_mut() + unsafe { + let kv = replace(self, |leaf_edge| { + let kv = leaf_edge.next_back_kv(); + let kv = unwrap_unchecked(kv.ok()); + (ptr::read(&kv).next_back_leaf_edge(), kv) + }); + // Doing the descend (and perhaps another move) invalidates the references + // returned by `into_kv_mut`, so we have to do this last. + kv.into_kv_mut() + } } } @@ -159,12 +171,14 @@ impl Handle, marker::Edge> { /// if the two preconditions above hold. /// - Using the updated handle may well invalidate the returned references. pub unsafe fn next_unchecked(&mut self) -> (K, V) { - replace(self, |leaf_edge| { - let kv = next_kv_unchecked_dealloc(leaf_edge); - let k = ptr::read(kv.reborrow().into_kv().0); - let v = ptr::read(kv.reborrow().into_kv().1); - (kv.next_leaf_edge(), (k, v)) - }) + unsafe { + replace(self, |leaf_edge| { + let kv = next_kv_unchecked_dealloc(leaf_edge); + let k = ptr::read(kv.reborrow().into_kv().0); + let v = ptr::read(kv.reborrow().into_kv().1); + (kv.next_leaf_edge(), (k, v)) + }) + } } /// Moves the leaf edge handle to the previous leaf edge and returns the key @@ -179,12 +193,14 @@ impl Handle, marker::Edge> { /// if the two preconditions above hold. /// - Using the updated handle may well invalidate the returned references. pub unsafe fn next_back_unchecked(&mut self) -> (K, V) { - replace(self, |leaf_edge| { - let kv = next_back_kv_unchecked_dealloc(leaf_edge); - let k = ptr::read(kv.reborrow().into_kv().0); - let v = ptr::read(kv.reborrow().into_kv().1); - (kv.next_back_leaf_edge(), (k, v)) - }) + unsafe { + replace(self, |leaf_edge| { + let kv = next_back_kv_unchecked_dealloc(leaf_edge); + let k = ptr::read(kv.reborrow().into_kv().0); + let v = ptr::read(kv.reborrow().into_kv().1); + (kv.next_back_leaf_edge(), (k, v)) + }) + } } } diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs index 5569c293e2f66..a4b6cf12a23bd 100644 --- a/src/liballoc/collections/btree/node.rs +++ b/src/liballoc/collections/btree/node.rs @@ -107,7 +107,7 @@ impl InternalNode { /// `len` of 0), there must be one initialized and valid edge. This function does not set up /// such an edge. unsafe fn new() -> Self { - InternalNode { data: LeafNode::new(), edges: [MaybeUninit::UNINIT; 2 * B] } + InternalNode { data: unsafe { LeafNode::new() }, edges: [MaybeUninit::UNINIT; 2 * B] } } } @@ -131,7 +131,7 @@ impl BoxedNode { } unsafe fn from_ptr(ptr: NonNull>) -> Self { - BoxedNode { ptr: Unique::new_unchecked(ptr.as_ptr()) } + BoxedNode { ptr: unsafe { Unique::new_unchecked(ptr.as_ptr()) } } } fn as_ptr(&self) -> NonNull> { @@ -392,14 +392,16 @@ impl NodeRef { let height = self.height; let node = self.node; let ret = self.ascend().ok(); - Global.dealloc( - node.cast(), - if height > 0 { - Layout::new::>() - } else { - Layout::new::>() - }, - ); + unsafe { + Global.dealloc( + node.cast(), + if height > 0 { + Layout::new::>() + } else { + Layout::new::>() + }, + ); + } ret } } @@ -565,7 +567,7 @@ impl<'a, K, V> NodeRef, K, V, marker::Internal> { debug_assert!(first <= self.len()); debug_assert!(after_last <= self.len() + 1); for i in first..after_last { - Handle::new_edge(self.reborrow_mut(), i).correct_parent_link(); + unsafe { Handle::new_edge(self.reborrow_mut(), i) }.correct_parent_link(); } } @@ -789,7 +791,7 @@ impl<'a, K, V, NodeType, HandleType> Handle, K, V, NodeT &mut self, ) -> Handle, K, V, NodeType>, HandleType> { // We can't use Handle::new_kv or Handle::new_edge because we don't know our type - Handle { node: self.node.reborrow_mut(), idx: self.idx, _marker: PhantomData } + Handle { node: unsafe { self.node.reborrow_mut() }, idx: self.idx, _marker: PhantomData } } } @@ -885,7 +887,7 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: unsafe fn cast_unchecked( &mut self, ) -> Handle, K, V, NewType>, marker::Edge> { - Handle::new_edge(self.node.cast_unchecked(), self.idx) + unsafe { Handle::new_edge(self.node.cast_unchecked(), self.idx) } } /// Inserts a new key/value pair and an edge that will go to the right of that new pair @@ -1330,8 +1332,10 @@ unsafe fn move_kv( dest_offset: usize, count: usize, ) { - ptr::copy_nonoverlapping(source.0.add(source_offset), dest.0.add(dest_offset), count); - ptr::copy_nonoverlapping(source.1.add(source_offset), dest.1.add(dest_offset), count); + unsafe { + ptr::copy_nonoverlapping(source.0.add(source_offset), dest.0.add(dest_offset), count); + ptr::copy_nonoverlapping(source.1.add(source_offset), dest.1.add(dest_offset), count); + } } // Source and destination must have the same height. @@ -1344,8 +1348,10 @@ unsafe fn move_edges( ) { let source_ptr = source.as_internal_mut().edges.as_mut_ptr(); let dest_ptr = dest.as_internal_mut().edges.as_mut_ptr(); - ptr::copy_nonoverlapping(source_ptr.add(source_offset), dest_ptr.add(dest_offset), count); - dest.correct_childrens_parent_links(dest_offset, dest_offset + count); + unsafe { + ptr::copy_nonoverlapping(source_ptr.add(source_offset), dest_ptr.add(dest_offset), count); + dest.correct_childrens_parent_links(dest_offset, dest_offset + count); + } } impl Handle, marker::Edge> { @@ -1459,12 +1465,16 @@ pub mod marker { } unsafe fn slice_insert(slice: &mut [T], idx: usize, val: T) { - ptr::copy(slice.as_ptr().add(idx), slice.as_mut_ptr().add(idx + 1), slice.len() - idx); - ptr::write(slice.get_unchecked_mut(idx), val); + unsafe { + ptr::copy(slice.as_ptr().add(idx), slice.as_mut_ptr().add(idx + 1), slice.len() - idx); + ptr::write(slice.get_unchecked_mut(idx), val); + } } unsafe fn slice_remove(slice: &mut [T], idx: usize) -> T { - let ret = ptr::read(slice.get_unchecked(idx)); - ptr::copy(slice.as_ptr().add(idx + 1), slice.as_mut_ptr().add(idx), slice.len() - idx - 1); - ret + unsafe { + let ret = ptr::read(slice.get_unchecked(idx)); + ptr::copy(slice.as_ptr().add(idx + 1), slice.as_mut_ptr().add(idx), slice.len() - idx - 1); + ret + } } diff --git a/src/liballoc/collections/linked_list.rs b/src/liballoc/collections/linked_list.rs index 85f2505f756aa..36b5785fdf6c5 100644 --- a/src/liballoc/collections/linked_list.rs +++ b/src/liballoc/collections/linked_list.rs @@ -225,17 +225,17 @@ impl LinkedList { /// maintain validity of aliasing pointers. #[inline] unsafe fn unlink_node(&mut self, mut node: NonNull>) { - let node = node.as_mut(); // this one is ours now, we can create an &mut. + let node = unsafe { node.as_mut() }; // this one is ours now, we can create an &mut. // Not creating new mutable (unique!) references overlapping `element`. match node.prev { - Some(prev) => (*prev.as_ptr()).next = node.next, + Some(prev) => unsafe { (*prev.as_ptr()).next = node.next }, // this node is the head node None => self.head = node.next, }; match node.next { - Some(next) => (*next.as_ptr()).prev = node.prev, + Some(next) => unsafe { (*next.as_ptr()).prev = node.prev }, // this node is the tail node None => self.tail = node.prev, }; @@ -258,17 +258,23 @@ impl LinkedList { // This method takes care not to create multiple mutable references to whole nodes at the same time, // to maintain validity of aliasing pointers into `element`. if let Some(mut existing_prev) = existing_prev { - existing_prev.as_mut().next = Some(splice_start); + unsafe { + existing_prev.as_mut().next = Some(splice_start); + } } else { self.head = Some(splice_start); } if let Some(mut existing_next) = existing_next { - existing_next.as_mut().prev = Some(splice_end); + unsafe { + existing_next.as_mut().prev = Some(splice_end); + } } else { self.tail = Some(splice_end); } - splice_start.as_mut().prev = existing_prev; - splice_end.as_mut().next = existing_next; + unsafe { + splice_start.as_mut().prev = existing_prev; + splice_end.as_mut().next = existing_next; + } self.len += splice_length; } @@ -297,9 +303,13 @@ impl LinkedList { if let Some(mut split_node) = split_node { let first_part_head; let first_part_tail; - first_part_tail = split_node.as_mut().prev.take(); + unsafe { + first_part_tail = split_node.as_mut().prev.take(); + } if let Some(mut tail) = first_part_tail { - tail.as_mut().next = None; + unsafe { + tail.as_mut().next = None; + } first_part_head = self.head; } else { first_part_head = None; @@ -333,9 +343,13 @@ impl LinkedList { if let Some(mut split_node) = split_node { let second_part_head; let second_part_tail; - second_part_head = split_node.as_mut().next.take(); + unsafe { + second_part_head = split_node.as_mut().next.take(); + } if let Some(mut head) = second_part_head { - head.as_mut().prev = None; + unsafe { + head.as_mut().prev = None; + } second_part_tail = self.tail; } else { second_part_tail = None; diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index ae54d3971baac..15f3a94ca2d6a 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -7,6 +7,8 @@ #![stable(feature = "rust1", since = "1.0.0")] +// ignore-tidy-filelength + use core::array::LengthAtMost32; use core::cmp::{self, Ordering}; use core::fmt; @@ -201,25 +203,27 @@ impl VecDeque { /// Turn ptr into a slice #[inline] unsafe fn buffer_as_slice(&self) -> &[T] { - slice::from_raw_parts(self.ptr(), self.cap()) + unsafe { slice::from_raw_parts(self.ptr(), self.cap()) } } /// Turn ptr into a mut slice #[inline] unsafe fn buffer_as_mut_slice(&mut self) -> &mut [T] { - slice::from_raw_parts_mut(self.ptr(), self.cap()) + unsafe { slice::from_raw_parts_mut(self.ptr(), self.cap()) } } /// Moves an element out of the buffer #[inline] unsafe fn buffer_read(&mut self, off: usize) -> T { - ptr::read(self.ptr().add(off)) + unsafe { ptr::read(self.ptr().add(off)) } } /// Writes an element into the buffer, moving it. #[inline] unsafe fn buffer_write(&mut self, off: usize, value: T) { - ptr::write(self.ptr().add(off), value); + unsafe { + ptr::write(self.ptr().add(off), value); + } } /// Returns `true` if the buffer is at full capacity. @@ -268,7 +272,9 @@ impl VecDeque { len, self.cap() ); - ptr::copy(self.ptr().add(src), self.ptr().add(dst), len); + unsafe { + ptr::copy(self.ptr().add(src), self.ptr().add(dst), len); + } } /// Copies a contiguous block of memory len long from src to dst @@ -290,7 +296,9 @@ impl VecDeque { len, self.cap() ); - ptr::copy_nonoverlapping(self.ptr().add(src), self.ptr().add(dst), len); + unsafe { + ptr::copy_nonoverlapping(self.ptr().add(src), self.ptr().add(dst), len); + } } /// Copies a potentially wrapping block of memory len long from src to dest. @@ -330,7 +338,9 @@ impl VecDeque { // 2 [_ _ A A A A B B _] // D . . . // - self.copy(dst, src, len); + unsafe { + self.copy(dst, src, len); + } } (false, false, true) => { // dst before src, src doesn't wrap, dst wraps @@ -341,8 +351,10 @@ impl VecDeque { // 3 [B B B B _ _ _ A A] // . . D . // - self.copy(dst, src, dst_pre_wrap_len); - self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len); + unsafe { + self.copy(dst, src, dst_pre_wrap_len); + self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len); + } } (true, false, true) => { // src before dst, src doesn't wrap, dst wraps @@ -353,8 +365,10 @@ impl VecDeque { // 3 [B B _ _ _ A A A A] // . . D . // - self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len); - self.copy(dst, src, dst_pre_wrap_len); + unsafe { + self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len); + self.copy(dst, src, dst_pre_wrap_len); + } } (false, true, false) => { // dst before src, src wraps, dst doesn't wrap @@ -365,8 +379,10 @@ impl VecDeque { // 3 [C C _ _ _ B B C C] // D . . . // - self.copy(dst, src, src_pre_wrap_len); - self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len); + unsafe { + self.copy(dst, src, src_pre_wrap_len); + self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len); + } } (true, true, false) => { // src before dst, src wraps, dst doesn't wrap @@ -377,8 +393,10 @@ impl VecDeque { // 3 [C C A A _ _ _ C C] // D . . . // - self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len); - self.copy(dst, src, src_pre_wrap_len); + unsafe { + self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len); + self.copy(dst, src, src_pre_wrap_len); + } } (false, true, true) => { // dst before src, src wraps, dst wraps @@ -392,9 +410,11 @@ impl VecDeque { // debug_assert!(dst_pre_wrap_len > src_pre_wrap_len); let delta = dst_pre_wrap_len - src_pre_wrap_len; - self.copy(dst, src, src_pre_wrap_len); - self.copy(dst + src_pre_wrap_len, 0, delta); - self.copy(0, delta, len - dst_pre_wrap_len); + unsafe { + self.copy(dst, src, src_pre_wrap_len); + self.copy(dst + src_pre_wrap_len, 0, delta); + self.copy(0, delta, len - dst_pre_wrap_len); + } } (true, true, true) => { // src before dst, src wraps, dst wraps @@ -408,9 +428,11 @@ impl VecDeque { // debug_assert!(src_pre_wrap_len > dst_pre_wrap_len); let delta = src_pre_wrap_len - dst_pre_wrap_len; - self.copy(delta, 0, len - src_pre_wrap_len); - self.copy(0, self.cap() - delta, delta); - self.copy(dst, src, dst_pre_wrap_len); + unsafe { + self.copy(delta, 0, len - src_pre_wrap_len); + self.copy(0, self.cap() - delta, delta); + self.copy(dst, src, dst_pre_wrap_len); + } } } } @@ -440,13 +462,17 @@ impl VecDeque { // Nop } else if self.head < old_capacity - self.tail { // B - self.copy_nonoverlapping(old_capacity, 0, self.head); + unsafe { + self.copy_nonoverlapping(old_capacity, 0, self.head); + } self.head += old_capacity; debug_assert!(self.head > self.tail); } else { // C let new_tail = new_capacity - (old_capacity - self.tail); - self.copy_nonoverlapping(new_tail, self.tail, old_capacity - self.tail); + unsafe { + self.copy_nonoverlapping(new_tail, self.tail, old_capacity - self.tail); + } self.tail = new_tail; debug_assert!(self.head < self.tail); } @@ -2297,7 +2323,9 @@ impl VecDeque { unsafe fn rotate_left_inner(&mut self, mid: usize) { debug_assert!(mid * 2 <= self.len()); - self.wrap_copy(self.head, self.tail, mid); + unsafe { + self.wrap_copy(self.head, self.tail, mid); + } self.head = self.wrap_add(self.head, mid); self.tail = self.wrap_add(self.tail, mid); } @@ -2306,7 +2334,9 @@ impl VecDeque { debug_assert!(k * 2 <= self.len()); self.head = self.wrap_sub(self.head, k); self.tail = self.wrap_sub(self.tail, k); - self.wrap_copy(self.tail, self.head, k); + unsafe { + self.wrap_copy(self.tail, self.head, k); + } } } diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 9bcfc9457f50e..41c2b221704e6 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -72,6 +72,7 @@ #![deny(intra_doc_link_resolution_failure)] // rustdoc is run without -D warnings #![allow(explicit_outlives_requirements)] #![allow(incomplete_features)] +#![deny(unsafe_op_in_unsafe_fn)] #![cfg_attr(not(test), feature(generator_trait))] #![cfg_attr(test, feature(test))] #![feature(allocator_api)] @@ -118,6 +119,7 @@ #![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(unicode_internals)] +#![feature(unsafe_block_in_unsafe_fn)] #![feature(unsize)] #![feature(unsized_locals)] #![feature(allocator_internals)] diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 805dbfe277584..15e81f9288722 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -108,7 +108,7 @@ impl RawVec { /// If the `ptr` and `capacity` come from a `RawVec`, then this is guaranteed. #[inline] pub unsafe fn from_raw_parts(ptr: *mut T, capacity: usize) -> Self { - Self::from_raw_parts_in(ptr, capacity, Global) + unsafe { Self::from_raw_parts_in(ptr, capacity, Global) } } /// Converts a `Box<[T]>` into a `RawVec`. @@ -139,8 +139,10 @@ impl RawVec { ); let me = ManuallyDrop::new(self); - let slice = slice::from_raw_parts_mut(me.ptr() as *mut MaybeUninit, len); - Box::from_raw(slice) + unsafe { + let slice = slice::from_raw_parts_mut(me.ptr() as *mut MaybeUninit, len); + Box::from_raw(slice) + } } } @@ -192,7 +194,7 @@ impl RawVec { /// If the `ptr` and `capacity` come from a `RawVec` created via `a`, then this is guaranteed. #[inline] pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, a: A) -> Self { - Self { ptr: Unique::new_unchecked(ptr), cap: capacity, alloc: a } + Self { ptr: unsafe { Unique::new_unchecked(ptr) }, cap: capacity, alloc: a } } /// Gets a raw pointer to the start of the allocation. Note that this is diff --git a/src/liballoc/raw_vec/tests.rs b/src/liballoc/raw_vec/tests.rs index 17622d72a059c..6418c4a9823f2 100644 --- a/src/liballoc/raw_vec/tests.rs +++ b/src/liballoc/raw_vec/tests.rs @@ -35,7 +35,7 @@ fn allocator_param() { } } unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { - Global.dealloc(ptr, layout) + unsafe { Global.dealloc(ptr, layout) } } } diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 0327a9f9a96e5..4d50ae9efca95 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -304,7 +304,7 @@ impl Rc { } unsafe fn from_ptr(ptr: *mut RcBox) -> Self { - Self::from_inner(NonNull::new_unchecked(ptr)) + Self::from_inner(unsafe { NonNull::new_unchecked(ptr) }) } } @@ -544,7 +544,7 @@ impl Rc<[mem::MaybeUninit]> { #[unstable(feature = "new_uninit", issue = "63291")] #[inline] pub unsafe fn assume_init(self) -> Rc<[T]> { - Rc::from_ptr(mem::ManuallyDrop::new(self).ptr.as_ptr() as _) + unsafe { Rc::from_ptr(mem::ManuallyDrop::new(self).ptr.as_ptr() as _) } } } @@ -643,13 +643,13 @@ impl Rc { /// ``` #[stable(feature = "rc_raw", since = "1.17.0")] pub unsafe fn from_raw(ptr: *const T) -> Self { - let offset = data_offset(ptr); + let offset = unsafe { data_offset(ptr) }; // Reverse the offset to find the original RcBox. let fake_ptr = ptr as *mut RcBox; - let rc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)); + let rc_ptr = unsafe { set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)) }; - Self::from_ptr(rc_ptr) + unsafe { Self::from_ptr(rc_ptr) } } /// Consumes the `Rc`, returning the wrapped pointer as `NonNull`. @@ -805,7 +805,7 @@ impl Rc { #[inline] #[unstable(feature = "get_mut_unchecked", issue = "63292")] pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T { - &mut this.ptr.as_mut().value + unsafe { &mut this.ptr.as_mut().value } } #[inline] @@ -964,10 +964,12 @@ impl Rc { // Initialize the RcBox let inner = mem_to_rcbox(mem.ptr.as_ptr()); - debug_assert_eq!(Layout::for_value(&*inner), layout); + unsafe { + debug_assert_eq!(Layout::for_value(&*inner), layout); - ptr::write(&mut (*inner).strong, Cell::new(1)); - ptr::write(&mut (*inner).weak, Cell::new(1)); + ptr::write(&mut (*inner).strong, Cell::new(1)); + ptr::write(&mut (*inner).weak, Cell::new(1)); + } inner } @@ -975,9 +977,11 @@ impl Rc { /// Allocates an `RcBox` with sufficient space for an unsized inner value unsafe fn allocate_for_ptr(ptr: *const T) -> *mut RcBox { // Allocate for the `RcBox` using the given value. - Self::allocate_for_layout(Layout::for_value(&*ptr), |mem| { - set_data_ptr(ptr as *mut T, mem) as *mut RcBox - }) + unsafe { + Self::allocate_for_layout(Layout::for_value(&*ptr), |mem| { + set_data_ptr(ptr as *mut T, mem) as *mut RcBox + }) + } } fn from_box(v: Box) -> Rc { @@ -1006,9 +1010,11 @@ impl Rc { impl Rc<[T]> { /// Allocates an `RcBox<[T]>` with the given length. unsafe fn allocate_for_slice(len: usize) -> *mut RcBox<[T]> { - Self::allocate_for_layout(Layout::array::(len).unwrap(), |mem| { - ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut RcBox<[T]> - }) + unsafe { + Self::allocate_for_layout(Layout::array::(len).unwrap(), |mem| { + ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut RcBox<[T]> + }) + } } } @@ -1017,7 +1023,9 @@ impl Rc<[T]> { /// For a slice/trait object, this sets the `data` field and leaves the rest /// unchanged. For a sized raw pointer, this simply sets the pointer. unsafe fn set_data_ptr(mut ptr: *mut T, data: *mut U) -> *mut T { - ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8); + unsafe { + ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8); + } ptr } @@ -1026,11 +1034,11 @@ impl Rc<[T]> { /// /// Unsafe because the caller must either take ownership or bind `T: Copy` unsafe fn copy_from_slice(v: &[T]) -> Rc<[T]> { - let ptr = Self::allocate_for_slice(v.len()); - - ptr::copy_nonoverlapping(v.as_ptr(), &mut (*ptr).value as *mut [T] as *mut T, v.len()); - - Self::from_ptr(ptr) + unsafe { + let ptr = Self::allocate_for_slice(v.len()); + ptr::copy_nonoverlapping(v.as_ptr(), &mut (*ptr).value as *mut [T] as *mut T, v.len()); + Self::from_ptr(ptr) + } } /// Constructs an `Rc<[T]>` from an iterator known to be of a certain size. @@ -1058,25 +1066,27 @@ impl Rc<[T]> { } } - let ptr = Self::allocate_for_slice(len); + unsafe { + let ptr = Self::allocate_for_slice(len); - let mem = ptr as *mut _ as *mut u8; - let layout = Layout::for_value(&*ptr); + let mem = ptr as *mut _ as *mut u8; + let layout = Layout::for_value(&*ptr); - // Pointer to first element - let elems = &mut (*ptr).value as *mut [T] as *mut T; + // Pointer to first element + let elems = &mut (*ptr).value as *mut [T] as *mut T; - let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 }; + let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 }; - for (i, item) in iter.enumerate() { - ptr::write(elems.add(i), item); - guard.n_elems += 1; - } + for (i, item) in iter.enumerate() { + ptr::write(elems.add(i), item); + guard.n_elems += 1; + } - // All clear. Forget the guard so it doesn't free the new RcBox. - forget(guard); + // All clear. Forget the guard so it doesn't free the new RcBox. + forget(guard); - Self::from_ptr(ptr) + Self::from_ptr(ptr) + } } } @@ -1786,10 +1796,12 @@ impl Weak { Self::new() } else { // See Rc::from_raw for details - let offset = data_offset(ptr); - let fake_ptr = ptr as *mut RcBox; - let ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)); - Weak { ptr: NonNull::new(ptr).expect("Invalid pointer passed to from_raw") } + unsafe { + let offset = data_offset(ptr); + let fake_ptr = ptr as *mut RcBox; + let ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)); + Weak { ptr: NonNull::new(ptr).expect("Invalid pointer passed to from_raw") } + } } } } @@ -2106,7 +2118,7 @@ unsafe fn data_offset(ptr: *const T) -> isize { // Because it is ?Sized, it will always be the last field in memory. // Note: This is a detail of the current implementation of the compiler, // and is not a guaranteed language detail. Do not rely on it outside of std. - data_offset_align(align_of_val(&*ptr)) + unsafe { data_offset_align(align_of_val(&*ptr)) } } /// Computes the offset of the data field within `RcBox`. diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 53477288b59ee..d7dc2174d665f 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -831,8 +831,7 @@ where { let len = v.len(); let v = v.as_mut_ptr(); - let v_mid = v.add(mid); - let v_end = v.add(len); + let (v_mid, v_end) = unsafe { (v.add(mid), v.add(len)) }; // The merge process first copies the shorter run into `buf`. Then it traces the newly copied // run and the longer run forwards (or backwards), comparing their next unconsumed elements and @@ -855,8 +854,10 @@ where if mid <= len - mid { // The left run is shorter. - ptr::copy_nonoverlapping(v, buf, mid); - hole = MergeHole { start: buf, end: buf.add(mid), dest: v }; + unsafe { + ptr::copy_nonoverlapping(v, buf, mid); + hole = MergeHole { start: buf, end: buf.add(mid), dest: v }; + } // Initially, these pointers point to the beginnings of their arrays. let left = &mut hole.start; @@ -866,17 +867,21 @@ where while *left < hole.end && right < v_end { // Consume the lesser side. // If equal, prefer the left run to maintain stability. - let to_copy = if is_less(&*right, &**left) { - get_and_increment(&mut right) - } else { - get_and_increment(left) - }; - ptr::copy_nonoverlapping(to_copy, get_and_increment(out), 1); + unsafe { + let to_copy = if is_less(&*right, &**left) { + get_and_increment(&mut right) + } else { + get_and_increment(left) + }; + ptr::copy_nonoverlapping(to_copy, get_and_increment(out), 1); + } } } else { // The right run is shorter. - ptr::copy_nonoverlapping(v_mid, buf, len - mid); - hole = MergeHole { start: buf, end: buf.add(len - mid), dest: v_mid }; + unsafe { + ptr::copy_nonoverlapping(v_mid, buf, len - mid); + hole = MergeHole { start: buf, end: buf.add(len - mid), dest: v_mid }; + } // Initially, these pointers point past the ends of their arrays. let left = &mut hole.dest; @@ -886,12 +891,14 @@ where while v < *left && buf < *right { // Consume the greater side. // If equal, prefer the right run to maintain stability. - let to_copy = if is_less(&*right.offset(-1), &*left.offset(-1)) { - decrement_and_get(left) - } else { - decrement_and_get(right) - }; - ptr::copy_nonoverlapping(to_copy, decrement_and_get(&mut out), 1); + unsafe { + let to_copy = if is_less(&*right.offset(-1), &*left.offset(-1)) { + decrement_and_get(left) + } else { + decrement_and_get(right) + }; + ptr::copy_nonoverlapping(to_copy, decrement_and_get(&mut out), 1); + } } } // Finally, `hole` gets dropped. If the shorter run was not fully consumed, whatever remains of @@ -899,12 +906,12 @@ where unsafe fn get_and_increment(ptr: &mut *mut T) -> *mut T { let old = *ptr; - *ptr = ptr.offset(1); + *ptr = unsafe { ptr.offset(1) }; old } unsafe fn decrement_and_get(ptr: &mut *mut T) -> *mut T { - *ptr = ptr.offset(-1); + *ptr = unsafe { ptr.offset(-1) }; *ptr } diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index 70860c09a2c31..57927c688479b 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -583,5 +583,5 @@ impl str { #[stable(feature = "str_box_extras", since = "1.20.0")] #[inline] pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box { - Box::from_raw(Box::into_raw(v) as *mut str) + unsafe { Box::from_raw(Box::into_raw(v) as *mut str) } } diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 0378ff5362a8b..64d9692244dde 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -724,7 +724,7 @@ impl String { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> String { - String { vec: Vec::from_raw_parts(buf, length, capacity) } + unsafe { String { vec: Vec::from_raw_parts(buf, length, capacity) } } } /// Converts a vector of bytes to a `String` without checking that the @@ -1329,9 +1329,11 @@ impl String { let amt = bytes.len(); self.vec.reserve(amt); - ptr::copy(self.vec.as_ptr().add(idx), self.vec.as_mut_ptr().add(idx + amt), len - idx); - ptr::copy(bytes.as_ptr(), self.vec.as_mut_ptr().add(idx), amt); - self.vec.set_len(len + amt); + unsafe { + ptr::copy(self.vec.as_ptr().add(idx), self.vec.as_mut_ptr().add(idx + amt), len - idx); + ptr::copy(bytes.as_ptr(), self.vec.as_mut_ptr().add(idx), amt); + self.vec.set_len(len + amt); + } } /// Inserts a string slice into this `String` at a byte position. @@ -2228,6 +2230,14 @@ impl ToString for T { } } +#[stable(feature = "char_to_string_specialization", since = "1.46.0")] +impl ToString for char { + #[inline] + fn to_string(&self) -> String { + String::from(self.encode_utf8(&mut [0; 4])) + } +} + #[stable(feature = "str_to_string_specialization", since = "1.9.0")] impl ToString for str { #[inline] diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index cd4172d6a2d24..826f0c8fa833f 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -232,7 +232,7 @@ impl Arc { } unsafe fn from_ptr(ptr: *mut ArcInner) -> Self { - Self::from_inner(NonNull::new_unchecked(ptr)) + unsafe { Self::from_inner(NonNull::new_unchecked(ptr)) } } } @@ -543,7 +543,7 @@ impl Arc<[mem::MaybeUninit]> { #[unstable(feature = "new_uninit", issue = "63291")] #[inline] pub unsafe fn assume_init(self) -> Arc<[T]> { - Arc::from_ptr(mem::ManuallyDrop::new(self).ptr.as_ptr() as _) + unsafe { Arc::from_ptr(mem::ManuallyDrop::new(self).ptr.as_ptr() as _) } } } @@ -642,13 +642,15 @@ impl Arc { /// ``` #[stable(feature = "rc_raw", since = "1.17.0")] pub unsafe fn from_raw(ptr: *const T) -> Self { - let offset = data_offset(ptr); + unsafe { + let offset = data_offset(ptr); - // Reverse the offset to find the original ArcInner. - let fake_ptr = ptr as *mut ArcInner; - let arc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)); + // Reverse the offset to find the original ArcInner. + let fake_ptr = ptr as *mut ArcInner; + let arc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)); - Self::from_ptr(arc_ptr) + Self::from_ptr(arc_ptr) + } } /// Consumes the `Arc`, returning the wrapped pointer as `NonNull`. @@ -807,7 +809,7 @@ impl Arc { #[unstable(feature = "arc_mutate_strong_count", issue = "71983")] pub unsafe fn incr_strong_count(ptr: *const T) { // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop - let arc = mem::ManuallyDrop::new(Arc::::from_raw(ptr)); + let arc = unsafe { mem::ManuallyDrop::new(Arc::::from_raw(ptr)) }; // Now increase refcount, but don't drop new refcount either let _arc_clone: mem::ManuallyDrop<_> = arc.clone(); } @@ -847,7 +849,7 @@ impl Arc { #[inline] #[unstable(feature = "arc_mutate_strong_count", issue = "71983")] pub unsafe fn decr_strong_count(ptr: *const T) { - mem::drop(Arc::from_raw(ptr)); + unsafe { mem::drop(Arc::from_raw(ptr)) }; } #[inline] @@ -865,7 +867,7 @@ impl Arc { unsafe fn drop_slow(&mut self) { // Destroy the data at this time, even though we may not free the box // allocation itself (there may still be weak pointers lying around). - ptr::drop_in_place(Self::get_mut_unchecked(self)); + unsafe { ptr::drop_in_place(Self::get_mut_unchecked(self)) }; // Drop the weak ref collectively held by all strong references drop(Weak { ptr: self.ptr }); @@ -917,10 +919,12 @@ impl Arc { // Initialize the ArcInner let inner = mem_to_arcinner(mem.ptr.as_ptr()); - debug_assert_eq!(Layout::for_value(&*inner), layout); + debug_assert_eq!(unsafe { Layout::for_value(&*inner) }, layout); - ptr::write(&mut (*inner).strong, atomic::AtomicUsize::new(1)); - ptr::write(&mut (*inner).weak, atomic::AtomicUsize::new(1)); + unsafe { + ptr::write(&mut (*inner).strong, atomic::AtomicUsize::new(1)); + ptr::write(&mut (*inner).weak, atomic::AtomicUsize::new(1)); + } inner } @@ -928,9 +932,11 @@ impl Arc { /// Allocates an `ArcInner` with sufficient space for an unsized inner value. unsafe fn allocate_for_ptr(ptr: *const T) -> *mut ArcInner { // Allocate for the `ArcInner` using the given value. - Self::allocate_for_layout(Layout::for_value(&*ptr), |mem| { - set_data_ptr(ptr as *mut T, mem) as *mut ArcInner - }) + unsafe { + Self::allocate_for_layout(Layout::for_value(&*ptr), |mem| { + set_data_ptr(ptr as *mut T, mem) as *mut ArcInner + }) + } } fn from_box(v: Box) -> Arc { @@ -959,9 +965,11 @@ impl Arc { impl Arc<[T]> { /// Allocates an `ArcInner<[T]>` with the given length. unsafe fn allocate_for_slice(len: usize) -> *mut ArcInner<[T]> { - Self::allocate_for_layout(Layout::array::(len).unwrap(), |mem| { - ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[T]> - }) + unsafe { + Self::allocate_for_layout(Layout::array::(len).unwrap(), |mem| { + ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[T]> + }) + } } } @@ -970,7 +978,9 @@ impl Arc<[T]> { /// For a slice/trait object, this sets the `data` field and leaves the rest /// unchanged. For a sized raw pointer, this simply sets the pointer. unsafe fn set_data_ptr(mut ptr: *mut T, data: *mut U) -> *mut T { - ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8); + unsafe { + ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8); + } ptr } @@ -979,11 +989,13 @@ impl Arc<[T]> { /// /// Unsafe because the caller must either take ownership or bind `T: Copy`. unsafe fn copy_from_slice(v: &[T]) -> Arc<[T]> { - let ptr = Self::allocate_for_slice(v.len()); + unsafe { + let ptr = Self::allocate_for_slice(v.len()); - ptr::copy_nonoverlapping(v.as_ptr(), &mut (*ptr).data as *mut [T] as *mut T, v.len()); + ptr::copy_nonoverlapping(v.as_ptr(), &mut (*ptr).data as *mut [T] as *mut T, v.len()); - Self::from_ptr(ptr) + Self::from_ptr(ptr) + } } /// Constructs an `Arc<[T]>` from an iterator known to be of a certain size. @@ -1011,25 +1023,27 @@ impl Arc<[T]> { } } - let ptr = Self::allocate_for_slice(len); + unsafe { + let ptr = Self::allocate_for_slice(len); - let mem = ptr as *mut _ as *mut u8; - let layout = Layout::for_value(&*ptr); + let mem = ptr as *mut _ as *mut u8; + let layout = Layout::for_value(&*ptr); - // Pointer to first element - let elems = &mut (*ptr).data as *mut [T] as *mut T; + // Pointer to first element + let elems = &mut (*ptr).data as *mut [T] as *mut T; - let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 }; + let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 }; - for (i, item) in iter.enumerate() { - ptr::write(elems.add(i), item); - guard.n_elems += 1; - } + for (i, item) in iter.enumerate() { + ptr::write(elems.add(i), item); + guard.n_elems += 1; + } - // All clear. Forget the guard so it doesn't free the new ArcInner. - mem::forget(guard); + // All clear. Forget the guard so it doesn't free the new ArcInner. + mem::forget(guard); - Self::from_ptr(ptr) + Self::from_ptr(ptr) + } } } @@ -1274,7 +1288,7 @@ impl Arc { pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T { // We are careful to *not* create a reference covering the "count" fields, as // this would alias with concurrent access to the reference counts (e.g. by `Weak`). - &mut (*this.ptr.as_ptr()).data + unsafe { &mut (*this.ptr.as_ptr()).data } } /// Determine whether this is the unique reference (including weak refs) to @@ -1551,10 +1565,12 @@ impl Weak { Self::new() } else { // See Arc::from_raw for details - let offset = data_offset(ptr); - let fake_ptr = ptr as *mut ArcInner; - let ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)); - Weak { ptr: NonNull::new(ptr).expect("Invalid pointer passed to from_raw") } + unsafe { + let offset = data_offset(ptr); + let fake_ptr = ptr as *mut ArcInner; + let ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)); + Weak { ptr: NonNull::new(ptr).expect("Invalid pointer passed to from_raw") } + } } } } @@ -2260,7 +2276,7 @@ unsafe fn data_offset(ptr: *const T) -> isize { // Because it is `?Sized`, it will always be the last field in memory. // Note: This is a detail of the current implementation of the compiler, // and is not a guaranteed language detail. Do not rely on it outside of std. - data_offset_align(align_of_val(&*ptr)) + unsafe { data_offset_align(align_of_val(&*ptr)) } } /// Computes the offset of the data field within `ArcInner`. diff --git a/src/liballoc/task.rs b/src/liballoc/task.rs index 745444a152e1b..0d1cc99df47c5 100644 --- a/src/liballoc/task.rs +++ b/src/liballoc/task.rs @@ -60,7 +60,7 @@ impl From> for RawWaker { fn raw_waker(waker: Arc) -> RawWaker { // Increment the reference count of the arc to clone it. unsafe fn clone_waker(waker: *const ()) -> RawWaker { - Arc::incr_strong_count(waker as *const W); + unsafe { Arc::incr_strong_count(waker as *const W) }; RawWaker::new( waker as *const (), &RawWakerVTable::new(clone_waker::, wake::, wake_by_ref::, drop_waker::), @@ -69,19 +69,20 @@ fn raw_waker(waker: Arc) -> RawWaker { // Wake by value, moving the Arc into the Wake::wake function unsafe fn wake(waker: *const ()) { - let waker: Arc = Arc::from_raw(waker as *const W); + let waker: Arc = unsafe { Arc::from_raw(waker as *const W) }; ::wake(waker); } // Wake by reference, wrap the waker in ManuallyDrop to avoid dropping it unsafe fn wake_by_ref(waker: *const ()) { - let waker: ManuallyDrop> = ManuallyDrop::new(Arc::from_raw(waker as *const W)); + let waker: ManuallyDrop> = + unsafe { ManuallyDrop::new(Arc::from_raw(waker as *const W)) }; ::wake_by_ref(&waker); } // Decrement the reference count of the Arc on drop unsafe fn drop_waker(waker: *const ()) { - Arc::decr_strong_count(waker as *const W); + unsafe { Arc::decr_strong_count(waker as *const W) }; } RawWaker::new( diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index f16cac05ea039..95c3b3b186161 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -465,7 +465,7 @@ impl Vec { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Vec { - Vec { buf: RawVec::from_raw_parts(ptr, capacity), len: length } + unsafe { Vec { buf: RawVec::from_raw_parts(ptr, capacity), len: length } } } /// Returns the number of elements the vector can hold without @@ -1264,10 +1264,10 @@ impl Vec { /// Appends elements to `Self` from other buffer. #[inline] unsafe fn append_elements(&mut self, other: *const [T]) { - let count = (*other).len(); + let count = unsafe { (*other).len() }; self.reserve(count); let len = self.len(); - ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count); + unsafe { ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count) }; self.len += count; } @@ -2965,15 +2965,16 @@ impl Drain<'_, T> { /// Fill that range as much as possible with new elements from the `replace_with` iterator. /// Returns `true` if we filled the entire range. (`replace_with.next()` didn’t return `None`.) unsafe fn fill>(&mut self, replace_with: &mut I) -> bool { - let vec = self.vec.as_mut(); + let vec = unsafe { self.vec.as_mut() }; let range_start = vec.len; let range_end = self.tail_start; - let range_slice = - slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start); + let range_slice = unsafe { + slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start) + }; for place in range_slice { if let Some(new_item) = replace_with.next() { - ptr::write(place, new_item); + unsafe { ptr::write(place, new_item) }; vec.len += 1; } else { return false; @@ -2984,14 +2985,16 @@ impl Drain<'_, T> { /// Makes room for inserting more elements before the tail. unsafe fn move_tail(&mut self, additional: usize) { - let vec = self.vec.as_mut(); + let vec = unsafe { self.vec.as_mut() }; let len = self.tail_start + self.tail_len; vec.buf.reserve(len, additional); let new_tail_start = self.tail_start + additional; - let src = vec.as_ptr().add(self.tail_start); - let dst = vec.as_mut_ptr().add(new_tail_start); - ptr::copy(src, dst, self.tail_len); + unsafe { + let src = vec.as_ptr().add(self.tail_start); + let dst = vec.as_mut_ptr().add(new_tail_start); + ptr::copy(src, dst, self.tail_len); + } self.tail_start = new_tail_start; } } diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index be3e7aaa2e89a..8b2ac294764ff 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -1,6 +1,6 @@ //! Slice sorting //! -//! This module contains an sort algorithm based on Orson Peters' pattern-defeating quicksort, +//! This module contains a sorting algorithm based on Orson Peters' pattern-defeating quicksort, //! published at: https://github.com/orlp/pdqsort //! //! Unstable sorting is compatible with libcore because it doesn't allocate memory, unlike our @@ -20,6 +20,9 @@ struct CopyOnDrop { impl Drop for CopyOnDrop { fn drop(&mut self) { + // SAFETY: This is a helper class. + // Please refer to its usage for correctness. + // Namely, one must be sure that `src` and `dst` does not overlap as required by `ptr::copy_nonoverlapping`. unsafe { ptr::copy_nonoverlapping(self.src, self.dest, 1); } @@ -32,6 +35,21 @@ where F: FnMut(&T, &T) -> bool, { let len = v.len(); + // SAFETY: The unsafe operations below involves indexing without a bound check (`get_unchecked` and `get_unchecked_mut`) + // and copying memory (`ptr::copy_nonoverlapping`). + // + // a. Indexing: + // 1. We checked the size of the array to >=2. + // 2. All the indexing that we will do is always between {0 <= index < len} at most. + // + // b. Memory copying + // 1. We are obtaining pointers to references which are guaranteed to be valid. + // 2. They cannot overlap because we obtain pointers to difference indices of the slice. + // Namely, `i` and `i-1`. + // 3. If the slice is properly aligned, the elements are properly aligned. + // It is the caller's responsibility to make sure the slice is properly aligned. + // + // See comments below for further detail. unsafe { // If the first two elements are out-of-order... if len >= 2 && is_less(v.get_unchecked(1), v.get_unchecked(0)) { @@ -62,6 +80,21 @@ where F: FnMut(&T, &T) -> bool, { let len = v.len(); + // SAFETY: The unsafe operations below involves indexing without a bound check (`get_unchecked` and `get_unchecked_mut`) + // and copying memory (`ptr::copy_nonoverlapping`). + // + // a. Indexing: + // 1. We checked the size of the array to >= 2. + // 2. All the indexing that we will do is always between `0 <= index < len-1` at most. + // + // b. Memory copying + // 1. We are obtaining pointers to references which are guaranteed to be valid. + // 2. They cannot overlap because we obtain pointers to difference indices of the slice. + // Namely, `i` and `i+1`. + // 3. If the slice is properly aligned, the elements are properly aligned. + // It is the caller's responsibility to make sure the slice is properly aligned. + // + // See comments below for further detail. unsafe { // If the last two elements are out-of-order... if len >= 2 && is_less(v.get_unchecked(len - 1), v.get_unchecked(len - 2)) { @@ -103,6 +136,8 @@ where let mut i = 1; for _ in 0..MAX_STEPS { + // SAFETY: We already explicitly did the bound checking with `i < len`. + // All our subsequent indexing is only in the range `0 <= index < len` unsafe { // Find the next pair of adjacent out-of-order elements. while i < len && !is_less(v.get_unchecked(i), v.get_unchecked(i - 1)) { @@ -220,6 +255,7 @@ where let mut offsets_l = [MaybeUninit::::uninit(); BLOCK]; // The current block on the right side (from `r.sub(block_r)` to `r`). + // SAFETY: The documentation for .add() specifically mention that `vec.as_ptr().add(vec.len())` is always safe` let mut r = unsafe { l.add(v.len()) }; let mut block_r = BLOCK; let mut start_r = ptr::null_mut(); @@ -268,6 +304,16 @@ where let mut elem = l; for i in 0..block_l { + // SAFETY: The unsafety operations below involve the usage of the `offset`. + // According to the conditions required by the function, we satisfy them because: + // 1. `offsets_l` is stack-allocated, and thus considered separate allocated object. + // 2. The function `is_less` returns a `bool`. + // Casting a `bool` will never overflow `isize`. + // 3. We have guaranteed that `block_l` will be `<= BLOCK`. + // Plus, `end_l` was initially set to the begin pointer of `offsets_` which was declared on the stack. + // Thus, we know that even in the worst case (all invocations of `is_less` returns false) we will only be at most 1 byte pass the end. + // Another unsafety operation here is dereferencing `elem`. + // However, `elem` was initially the begin pointer to the slice which is always valid. unsafe { // Branchless comparison. *end_l = i as u8; @@ -284,6 +330,17 @@ where let mut elem = r; for i in 0..block_r { + // SAFETY: The unsafety operations below involve the usage of the `offset`. + // According to the conditions required by the function, we satisfy them because: + // 1. `offsets_r` is stack-allocated, and thus considered separate allocated object. + // 2. The function `is_less` returns a `bool`. + // Casting a `bool` will never overflow `isize`. + // 3. We have guaranteed that `block_r` will be `<= BLOCK`. + // Plus, `end_r` was initially set to the begin pointer of `offsets_` which was declared on the stack. + // Thus, we know that even in the worst case (all invocations of `is_less` returns true) we will only be at most 1 byte pass the end. + // Another unsafety operation here is dereferencing `elem`. + // However, `elem` was initially `1 * sizeof(T)` past the end and we decrement it by `1 * sizeof(T)` before accessing it. + // Plus, `block_r` was asserted to be less than `BLOCK` and `elem` will therefore at most be pointing to the beginning of the slice. unsafe { // Branchless comparison. elem = elem.offset(-1); @@ -404,8 +461,13 @@ where // Find the first pair of out-of-order elements. let mut l = 0; let mut r = v.len(); + + // SAFETY: The unsafety below involves indexing an array. + // For the first one: We already do the bounds checking here with `l < r`. + // For the second one: We initially have `l == 0` and `r == v.len()` and we checked that `l < r` at every indexing operation. + // From here we know that `r` must be at least `r == l` which was shown to be valid from the first one. unsafe { - // Find the first element greater then or equal to the pivot. + // Find the first element greater than or equal to the pivot. while l < r && is_less(v.get_unchecked(l), pivot) { l += 1; } @@ -444,6 +506,7 @@ where // Read the pivot into a stack-allocated variable for efficiency. If a following comparison // operation panics, the pivot will be automatically written back into the slice. + // SAFETY: The pointer here is valid because it is obtained from a reference to a slice. let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) }); let _pivot_guard = CopyOnDrop { src: &mut *tmp, dest: pivot }; let pivot = &*tmp; @@ -452,8 +515,12 @@ where let mut l = 0; let mut r = v.len(); loop { + // SAFETY: The unsafety below involves indexing an array. + // For the first one: We already do the bounds checking here with `l < r`. + // For the second one: We initially have `l == 0` and `r == v.len()` and we checked that `l < r` at every indexing operation. + // From here we know that `r` must be at least `r == l` which was shown to be valid from the first one. unsafe { - // Find the first element greater that the pivot. + // Find the first element greater than the pivot. while l < r && !is_less(pivot, v.get_unchecked(l)) { l += 1; } diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs index ce186c4834d72..e98d709539d79 100644 --- a/src/librustc_ast/ast.rs +++ b/src/librustc_ast/ast.rs @@ -1905,7 +1905,7 @@ impl fmt::Display for InlineAsmTemplatePiece { match c { '{' => f.write_str("{{")?, '}' => f.write_str("}}")?, - _ => write!(f, "{}", c.escape_debug())?, + _ => c.fmt(f)?, } } Ok(()) diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index 480ee97f20552..2988567960464 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -11,7 +11,7 @@ use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{InnerSpan, Span}; struct AsmArgs { - template: P, + templates: Vec>, operands: Vec<(ast::InlineAsmOperand, Span)>, named_args: FxHashMap, reg_args: FxHashSet, @@ -52,9 +52,9 @@ fn parse_args<'a>( return Err(err); } - let template = p.parse_expr()?; + let first_template = p.parse_expr()?; let mut args = AsmArgs { - template, + templates: vec![first_template], operands: vec![], named_args: FxHashMap::default(), reg_args: FxHashSet::default(), @@ -62,11 +62,11 @@ fn parse_args<'a>( options_span: None, }; - let mut first = true; + let mut allow_templates = true; while p.token != token::Eof { if !p.eat(&token::Comma) { - if first { - // After `asm!(""` we always expect *only* a comma... + if allow_templates { + // After a template string, we always expect *only* a comma... let mut err = ecx.struct_span_err(p.token.span, "expected token: `,`"); err.span_label(p.token.span, "expected `,`"); p.maybe_annotate_with_ascription(&mut err, false); @@ -76,7 +76,6 @@ fn parse_args<'a>( return Err(p.expect(&token::Comma).err().unwrap()); } } - first = false; if p.token == token::Eof { break; } // accept trailing commas @@ -84,6 +83,7 @@ fn parse_args<'a>( // Parse options if p.eat(&token::Ident(sym::options, false)) { parse_options(&mut p, &mut args)?; + allow_templates = false; continue; } @@ -94,6 +94,7 @@ fn parse_args<'a>( let (ident, _) = p.token.ident().unwrap(); p.bump(); p.expect(&token::Eq)?; + allow_templates = false; Some(ident.name) } else { None @@ -135,8 +136,7 @@ fn parse_args<'a>( } else if p.eat(&token::Ident(kw::Const, false)) { let expr = p.parse_expr()?; ast::InlineAsmOperand::Const { expr } - } else { - p.expect(&token::Ident(sym::sym, false))?; + } else if p.eat(&token::Ident(sym::sym, false)) { let expr = p.parse_expr()?; match expr.kind { ast::ExprKind::Path(..) => {} @@ -147,8 +147,27 @@ fn parse_args<'a>( } } ast::InlineAsmOperand::Sym { expr } + } else if allow_templates { + let template = p.parse_expr()?; + // If it can't possibly expand to a string, provide diagnostics here to include other + // things it could have been. + match template.kind { + ast::ExprKind::Lit(ast::Lit { kind: ast::LitKind::Str(..), .. }) => {} + ast::ExprKind::MacCall(..) => {} + _ => { + let errstr = "expected operand, options, or additional template string"; + let mut err = ecx.struct_span_err(template.span, errstr); + err.span_label(template.span, errstr); + return Err(err); + } + } + args.templates.push(template); + continue; + } else { + return Err(p.expect_one_of(&[], &[]).unwrap_err()); }; + allow_templates = false; let span = span_start.to(p.prev_token.span); let slot = args.operands.len(); args.operands.push((op, span)); @@ -330,155 +349,180 @@ fn parse_reg<'a>( } fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P { - let msg = "asm template must be a string literal"; - let template_sp = args.template.span; - let (template_str, template_style, template_span) = - match expr_to_spanned_string(ecx, args.template, msg) { - Ok(template) => template, - Err(err) => { - if let Some(mut err) = err { - err.emit(); - } - return DummyResult::raw_expr(sp, true); - } - }; - - let str_style = match template_style { - ast::StrStyle::Cooked => None, - ast::StrStyle::Raw(raw) => Some(raw as usize), - }; - - let template_str = &template_str.as_str(); - let template_snippet = ecx.source_map().span_to_snippet(template_sp).ok(); - let mut parser = parse::Parser::new( - template_str, - str_style, - template_snippet, - false, - parse::ParseMode::InlineAsm, - ); - - let mut unverified_pieces = Vec::new(); - while let Some(piece) = parser.next() { - if !parser.errors.is_empty() { - break; - } else { - unverified_pieces.push(piece); - } - } - - if !parser.errors.is_empty() { - let err = parser.errors.remove(0); - let err_sp = template_span.from_inner(err.span); - let mut e = ecx - .struct_span_err(err_sp, &format!("invalid asm template string: {}", err.description)); - e.span_label(err_sp, err.label + " in asm template string"); - if let Some(note) = err.note { - e.note(¬e); - } - if let Some((label, span)) = err.secondary_label { - let err_sp = template_span.from_inner(span); - e.span_label(err_sp, label); - } - e.emit(); - return DummyResult::raw_expr(sp, true); - } - + let mut template = vec![]; // Register operands are implicitly used since they are not allowed to be // referenced in the template string. let mut used = vec![false; args.operands.len()]; for pos in &args.reg_args { used[*pos] = true; } - let named_pos: FxHashMap = args.named_args.iter().map(|(&sym, &idx)| (idx, sym)).collect(); - let mut arg_spans = parser.arg_places.iter().map(|span| template_span.from_inner(*span)); - let mut template = vec![]; - for piece in unverified_pieces { - match piece { - parse::Piece::String(s) => { - template.push(ast::InlineAsmTemplatePiece::String(s.to_string())) + let mut line_spans = Vec::with_capacity(args.templates.len()); + let mut curarg = 0; + + for template_expr in args.templates.into_iter() { + if !template.is_empty() { + template.push(ast::InlineAsmTemplatePiece::String("\n".to_string())); + } + + let msg = "asm template must be a string literal"; + let template_sp = template_expr.span; + let (template_str, template_style, template_span) = + match expr_to_spanned_string(ecx, template_expr, msg) { + Ok(template_part) => template_part, + Err(err) => { + if let Some(mut err) = err { + err.emit(); + } + return DummyResult::raw_expr(sp, true); + } + }; + + let str_style = match template_style { + ast::StrStyle::Cooked => None, + ast::StrStyle::Raw(raw) => Some(raw as usize), + }; + + let template_str = &template_str.as_str(); + let template_snippet = ecx.source_map().span_to_snippet(template_sp).ok(); + let mut parser = parse::Parser::new( + template_str, + str_style, + template_snippet, + false, + parse::ParseMode::InlineAsm, + ); + parser.curarg = curarg; + + let mut unverified_pieces = Vec::new(); + while let Some(piece) = parser.next() { + if !parser.errors.is_empty() { + break; + } else { + unverified_pieces.push(piece); } - parse::Piece::NextArgument(arg) => { - let span = arg_spans.next().unwrap_or(template_sp); - - let operand_idx = match arg.position { - parse::ArgumentIs(idx) | parse::ArgumentImplicitlyIs(idx) => { - if idx >= args.operands.len() - || named_pos.contains_key(&idx) - || args.reg_args.contains(&idx) - { - let msg = format!("invalid reference to argument at index {}", idx); - let mut err = ecx.struct_span_err(span, &msg); - err.span_label(span, "from here"); - - let positional_args = - args.operands.len() - args.named_args.len() - args.reg_args.len(); - let positional = if positional_args != args.operands.len() { - "positional " + } + + if !parser.errors.is_empty() { + let err = parser.errors.remove(0); + let err_sp = template_span.from_inner(err.span); + let msg = &format!("invalid asm template string: {}", err.description); + let mut e = ecx.struct_span_err(err_sp, msg); + e.span_label(err_sp, err.label + " in asm template string"); + if let Some(note) = err.note { + e.note(¬e); + } + if let Some((label, span)) = err.secondary_label { + let err_sp = template_span.from_inner(span); + e.span_label(err_sp, label); + } + e.emit(); + return DummyResult::raw_expr(sp, true); + } + + curarg = parser.curarg; + + let mut arg_spans = parser.arg_places.iter().map(|span| template_span.from_inner(*span)); + for piece in unverified_pieces { + match piece { + parse::Piece::String(s) => { + template.push(ast::InlineAsmTemplatePiece::String(s.to_string())) + } + parse::Piece::NextArgument(arg) => { + let span = arg_spans.next().unwrap_or(template_sp); + + let operand_idx = match arg.position { + parse::ArgumentIs(idx) | parse::ArgumentImplicitlyIs(idx) => { + if idx >= args.operands.len() + || named_pos.contains_key(&idx) + || args.reg_args.contains(&idx) + { + let msg = format!("invalid reference to argument at index {}", idx); + let mut err = ecx.struct_span_err(span, &msg); + err.span_label(span, "from here"); + + let positional_args = args.operands.len() + - args.named_args.len() + - args.reg_args.len(); + let positional = if positional_args != args.operands.len() { + "positional " + } else { + "" + }; + let msg = match positional_args { + 0 => format!("no {}arguments were given", positional), + 1 => format!("there is 1 {}argument", positional), + x => format!("there are {} {}arguments", x, positional), + }; + err.note(&msg); + + if named_pos.contains_key(&idx) { + err.span_label(args.operands[idx].1, "named argument"); + err.span_note( + args.operands[idx].1, + "named arguments cannot be referenced by position", + ); + } else if args.reg_args.contains(&idx) { + err.span_label( + args.operands[idx].1, + "explicit register argument", + ); + err.span_note( + args.operands[idx].1, + "explicit register arguments cannot be used in the asm template", + ); + } + err.emit(); + None } else { - "" - }; - let msg = match positional_args { - 0 => format!("no {}arguments were given", positional), - 1 => format!("there is 1 {}argument", positional), - x => format!("there are {} {}arguments", x, positional), - }; - err.note(&msg); - - if named_pos.contains_key(&idx) { - err.span_label(args.operands[idx].1, "named argument"); - err.span_note( - args.operands[idx].1, - "named arguments cannot be referenced by position", - ); - } else if args.reg_args.contains(&idx) { - err.span_label(args.operands[idx].1, "explicit register argument"); - err.span_note( - args.operands[idx].1, - "explicit register arguments cannot be used in the asm template", - ); + Some(idx) } - err.emit(); - None - } else { - Some(idx) - } - } - parse::ArgumentNamed(name) => match args.named_args.get(&name) { - Some(&idx) => Some(idx), - None => { - let msg = format!("there is no argument named `{}`", name); - ecx.struct_span_err(span, &msg[..]).emit(); - None } - }, - }; - - let mut chars = arg.format.ty.chars(); - let mut modifier = chars.next(); - if chars.next().is_some() { - let span = arg - .format - .ty_span - .map(|sp| template_sp.from_inner(sp)) - .unwrap_or(template_sp); - ecx.struct_span_err(span, "asm template modifier must be a single character") + parse::ArgumentNamed(name) => match args.named_args.get(&name) { + Some(&idx) => Some(idx), + None => { + let msg = format!("there is no argument named `{}`", name); + ecx.struct_span_err(span, &msg[..]).emit(); + None + } + }, + }; + + let mut chars = arg.format.ty.chars(); + let mut modifier = chars.next(); + if chars.next().is_some() { + let span = arg + .format + .ty_span + .map(|sp| template_sp.from_inner(sp)) + .unwrap_or(template_sp); + ecx.struct_span_err( + span, + "asm template modifier must be a single character", + ) .emit(); - modifier = None; - } + modifier = None; + } - if let Some(operand_idx) = operand_idx { - used[operand_idx] = true; - template.push(ast::InlineAsmTemplatePiece::Placeholder { - operand_idx, - modifier, - span, - }); + if let Some(operand_idx) = operand_idx { + used[operand_idx] = true; + template.push(ast::InlineAsmTemplatePiece::Placeholder { + operand_idx, + modifier, + span, + }); + } } } } + + if parser.line_spans.is_empty() { + let template_num_lines = 1 + template_str.matches('\n').count(); + line_spans.extend(std::iter::repeat(template_sp).take(template_num_lines)); + } else { + line_spans.extend(parser.line_spans.iter().map(|span| template_span.from_inner(*span))); + }; } let mut unused_operands = vec![]; @@ -525,12 +569,6 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P for Builder<'a, 'll, 'tcx> { } InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {} InlineAsmArch::Nvptx64 => {} + InlineAsmArch::Hexagon => {} } } if !options.contains(InlineAsmOptions::NOMEM) { @@ -427,6 +428,7 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass) -> String { | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => "x", InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "w", + InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r", InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h", InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r", InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l", @@ -472,6 +474,7 @@ fn modifier_to_llvm( modifier } } + InlineAsmRegClass::Hexagon(_) => None, InlineAsmRegClass::Nvptx(_) => None, InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) | InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => None, @@ -523,6 +526,7 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => { cx.type_vector(cx.type_i64(), 2) } + InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(), diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index bed2044c70855..eb1db46fd2bda 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -12,6 +12,7 @@ use rustc_ast::node_id::NodeMap; use rustc_ast::util::parser::ExprPrecedence; use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; use rustc_macros::HashStable_Generic; +use rustc_span::def_id::LocalDefId; use rustc_span::source_map::{SourceMap, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{MultiSpan, Span, DUMMY_SP}; @@ -2651,25 +2652,11 @@ pub type CaptureModeMap = NodeMap; // has length > 0 if the trait is found through an chain of imports, starting with the // import/use statement in the scope where the trait is used. #[derive(Clone, Debug)] -pub struct TraitCandidate { +pub struct TraitCandidate { pub def_id: DefId, - pub import_ids: SmallVec<[ID; 1]>, + pub import_ids: SmallVec<[LocalDefId; 1]>, } -impl TraitCandidate { - pub fn map_import_ids(self, f: F) -> TraitCandidate - where - F: Fn(ID) -> T, - { - let TraitCandidate { def_id, import_ids } = self; - let import_ids = import_ids.into_iter().map(f).collect(); - TraitCandidate { def_id, import_ids } - } -} - -// Trait method resolution -pub type TraitMap = NodeMap>>; - #[derive(Copy, Clone, Debug, HashStable_Generic)] pub enum Node<'hir> { Param(&'hir Param<'hir>), @@ -2741,14 +2728,8 @@ impl Node<'_> { pub fn generics(&self) -> Option<&Generics<'_>> { match self { Node::TraitItem(TraitItem { generics, .. }) - | Node::ImplItem(ImplItem { generics, .. }) - | Node::Item(Item { - kind: - ItemKind::Trait(_, _, generics, ..) - | ItemKind::Impl { generics, .. } - | ItemKind::Fn(_, generics, _), - .. - }) => Some(generics), + | Node::ImplItem(ImplItem { generics, .. }) => Some(generics), + Node::Item(item) => item.kind.generics(), _ => None, } } diff --git a/src/librustc_lint/early.rs b/src/librustc_lint/early.rs index 06987ffa3d569..d891466611ad3 100644 --- a/src/librustc_lint/early.rs +++ b/src/librustc_lint/early.rs @@ -55,7 +55,8 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> { where F: FnOnce(&mut Self), { - let push = self.context.builder.push(attrs, &self.context.lint_store); + let is_crate_node = id == ast::CRATE_NODE_ID; + let push = self.context.builder.push(attrs, &self.context.lint_store, is_crate_node); self.check_id(id); self.enter_attrs(attrs); f(self); diff --git a/src/librustc_lint/levels.rs b/src/librustc_lint/levels.rs index 05e7c9a0c780d..f875e2750a5c5 100644 --- a/src/librustc_lint/levels.rs +++ b/src/librustc_lint/levels.rs @@ -29,7 +29,7 @@ fn lint_levels(tcx: TyCtxt<'_>, cnum: CrateNum) -> LintLevelMap { let mut builder = LintLevelMapBuilder { levels, tcx, store }; let krate = tcx.hir().krate(); - let push = builder.levels.push(&krate.item.attrs, &store); + let push = builder.levels.push(&krate.item.attrs, &store, true); builder.levels.register_id(hir::CRATE_HIR_ID); for macro_def in krate.exported_macros { builder.levels.register_id(macro_def.hir_id); @@ -109,7 +109,12 @@ impl<'s> LintLevelsBuilder<'s> { /// `#[allow]` /// /// Don't forget to call `pop`! - pub fn push(&mut self, attrs: &[ast::Attribute], store: &LintStore) -> BuilderPush { + pub fn push( + &mut self, + attrs: &[ast::Attribute], + store: &LintStore, + is_crate_node: bool, + ) -> BuilderPush { let mut specs = FxHashMap::default(); let sess = self.sess; let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input"); @@ -333,6 +338,40 @@ impl<'s> LintLevelsBuilder<'s> { } } + if !is_crate_node { + for (id, &(level, ref src)) in specs.iter() { + if !id.lint.crate_level_only { + continue; + } + + let (lint_attr_name, lint_attr_span) = match *src { + LintSource::Node(name, span, _) => (name, span), + _ => continue, + }; + + let lint = builtin::UNUSED_ATTRIBUTES; + let (lint_level, lint_src) = + self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess); + struct_lint_level( + self.sess, + lint, + lint_level, + lint_src, + Some(lint_attr_span.into()), + |lint| { + let mut db = lint.build(&format!( + "{}({}) is ignored unless specified at crate level", + level.as_str(), + lint_attr_name + )); + db.emit(); + }, + ); + // don't set a separate error for every lint in the group + break; + } + } + for (id, &(level, ref src)) in specs.iter() { if level == Level::Forbid { continue; @@ -449,7 +488,8 @@ impl LintLevelMapBuilder<'_, '_> { where F: FnOnce(&mut Self), { - let push = self.levels.push(attrs, self.store); + let is_crate_hir = id == hir::CRATE_HIR_ID; + let push = self.levels.push(attrs, self.store, is_crate_hir); if push.changed { self.levels.register_id(id); } diff --git a/src/librustc_lint/non_ascii_idents.rs b/src/librustc_lint/non_ascii_idents.rs index ad02b2637d22f..064b0255397ce 100644 --- a/src/librustc_lint/non_ascii_idents.rs +++ b/src/librustc_lint/non_ascii_idents.rs @@ -8,20 +8,23 @@ use std::ops::Deref; declare_lint! { pub NON_ASCII_IDENTS, Allow, - "detects non-ASCII identifiers" + "detects non-ASCII identifiers", + crate_level_only } declare_lint! { pub UNCOMMON_CODEPOINTS, Warn, - "detects uncommon Unicode codepoints in identifiers" + "detects uncommon Unicode codepoints in identifiers", + crate_level_only } // FIXME: Change this to warn. declare_lint! { pub CONFUSABLE_IDENTS, Allow, - "detects visually confusable pairs between identifiers" + "detects visually confusable pairs between identifiers", + crate_level_only } declare_lint_pass!(NonAsciiIdents => [NON_ASCII_IDENTS, UNCOMMON_CODEPOINTS, CONFUSABLE_IDENTS]); diff --git a/src/librustc_middle/arena.rs b/src/librustc_middle/arena.rs index f861d63aba0f3..aaef9871aa557 100644 --- a/src/librustc_middle/arena.rs +++ b/src/librustc_middle/arena.rs @@ -114,6 +114,7 @@ macro_rules! arena_types { // This is used to decode the &'tcx [Span] for InlineAsm's line_spans. [decode] span: rustc_span::Span, rustc_span::Span; + [decode] used_trait_imports: rustc_data_structures::fx::FxHashSet, rustc_data_structures::fx::FxHashSet; ], $tcx); ) } diff --git a/src/librustc_middle/ich/impls_hir.rs b/src/librustc_middle/ich/impls_hir.rs index f668cc99754f4..78b9167ddd967 100644 --- a/src/librustc_middle/ich/impls_hir.rs +++ b/src/librustc_middle/ich/impls_hir.rs @@ -210,16 +210,15 @@ impl<'a> HashStable> for hir::TraitCandidate { } impl<'a> ToStableHashKey> for hir::TraitCandidate { - type KeyType = (DefPathHash, SmallVec<[(DefPathHash, hir::ItemLocalId); 1]>); + type KeyType = (DefPathHash, SmallVec<[DefPathHash; 1]>); fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Self::KeyType { let hir::TraitCandidate { def_id, import_ids } = self; - let import_keys = import_ids - .iter() - .map(|hir_id| (hcx.local_def_path_hash(hir_id.owner), hir_id.local_id)) - .collect(); - (hcx.def_path_hash(*def_id), import_keys) + ( + hcx.def_path_hash(*def_id), + import_ids.iter().map(|def_id| hcx.local_def_path_hash(*def_id)).collect(), + ) } } diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index 3b6d54a1bc1ee..b3751beede25a 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -526,7 +526,7 @@ rustc_queries! { } Other { - query used_trait_imports(key: LocalDefId) -> &'tcx DefIdSet { + query used_trait_imports(key: LocalDefId) -> &'tcx FxHashSet { desc { |tcx| "used_trait_imports `{}`", tcx.def_path_str(key.to_def_id()) } cache_on_disk_if { true } } diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index 62d6de2d71e6d..c77c7b95bc095 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -35,7 +35,7 @@ use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal}; use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; use rustc_hir::definitions::{DefPathHash, Definitions}; use rustc_hir::lang_items::{self, PanicLocationLangItem}; use rustc_hir::{HirId, ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet, Node, TraitCandidate}; @@ -390,7 +390,7 @@ pub struct TypeckTables<'tcx> { /// This is used for warning unused imports. During type /// checking, this `Lrc` should not be cloned: it must have a ref-count /// of 1 so that we can insert things into the set mutably. - pub used_trait_imports: Lrc, + pub used_trait_imports: Lrc>, /// If any errors occurred while type-checking this body, /// this field will be set to `Some(ErrorReported)`. diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index b4e3e6ab5ab7e..e26e09ae6a942 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -121,7 +121,7 @@ pub struct ResolverOutputs { pub definitions: rustc_hir::definitions::Definitions, pub cstore: Box, pub extern_crate_map: FxHashMap, - pub trait_map: FxHashMap>>, + pub trait_map: FxHashMap>, pub maybe_unused_trait_imports: FxHashSet, pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>, pub export_map: ExportMap, diff --git a/src/librustc_parse_format/lib.rs b/src/librustc_parse_format/lib.rs index 23bf7b35419db..a5b5a1090cbfd 100644 --- a/src/librustc_parse_format/lib.rs +++ b/src/librustc_parse_format/lib.rs @@ -178,7 +178,7 @@ pub struct Parser<'a> { /// Error messages accumulated during parsing pub errors: Vec, /// Current position of implicit positional argument pointer - curarg: usize, + pub curarg: usize, /// `Some(raw count)` when the string is "raw", used to position spans correctly style: Option, /// Start and end byte offset of every successfully parsed argument @@ -243,11 +243,13 @@ impl<'a> Iterator for Parser<'a> { _ => Some(String(self.string(pos))), } } else { - if self.is_literal && self.cur_line_start != self.input.len() { + if self.is_literal { let start = self.to_span_index(self.cur_line_start); let end = self.to_span_index(self.input.len()); - self.line_spans.push(start.to(end)); - self.cur_line_start = self.input.len(); + let span = start.to(end); + if self.line_spans.last() != Some(&span) { + self.line_spans.push(span); + } } None } diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 7166fef2d1395..61f20df8cc6c0 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -24,6 +24,7 @@ use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_hir::TraitCandidate; use rustc_middle::{bug, span_bug}; use rustc_session::lint; +use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; use smallvec::{smallvec, SmallVec}; @@ -2188,7 +2189,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { &mut self, mut ident: Ident, ns: Namespace, - ) -> Vec> { + ) -> Vec { debug!("(getting traits containing item) looking for '{}'", ident.name); let mut found_traits = Vec::new(); @@ -2233,7 +2234,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ident: Ident, ns: Namespace, module: Module<'a>, - found_traits: &mut Vec>, + found_traits: &mut Vec, ) { assert!(ns == TypeNS || ns == ValueNS); let mut traits = module.traits.borrow_mut(); @@ -2292,13 +2293,13 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { &mut self, mut kind: &NameBindingKind<'_>, trait_name: Ident, - ) -> SmallVec<[NodeId; 1]> { + ) -> SmallVec<[LocalDefId; 1]> { let mut import_ids = smallvec![]; while let NameBindingKind::Import { import, binding, .. } = kind { let id = self.r.definitions.local_def_id(import.id); self.r.maybe_unused_trait_imports.insert(id); self.r.add_to_glob_map(&import, trait_name); - import_ids.push(import.id); + import_ids.push(id); kind = &binding.kind; } import_ids diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index cca9eabe7bcf8..66e5612b627b4 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -38,7 +38,7 @@ use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX}; use rustc_hir::definitions::{DefKey, Definitions}; use rustc_hir::PrimTy::{self, Bool, Char, Float, Int, Str, Uint}; -use rustc_hir::TraitMap; +use rustc_hir::TraitCandidate; use rustc_metadata::creader::{CStore, CrateLoader}; use rustc_middle::hir::exports::ExportMap; use rustc_middle::middle::cstore::{CrateStore, MetadataLoaderDyn}; @@ -881,7 +881,7 @@ pub struct Resolver<'a> { /// `CrateNum` resolutions of `extern crate` items. extern_crate_map: FxHashMap, export_map: ExportMap, - trait_map: TraitMap, + trait_map: NodeMap>, /// A map from nodes to anonymous modules. /// Anonymous modules are pseudo-modules that are implicitly created around items @@ -1287,14 +1287,7 @@ impl<'a> Resolver<'a> { let trait_map = self .trait_map .into_iter() - .map(|(k, v)| { - ( - definitions.node_id_to_hir_id(k), - v.into_iter() - .map(|tc| tc.map_import_ids(|id| definitions.node_id_to_hir_id(id))) - .collect(), - ) - }) + .map(|(k, v)| (definitions.node_id_to_hir_id(k), v)) .collect(); let maybe_unused_trait_imports = self.maybe_unused_trait_imports; let maybe_unused_extern_crates = self.maybe_unused_extern_crates; @@ -1325,17 +1318,7 @@ impl<'a> Resolver<'a> { trait_map: self .trait_map .iter() - .map(|(&k, v)| { - ( - self.definitions.node_id_to_hir_id(k), - v.iter() - .cloned() - .map(|tc| { - tc.map_import_ids(|id| self.definitions.node_id_to_hir_id(id)) - }) - .collect(), - ) - }) + .map(|(&k, v)| (self.definitions.node_id_to_hir_id(k), v.clone())) .collect(), glob_map: self.glob_map.clone(), maybe_unused_trait_imports: self.maybe_unused_trait_imports.clone(), diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index cae501e942b65..f5c3e84c62426 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -518,24 +518,13 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { } pub fn get_expr_data(&self, expr: &hir::Expr<'_>) -> Option { - let hir_node = self.tcx.hir().expect_expr(expr.hir_id); - let ty = self.tables.expr_ty_adjusted_opt(&hir_node); - if ty.is_none() || matches!(ty.unwrap().kind, ty::Error(_)) { + let ty = self.tables.expr_ty_adjusted_opt(expr)?; + if matches!(ty.kind, ty::Error(_)) { return None; } match expr.kind { hir::ExprKind::Field(ref sub_ex, ident) => { - let hir_node = match self.tcx.hir().find(sub_ex.hir_id) { - Some(Node::Expr(expr)) => expr, - _ => { - debug!( - "Missing or weird node for sub-expression {} in {:?}", - sub_ex.hir_id, expr - ); - return None; - } - }; - match self.tables.expr_ty_adjusted(&hir_node).kind { + match self.tables.expr_ty_adjusted(&sub_ex).kind { ty::Adt(def, _) if !def.is_enum() => { let variant = &def.non_enum_variant(); filter!(self.span_utils, ident.span); @@ -562,8 +551,8 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { hir::QPath::Resolved(_, path) => path.segments.last().unwrap(), hir::QPath::TypeRelative(_, segment) => segment, }; - match self.tables.expr_ty_adjusted(&hir_node).kind { - ty::Adt(def, _) if !def.is_enum() => { + match ty.kind { + ty::Adt(def, _) => { let sub_span = segment.ident.span; filter!(self.span_utils, sub_span); let span = self.span_from_span(sub_span); @@ -574,9 +563,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { })) } _ => { - // FIXME ty could legitimately be an enum, but then we will fail - // later if we try to look up the fields. - debug!("expected struct or union, found {:?}", ty); + debug!("expected adt, found {:?}", ty); None } } diff --git a/src/librustc_session/lint.rs b/src/librustc_session/lint.rs index ffb4579309075..0dcbee08abea1 100644 --- a/src/librustc_session/lint.rs +++ b/src/librustc_session/lint.rs @@ -88,6 +88,8 @@ pub struct Lint { /// `Some` if this lint is feature gated, otherwise `None`. pub feature_gate: Option, + + pub crate_level_only: bool, } /// Extra information for a future incompatibility lint. @@ -111,6 +113,7 @@ impl Lint { report_in_external_macro: false, future_incompatible: None, feature_gate: None, + crate_level_only: false, } } @@ -336,6 +339,7 @@ macro_rules! declare_tool_lint { future_incompatible: None, is_plugin: true, feature_gate: None, + crate_level_only: false, }; ); } diff --git a/src/librustc_session/lint/builtin.rs b/src/librustc_session/lint/builtin.rs index 5a8f5c1b9fbca..5deee6eb48e6a 100644 --- a/src/librustc_session/lint/builtin.rs +++ b/src/librustc_session/lint/builtin.rs @@ -17,6 +17,7 @@ declare_lint! { reference: "issue #57571 ", edition: None, }; + crate_level_only } declare_lint! { @@ -75,7 +76,8 @@ declare_lint! { declare_lint! { pub UNUSED_CRATE_DEPENDENCIES, Allow, - "crate dependencies that are never used" + "crate dependencies that are never used", + crate_level_only } declare_lint! { @@ -166,7 +168,8 @@ declare_lint! { declare_lint! { pub UNKNOWN_CRATE_TYPES, Deny, - "unknown crate type found in `#[crate_type]` directive" + "unknown crate type found in `#[crate_type]` directive", + crate_level_only } declare_lint! { @@ -339,7 +342,8 @@ declare_lint! { declare_lint! { pub ELIDED_LIFETIMES_IN_PATHS, Allow, - "hidden lifetime parameters in types are deprecated" + "hidden lifetime parameters in types are deprecated", + crate_level_only } declare_lint! { @@ -459,6 +463,7 @@ declare_lint! { reference: "issue #52234 ", edition: None, }; + crate_level_only } declare_lint! { diff --git a/src/librustc_target/asm/hexagon.rs b/src/librustc_target/asm/hexagon.rs new file mode 100644 index 0000000000000..d41941d0b4cd7 --- /dev/null +++ b/src/librustc_target/asm/hexagon.rs @@ -0,0 +1,93 @@ +use super::{InlineAsmArch, InlineAsmType}; +use rustc_macros::HashStable_Generic; +use std::fmt; + +def_reg_class! { + Hexagon HexagonInlineAsmRegClass { + reg, + } +} + +impl HexagonInlineAsmRegClass { + pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] { + &[] + } + + pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option { + None + } + + pub fn suggest_modifier( + self, + _arch: InlineAsmArch, + _ty: InlineAsmType, + ) -> Option<(char, &'static str)> { + None + } + + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + None + } + + pub fn supported_types( + self, + _arch: InlineAsmArch, + ) -> &'static [(InlineAsmType, Option<&'static str>)] { + match self { + Self::reg => types! { _: I8, I16, I32, F32; }, + } + } +} + +def_regs! { + Hexagon HexagonInlineAsmReg HexagonInlineAsmRegClass { + r0: reg = ["r0"], + r1: reg = ["r1"], + r2: reg = ["r2"], + r3: reg = ["r3"], + r4: reg = ["r4"], + r5: reg = ["r5"], + r6: reg = ["r6"], + r7: reg = ["r7"], + r8: reg = ["r8"], + r9: reg = ["r9"], + r10: reg = ["r10"], + r11: reg = ["r11"], + r12: reg = ["r12"], + r13: reg = ["r13"], + r14: reg = ["r14"], + r15: reg = ["r15"], + r16: reg = ["r16"], + r17: reg = ["r17"], + r18: reg = ["r18"], + r19: reg = ["r19"], + r20: reg = ["r20"], + r21: reg = ["r21"], + r22: reg = ["r22"], + r23: reg = ["r23"], + r24: reg = ["r24"], + r25: reg = ["r25"], + r26: reg = ["r26"], + r27: reg = ["r27"], + r28: reg = ["r28"], + #error = ["r29", "sp"] => + "the stack pointer cannot be used as an operand for inline asm", + #error = ["r30", "fr"] => + "the frame register cannot be used as an operand for inline asm", + #error = ["r31", "lr"] => + "the link register cannot be used as an operand for inline asm", + } +} + +impl HexagonInlineAsmReg { + pub fn emit( + self, + out: &mut dyn fmt::Write, + _arch: InlineAsmArch, + _modifier: Option, + ) -> fmt::Result { + out.write_str(self.name()) + } + + pub fn overlapping_regs(self, mut _cb: impl FnMut(HexagonInlineAsmReg)) {} +} diff --git a/src/librustc_target/asm/mod.rs b/src/librustc_target/asm/mod.rs index a18a4dbd3e214..834d7c6d381a3 100644 --- a/src/librustc_target/asm/mod.rs +++ b/src/librustc_target/asm/mod.rs @@ -148,12 +148,14 @@ macro_rules! types { mod aarch64; mod arm; +mod hexagon; mod nvptx; mod riscv; mod x86; pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass}; pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass}; +pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass}; pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass}; pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass}; pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass}; @@ -167,6 +169,7 @@ pub enum InlineAsmArch { RiscV32, RiscV64, Nvptx64, + Hexagon, } impl FromStr for InlineAsmArch { @@ -181,6 +184,7 @@ impl FromStr for InlineAsmArch { "riscv32" => Ok(Self::RiscV32), "riscv64" => Ok(Self::RiscV64), "nvptx64" => Ok(Self::Nvptx64), + "hexagon" => Ok(Self::Hexagon), _ => Err(()), } } @@ -203,6 +207,7 @@ pub enum InlineAsmReg { AArch64(AArch64InlineAsmReg), RiscV(RiscVInlineAsmReg), Nvptx(NvptxInlineAsmReg), + Hexagon(HexagonInlineAsmReg), } impl InlineAsmReg { @@ -212,6 +217,7 @@ impl InlineAsmReg { Self::Arm(r) => r.name(), Self::AArch64(r) => r.name(), Self::RiscV(r) => r.name(), + Self::Hexagon(r) => r.name(), } } @@ -221,6 +227,7 @@ impl InlineAsmReg { Self::Arm(r) => InlineAsmRegClass::Arm(r.reg_class()), Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()), Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()), + Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()), } } @@ -246,6 +253,9 @@ impl InlineAsmReg { InlineAsmArch::Nvptx64 => { Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, &name)?) } + InlineAsmArch::Hexagon => { + Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, &name)?) + } }) } @@ -262,6 +272,7 @@ impl InlineAsmReg { Self::Arm(r) => r.emit(out, arch, modifier), Self::AArch64(r) => r.emit(out, arch, modifier), Self::RiscV(r) => r.emit(out, arch, modifier), + Self::Hexagon(r) => r.emit(out, arch, modifier), } } @@ -271,6 +282,7 @@ impl InlineAsmReg { Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))), Self::AArch64(_) => cb(self), Self::RiscV(_) => cb(self), + Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))), } } } @@ -292,6 +304,7 @@ pub enum InlineAsmRegClass { AArch64(AArch64InlineAsmRegClass), RiscV(RiscVInlineAsmRegClass), Nvptx(NvptxInlineAsmRegClass), + Hexagon(HexagonInlineAsmRegClass), } impl InlineAsmRegClass { @@ -302,6 +315,7 @@ impl InlineAsmRegClass { Self::AArch64(r) => r.name(), Self::RiscV(r) => r.name(), Self::Nvptx(r) => r.name(), + Self::Hexagon(r) => r.name(), } } @@ -315,6 +329,7 @@ impl InlineAsmRegClass { Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64), Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV), Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx), + Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon), } } @@ -335,6 +350,7 @@ impl InlineAsmRegClass { Self::AArch64(r) => r.suggest_modifier(arch, ty), Self::RiscV(r) => r.suggest_modifier(arch, ty), Self::Nvptx(r) => r.suggest_modifier(arch, ty), + Self::Hexagon(r) => r.suggest_modifier(arch, ty), } } @@ -351,6 +367,7 @@ impl InlineAsmRegClass { Self::AArch64(r) => r.default_modifier(arch), Self::RiscV(r) => r.default_modifier(arch), Self::Nvptx(r) => r.default_modifier(arch), + Self::Hexagon(r) => r.default_modifier(arch), } } @@ -366,6 +383,7 @@ impl InlineAsmRegClass { Self::AArch64(r) => r.supported_types(arch), Self::RiscV(r) => r.supported_types(arch), Self::Nvptx(r) => r.supported_types(arch), + Self::Hexagon(r) => r.supported_types(arch), } } @@ -384,6 +402,9 @@ impl InlineAsmRegClass { Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?) } InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?), + InlineAsmArch::Hexagon => { + Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?) + } }) }) } @@ -397,6 +418,7 @@ impl InlineAsmRegClass { Self::AArch64(r) => r.valid_modifiers(arch), Self::RiscV(r) => r.valid_modifiers(arch), Self::Nvptx(r) => r.valid_modifiers(arch), + Self::Hexagon(r) => r.valid_modifiers(arch), } } } @@ -541,5 +563,10 @@ pub fn allocatable_registers( nvptx::fill_reg_map(arch, has_feature, &mut map); map } + InlineAsmArch::Hexagon => { + let mut map = hexagon::regclass_map(); + hexagon::fill_reg_map(arch, has_feature, &mut map); + map + } } } diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index e5a6c9a2e391a..060877f80adef 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -15,6 +15,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_hir::intravisit::Visitor; use rustc_hir::Node; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::error::ExpectedFound; @@ -25,7 +26,7 @@ use rustc_middle::ty::{ TypeFoldable, WithConstness, }; use rustc_session::DiagnosticMessageId; -use rustc_span::{ExpnKind, Span, DUMMY_SP}; +use rustc_span::{ExpnKind, MultiSpan, Span, DUMMY_SP}; use std::fmt; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; @@ -1695,36 +1696,95 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { err: &mut DiagnosticBuilder<'tcx>, obligation: &PredicateObligation<'tcx>, ) { - if let ( - ty::PredicateKind::Trait(pred, _), - ObligationCauseCode::BindingObligation(item_def_id, span), - ) = (obligation.predicate.kind(), &obligation.cause.code) - { - if let (Some(generics), true) = ( - self.tcx.hir().get_if_local(*item_def_id).as_ref().and_then(|n| n.generics()), - Some(pred.def_id()) == self.tcx.lang_items().sized_trait(), - ) { - for param in generics.params { - if param.span == *span - && !param.bounds.iter().any(|bound| { - bound.trait_ref().and_then(|trait_ref| trait_ref.trait_def_id()) - == self.tcx.lang_items().sized_trait() - }) - { - let (span, separator) = match param.bounds { - [] => (span.shrink_to_hi(), ":"), - [.., bound] => (bound.span().shrink_to_hi(), " +"), - }; - err.span_suggestion_verbose( - span, - "consider relaxing the implicit `Sized` restriction", - format!("{} ?Sized", separator), - Applicability::MachineApplicable, + let (pred, item_def_id, span) = + match (obligation.predicate.kind(), &obligation.cause.code.peel_derives()) { + ( + ty::PredicateKind::Trait(pred, _), + ObligationCauseCode::BindingObligation(item_def_id, span), + ) => (pred, item_def_id, span), + _ => return, + }; + + let node = match ( + self.tcx.hir().get_if_local(*item_def_id), + Some(pred.def_id()) == self.tcx.lang_items().sized_trait(), + ) { + (Some(node), true) => node, + _ => return, + }; + let generics = match node.generics() { + Some(generics) => generics, + None => return, + }; + for param in generics.params { + if param.span != *span + || param.bounds.iter().any(|bound| { + bound.trait_ref().and_then(|trait_ref| trait_ref.trait_def_id()) + == self.tcx.lang_items().sized_trait() + }) + { + continue; + } + match node { + hir::Node::Item( + item + @ + hir::Item { + kind: + hir::ItemKind::Enum(..) + | hir::ItemKind::Struct(..) + | hir::ItemKind::Union(..), + .. + }, + ) => { + // Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a + // borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S(T);` + // is not. + let mut visitor = FindTypeParam { + param: param.name.ident().name, + invalid_spans: vec![], + nested: false, + }; + visitor.visit_item(item); + if !visitor.invalid_spans.is_empty() { + let mut multispan: MultiSpan = param.span.into(); + multispan.push_span_label( + param.span, + format!("this could be changed to `{}: ?Sized`...", param.name.ident()), + ); + for sp in visitor.invalid_spans { + multispan.push_span_label( + sp, + format!( + "...if indirection was used here: `Box<{}>`", + param.name.ident(), + ), + ); + } + err.span_help( + multispan, + &format!( + "you could relax the implicit `Sized` bound on `{T}` if it were \ + used through indirection like `&{T}` or `Box<{T}>`", + T = param.name.ident(), + ), ); return; } } + _ => {} } + let (span, separator) = match param.bounds { + [] => (span.shrink_to_hi(), ":"), + [.., bound] => (bound.span().shrink_to_hi(), " +"), + }; + err.span_suggestion_verbose( + span, + "consider relaxing the implicit `Sized` restriction", + format!("{} ?Sized", separator), + Applicability::MachineApplicable, + ); + return; } } @@ -1744,6 +1804,50 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { } } +/// Look for type `param` in an ADT being used only through a reference to confirm that suggesting +/// `param: ?Sized` would be a valid constraint. +struct FindTypeParam { + param: rustc_span::Symbol, + invalid_spans: Vec, + nested: bool, +} + +impl<'v> Visitor<'v> for FindTypeParam { + type Map = rustc_hir::intravisit::ErasedMap<'v>; + + fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap { + hir::intravisit::NestedVisitorMap::None + } + + fn visit_ty(&mut self, ty: &hir::Ty<'_>) { + // We collect the spans of all uses of the "bare" type param, like in `field: T` or + // `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be + // valid like `field: &'a T` or `field: *mut T` and cases that *might* have further `Sized` + // obligations like `Box` and `Vec`, but we perform no extra analysis for those cases + // and suggest `T: ?Sized` regardless of their obligations. This is fine because the errors + // in that case should make what happened clear enough. + match ty.kind { + hir::TyKind::Ptr(_) | hir::TyKind::Rptr(..) | hir::TyKind::TraitObject(..) => {} + hir::TyKind::Path(hir::QPath::Resolved(None, path)) + if path.segments.len() == 1 && path.segments[0].ident.name == self.param => + { + if !self.nested { + self.invalid_spans.push(ty.span); + } + } + hir::TyKind::Path(_) => { + let prev = self.nested; + self.nested = true; + hir::intravisit::walk_ty(self, ty); + self.nested = prev; + } + _ => { + hir::intravisit::walk_ty(self, ty); + } + } + } +} + pub fn recursive_type_with_infinite_size_error( tcx: TyCtxt<'tcx>, type_def_id: DefId, diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 019b4ca66060c..bcfc0cf347cbc 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -783,6 +783,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let literal_is_ty_suffixed = |expr: &hir::Expr<'_>| { if let hir::ExprKind::Lit(lit) = &expr.kind { lit.node.is_suffixed() } else { false } }; + let is_negative_int = + |expr: &hir::Expr<'_>| matches!(expr.kind, hir::ExprKind::Unary(hir::UnOp::UnNeg, ..)); + let is_uint = |ty: Ty<'_>| matches!(ty.kind, ty::Uint(..)); let in_const_context = self.tcx.hir().is_inside_const_context(expr.hir_id); @@ -807,7 +810,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "you can convert `{}` from `{}` to `{}`, matching the type of `{}`", lhs_src, expected_ty, checked_ty, src ); - let suggestion = format!("{}::from({})", checked_ty, lhs_src,); + let suggestion = format!("{}::from({})", checked_ty, lhs_src); (lhs_expr.span, msg, suggestion) } else { let msg = format!("{} and panic if the converted value wouldn't fit", msg); @@ -822,8 +825,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |err: &mut DiagnosticBuilder<'_>, found_to_exp_is_fallible: bool, exp_to_found_is_fallible: bool| { + let always_fallible = found_to_exp_is_fallible + && (exp_to_found_is_fallible || expected_ty_expr.is_none()); let msg = if literal_is_ty_suffixed(expr) { &lit_msg + } else if always_fallible && (is_negative_int(expr) && is_uint(expected_ty)) { + // We now know that converting either the lhs or rhs is fallible. Before we + // suggest a fallible conversion, check if the value can never fit in the + // expected type. + let msg = format!("`{}` cannot fit into type `{}`", src, expected_ty); + err.note(&msg); + return; } else if in_const_context { // Do not recommend `into` or `try_into` in const contexts. return; diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 188f4a9401422..6a00667637155 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -888,10 +888,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rcvr, probe::ProbeScope::AllTraits, ) { - err.span_label( - pick.item.ident.span, - &format!("the method is available for `{}` here", new_rcvr_t), - ); + debug!("try_alt_rcvr: pick candidate {:?}", pick); + // Make sure the method is defined for the *actual* receiver: + // we don't want to treat `Box` as a receiver if + // it only works because of an autoderef to `&self` + if pick.autoderefs == 0 { + err.span_label( + pick.item.ident.span, + &format!("the method is available for `{}` here", new_rcvr_t), + ); + } } } }; diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index ac3fa15417e9c..259c4a8664f1b 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -194,11 +194,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.lookup_probe(span, segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?; for import_id in &pick.import_ids { - let import_def_id = self.tcx.hir().local_def_id(*import_id); - debug!("used_trait_import: {:?}", import_def_id); + debug!("used_trait_import: {:?}", import_id); Lrc::get_mut(&mut self.tables.borrow_mut().used_trait_imports) .unwrap() - .insert(import_def_id.to_def_id()); + .insert(*import_id); } self.tcx.check_stability(pick.item.def_id, Some(call_expr.hir_id), span); @@ -461,9 +460,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut tables = self.tables.borrow_mut(); let used_trait_imports = Lrc::get_mut(&mut tables.used_trait_imports).unwrap(); for import_id in pick.import_ids { - let import_def_id = tcx.hir().local_def_id(import_id); - debug!("resolve_ufcs: used_trait_import: {:?}", import_def_id); - used_trait_imports.insert(import_def_id.to_def_id()); + debug!("resolve_ufcs: used_trait_import: {:?}", import_id); + used_trait_imports.insert(import_id); } } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 93bcd5cf29149..eb8f76687174e 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -28,6 +28,7 @@ use rustc_middle::ty::{ }; use rustc_session::config::nightly_options; use rustc_session::lint; +use rustc_span::def_id::LocalDefId; use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy; @@ -129,7 +130,7 @@ struct Candidate<'tcx> { xform_ret_ty: Option>, item: ty::AssocItem, kind: CandidateKind<'tcx>, - import_ids: SmallVec<[hir::HirId; 1]>, + import_ids: SmallVec<[LocalDefId; 1]>, } #[derive(Debug)] @@ -158,7 +159,7 @@ enum ProbeResult { pub struct Pick<'tcx> { pub item: ty::AssocItem, pub kind: PickKind<'tcx>, - pub import_ids: SmallVec<[hir::HirId; 1]>, + pub import_ids: SmallVec<[LocalDefId; 1]>, // Indicates that the source expression should be autoderef'd N times // @@ -930,7 +931,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { fn assemble_extension_candidates_for_trait( &mut self, - import_ids: &SmallVec<[hir::HirId; 1]>, + import_ids: &SmallVec<[LocalDefId; 1]>, trait_def_id: DefId, ) -> Result<(), MethodError<'tcx>> { debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 2ece8e8c28423..775441cb74666 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -97,7 +97,7 @@ use rustc_errors::ErrorReported; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::lang_items::{ @@ -840,7 +840,7 @@ fn has_typeck_tables(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } } -fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &DefIdSet { +fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet { &*tcx.typeck_tables_of(def_id).used_trait_imports } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 90ba15aa08988..d3bccaaa3e4b9 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -439,7 +439,10 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { /// Invoked on any adjustments that occur. Checks that if this is a region pointer being /// dereferenced, the lifetime of the pointer includes the deref expr. - fn constrain_adjustments(&mut self, expr: &hir::Expr<'_>) -> mc::McResult> { + fn constrain_adjustments( + &mut self, + expr: &hir::Expr<'_>, + ) -> mc::McResult> { debug!("constrain_adjustments(expr={:?})", expr); let mut place = self.with_mc(|mc| mc.cat_expr_unadjusted(expr))?; @@ -480,12 +483,12 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { fn check_safety_of_rvalue_destructor_if_necessary( &mut self, - place: &mc::Place<'tcx>, + place_with_id: &mc::PlaceWithHirId<'tcx>, span: Span, ) { - if let mc::PlaceBase::Rvalue = place.base { - if place.projections.is_empty() { - let typ = self.resolve_type(place.ty); + if let mc::PlaceBase::Rvalue = place_with_id.place.base { + if place_with_id.place.projections.is_empty() { + let typ = self.resolve_type(place_with_id.place.ty); let body_id = self.body_id; let _ = dropck::check_drop_obligations(self, typ, span, body_id); } @@ -570,7 +573,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { /// Link lifetimes of any ref bindings in `root_pat` to the pointers found /// in the discriminant, if needed. - fn link_pattern(&self, discr_cmt: mc::Place<'tcx>, root_pat: &hir::Pat<'_>) { + fn link_pattern(&self, discr_cmt: mc::PlaceWithHirId<'tcx>, root_pat: &hir::Pat<'_>) { debug!("link_pattern(discr_cmt={:?}, root_pat={:?})", discr_cmt, root_pat); ignore_err!(self.with_mc(|mc| { mc.cat_pattern(discr_cmt, root_pat, |sub_cmt, hir::Pat { kind, span, hir_id }| { @@ -591,7 +594,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { fn link_autoref( &self, expr: &hir::Expr<'_>, - expr_cmt: &mc::Place<'tcx>, + expr_cmt: &mc::PlaceWithHirId<'tcx>, autoref: &adjustment::AutoBorrow<'tcx>, ) { debug!("link_autoref(autoref={:?}, expr_cmt={:?})", autoref, expr_cmt); @@ -612,7 +615,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { span: Span, id: hir::HirId, mutbl: hir::Mutability, - cmt_borrowed: &mc::Place<'tcx>, + cmt_borrowed: &mc::PlaceWithHirId<'tcx>, ) { debug!( "link_region_from_node_type(id={:?}, mutbl={:?}, cmt_borrowed={:?})", @@ -635,12 +638,12 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { span: Span, borrow_region: ty::Region<'tcx>, borrow_kind: ty::BorrowKind, - borrow_place: &mc::Place<'tcx>, + borrow_place: &mc::PlaceWithHirId<'tcx>, ) { - let origin = infer::DataBorrowed(borrow_place.ty, span); - self.type_must_outlive(origin, borrow_place.ty, borrow_region); + let origin = infer::DataBorrowed(borrow_place.place.ty, span); + self.type_must_outlive(origin, borrow_place.place.ty, borrow_region); - for pointer_ty in borrow_place.deref_tys() { + for pointer_ty in borrow_place.place.deref_tys() { debug!( "link_region(borrow_region={:?}, borrow_kind={:?}, pointer_ty={:?})", borrow_region, borrow_kind, borrow_place @@ -656,7 +659,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { _ => assert!(pointer_ty.is_box(), "unexpected built-in deref type {}", pointer_ty), } } - if let mc::PlaceBase::Upvar(upvar_id) = borrow_place.base { + if let mc::PlaceBase::Upvar(upvar_id) = borrow_place.place.base { self.link_upvar_region(span, borrow_region, upvar_id); } } diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 8403c99f01bb5..0f3133e0695f1 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -270,10 +270,13 @@ struct InferBorrowKind<'a, 'tcx> { impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { fn adjust_upvar_borrow_kind_for_consume( &mut self, - place: &mc::Place<'tcx>, + place_with_id: &mc::PlaceWithHirId<'tcx>, mode: euv::ConsumeMode, ) { - debug!("adjust_upvar_borrow_kind_for_consume(place={:?}, mode={:?})", place, mode); + debug!( + "adjust_upvar_borrow_kind_for_consume(place_with_id={:?}, mode={:?})", + place_with_id, mode + ); // we only care about moves match mode { @@ -284,7 +287,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { } let tcx = self.fcx.tcx; - let upvar_id = if let PlaceBase::Upvar(upvar_id) = place.base { + let upvar_id = if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base { upvar_id } else { return; @@ -296,22 +299,22 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { self.adjust_closure_kind( upvar_id.closure_expr_id, ty::ClosureKind::FnOnce, - place.span, + tcx.hir().span(place_with_id.hir_id), var_name(tcx, upvar_id.var_path.hir_id), ); self.adjust_upvar_captures.insert(upvar_id, ty::UpvarCapture::ByValue); } - /// Indicates that `place` is being directly mutated (e.g., assigned + /// Indicates that `place_with_id` is being directly mutated (e.g., assigned /// to). If the place is based on a by-ref upvar, this implies that /// the upvar must be borrowed using an `&mut` borrow. - fn adjust_upvar_borrow_kind_for_mut(&mut self, place: &mc::Place<'tcx>) { - debug!("adjust_upvar_borrow_kind_for_mut(place={:?})", place); + fn adjust_upvar_borrow_kind_for_mut(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>) { + debug!("adjust_upvar_borrow_kind_for_mut(place_with_id={:?})", place_with_id); - if let PlaceBase::Upvar(upvar_id) = place.base { + if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base { let mut borrow_kind = ty::MutBorrow; - for pointer_ty in place.deref_tys() { + for pointer_ty in place_with_id.place.deref_tys() { match pointer_ty.kind { // Raw pointers don't inherit mutability. ty::RawPtr(_) => return, @@ -323,20 +326,28 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { _ => (), } } - self.adjust_upvar_deref(upvar_id, place.span, borrow_kind); + self.adjust_upvar_deref( + upvar_id, + self.fcx.tcx.hir().span(place_with_id.hir_id), + borrow_kind, + ); } } - fn adjust_upvar_borrow_kind_for_unique(&mut self, place: &mc::Place<'tcx>) { - debug!("adjust_upvar_borrow_kind_for_unique(place={:?})", place); + fn adjust_upvar_borrow_kind_for_unique(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>) { + debug!("adjust_upvar_borrow_kind_for_unique(place_with_id={:?})", place_with_id); - if let PlaceBase::Upvar(upvar_id) = place.base { - if place.deref_tys().any(ty::TyS::is_unsafe_ptr) { + if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base { + if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) { // Raw pointers don't inherit mutability. return; } // for a borrowed pointer to be unique, its base must be unique - self.adjust_upvar_deref(upvar_id, place.span, ty::UniqueImmBorrow); + self.adjust_upvar_deref( + upvar_id, + self.fcx.tcx.hir().span(place_with_id.hir_id), + ty::UniqueImmBorrow, + ); } } @@ -453,26 +464,26 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { } impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { - fn consume(&mut self, place: &mc::Place<'tcx>, mode: euv::ConsumeMode) { - debug!("consume(place={:?},mode={:?})", place, mode); - self.adjust_upvar_borrow_kind_for_consume(place, mode); + fn consume(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>, mode: euv::ConsumeMode) { + debug!("consume(place_with_id={:?},mode={:?})", place_with_id, mode); + self.adjust_upvar_borrow_kind_for_consume(place_with_id, mode); } - fn borrow(&mut self, place: &mc::Place<'tcx>, bk: ty::BorrowKind) { - debug!("borrow(place={:?}, bk={:?})", place, bk); + fn borrow(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>, bk: ty::BorrowKind) { + debug!("borrow(place_with_id={:?}, bk={:?})", place_with_id, bk); match bk { ty::ImmBorrow => {} ty::UniqueImmBorrow => { - self.adjust_upvar_borrow_kind_for_unique(place); + self.adjust_upvar_borrow_kind_for_unique(place_with_id); } ty::MutBorrow => { - self.adjust_upvar_borrow_kind_for_mut(place); + self.adjust_upvar_borrow_kind_for_mut(place_with_id); } } } - fn mutate(&mut self, assignee_place: &mc::Place<'tcx>) { + fn mutate(&mut self, assignee_place: &mc::PlaceWithHirId<'tcx>) { debug!("mutate(assignee_place={:?})", assignee_place); self.adjust_upvar_borrow_kind_for_mut(assignee_place); diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index ba806430f17fd..4704d8fc7666f 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -4,10 +4,8 @@ use crate::check::FnCtxt; -use rustc_data_structures::sync::Lrc; use rustc_errors::ErrorReported; use rustc_hir as hir; -use rustc_hir::def_id::DefIdSet; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; use rustc_infer::infer::InferCtxt; @@ -67,10 +65,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { wbcx.visit_user_provided_sigs(); wbcx.visit_generator_interior_types(); - let used_trait_imports = mem::replace( - &mut self.tables.borrow_mut().used_trait_imports, - Lrc::new(DefIdSet::default()), - ); + let used_trait_imports = mem::take(&mut self.tables.borrow_mut().used_trait_imports); debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports); wbcx.tables.used_trait_imports = used_trait_imports; diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index eaaff70472bfb..81daf064bb368 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -1,14 +1,14 @@ -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::def_id::{DefId, DefIdSet, LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_middle::ty::TyCtxt; use rustc_session::lint; use rustc_span::{Span, Symbol}; pub fn check_crate(tcx: TyCtxt<'_>) { - let mut used_trait_imports = DefIdSet::default(); + let mut used_trait_imports = FxHashSet::default(); for &body_id in tcx.hir().krate().bodies.keys() { let item_def_id = tcx.hir().body_owner_def_id(body_id); let imports = tcx.used_trait_imports(item_def_id); @@ -39,7 +39,7 @@ impl ItemLikeVisitor<'v> for CheckVisitor<'tcx> { struct CheckVisitor<'tcx> { tcx: TyCtxt<'tcx>, - used_trait_imports: DefIdSet, + used_trait_imports: FxHashSet, } impl CheckVisitor<'tcx> { @@ -49,7 +49,7 @@ impl CheckVisitor<'tcx> { return; } - if self.used_trait_imports.contains(&def_id.to_def_id()) { + if self.used_trait_imports.contains(&def_id) { return; } diff --git a/src/librustc_typeck/expr_use_visitor.rs b/src/librustc_typeck/expr_use_visitor.rs index 6baadb8febd36..b72fae96e4ca0 100644 --- a/src/librustc_typeck/expr_use_visitor.rs +++ b/src/librustc_typeck/expr_use_visitor.rs @@ -5,7 +5,7 @@ pub use self::ConsumeMode::*; // Export these here so that Clippy can use them. -pub use mc::{Place, PlaceBase, Projection}; +pub use mc::{PlaceBase, PlaceWithHirId, Projection}; use rustc_hir as hir; use rustc_hir::def::Res; @@ -25,13 +25,13 @@ use rustc_span::Span; pub trait Delegate<'tcx> { // The value found at `place` is either copied or moved, depending // on mode. - fn consume(&mut self, place: &mc::Place<'tcx>, mode: ConsumeMode); + fn consume(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>, mode: ConsumeMode); // The value found at `place` is being borrowed with kind `bk`. - fn borrow(&mut self, place: &mc::Place<'tcx>, bk: ty::BorrowKind); + fn borrow(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>, bk: ty::BorrowKind); - // The path at `place` is being assigned to. - fn mutate(&mut self, assignee_place: &mc::Place<'tcx>); + // The path at `place_with_id` is being assigned to. + fn mutate(&mut self, assignee_place: &mc::PlaceWithHirId<'tcx>); } #[derive(Copy, Clone, PartialEq, Debug)] @@ -113,11 +113,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { self.mc.tcx() } - fn delegate_consume(&mut self, place: &Place<'tcx>) { - debug!("delegate_consume(place={:?})", place); + fn delegate_consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>) { + debug!("delegate_consume(place_with_id={:?})", place_with_id); - let mode = copy_or_move(&self.mc, place); - self.delegate.consume(place, mode); + let mode = copy_or_move(&self.mc, place_with_id); + self.delegate.consume(place_with_id, mode); } fn consume_exprs(&mut self, exprs: &[hir::Expr<'_>]) { @@ -129,22 +129,22 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { pub fn consume_expr(&mut self, expr: &hir::Expr<'_>) { debug!("consume_expr(expr={:?})", expr); - let place = return_if_err!(self.mc.cat_expr(expr)); - self.delegate_consume(&place); + let place_with_id = return_if_err!(self.mc.cat_expr(expr)); + self.delegate_consume(&place_with_id); self.walk_expr(expr); } fn mutate_expr(&mut self, expr: &hir::Expr<'_>) { - let place = return_if_err!(self.mc.cat_expr(expr)); - self.delegate.mutate(&place); + let place_with_id = return_if_err!(self.mc.cat_expr(expr)); + self.delegate.mutate(&place_with_id); self.walk_expr(expr); } fn borrow_expr(&mut self, expr: &hir::Expr<'_>, bk: ty::BorrowKind) { debug!("borrow_expr(expr={:?}, bk={:?})", expr, bk); - let place = return_if_err!(self.mc.cat_expr(expr)); - self.delegate.borrow(&place, bk); + let place_with_id = return_if_err!(self.mc.cat_expr(expr)); + self.delegate.borrow(&place_with_id, bk); self.walk_expr(expr) } @@ -384,7 +384,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // Select just those fields of the `with` // expression that will actually be used - match with_place.ty.kind { + match with_place.place.ty.kind { ty::Adt(adt, substs) if adt.is_struct() => { // Consume those fields of the with expression that are needed. for (f_index, with_field) in adt.non_enum_variant().fields.iter().enumerate() { @@ -422,14 +422,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // process. fn walk_adjustment(&mut self, expr: &hir::Expr<'_>) { let adjustments = self.mc.tables.expr_adjustments(expr); - let mut place = return_if_err!(self.mc.cat_expr_unadjusted(expr)); + let mut place_with_id = return_if_err!(self.mc.cat_expr_unadjusted(expr)); for adjustment in adjustments { debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment); match adjustment.kind { adjustment::Adjust::NeverToAny | adjustment::Adjust::Pointer(_) => { // Creating a closure/fn-pointer or unsizing consumes // the input and stores it into the resulting rvalue. - self.delegate_consume(&place); + self.delegate_consume(&place_with_id); } adjustment::Adjust::Deref(None) => {} @@ -441,14 +441,15 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // this is an autoref of `x`. adjustment::Adjust::Deref(Some(ref deref)) => { let bk = ty::BorrowKind::from_mutbl(deref.mutbl); - self.delegate.borrow(&place, bk); + self.delegate.borrow(&place_with_id, bk); } adjustment::Adjust::Borrow(ref autoref) => { - self.walk_autoref(expr, &place, autoref); + self.walk_autoref(expr, &place_with_id, autoref); } } - place = return_if_err!(self.mc.cat_expr_adjusted(expr, place, &adjustment)); + place_with_id = + return_if_err!(self.mc.cat_expr_adjusted(expr, place_with_id, &adjustment)); } } @@ -458,7 +459,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { fn walk_autoref( &mut self, expr: &hir::Expr<'_>, - base_place: &mc::Place<'tcx>, + base_place: &mc::PlaceWithHirId<'tcx>, autoref: &adjustment::AutoBorrow<'tcx>, ) { debug!( @@ -479,7 +480,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } } - fn walk_arm(&mut self, discr_place: &Place<'tcx>, arm: &hir::Arm<'_>) { + fn walk_arm(&mut self, discr_place: &PlaceWithHirId<'tcx>, arm: &hir::Arm<'_>) { self.walk_pat(discr_place, &arm.pat); if let Some(hir::Guard::If(ref e)) = arm.guard { @@ -491,12 +492,12 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { /// Walks a pat that occurs in isolation (i.e., top-level of fn argument or /// let binding, and *not* a match arm or nested pat.) - fn walk_irrefutable_pat(&mut self, discr_place: &Place<'tcx>, pat: &hir::Pat<'_>) { + fn walk_irrefutable_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) { self.walk_pat(discr_place, pat); } /// The core driver for walking a pattern - fn walk_pat(&mut self, discr_place: &Place<'tcx>, pat: &hir::Pat<'_>) { + fn walk_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) { debug!("walk_pat(discr_place={:?}, pat={:?})", discr_place, pat); let tcx = self.tcx(); @@ -569,7 +570,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { closure_hir_id: hir::HirId, closure_span: Span, var_id: hir::HirId, - ) -> mc::McResult> { + ) -> mc::McResult> { // Create the place for the variable being borrowed, from the // perspective of the creator (parent) of the closure. let var_ty = self.mc.node_ty(var_id)?; @@ -579,7 +580,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { fn copy_or_move<'a, 'tcx>( mc: &mc::MemCategorizationContext<'a, 'tcx>, - place: &Place<'tcx>, + place_with_id: &PlaceWithHirId<'tcx>, ) -> ConsumeMode { - if !mc.type_is_copy_modulo_regions(place.ty, place.span) { Move } else { Copy } + if !mc.type_is_copy_modulo_regions( + place_with_id.place.ty, + mc.tcx().hir().span(place_with_id.hir_id), + ) { + Move + } else { + Copy + } } diff --git a/src/librustc_typeck/mem_categorization.rs b/src/librustc_typeck/mem_categorization.rs index 93d01ccd66f1e..d619d37be2d7b 100644 --- a/src/librustc_typeck/mem_categorization.rs +++ b/src/librustc_typeck/mem_categorization.rs @@ -74,22 +74,24 @@ pub enum PlaceBase { } #[derive(Clone, Debug)] -pub enum Projection<'tcx> { +pub enum ProjectionKind<'tcx> { /// A dereference of a pointer, reference or `Box` of the given type Deref(Ty<'tcx>), /// An index or a field Other, } +#[derive(Clone, Debug)] +pub struct Projection<'tcx> { + /// Defines the type of access + kind: ProjectionKind<'tcx>, +} + /// A `Place` represents how a value is located in memory. /// /// This is an HIR version of `mir::Place` #[derive(Clone, Debug)] pub struct Place<'tcx> { - /// `HirId` of the expression or pattern producing this value. - pub hir_id: hir::HirId, - /// The `Span` of the expression or pattern producing this value. - pub span: Span, /// The type of the `Place` pub ty: Ty<'tcx>, /// The "outermost" place that holds this value. @@ -98,6 +100,32 @@ pub struct Place<'tcx> { pub projections: Vec>, } +/// A `PlaceWithHirId` represents how a value is located in memory. +/// +/// This is an HIR version of `mir::Place` +#[derive(Clone, Debug)] +pub struct PlaceWithHirId<'tcx> { + /// `HirId` of the expression or pattern producing this value. + pub hir_id: hir::HirId, + + /// Information about the `Place` + pub place: Place<'tcx>, +} + +impl<'tcx> PlaceWithHirId<'tcx> { + crate fn new( + hir_id: hir::HirId, + ty: Ty<'tcx>, + base: PlaceBase, + projections: Vec>, + ) -> PlaceWithHirId<'tcx> { + PlaceWithHirId { + hir_id: hir_id, + place: Place { ty: ty, base: base, projections: projections }, + } + } +} + impl<'tcx> Place<'tcx> { /// Returns an iterator of the types that have to be dereferenced to access /// the `Place`. @@ -107,7 +135,7 @@ impl<'tcx> Place<'tcx> { ///`*const u32` then `&*const u32`. crate fn deref_tys(&self) -> impl Iterator> + '_ { self.projections.iter().rev().filter_map(|proj| { - if let Projection::Deref(deref_ty) = *proj { Some(deref_ty) } else { None } + if let ProjectionKind::Deref(deref_ty) = proj.kind { Some(deref_ty) } else { None } }) } } @@ -280,14 +308,14 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { Ok(ret_ty) } - crate fn cat_expr(&self, expr: &hir::Expr<'_>) -> McResult> { + crate fn cat_expr(&self, expr: &hir::Expr<'_>) -> McResult> { // This recursion helper avoids going through *too many* // adjustments, since *only* non-overloaded deref recurses. fn helper<'a, 'tcx>( mc: &MemCategorizationContext<'a, 'tcx>, expr: &hir::Expr<'_>, adjustments: &[adjustment::Adjustment<'tcx>], - ) -> McResult> { + ) -> McResult> { match adjustments.split_last() { None => mc.cat_expr_unadjusted(expr), Some((adjustment, previous)) => { @@ -302,9 +330,9 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { crate fn cat_expr_adjusted( &self, expr: &hir::Expr<'_>, - previous: Place<'tcx>, + previous: PlaceWithHirId<'tcx>, adjustment: &adjustment::Adjustment<'tcx>, - ) -> McResult> { + ) -> McResult> { self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment) } @@ -313,9 +341,9 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { expr: &hir::Expr<'_>, previous: F, adjustment: &adjustment::Adjustment<'tcx>, - ) -> McResult> + ) -> McResult> where - F: FnOnce() -> McResult>, + F: FnOnce() -> McResult>, { debug!("cat_expr_adjusted_with({:?}): {:?}", adjustment, expr); let target = self.resolve_vars_if_possible(&adjustment.target); @@ -342,7 +370,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { } } - crate fn cat_expr_unadjusted(&self, expr: &hir::Expr<'_>) -> McResult> { + crate fn cat_expr_unadjusted(&self, expr: &hir::Expr<'_>) -> McResult> { debug!("cat_expr: id={} expr={:?}", expr.hir_id, expr); let expr_ty = self.expr_ty(expr)?; @@ -418,7 +446,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { span: Span, expr_ty: Ty<'tcx>, res: Res, - ) -> McResult> { + ) -> McResult> { debug!("cat_res: id={:?} expr={:?} def={:?}", hir_id, expr_ty, res); match res { @@ -433,25 +461,15 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { ) | Res::SelfCtor(..) => Ok(self.cat_rvalue(hir_id, span, expr_ty)), - Res::Def(DefKind::Static, _) => Ok(Place { - hir_id, - span, - ty: expr_ty, - base: PlaceBase::StaticItem, - projections: Vec::new(), - }), + Res::Def(DefKind::Static, _) => { + Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::StaticItem, Vec::new())) + } Res::Local(var_id) => { if self.upvars.map_or(false, |upvars| upvars.contains_key(&var_id)) { - self.cat_upvar(hir_id, span, var_id) + self.cat_upvar(hir_id, var_id) } else { - Ok(Place { - hir_id, - span, - ty: expr_ty, - base: PlaceBase::Local(var_id), - projections: Vec::new(), - }) + Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Local(var_id), Vec::new())) } } @@ -464,12 +482,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { /// Note: the actual upvar access contains invisible derefs of closure /// environment and upvar reference as appropriate. Only regionck cares /// about these dereferences, so we let it compute them as needed. - fn cat_upvar( - &self, - hir_id: hir::HirId, - span: Span, - var_id: hir::HirId, - ) -> McResult> { + fn cat_upvar(&self, hir_id: hir::HirId, var_id: hir::HirId) -> McResult> { let closure_expr_def_id = self.body_owner; let upvar_id = ty::UpvarId { @@ -478,22 +491,20 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { }; let var_ty = self.node_ty(var_id)?; - let ret = Place { - hir_id, - span, - ty: var_ty, - base: PlaceBase::Upvar(upvar_id), - projections: Vec::new(), - }; + let ret = PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new()); debug!("cat_upvar ret={:?}", ret); Ok(ret) } - crate fn cat_rvalue(&self, hir_id: hir::HirId, span: Span, expr_ty: Ty<'tcx>) -> Place<'tcx> { + crate fn cat_rvalue( + &self, + hir_id: hir::HirId, + span: Span, + expr_ty: Ty<'tcx>, + ) -> PlaceWithHirId<'tcx> { debug!("cat_rvalue hir_id={:?}, expr_ty={:?}, span={:?}", hir_id, expr_ty, span); - let ret = - Place { hir_id, span, base: PlaceBase::Rvalue, projections: Vec::new(), ty: expr_ty }; + let ret = PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new()); debug!("cat_rvalue ret={:?}", ret); ret } @@ -501,18 +512,12 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { crate fn cat_projection( &self, node: &N, - base_place: Place<'tcx>, + base_place: PlaceWithHirId<'tcx>, ty: Ty<'tcx>, - ) -> Place<'tcx> { - let mut projections = base_place.projections; - projections.push(Projection::Other); - let ret = Place { - hir_id: node.hir_id(), - span: node.span(), - ty, - base: base_place.base, - projections, - }; + ) -> PlaceWithHirId<'tcx> { + let mut projections = base_place.place.projections; + projections.push(Projection { kind: ProjectionKind::Other }); + let ret = PlaceWithHirId::new(node.hir_id(), ty, base_place.place.base, projections); debug!("cat_field ret {:?}", ret); ret } @@ -521,7 +526,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { &self, expr: &hir::Expr<'_>, base: &hir::Expr<'_>, - ) -> McResult> { + ) -> McResult> { debug!("cat_overloaded_place(expr={:?}, base={:?})", expr, base); // Reconstruct the output assuming it's a reference with the @@ -540,10 +545,14 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { self.cat_deref(expr, base) } - fn cat_deref(&self, node: &impl HirNode, base_place: Place<'tcx>) -> McResult> { + fn cat_deref( + &self, + node: &impl HirNode, + base_place: PlaceWithHirId<'tcx>, + ) -> McResult> { debug!("cat_deref: base_place={:?}", base_place); - let base_ty = base_place.ty; + let base_ty = base_place.place.ty; let deref_ty = match base_ty.builtin_deref(true) { Some(mt) => mt.ty, None => { @@ -551,28 +560,22 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { return Err(()); } }; - let mut projections = base_place.projections; - projections.push(Projection::Deref(base_ty)); - - let ret = Place { - hir_id: node.hir_id(), - span: node.span(), - ty: deref_ty, - base: base_place.base, - projections, - }; + let mut projections = base_place.place.projections; + projections.push(Projection { kind: ProjectionKind::Deref(base_ty) }); + + let ret = PlaceWithHirId::new(node.hir_id(), deref_ty, base_place.place.base, projections); debug!("cat_deref ret {:?}", ret); Ok(ret) } crate fn cat_pattern( &self, - place: Place<'tcx>, + place: PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>, mut op: F, ) -> McResult<()> where - F: FnMut(&Place<'tcx>, &hir::Pat<'_>), + F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>), { self.cat_pattern_(place, pat, &mut op) } @@ -580,24 +583,24 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { // FIXME(#19596) This is a workaround, but there should be a better way to do this fn cat_pattern_( &self, - mut place: Place<'tcx>, + mut place_with_id: PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>, op: &mut F, ) -> McResult<()> where - F: FnMut(&Place<'tcx>, &hir::Pat<'_>), + F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>), { - // Here, `place` is the `Place` being matched and pat is the pattern it + // Here, `place` is the `PlaceWithHirId` being matched and pat is the pattern it // is being matched against. // // In general, the way that this works is that we walk down the pattern, - // constructing a `Place` that represents the path that will be taken + // constructing a `PlaceWithHirId` that represents the path that will be taken // to reach the value being matched. - debug!("cat_pattern(pat={:?}, place={:?})", pat, place); + debug!("cat_pattern(pat={:?}, place_with_id={:?})", pat, place_with_id); - // If (pattern) adjustments are active for this pattern, adjust the `Place` correspondingly. - // `Place`s are constructed differently from patterns. For example, in + // If (pattern) adjustments are active for this pattern, adjust the `PlaceWithHirId` correspondingly. + // `PlaceWithHirId`s are constructed differently from patterns. For example, in // // ``` // match foo { @@ -607,7 +610,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { // ``` // // the pattern `&&Some(x,)` is represented as `Ref { Ref { TupleStruct }}`. To build the - // corresponding `Place` we start with the `Place` for `foo`, and then, by traversing the + // corresponding `PlaceWithHirId` we start with the `PlaceWithHirId` for `foo`, and then, by traversing the // pattern, try to answer the question: given the address of `foo`, how is `x` reached? // // `&&Some(x,)` `place_foo` @@ -629,29 +632,29 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { // `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)` // and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`. for _ in 0..self.tables.pat_adjustments().get(pat.hir_id).map(|v| v.len()).unwrap_or(0) { - debug!("cat_pattern: applying adjustment to place={:?}", place); - place = self.cat_deref(pat, place)?; + debug!("cat_pattern: applying adjustment to place_with_id={:?}", place_with_id); + place_with_id = self.cat_deref(pat, place_with_id)?; } - let place = place; // lose mutability - debug!("cat_pattern: applied adjustment derefs to get place={:?}", place); + let place_with_id = place_with_id; // lose mutability + debug!("cat_pattern: applied adjustment derefs to get place_with_id={:?}", place_with_id); - // Invoke the callback, but only now, after the `place` has adjusted. + // Invoke the callback, but only now, after the `place_with_id` has adjusted. // // To see that this makes sense, consider `match &Some(3) { Some(x) => { ... }}`. In that - // case, the initial `place` will be that for `&Some(3)` and the pattern is `Some(x)`. We + // case, the initial `place_with_id` will be that for `&Some(3)` and the pattern is `Some(x)`. We // don't want to call `op` with these incompatible values. As written, what happens instead // is that `op` is called with the adjusted place (that for `*&Some(3)`) and the pattern // `Some(x)` (which matches). Recursing once more, `*&Some(3)` and the pattern `Some(x)` // result in the place `Downcast(*&Some(3)).0` associated to `x` and invoke `op` with // that (where the `ref` on `x` is implied). - op(&place, pat); + op(&place_with_id, pat); match pat.kind { PatKind::TupleStruct(_, ref subpats, _) | PatKind::Tuple(ref subpats, _) => { // S(p1, ..., pN) or (p1, ..., pN) for subpat in subpats.iter() { let subpat_ty = self.pat_ty_adjusted(&subpat)?; - let sub_place = self.cat_projection(pat, place.clone(), subpat_ty); + let sub_place = self.cat_projection(pat, place_with_id.clone(), subpat_ty); self.cat_pattern_(sub_place, &subpat, op)?; } } @@ -660,44 +663,44 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { // S { f1: p1, ..., fN: pN } for fp in field_pats { let field_ty = self.pat_ty_adjusted(&fp.pat)?; - let field_place = self.cat_projection(pat, place.clone(), field_ty); + let field_place = self.cat_projection(pat, place_with_id.clone(), field_ty); self.cat_pattern_(field_place, &fp.pat, op)?; } } PatKind::Or(pats) => { for pat in pats { - self.cat_pattern_(place.clone(), &pat, op)?; + self.cat_pattern_(place_with_id.clone(), &pat, op)?; } } PatKind::Binding(.., Some(ref subpat)) => { - self.cat_pattern_(place, &subpat, op)?; + self.cat_pattern_(place_with_id, &subpat, op)?; } PatKind::Box(ref subpat) | PatKind::Ref(ref subpat, _) => { // box p1, &p1, &mut p1. we can ignore the mutability of // PatKind::Ref since that information is already contained // in the type. - let subplace = self.cat_deref(pat, place)?; + let subplace = self.cat_deref(pat, place_with_id)?; self.cat_pattern_(subplace, &subpat, op)?; } PatKind::Slice(before, ref slice, after) => { - let element_ty = match place.ty.builtin_index() { + let element_ty = match place_with_id.place.ty.builtin_index() { Some(ty) => ty, None => { - debug!("explicit index of non-indexable type {:?}", place); + debug!("explicit index of non-indexable type {:?}", place_with_id); return Err(()); } }; - let elt_place = self.cat_projection(pat, place.clone(), element_ty); + let elt_place = self.cat_projection(pat, place_with_id.clone(), element_ty); for before_pat in before { self.cat_pattern_(elt_place.clone(), &before_pat, op)?; } if let Some(ref slice_pat) = *slice { let slice_pat_ty = self.pat_ty_adjusted(&slice_pat)?; - let slice_place = self.cat_projection(pat, place, slice_pat_ty); + let slice_place = self.cat_projection(pat, place_with_id, slice_pat_ty); self.cat_pattern_(slice_place, &slice_pat, op)?; } for after_pat in after { diff --git a/src/test/assembly/asm/hexagon-types.rs b/src/test/assembly/asm/hexagon-types.rs new file mode 100644 index 0000000000000..ba2d8a363cd4e --- /dev/null +++ b/src/test/assembly/asm/hexagon-types.rs @@ -0,0 +1,130 @@ +// no-system-llvm +// assembly-output: emit-asm +// compile-flags: --target hexagon-unknown-linux-musl + +#![feature(no_core, lang_items, rustc_attrs, repr_simd)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! stringify { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *const i32; + +impl Copy for i8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for f32 {} +impl Copy for ptr {} +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +macro_rules! check { + ($func:ident $ty:ident $class:ident) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + // Hack to avoid function merging + extern "Rust" { + fn dont_merge(s: &str); + } + dont_merge(stringify!($func)); + + let y; + asm!("{} = {}", out($class) y, in($class) x); + y + } + }; +} + +// CHECK-LABEL: sym_static: +// CHECK: InlineAsm Start +// CHECK: r0 = #extern_static +// CHECK: InlineAsm End +#[no_mangle] +pub unsafe fn sym_static() { + // Hack to avoid function merging + extern "Rust" { + fn dont_merge(s: &str); + } + dont_merge(stringify!($func)); + + asm!("r0 = #{}", sym extern_static); +} + +// CHECK-LABEL: sym_fn: +// CHECK: InlineAsm Start +// CHECK: r0 = #extern_func +// CHECK: InlineAsm End +#[no_mangle] +pub unsafe fn sym_fn() { + // Hack to avoid function merging + extern "Rust" { + fn dont_merge(s: &str); + } + dont_merge(stringify!($func)); + + asm!("r0 = #{}", sym extern_func); +} + +// This is a test for multi-instruction packets, +// which require the escaped braces. +// +// CHECK-LABEL: packet: +// CHECK: InlineAsm Start +// CHECK: { +// CHECK: r{{[0-9]+}} = r0 +// CHECK: memw(r1) = r{{[0-9]+}} +// CHECK: } +// CHECK: InlineAsm End +#[no_mangle] +pub unsafe fn packet() { + let val = 1024; + asm!("{{ + {} = r0 + memw(r1) = {} + }}", out(reg) _, in(reg) &val); +} + +// CHECK-LABEL: ptr: +// CHECK: InlineAsm Start +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: InlineAsm End +check!(reg_ptr ptr reg); + +// CHECK-LABEL: reg_f32: +// CHECK: InlineAsm Start +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: InlineAsm End +check!(reg_f32 f32 reg); + +// CHECK-LABEL: reg_i32: +// CHECK: InlineAsm Start +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: InlineAsm End +check!(reg_i32 i32 reg); + +// CHECK-LABEL: reg_i8: +// CHECK: InlineAsm Start +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: InlineAsm End +check!(reg_i8 i8 reg); + +// CHECK-LABEL: reg_i16: +// CHECK: InlineAsm Start +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: InlineAsm End +check!(reg_i16 i16 reg); diff --git a/src/test/pretty/asm.pp b/src/test/pretty/asm.pp index 4903050e08ed2..b3d188dd70881 100644 --- a/src/test/pretty/asm.pp +++ b/src/test/pretty/asm.pp @@ -22,5 +22,13 @@ asm!("{0}", inout(reg) b); asm!("{0} {1}", out(reg) _, inlateout(reg) b => _); asm!("", out("al") _, lateout("rbx") _); + asm!("inst1\ninst2"); + asm!("inst1 {0}, 42\ninst2 {1}, 24", in(reg) a, out(reg) b); + asm!("inst2 {1}, 24\ninst1 {0}, 42", in(reg) a, out(reg) b); + asm!("inst1 {0}, 42\ninst2 {1}, 24", in(reg) a, out(reg) b); + asm!("inst1\ninst2"); + asm!("inst1\ninst2"); + asm!("inst1\n\tinst2"); + asm!("inst1\ninst2\ninst3\ninst4"); } } diff --git a/src/test/pretty/asm.rs b/src/test/pretty/asm.rs index 12c32e6721b33..33f25e5216b4e 100644 --- a/src/test/pretty/asm.rs +++ b/src/test/pretty/asm.rs @@ -16,5 +16,14 @@ pub fn main() { asm!("{name}", name = inout(reg) b); asm!("{} {}", out(reg) _, inlateout(reg) b => _); asm!("", out("al") _, lateout("rbx") _); + asm!("inst1", "inst2"); + asm!("inst1 {}, 42", "inst2 {}, 24", in(reg) a, out(reg) b); + asm!("inst2 {1}, 24", "inst1 {0}, 42", in(reg) a, out(reg) b); + asm!("inst1 {}, 42", "inst2 {name}, 24", in(reg) a, name = out(reg) b); + asm!("inst1 +inst2"); + asm!("inst1\ninst2"); + asm!("inst1\n\tinst2"); + asm!("inst1\ninst2", "inst3\ninst4"); } } diff --git a/src/test/ui/asm/parse-error.rs b/src/test/ui/asm/parse-error.rs index 2b1f018f3642e..fbf399d8b075c 100644 --- a/src/test/ui/asm/parse-error.rs +++ b/src/test/ui/asm/parse-error.rs @@ -13,7 +13,7 @@ fn main() { asm!("{}" foo); //~^ ERROR expected token: `,` asm!("{}", foo); - //~^ ERROR expected one of + //~^ ERROR expected operand, options, or additional template string asm!("{}", in foo); //~^ ERROR expected `(`, found `foo` asm!("{}", in(reg foo)); @@ -52,5 +52,13 @@ fn main() { //~^ ERROR named arguments cannot follow explicit register arguments asm!("{1}", in("eax") foo, const bar); //~^ ERROR positional arguments cannot follow named arguments or explicit register arguments + asm!("", options(), ""); + //~^ ERROR expected one of + asm!("{}", in(reg) foo, "{}", out(reg) foo); + //~^ ERROR expected one of + asm!(format!("{{{}}}", 0), in(reg) foo); + //~^ ERROR asm template must be a string literal + asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar); + //~^ ERROR asm template must be a string literal } } diff --git a/src/test/ui/asm/parse-error.stderr b/src/test/ui/asm/parse-error.stderr index 583a10570360b..ba7e8f7a03cca 100644 --- a/src/test/ui/asm/parse-error.stderr +++ b/src/test/ui/asm/parse-error.stderr @@ -16,11 +16,11 @@ error: expected token: `,` LL | asm!("{}" foo); | ^^^ expected `,` -error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `foo` +error: expected operand, options, or additional template string --> $DIR/parse-error.rs:15:20 | LL | asm!("{}", foo); - | ^^^ expected one of 8 possible tokens + | ^^^ expected operand, options, or additional template string error: expected `(`, found `foo` --> $DIR/parse-error.rs:17:23 @@ -160,5 +160,33 @@ LL | asm!("{1}", in("eax") foo, const bar); | | | explicit register argument -error: aborting due to 24 previous errors +error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""` + --> $DIR/parse-error.rs:55:29 + | +LL | asm!("", options(), ""); + | ^^ expected one of 8 possible tokens + +error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"` + --> $DIR/parse-error.rs:57:33 + | +LL | asm!("{}", in(reg) foo, "{}", out(reg) foo); + | ^^^^ expected one of 8 possible tokens + +error: asm template must be a string literal + --> $DIR/parse-error.rs:59:14 + | +LL | asm!(format!("{{{}}}", 0), in(reg) foo); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: asm template must be a string literal + --> $DIR/parse-error.rs:61:21 + | +LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 28 previous errors diff --git a/src/test/ui/asm/srcloc.rs b/src/test/ui/asm/srcloc.rs index 402adc50d5b44..1477e3dd5665c 100644 --- a/src/test/ui/asm/srcloc.rs +++ b/src/test/ui/asm/srcloc.rs @@ -40,5 +40,85 @@ fn main() { asm!("movaps %xmm3, (%esi, 2)", options(att_syntax)); //~^ WARN: scale factor without index register is ignored + + asm!( + "invalid_instruction", + ); + //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!( + "mov eax, eax", + "invalid_instruction", + "mov eax, eax", + ); + //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!( + "mov eax, eax\n", + "invalid_instruction", + "mov eax, eax", + ); + //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!( + "mov eax, eax", + concat!("invalid", "_", "instruction"), + "mov eax, eax", + ); + //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!( + concat!("mov eax", ", ", "eax"), + concat!("invalid", "_", "instruction"), + concat!("mov eax", ", ", "eax"), + ); + //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + // Make sure template strings get separated + asm!( + "invalid_instruction1", + "invalid_instruction2", + ); + //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1' + //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2' + + asm!( + concat!( + "invalid", "_", "instruction1", "\n", + "invalid", "_", "instruction2", + ), + ); + //~^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1' + //~^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2' + + asm!( + concat!( + "invalid", "_", "instruction1", "\n", + "invalid", "_", "instruction2", + ), + concat!( + "invalid", "_", "instruction3", "\n", + "invalid", "_", "instruction4", + ), + ); + //~^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1' + //~^^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2' + //~^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction3' + //~^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction4' + + asm!( + concat!( + "invalid", "_", "instruction1", "\n", + "invalid", "_", "instruction2", "\n", + ), + concat!( + "invalid", "_", "instruction3", "\n", + "invalid", "_", "instruction4", "\n", + ), + ); + //~^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1' + //~^^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2' + //~^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction3' + //~^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction4' } } diff --git a/src/test/ui/asm/srcloc.stderr b/src/test/ui/asm/srcloc.stderr index d5d12b004816f..b62c8948289dd 100644 --- a/src/test/ui/asm/srcloc.stderr +++ b/src/test/ui/asm/srcloc.stderr @@ -82,5 +82,209 @@ note: instantiated into assembly here LL | movaps %xmm3, (%esi, 2) | ^ -error: aborting due to 6 previous errors; 1 warning emitted +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:45:14 + | +LL | "invalid_instruction", + | ^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:51:14 + | +LL | "invalid_instruction", + | ^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:58:14 + | +LL | "invalid_instruction", + | ^ + | +note: instantiated into assembly here + --> :4:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:65:13 + | +LL | concat!("invalid", "_", "instruction"), + | ^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:72:13 + | +LL | concat!("invalid", "_", "instruction"), + | ^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction1' + --> $DIR/srcloc.rs:79:14 + | +LL | "invalid_instruction1", + | ^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction1 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction2' + --> $DIR/srcloc.rs:80:14 + | +LL | "invalid_instruction2", + | ^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction2 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction1' + --> $DIR/srcloc.rs:86:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction1 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction2' + --> $DIR/srcloc.rs:86:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction2 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction1' + --> $DIR/srcloc.rs:95:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction1 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction2' + --> $DIR/srcloc.rs:95:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction2 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction3' + --> $DIR/srcloc.rs:99:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :4:1 + | +LL | invalid_instruction3 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction4' + --> $DIR/srcloc.rs:99:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :5:1 + | +LL | invalid_instruction4 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction1' + --> $DIR/srcloc.rs:110:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction1 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction2' + --> $DIR/srcloc.rs:110:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction2 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction3' + --> $DIR/srcloc.rs:114:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :5:1 + | +LL | invalid_instruction3 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction4' + --> $DIR/srcloc.rs:114:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :6:1 + | +LL | invalid_instruction4 + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 23 previous errors; 1 warning emitted diff --git a/src/test/ui/dst/dst-sized-trait-param.stderr b/src/test/ui/dst/dst-sized-trait-param.stderr index 749d569b9aedc..006a334021b14 100644 --- a/src/test/ui/dst/dst-sized-trait-param.stderr +++ b/src/test/ui/dst/dst-sized-trait-param.stderr @@ -9,6 +9,10 @@ LL | impl Foo<[isize]> for usize { } | = help: the trait `std::marker::Sized` is not implemented for `[isize]` = note: to learn more, visit +help: consider relaxing the implicit `Sized` restriction + | +LL | trait Foo : Sized { fn take(self, x: &T) { } } // Note: T is sized + | ^^^^^^^^ error[E0277]: the size for values of type `[usize]` cannot be known at compilation time --> $DIR/dst-sized-trait-param.rs:10:6 diff --git a/src/test/ui/extern/extern-types-unsized.stderr b/src/test/ui/extern/extern-types-unsized.stderr index 9ed52511fa399..0c7995fde3273 100644 --- a/src/test/ui/extern/extern-types-unsized.stderr +++ b/src/test/ui/extern/extern-types-unsized.stderr @@ -26,6 +26,10 @@ LL | assert_sized::(); = help: within `Foo`, the trait `std::marker::Sized` is not implemented for `A` = note: to learn more, visit = note: required because it appears within the type `Foo` +help: consider relaxing the implicit `Sized` restriction + | +LL | fn assert_sized() { } + | ^^^^^^^^ error[E0277]: the size for values of type `A` cannot be known at compilation time --> $DIR/extern-types-unsized.rs:28:5 @@ -39,6 +43,10 @@ LL | assert_sized::>(); = help: within `Bar`, the trait `std::marker::Sized` is not implemented for `A` = note: to learn more, visit = note: required because it appears within the type `Bar` +help: consider relaxing the implicit `Sized` restriction + | +LL | fn assert_sized() { } + | ^^^^^^^^ error[E0277]: the size for values of type `A` cannot be known at compilation time --> $DIR/extern-types-unsized.rs:31:5 @@ -53,6 +61,10 @@ LL | assert_sized::>>(); = note: to learn more, visit = note: required because it appears within the type `Bar` = note: required because it appears within the type `Bar>` +help: consider relaxing the implicit `Sized` restriction + | +LL | fn assert_sized() { } + | ^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/impl-trait/no-method-suggested-traits.stderr b/src/test/ui/impl-trait/no-method-suggested-traits.stderr index b5135b53e1890..3cd4d0dd391af 100644 --- a/src/test/ui/impl-trait/no-method-suggested-traits.stderr +++ b/src/test/ui/impl-trait/no-method-suggested-traits.stderr @@ -49,14 +49,6 @@ LL | use foo::Bar; error[E0599]: no method named `method` found for struct `std::rc::Rc<&mut std::boxed::Box<&char>>` in the current scope --> $DIR/no-method-suggested-traits.rs:32:43 | -LL | fn method(&self) {} - | ------ - | | - | the method is available for `std::boxed::Box>>` here - | the method is available for `std::pin::Pin>>` here - | the method is available for `std::sync::Arc>>` here - | the method is available for `std::rc::Rc>>` here -... LL | std::rc::Rc::new(&mut Box::new(&'a')).method(); | ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&char>>` | @@ -83,16 +75,6 @@ error[E0599]: no method named `method` found for struct `std::rc::Rc<&mut std::b | LL | std::rc::Rc::new(&mut Box::new(&1i32)).method(); | ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&i32>>` - | - ::: $DIR/auxiliary/no_method_suggested_traits.rs:8:12 - | -LL | fn method(&self) {} - | ------ - | | - | the method is available for `std::boxed::Box>>` here - | the method is available for `std::pin::Pin>>` here - | the method is available for `std::sync::Arc>>` here - | the method is available for `std::rc::Rc>>` here | = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: diff --git a/src/test/ui/issues/issue-10412.stderr b/src/test/ui/issues/issue-10412.stderr index 888576c43365f..d7a4bf4f21f18 100644 --- a/src/test/ui/issues/issue-10412.stderr +++ b/src/test/ui/issues/issue-10412.stderr @@ -57,6 +57,10 @@ LL | impl<'self> Serializable for &'self str { | = help: the trait `std::marker::Sized` is not implemented for `str` = note: to learn more, visit +help: consider relaxing the implicit `Sized` restriction + | +LL | trait Serializable<'self, T: ?Sized> { + | ^^^^^^^^ error: aborting due to 9 previous errors diff --git a/src/test/ui/issues/issue-18919.stderr b/src/test/ui/issues/issue-18919.stderr index 1ea40d0728ed1..383cdd4979ad9 100644 --- a/src/test/ui/issues/issue-18919.stderr +++ b/src/test/ui/issues/issue-18919.stderr @@ -9,6 +9,13 @@ LL | enum Option { | = help: the trait `std::marker::Sized` is not implemented for `dyn for<'r> std::ops::Fn(&'r isize) -> isize` = note: to learn more, visit +help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` + --> $DIR/issue-18919.rs:7:13 + | +LL | enum Option { + | ^ this could be changed to `T: ?Sized`... +LL | Some(T), + | - ...if indirection was used here: `Box` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-23281.stderr b/src/test/ui/issues/issue-23281.stderr index 3b4b8997a7009..cffa52361696c 100644 --- a/src/test/ui/issues/issue-23281.stderr +++ b/src/test/ui/issues/issue-23281.stderr @@ -9,6 +9,13 @@ LL | struct Vec { | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::Fn() + 'static)` = note: to learn more, visit +help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` + --> $DIR/issue-23281.rs:8:12 + | +LL | struct Vec { + | ^ this could be changed to `T: ?Sized`... +LL | t: T, + | - ...if indirection was used here: `Box` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-48508.rs b/src/test/ui/issues/issue-48508.rs index 87965c204ada7..8dc9351260ebc 100644 --- a/src/test/ui/issues/issue-48508.rs +++ b/src/test/ui/issues/issue-48508.rs @@ -11,7 +11,7 @@ // ignore-asmjs wasm2js does not support source maps yet #![feature(non_ascii_idents)] -#[allow(uncommon_codepoints)] +#![allow(uncommon_codepoints)] #[path = "issue-48508-aux.rs"] mod other_file; diff --git a/src/test/ui/lint/crate_level_only_lint.rs b/src/test/ui/lint/crate_level_only_lint.rs new file mode 100644 index 0000000000000..d9673faa2142e --- /dev/null +++ b/src/test/ui/lint/crate_level_only_lint.rs @@ -0,0 +1,22 @@ +#![deny(uncommon_codepoints, unused_attributes)] + +mod foo { +#![allow(uncommon_codepoints)] +//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] +//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] +//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] + +#[allow(uncommon_codepoints)] +//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] +//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] +//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] +const BAR: f64 = 0.000001; + +} + +#[allow(uncommon_codepoints)] +//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] +//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] +//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] +fn main() { +} diff --git a/src/test/ui/lint/crate_level_only_lint.stderr b/src/test/ui/lint/crate_level_only_lint.stderr new file mode 100644 index 0000000000000..8fb06df2a481a --- /dev/null +++ b/src/test/ui/lint/crate_level_only_lint.stderr @@ -0,0 +1,62 @@ +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:4:10 + | +LL | #![allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/crate_level_only_lint.rs:1:30 + | +LL | #![deny(uncommon_codepoints, unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:9:9 + | +LL | #[allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:17:9 + | +LL | #[allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:4:10 + | +LL | #![allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:9:9 + | +LL | #[allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:17:9 + | +LL | #[allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:4:10 + | +LL | #![allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:9:9 + | +LL | #[allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:17:9 + | +LL | #[allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 9 previous errors + diff --git a/src/test/ui/numeric/numeric-cast-no-fix.rs b/src/test/ui/numeric/numeric-cast-no-fix.rs new file mode 100644 index 0000000000000..63e5f098a25d3 --- /dev/null +++ b/src/test/ui/numeric/numeric-cast-no-fix.rs @@ -0,0 +1,87 @@ +#[allow(unused_must_use)] +fn main() { + let x_usize: usize = 1; + let x_u128: u128 = 2; + let x_u64: u64 = 3; + let x_u32: u32 = 4; + let x_u16: u16 = 5; + let x_u8: u8 = 6; + + x_usize > -1_isize; + //~^ ERROR mismatched types + x_u128 > -1_isize; + //~^ ERROR mismatched types + x_u64 > -1_isize; + //~^ ERROR mismatched types + x_u32 > -1_isize; + //~^ ERROR mismatched types + x_u16 > -1_isize; + //~^ ERROR mismatched types + x_u8 > -1_isize; + //~^ ERROR mismatched types + + x_usize > -1_i128; + //~^ ERROR mismatched types + x_u128 > -1_i128; + //~^ ERROR mismatched types + x_u64 > -1_i128; + //~^ ERROR mismatched types + x_u32 > -1_i128; + //~^ ERROR mismatched types + x_u16 > -1_i128; + //~^ ERROR mismatched types + x_u8 > -1_i128; + //~^ ERROR mismatched types + + x_usize > -1_i64; + //~^ ERROR mismatched types + x_u128 > -1_i64; + //~^ ERROR mismatched types + x_u64 > -1_i64; + //~^ ERROR mismatched types + x_u32 > -1_i64; + //~^ ERROR mismatched types + x_u16 > -1_i64; + //~^ ERROR mismatched types + x_u8 > -1_i64; + //~^ ERROR mismatched types + + x_usize > -1_i32; + //~^ ERROR mismatched types + x_u128 > -1_i32; + //~^ ERROR mismatched types + x_u64 > -1_i32; + //~^ ERROR mismatched types + x_u32 > -1_i32; + //~^ ERROR mismatched types + x_u16 > -1_i32; + //~^ ERROR mismatched types + x_u8 > -1_i32; + //~^ ERROR mismatched types + + x_usize > -1_i16; + //~^ ERROR mismatched types + x_u128 > -1_i16; + //~^ ERROR mismatched types + x_u64 > -1_i16; + //~^ ERROR mismatched types + x_u32 > -1_i16; + //~^ ERROR mismatched types + x_u16 > -1_i16; + //~^ ERROR mismatched types + x_u8 > -1_i16; + //~^ ERROR mismatched types + + x_usize > -1_i8; + //~^ ERROR mismatched types + x_u128 > -1_i8; + //~^ ERROR mismatched types + x_u64 > -1_i8; + //~^ ERROR mismatched types + x_u32 > -1_i8; + //~^ ERROR mismatched types + x_u16 > -1_i8; + //~^ ERROR mismatched types + x_u8 > -1_i8; + //~^ ERROR mismatched types +} diff --git a/src/test/ui/numeric/numeric-cast-no-fix.stderr b/src/test/ui/numeric/numeric-cast-no-fix.stderr new file mode 100644 index 0000000000000..4852e7047b47a --- /dev/null +++ b/src/test/ui/numeric/numeric-cast-no-fix.stderr @@ -0,0 +1,324 @@ +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:10:15 + | +LL | x_usize > -1_isize; + | ^^^^^^^^ expected `usize`, found `isize` + | + = note: `-1_isize` cannot fit into type `usize` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:12:14 + | +LL | x_u128 > -1_isize; + | ^^^^^^^^ expected `u128`, found `isize` + | + = note: `-1_isize` cannot fit into type `u128` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:14:13 + | +LL | x_u64 > -1_isize; + | ^^^^^^^^ expected `u64`, found `isize` + | + = note: `-1_isize` cannot fit into type `u64` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:16:13 + | +LL | x_u32 > -1_isize; + | ^^^^^^^^ expected `u32`, found `isize` + | + = note: `-1_isize` cannot fit into type `u32` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:18:13 + | +LL | x_u16 > -1_isize; + | ^^^^^^^^ expected `u16`, found `isize` + | + = note: `-1_isize` cannot fit into type `u16` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:20:12 + | +LL | x_u8 > -1_isize; + | ^^^^^^^^ expected `u8`, found `isize` + | +help: you can convert `x_u8` from `u8` to `isize`, matching the type of `-1_isize` + | +LL | isize::from(x_u8) > -1_isize; + | ^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:23:15 + | +LL | x_usize > -1_i128; + | ^^^^^^^ expected `usize`, found `i128` + | + = note: `-1_i128` cannot fit into type `usize` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:25:14 + | +LL | x_u128 > -1_i128; + | ^^^^^^^ expected `u128`, found `i128` + | + = note: `-1_i128` cannot fit into type `u128` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:27:13 + | +LL | x_u64 > -1_i128; + | ^^^^^^^ expected `u64`, found `i128` + | +help: you can convert `x_u64` from `u64` to `i128`, matching the type of `-1_i128` + | +LL | i128::from(x_u64) > -1_i128; + | ^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:29:13 + | +LL | x_u32 > -1_i128; + | ^^^^^^^ expected `u32`, found `i128` + | +help: you can convert `x_u32` from `u32` to `i128`, matching the type of `-1_i128` + | +LL | i128::from(x_u32) > -1_i128; + | ^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:31:13 + | +LL | x_u16 > -1_i128; + | ^^^^^^^ expected `u16`, found `i128` + | +help: you can convert `x_u16` from `u16` to `i128`, matching the type of `-1_i128` + | +LL | i128::from(x_u16) > -1_i128; + | ^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:33:12 + | +LL | x_u8 > -1_i128; + | ^^^^^^^ expected `u8`, found `i128` + | +help: you can convert `x_u8` from `u8` to `i128`, matching the type of `-1_i128` + | +LL | i128::from(x_u8) > -1_i128; + | ^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:36:15 + | +LL | x_usize > -1_i64; + | ^^^^^^ expected `usize`, found `i64` + | + = note: `-1_i64` cannot fit into type `usize` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:38:14 + | +LL | x_u128 > -1_i64; + | ^^^^^^ expected `u128`, found `i64` + | + = note: `-1_i64` cannot fit into type `u128` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:40:13 + | +LL | x_u64 > -1_i64; + | ^^^^^^ expected `u64`, found `i64` + | + = note: `-1_i64` cannot fit into type `u64` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:42:13 + | +LL | x_u32 > -1_i64; + | ^^^^^^ expected `u32`, found `i64` + | +help: you can convert `x_u32` from `u32` to `i64`, matching the type of `-1_i64` + | +LL | i64::from(x_u32) > -1_i64; + | ^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:44:13 + | +LL | x_u16 > -1_i64; + | ^^^^^^ expected `u16`, found `i64` + | +help: you can convert `x_u16` from `u16` to `i64`, matching the type of `-1_i64` + | +LL | i64::from(x_u16) > -1_i64; + | ^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:46:12 + | +LL | x_u8 > -1_i64; + | ^^^^^^ expected `u8`, found `i64` + | +help: you can convert `x_u8` from `u8` to `i64`, matching the type of `-1_i64` + | +LL | i64::from(x_u8) > -1_i64; + | ^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:49:15 + | +LL | x_usize > -1_i32; + | ^^^^^^ expected `usize`, found `i32` + | + = note: `-1_i32` cannot fit into type `usize` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:51:14 + | +LL | x_u128 > -1_i32; + | ^^^^^^ expected `u128`, found `i32` + | + = note: `-1_i32` cannot fit into type `u128` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:53:13 + | +LL | x_u64 > -1_i32; + | ^^^^^^ expected `u64`, found `i32` + | + = note: `-1_i32` cannot fit into type `u64` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:55:13 + | +LL | x_u32 > -1_i32; + | ^^^^^^ expected `u32`, found `i32` + | + = note: `-1_i32` cannot fit into type `u32` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:57:13 + | +LL | x_u16 > -1_i32; + | ^^^^^^ expected `u16`, found `i32` + | +help: you can convert `x_u16` from `u16` to `i32`, matching the type of `-1_i32` + | +LL | i32::from(x_u16) > -1_i32; + | ^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:59:12 + | +LL | x_u8 > -1_i32; + | ^^^^^^ expected `u8`, found `i32` + | +help: you can convert `x_u8` from `u8` to `i32`, matching the type of `-1_i32` + | +LL | i32::from(x_u8) > -1_i32; + | ^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:62:15 + | +LL | x_usize > -1_i16; + | ^^^^^^ expected `usize`, found `i16` + | + = note: `-1_i16` cannot fit into type `usize` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:64:14 + | +LL | x_u128 > -1_i16; + | ^^^^^^ expected `u128`, found `i16` + | + = note: `-1_i16` cannot fit into type `u128` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:66:13 + | +LL | x_u64 > -1_i16; + | ^^^^^^ expected `u64`, found `i16` + | + = note: `-1_i16` cannot fit into type `u64` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:68:13 + | +LL | x_u32 > -1_i16; + | ^^^^^^ expected `u32`, found `i16` + | + = note: `-1_i16` cannot fit into type `u32` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:70:13 + | +LL | x_u16 > -1_i16; + | ^^^^^^ expected `u16`, found `i16` + | + = note: `-1_i16` cannot fit into type `u16` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:72:12 + | +LL | x_u8 > -1_i16; + | ^^^^^^ expected `u8`, found `i16` + | +help: you can convert `x_u8` from `u8` to `i16`, matching the type of `-1_i16` + | +LL | i16::from(x_u8) > -1_i16; + | ^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:75:15 + | +LL | x_usize > -1_i8; + | ^^^^^ expected `usize`, found `i8` + | + = note: `-1_i8` cannot fit into type `usize` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:77:14 + | +LL | x_u128 > -1_i8; + | ^^^^^ expected `u128`, found `i8` + | + = note: `-1_i8` cannot fit into type `u128` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:79:13 + | +LL | x_u64 > -1_i8; + | ^^^^^ expected `u64`, found `i8` + | + = note: `-1_i8` cannot fit into type `u64` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:81:13 + | +LL | x_u32 > -1_i8; + | ^^^^^ expected `u32`, found `i8` + | + = note: `-1_i8` cannot fit into type `u32` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:83:13 + | +LL | x_u16 > -1_i8; + | ^^^^^ expected `u16`, found `i8` + | + = note: `-1_i8` cannot fit into type `u16` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:85:12 + | +LL | x_u8 > -1_i8; + | ^^^^^ expected `u8`, found `i8` + | + = note: `-1_i8` cannot fit into type `u8` + +error: aborting due to 36 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/repeat_count.stderr b/src/test/ui/repeat_count.stderr index 6a081e23d9d37..2eab3ebc7687d 100644 --- a/src/test/ui/repeat_count.stderr +++ b/src/test/ui/repeat_count.stderr @@ -39,12 +39,16 @@ error[E0308]: mismatched types | LL | let f = [0; -4_isize]; | ^^^^^^^^ expected `usize`, found `isize` + | + = note: `-4_isize` cannot fit into type `usize` error[E0308]: mismatched types --> $DIR/repeat_count.rs:22:23 | LL | let f = [0_usize; -1_isize]; | ^^^^^^^^ expected `usize`, found `isize` + | + = note: `-1_isize` cannot fit into type `usize` error[E0308]: mismatched types --> $DIR/repeat_count.rs:25:17 diff --git a/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.rs b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.rs new file mode 100644 index 0000000000000..ef64d799b65cf --- /dev/null +++ b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.rs @@ -0,0 +1,28 @@ +trait Trait { + fn func1() -> Struct1; //~ ERROR E0277 + fn func2<'a>() -> Struct2<'a, Self>; //~ ERROR E0277 + fn func3() -> Struct3; //~ ERROR E0277 + fn func4() -> Struct4; //~ ERROR E0277 +} + +struct Struct1{ + _t: std::marker::PhantomData<*const T>, +} +struct Struct2<'a, T>{ + _t: &'a T, +} +struct Struct3{ + _t: T, +} + +struct X(T); + +struct Struct4{ + _t: X, +} + +struct Struct5{ + _t: X, //~ ERROR E0277 +} + +fn main() {} diff --git a/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr new file mode 100644 index 0000000000000..ee08f51f80270 --- /dev/null +++ b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr @@ -0,0 +1,107 @@ +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/adt-param-with-implicit-sized-bound.rs:25:5 + | +LL | struct X(T); + | - required by this bound in `X` +... +LL | struct Struct5{ + | - this type parameter needs to be `std::marker::Sized` +LL | _t: X, + | ^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `T` + = note: to learn more, visit +help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` + --> $DIR/adt-param-with-implicit-sized-bound.rs:18:10 + | +LL | struct X(T); + | ^ - ...if indirection was used here: `Box` + | | + | this could be changed to `T: ?Sized`... + +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/adt-param-with-implicit-sized-bound.rs:2:19 + | +LL | fn func1() -> Struct1; + | ^^^^^^^^^^^^^ doesn't have a size known at compile-time +... +LL | struct Struct1{ + | - required by this bound in `Struct1` + | + = help: the trait `std::marker::Sized` is not implemented for `Self` + = note: to learn more, visit +help: consider further restricting `Self` + | +LL | fn func1() -> Struct1 where Self: std::marker::Sized; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider relaxing the implicit `Sized` restriction + | +LL | struct Struct1{ + | ^^^^^^^^ + +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/adt-param-with-implicit-sized-bound.rs:3:23 + | +LL | fn func2<'a>() -> Struct2<'a, Self>; + | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time +... +LL | struct Struct2<'a, T>{ + | - required by this bound in `Struct2` + | + = help: the trait `std::marker::Sized` is not implemented for `Self` + = note: to learn more, visit +help: consider further restricting `Self` + | +LL | fn func2<'a>() -> Struct2<'a, Self> where Self: std::marker::Sized; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider relaxing the implicit `Sized` restriction + | +LL | struct Struct2<'a, T: ?Sized>{ + | ^^^^^^^^ + +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/adt-param-with-implicit-sized-bound.rs:4:19 + | +LL | fn func3() -> Struct3; + | ^^^^^^^^^^^^^ doesn't have a size known at compile-time +... +LL | struct Struct3{ + | - required by this bound in `Struct3` + | + = help: the trait `std::marker::Sized` is not implemented for `Self` + = note: to learn more, visit +help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` + --> $DIR/adt-param-with-implicit-sized-bound.rs:14:16 + | +LL | struct Struct3{ + | ^ this could be changed to `T: ?Sized`... +LL | _t: T, + | - ...if indirection was used here: `Box` +help: consider further restricting `Self` + | +LL | fn func3() -> Struct3 where Self: std::marker::Sized; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/adt-param-with-implicit-sized-bound.rs:5:19 + | +LL | fn func4() -> Struct4; + | ^^^^^^^^^^^^^ doesn't have a size known at compile-time +... +LL | struct Struct4{ + | - required by this bound in `Struct4` + | + = help: the trait `std::marker::Sized` is not implemented for `Self` + = note: to learn more, visit +help: consider further restricting `Self` + | +LL | fn func4() -> Struct4 where Self: std::marker::Sized; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider relaxing the implicit `Sized` restriction + | +LL | struct Struct4{ + | ^^^^^^^^ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/traits/trait-item-privacy.stderr b/src/test/ui/traits/trait-item-privacy.stderr index 7fd5c11fcf090..3be4f11097311 100644 --- a/src/test/ui/traits/trait-item-privacy.stderr +++ b/src/test/ui/traits/trait-item-privacy.stderr @@ -20,13 +20,6 @@ error[E0599]: no method named `b` found for struct `S` in the current scope LL | struct S; | --------- method `b` not found for this ... -LL | fn b(&self) { } - | - - | | - | the method is available for `std::boxed::Box` here - | the method is available for `std::sync::Arc` here - | the method is available for `std::rc::Rc` here -... LL | S.b(); | ^ method not found in `S` | diff --git a/src/test/ui/unsized/unsized-enum.stderr b/src/test/ui/unsized/unsized-enum.stderr index f43d00f97398d..1908aee25ea7b 100644 --- a/src/test/ui/unsized/unsized-enum.stderr +++ b/src/test/ui/unsized/unsized-enum.stderr @@ -11,6 +11,13 @@ LL | fn foo2() { not_sized::>() } | = help: the trait `std::marker::Sized` is not implemented for `T` = note: to learn more, visit +help: you could relax the implicit `Sized` bound on `U` if it were used through indirection like `&U` or `Box` + --> $DIR/unsized-enum.rs:4:10 + | +LL | enum Foo { FooSome(U), FooNone } + | ^ - ...if indirection was used here: `Box` + | | + | this could be changed to `U: ?Sized`... error: aborting due to previous error diff --git a/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr b/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr index 808c9c583d458..e0f077d66f99c 100644 --- a/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr +++ b/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr @@ -11,6 +11,13 @@ LL | impl S5 { | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit +help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box` + --> $DIR/unsized-inherent-impl-self-type.rs:5:11 + | +LL | struct S5(Y); + | ^ - ...if indirection was used here: `Box` + | | + | this could be changed to `Y: ?Sized`... error: aborting due to previous error diff --git a/src/test/ui/unsized/unsized-struct.stderr b/src/test/ui/unsized/unsized-struct.stderr index 42fc5569eceb4..d92d1d9113e5c 100644 --- a/src/test/ui/unsized/unsized-struct.stderr +++ b/src/test/ui/unsized/unsized-struct.stderr @@ -11,6 +11,13 @@ LL | fn foo2() { not_sized::>() } | = help: the trait `std::marker::Sized` is not implemented for `T` = note: to learn more, visit +help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` + --> $DIR/unsized-struct.rs:4:12 + | +LL | struct Foo { data: T } + | ^ - ...if indirection was used here: `Box` + | | + | this could be changed to `T: ?Sized`... error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/unsized-struct.rs:13:24 diff --git a/src/test/ui/unsized/unsized-trait-impl-self-type.stderr b/src/test/ui/unsized/unsized-trait-impl-self-type.stderr index c2b2fe40ce67f..73c5439da53b6 100644 --- a/src/test/ui/unsized/unsized-trait-impl-self-type.stderr +++ b/src/test/ui/unsized/unsized-trait-impl-self-type.stderr @@ -11,6 +11,13 @@ LL | impl T3 for S5 { | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit +help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box` + --> $DIR/unsized-trait-impl-self-type.rs:8:11 + | +LL | struct S5(Y); + | ^ - ...if indirection was used here: `Box` + | | + | this could be changed to `Y: ?Sized`... error: aborting due to previous error diff --git a/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr b/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr index 4cf054d177f66..e423a9bdeab6f 100644 --- a/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr +++ b/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr @@ -11,6 +11,10 @@ LL | impl T2 for S4 { | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit +help: consider relaxing the implicit `Sized` restriction + | +LL | trait T2 { + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/unsized3.stderr b/src/test/ui/unsized3.stderr index 828e8bc9f4aa1..e0a0389dc4690 100644 --- a/src/test/ui/unsized3.stderr +++ b/src/test/ui/unsized3.stderr @@ -48,6 +48,10 @@ LL | f5(x1); = help: within `S`, the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit = note: required because it appears within the type `S` +help: consider relaxing the implicit `Sized` restriction + | +LL | fn f5(x: &Y) {} + | ^^^^^^^^ error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized3.rs:40:8 @@ -91,6 +95,10 @@ LL | f5(&(32, *x1)); = note: to learn more, visit = note: required because it appears within the type `S` = note: required because it appears within the type `({integer}, S)` +help: consider relaxing the implicit `Sized` restriction + | +LL | fn f5(x: &Y) {} + | ^^^^^^^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/unsized7.stderr b/src/test/ui/unsized7.stderr index d18644f005a88..e616a5cf0f9c2 100644 --- a/src/test/ui/unsized7.stderr +++ b/src/test/ui/unsized7.stderr @@ -11,6 +11,10 @@ LL | impl T1 for S3 { | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit +help: consider relaxing the implicit `Sized` restriction + | +LL | trait T1 { + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-fn-where-clause.stderr b/src/test/ui/wf/wf-fn-where-clause.stderr index 59a4f9bad9dfa..731d31ac34f62 100644 --- a/src/test/ui/wf/wf-fn-where-clause.stderr +++ b/src/test/ui/wf/wf-fn-where-clause.stderr @@ -23,6 +23,13 @@ LL | struct Vec { | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::marker::Copy + 'static)` = note: to learn more, visit +help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` + --> $DIR/wf-fn-where-clause.rs:16:12 + | +LL | struct Vec { + | ^ this could be changed to `T: ?Sized`... +LL | t: T, + | - ...if indirection was used here: `Box` error[E0038]: the trait `std::marker::Copy` cannot be made into an object --> $DIR/wf-fn-where-clause.rs:12:16 diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index 7227683aa5ac2..59af475af175e 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -6,7 +6,7 @@ use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_target::abi::LayoutOf; -use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Place, PlaceBase}; +use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceWithHirId, PlaceBase}; use crate::utils::span_lint; @@ -112,9 +112,9 @@ fn is_argument(map: rustc_middle::hir::map::Map<'_>, id: HirId) -> bool { } impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { - fn consume(&mut self, cmt: &Place<'tcx>, mode: ConsumeMode) { - if cmt.projections.is_empty() { - if let PlaceBase::Local(lid) = cmt.base { + fn consume(&mut self, cmt: &PlaceWithHirId<'tcx>, mode: ConsumeMode) { + if cmt.place.projections.is_empty() { + if let PlaceBase::Local(lid) = cmt.place.base { if let ConsumeMode::Move = mode { // moved out or in. clearly can't be localized self.set.remove(&lid); @@ -132,16 +132,16 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { } } - fn borrow(&mut self, cmt: &Place<'tcx>, _: ty::BorrowKind) { - if cmt.projections.is_empty() { - if let PlaceBase::Local(lid) = cmt.base { + fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: ty::BorrowKind) { + if cmt.place.projections.is_empty() { + if let PlaceBase::Local(lid) = cmt.place.base { self.set.remove(&lid); } } } - fn mutate(&mut self, cmt: &Place<'tcx>) { - if cmt.projections.is_empty() { + fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>) { + if cmt.place.projections.is_empty() { let map = &self.cx.tcx.hir(); if is_argument(*map, cmt.hir_id) { // Skip closure arguments @@ -150,7 +150,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { return; } - if is_non_trait_box(cmt.ty) && !self.is_large_box(cmt.ty) { + if is_non_trait_box(cmt.place.ty) && !self.is_large_box(cmt.place.ty) { self.set.insert(cmt.hir_id); } return; diff --git a/src/tools/clippy/clippy_lints/src/loops.rs b/src/tools/clippy/clippy_lints/src/loops.rs index 771bc8d055825..83093ec51bd90 100644 --- a/src/tools/clippy/clippy_lints/src/loops.rs +++ b/src/tools/clippy/clippy_lints/src/loops.rs @@ -28,7 +28,7 @@ use rustc_middle::ty::{self, Ty, TyS}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; -use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Place, PlaceBase}; +use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceWithHirId, PlaceBase}; use std::iter::{once, Iterator}; use std::mem; @@ -1489,42 +1489,43 @@ fn check_for_loop_over_map_kv<'a, 'tcx>( } } -struct MutatePairDelegate { +struct MutatePairDelegate<'a, 'tcx> { + cx: &'a LateContext<'a, 'tcx>, hir_id_low: Option, hir_id_high: Option, span_low: Option, span_high: Option, } -impl<'tcx> Delegate<'tcx> for MutatePairDelegate { - fn consume(&mut self, _: &Place<'tcx>, _: ConsumeMode) {} +impl<'a, 'tcx> Delegate<'tcx> for MutatePairDelegate<'a, 'tcx> { + fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: ConsumeMode) {} - fn borrow(&mut self, cmt: &Place<'tcx>, bk: ty::BorrowKind) { + fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, bk: ty::BorrowKind) { if let ty::BorrowKind::MutBorrow = bk { - if let PlaceBase::Local(id) = cmt.base { + if let PlaceBase::Local(id) = cmt.place.base { if Some(id) == self.hir_id_low { - self.span_low = Some(cmt.span) + self.span_low = Some(self.cx.tcx.hir().span(cmt.hir_id)) } if Some(id) == self.hir_id_high { - self.span_high = Some(cmt.span) + self.span_high = Some(self.cx.tcx.hir().span(cmt.hir_id)) } } } } - fn mutate(&mut self, cmt: &Place<'tcx>) { - if let PlaceBase::Local(id) = cmt.base { + fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>) { + if let PlaceBase::Local(id) = cmt.place.base { if Some(id) == self.hir_id_low { - self.span_low = Some(cmt.span) + self.span_low = Some(self.cx.tcx.hir().span(cmt.hir_id)) } if Some(id) == self.hir_id_high { - self.span_high = Some(cmt.span) + self.span_high = Some(self.cx.tcx.hir().span(cmt.hir_id)) } } } } -impl<'tcx> MutatePairDelegate { +impl<'a, 'tcx> MutatePairDelegate<'a, 'tcx> { fn mutation_span(&self) -> (Option, Option) { (self.span_low, self.span_high) } @@ -1579,12 +1580,13 @@ fn check_for_mutability(cx: &LateContext<'_, '_>, bound: &Expr<'_>) -> Option, +fn check_for_mutation<'a, 'tcx> ( + cx: &LateContext<'a, 'tcx>, body: &Expr<'_>, bound_ids: &[Option], ) -> (Option, Option) { let mut delegate = MutatePairDelegate { + cx: cx, hir_id_low: bound_ids[0], hir_id_high: bound_ids[1], span_low: None, diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 218b0d27f7486..ca87deac9891c 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -326,21 +326,21 @@ struct MovedVariablesCtxt { } impl MovedVariablesCtxt { - fn move_common(&mut self, cmt: &euv::Place<'_>) { - if let euv::PlaceBase::Local(vid) = cmt.base { + fn move_common(&mut self, cmt: &euv::PlaceWithHirId<'_>) { + if let euv::PlaceBase::Local(vid) = cmt.place.base { self.moved_vars.insert(vid); } } } impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt { - fn consume(&mut self, cmt: &euv::Place<'tcx>, mode: euv::ConsumeMode) { + fn consume(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, mode: euv::ConsumeMode) { if let euv::ConsumeMode::Move = mode { self.move_common(cmt); } } - fn borrow(&mut self, _: &euv::Place<'tcx>, _: ty::BorrowKind) {} + fn borrow(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: ty::BorrowKind) {} - fn mutate(&mut self, _: &euv::Place<'tcx>) {} + fn mutate(&mut self, _: &euv::PlaceWithHirId<'tcx>) {} } diff --git a/src/tools/clippy/clippy_lints/src/utils/usage.rs b/src/tools/clippy/clippy_lints/src/utils/usage.rs index 904d948ad29ed..6a7a1f1ceaaef 100644 --- a/src/tools/clippy/clippy_lints/src/utils/usage.rs +++ b/src/tools/clippy/clippy_lints/src/utils/usage.rs @@ -8,7 +8,7 @@ use rustc_lint::LateContext; use rustc_middle::hir::map::Map; use rustc_middle::ty; use rustc_span::symbol::{Ident, Symbol}; -use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Place, PlaceBase}; +use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceWithHirId, PlaceBase}; /// Returns a set of mutated local variable IDs, or `None` if mutations could not be determined. pub fn mutated_variables<'a, 'tcx>(expr: &'tcx Expr<'_>, cx: &'a LateContext<'a, 'tcx>) -> Option> { @@ -46,8 +46,8 @@ struct MutVarsDelegate { impl<'tcx> MutVarsDelegate { #[allow(clippy::similar_names)] - fn update(&mut self, cat: &Place<'tcx>) { - match cat.base { + fn update(&mut self, cat: &PlaceWithHirId<'tcx>) { + match cat.place.base { PlaceBase::Local(id) => { self.used_mutably.insert(id); }, @@ -63,15 +63,15 @@ impl<'tcx> MutVarsDelegate { } impl<'tcx> Delegate<'tcx> for MutVarsDelegate { - fn consume(&mut self, _: &Place<'tcx>, _: ConsumeMode) {} + fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: ConsumeMode) {} - fn borrow(&mut self, cmt: &Place<'tcx>, bk: ty::BorrowKind) { + fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, bk: ty::BorrowKind) { if let ty::BorrowKind::MutBorrow = bk { self.update(&cmt) } } - fn mutate(&mut self, cmt: &Place<'tcx>) { + fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>) { self.update(&cmt) } }