Auto merge of #73511 - Manishearth:rollup-3iffxd8, r=Manishearth
Rollup of 13 pull requests Successful merges: - #71568 (Document unsafety in slice/sort.rs) - #72709 (`#[deny(unsafe_op_in_unsafe_fn)]` in liballoc) - #73214 (Add asm!() support for hexagon) - #73248 (save_analysis: improve handling of enum struct variant) - #73257 (ty: projections in `transparent_newtype_field`) - #73261 (Suggest `?Sized` when applicable for ADTs) - #73300 (Implement crate-level-only lints checking.) - #73334 (Note numeric literals that can never fit in an expected type) - #73357 (Use `LocalDefId` for import IDs in trait map) - #73364 (asm: Allow multiple template string arguments; interpret them as newline-separated) - #73382 (Only display other method receiver candidates if they actually apply) - #73465 (Add specialization of `ToString for char`) - #73489 (Refactor hir::Place) Failed merges: r? @ghost
This commit is contained in:
commit
34c5cd9a64
87 changed files with 2505 additions and 805 deletions
|
@ -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 one of our operands has a type we haven't seen yet, `const`.
|
||||
Second, we can see that inputs are declared by writing `in` instead of `out`.
|
||||
|
||||
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.
|
||||
|
|
|
@ -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<u8>, 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<T: ?Sized, A: AllocRef>(Unique<T>, A)`,
|
||||
// this function has to be changed to `fn box_free<T: ?Sized, A: AllocRef>(Unique<T>, A)` as well.
|
||||
pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
|
||||
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.
|
||||
|
|
|
@ -311,7 +311,7 @@ impl<T> Box<mem::MaybeUninit<T>> {
|
|||
#[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) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -349,7 +349,7 @@ impl<T> Box<[mem::MaybeUninit<T>]> {
|
|||
#[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<T: ?Sized> Box<T> {
|
|||
#[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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1725,7 +1725,7 @@ impl<'a, K: 'a, V: 'a> DrainFilterInner<'a, K, V> {
|
|||
&mut self,
|
||||
) -> Option<Handle<NodeRef<marker::Mut<'a>, 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<K, V> 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() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,9 @@ pub unsafe fn unwrap_unchecked<T>(val: Option<T>) -> T {
|
|||
if cfg!(debug_assertions) {
|
||||
panic!("'unchecked' unwrap on None in BTreeMap");
|
||||
} else {
|
||||
core::intrinsics::unreachable();
|
||||
unsafe {
|
||||
core::intrinsics::unreachable();
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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<T, R>(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<NodeRef<marker::Immut<'a>, 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<NodeRef<marker::Mut<'a>, 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<NodeRef<marker::Mut<'a>, 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<K, V> Handle<NodeRef<marker::Owned, K, V, marker::Leaf>, 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<K, V> Handle<NodeRef<marker::Owned, K, V, marker::Leaf>, 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))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ impl<K, V> InternalNode<K, V> {
|
|||
/// `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<K, V> BoxedNode<K, V> {
|
|||
}
|
||||
|
||||
unsafe fn from_ptr(ptr: NonNull<LeafNode<K, V>>) -> Self {
|
||||
BoxedNode { ptr: Unique::new_unchecked(ptr.as_ptr()) }
|
||||
BoxedNode { ptr: unsafe { Unique::new_unchecked(ptr.as_ptr()) } }
|
||||
}
|
||||
|
||||
fn as_ptr(&self) -> NonNull<LeafNode<K, V>> {
|
||||
|
@ -392,14 +392,16 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
|
|||
let height = self.height;
|
||||
let node = self.node;
|
||||
let ret = self.ascend().ok();
|
||||
Global.dealloc(
|
||||
node.cast(),
|
||||
if height > 0 {
|
||||
Layout::new::<InternalNode<K, V>>()
|
||||
} else {
|
||||
Layout::new::<LeafNode<K, V>>()
|
||||
},
|
||||
);
|
||||
unsafe {
|
||||
Global.dealloc(
|
||||
node.cast(),
|
||||
if height > 0 {
|
||||
Layout::new::<InternalNode<K, V>>()
|
||||
} else {
|
||||
Layout::new::<LeafNode<K, V>>()
|
||||
},
|
||||
);
|
||||
}
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
@ -565,7 +567,7 @@ impl<'a, K, V> NodeRef<marker::Mut<'a>, 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<NodeRef<marker::Mut<'a>, K, V, NodeT
|
|||
&mut self,
|
||||
) -> Handle<NodeRef<marker::Mut<'_>, 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<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
|
|||
unsafe fn cast_unchecked<NewType>(
|
||||
&mut self,
|
||||
) -> Handle<NodeRef<marker::Mut<'_>, 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<K, V>(
|
|||
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<K, V>(
|
|||
) {
|
||||
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<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
|
||||
|
@ -1459,12 +1465,16 @@ pub mod marker {
|
|||
}
|
||||
|
||||
unsafe fn slice_insert<T>(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<T>(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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -225,17 +225,17 @@ impl<T> LinkedList<T> {
|
|||
/// maintain validity of aliasing pointers.
|
||||
#[inline]
|
||||
unsafe fn unlink_node(&mut self, mut node: NonNull<Node<T>>) {
|
||||
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<T> LinkedList<T> {
|
|||
// 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<T> LinkedList<T> {
|
|||
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<T> LinkedList<T> {
|
|||
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;
|
||||
|
|
|
@ -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<T> VecDeque<T> {
|
|||
/// 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<T> VecDeque<T> {
|
|||
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<T> VecDeque<T> {
|
|||
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<T> VecDeque<T> {
|
|||
// 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<T> VecDeque<T> {
|
|||
// 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<T> VecDeque<T> {
|
|||
// 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<T> VecDeque<T> {
|
|||
// 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<T> VecDeque<T> {
|
|||
// 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<T> VecDeque<T> {
|
|||
//
|
||||
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<T> VecDeque<T> {
|
|||
//
|
||||
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<T> VecDeque<T> {
|
|||
// 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<T> VecDeque<T> {
|
|||
|
||||
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<T> VecDeque<T> {
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -108,7 +108,7 @@ impl<T> RawVec<T, Global> {
|
|||
/// 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<T>`.
|
||||
|
@ -139,8 +139,10 @@ impl<T> RawVec<T, Global> {
|
|||
);
|
||||
|
||||
let me = ManuallyDrop::new(self);
|
||||
let slice = slice::from_raw_parts_mut(me.ptr() as *mut MaybeUninit<T>, len);
|
||||
Box::from_raw(slice)
|
||||
unsafe {
|
||||
let slice = slice::from_raw_parts_mut(me.ptr() as *mut MaybeUninit<T>, len);
|
||||
Box::from_raw(slice)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -192,7 +194,7 @@ impl<T, A: AllocRef> RawVec<T, A> {
|
|||
/// 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
|
||||
|
|
|
@ -35,7 +35,7 @@ fn allocator_param() {
|
|||
}
|
||||
}
|
||||
unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
|
||||
Global.dealloc(ptr, layout)
|
||||
unsafe { Global.dealloc(ptr, layout) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -304,7 +304,7 @@ impl<T: ?Sized> Rc<T> {
|
|||
}
|
||||
|
||||
unsafe fn from_ptr(ptr: *mut RcBox<T>) -> Self {
|
||||
Self::from_inner(NonNull::new_unchecked(ptr))
|
||||
Self::from_inner(unsafe { NonNull::new_unchecked(ptr) })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -544,7 +544,7 @@ impl<T> Rc<[mem::MaybeUninit<T>]> {
|
|||
#[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<T: ?Sized> Rc<T> {
|
|||
/// ```
|
||||
#[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<T>;
|
||||
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<T>`.
|
||||
|
@ -805,7 +805,7 @@ impl<T: ?Sized> Rc<T> {
|
|||
#[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<T: ?Sized> Rc<T> {
|
|||
|
||||
// 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<T: ?Sized> Rc<T> {
|
|||
/// Allocates an `RcBox<T>` with sufficient space for an unsized inner value
|
||||
unsafe fn allocate_for_ptr(ptr: *const T) -> *mut RcBox<T> {
|
||||
// Allocate for the `RcBox<T>` using the given value.
|
||||
Self::allocate_for_layout(Layout::for_value(&*ptr), |mem| {
|
||||
set_data_ptr(ptr as *mut T, mem) as *mut RcBox<T>
|
||||
})
|
||||
unsafe {
|
||||
Self::allocate_for_layout(Layout::for_value(&*ptr), |mem| {
|
||||
set_data_ptr(ptr as *mut T, mem) as *mut RcBox<T>
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn from_box(v: Box<T>) -> Rc<T> {
|
||||
|
@ -1006,9 +1010,11 @@ impl<T: ?Sized> Rc<T> {
|
|||
impl<T> 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::<T>(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::<T>(len).unwrap(), |mem| {
|
||||
ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut RcBox<[T]>
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1017,7 +1023,9 @@ impl<T> 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<T: ?Sized, U>(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<T> 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<T> 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);
|
||||
|
||||
Self::from_ptr(ptr)
|
||||
}
|
||||
|
||||
// All clear. Forget the guard so it doesn't free the new RcBox.
|
||||
forget(guard);
|
||||
|
||||
Self::from_ptr(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1786,10 +1796,12 @@ impl<T> Weak<T> {
|
|||
Self::new()
|
||||
} else {
|
||||
// See Rc::from_raw for details
|
||||
let offset = data_offset(ptr);
|
||||
let fake_ptr = ptr as *mut RcBox<T>;
|
||||
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<T>;
|
||||
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<T: ?Sized>(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`.
|
||||
|
|
|
@ -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<T>(ptr: &mut *mut T) -> *mut T {
|
||||
let old = *ptr;
|
||||
*ptr = ptr.offset(1);
|
||||
*ptr = unsafe { ptr.offset(1) };
|
||||
old
|
||||
}
|
||||
|
||||
unsafe fn decrement_and_get<T>(ptr: &mut *mut T) -> *mut T {
|
||||
*ptr = ptr.offset(-1);
|
||||
*ptr = unsafe { ptr.offset(-1) };
|
||||
*ptr
|
||||
}
|
||||
|
||||
|
|
|
@ -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<str> {
|
||||
Box::from_raw(Box::into_raw(v) as *mut str)
|
||||
unsafe { Box::from_raw(Box::into_raw(v) as *mut str) }
|
||||
}
|
||||
|
|
|
@ -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<T: fmt::Display + ?Sized> 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]
|
||||
|
|
|
@ -232,7 +232,7 @@ impl<T: ?Sized> Arc<T> {
|
|||
}
|
||||
|
||||
unsafe fn from_ptr(ptr: *mut ArcInner<T>) -> Self {
|
||||
Self::from_inner(NonNull::new_unchecked(ptr))
|
||||
unsafe { Self::from_inner(NonNull::new_unchecked(ptr)) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -543,7 +543,7 @@ impl<T> Arc<[mem::MaybeUninit<T>]> {
|
|||
#[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<T: ?Sized> Arc<T> {
|
|||
/// ```
|
||||
#[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<T>;
|
||||
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<T>;
|
||||
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<T>`.
|
||||
|
@ -807,7 +809,7 @@ impl<T: ?Sized> Arc<T> {
|
|||
#[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::<T>::from_raw(ptr));
|
||||
let arc = unsafe { mem::ManuallyDrop::new(Arc::<T>::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<T: ?Sized> Arc<T> {
|
|||
#[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<T: ?Sized> Arc<T> {
|
|||
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<T: ?Sized> Arc<T> {
|
|||
|
||||
// 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<T: ?Sized> Arc<T> {
|
|||
/// Allocates an `ArcInner<T>` with sufficient space for an unsized inner value.
|
||||
unsafe fn allocate_for_ptr(ptr: *const T) -> *mut ArcInner<T> {
|
||||
// Allocate for the `ArcInner<T>` using the given value.
|
||||
Self::allocate_for_layout(Layout::for_value(&*ptr), |mem| {
|
||||
set_data_ptr(ptr as *mut T, mem) as *mut ArcInner<T>
|
||||
})
|
||||
unsafe {
|
||||
Self::allocate_for_layout(Layout::for_value(&*ptr), |mem| {
|
||||
set_data_ptr(ptr as *mut T, mem) as *mut ArcInner<T>
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn from_box(v: Box<T>) -> Arc<T> {
|
||||
|
@ -959,9 +965,11 @@ impl<T: ?Sized> Arc<T> {
|
|||
impl<T> 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::<T>(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::<T>(len).unwrap(), |mem| {
|
||||
ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[T]>
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -970,7 +978,9 @@ impl<T> 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<T: ?Sized, U>(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<T> 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<T> 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);
|
||||
|
||||
Self::from_ptr(ptr)
|
||||
}
|
||||
|
||||
// All clear. Forget the guard so it doesn't free the new ArcInner.
|
||||
mem::forget(guard);
|
||||
|
||||
Self::from_ptr(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1274,7 +1288,7 @@ impl<T: ?Sized> Arc<T> {
|
|||
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<T> Weak<T> {
|
|||
Self::new()
|
||||
} else {
|
||||
// See Arc::from_raw for details
|
||||
let offset = data_offset(ptr);
|
||||
let fake_ptr = ptr as *mut ArcInner<T>;
|
||||
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<T>;
|
||||
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<T: ?Sized>(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`.
|
||||
|
|
|
@ -60,7 +60,7 @@ impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
|
|||
fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
|
||||
// Increment the reference count of the arc to clone it.
|
||||
unsafe fn clone_waker<W: Wake + Send + Sync + 'static>(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::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>),
|
||||
|
@ -69,19 +69,20 @@ fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
|
|||
|
||||
// Wake by value, moving the Arc into the Wake::wake function
|
||||
unsafe fn wake<W: Wake + Send + Sync + 'static>(waker: *const ()) {
|
||||
let waker: Arc<W> = Arc::from_raw(waker as *const W);
|
||||
let waker: Arc<W> = unsafe { Arc::from_raw(waker as *const W) };
|
||||
<W as Wake>::wake(waker);
|
||||
}
|
||||
|
||||
// Wake by reference, wrap the waker in ManuallyDrop to avoid dropping it
|
||||
unsafe fn wake_by_ref<W: Wake + Send + Sync + 'static>(waker: *const ()) {
|
||||
let waker: ManuallyDrop<Arc<W>> = ManuallyDrop::new(Arc::from_raw(waker as *const W));
|
||||
let waker: ManuallyDrop<Arc<W>> =
|
||||
unsafe { ManuallyDrop::new(Arc::from_raw(waker as *const W)) };
|
||||
<W as Wake>::wake_by_ref(&waker);
|
||||
}
|
||||
|
||||
// Decrement the reference count of the Arc on drop
|
||||
unsafe fn drop_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) {
|
||||
Arc::decr_strong_count(waker as *const W);
|
||||
unsafe { Arc::decr_strong_count(waker as *const W) };
|
||||
}
|
||||
|
||||
RawWaker::new(
|
||||
|
|
|
@ -465,7 +465,7 @@ impl<T> Vec<T> {
|
|||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Vec<T> {
|
||||
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<T> Vec<T> {
|
|||
/// 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<T> 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<I: Iterator<Item = T>>(&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<T> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<T> {
|
|||
|
||||
impl<T> Drop for CopyOnDrop<T> {
|
||||
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::<u8>::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;
|
||||
}
|
||||
|
|
|
@ -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(())
|
||||
|
|
|
@ -11,7 +11,7 @@ use rustc_span::symbol::{kw, sym, Symbol};
|
|||
use rustc_span::{InnerSpan, Span};
|
||||
|
||||
struct AsmArgs {
|
||||
template: P<ast::Expr>,
|
||||
templates: Vec<P<ast::Expr>>,
|
||||
operands: Vec<(ast::InlineAsmOperand, Span)>,
|
||||
named_args: FxHashMap<Symbol, usize>,
|
||||
reg_args: FxHashSet<usize>,
|
||||
|
@ -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<ast::Expr> {
|
||||
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<usize, Symbol> =
|
||||
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()))
|
||||
}
|
||||
parse::Piece::NextArgument(arg) => {
|
||||
let span = arg_spans.next().unwrap_or(template_sp);
|
||||
let mut line_spans = Vec::with_capacity(args.templates.len());
|
||||
let mut curarg = 0;
|
||||
|
||||
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");
|
||||
for template_expr in args.templates.into_iter() {
|
||||
if !template.is_empty() {
|
||||
template.push(ast::InlineAsmTemplatePiece::String("\n".to_string()));
|
||||
}
|
||||
|
||||
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 {
|
||||
Some(idx)
|
||||
}
|
||||
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();
|
||||
}
|
||||
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;
|
||||
return DummyResult::raw_expr(sp, true);
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(operand_idx) = operand_idx {
|
||||
used[operand_idx] = true;
|
||||
template.push(ast::InlineAsmTemplatePiece::Placeholder {
|
||||
operand_idx,
|
||||
modifier,
|
||||
span,
|
||||
});
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
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",
|
||||
)
|
||||
.emit();
|
||||
modifier = None;
|
||||
}
|
||||
|
||||
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<ast
|
|||
}
|
||||
}
|
||||
|
||||
let line_spans = if parser.line_spans.is_empty() {
|
||||
vec![template_sp]
|
||||
} else {
|
||||
parser.line_spans.iter().map(|span| template_span.from_inner(*span)).collect()
|
||||
};
|
||||
|
||||
let inline_asm =
|
||||
ast::InlineAsm { template, operands: args.operands, options: args.options, line_spans };
|
||||
P(ast::Expr {
|
||||
|
|
|
@ -255,6 +255,7 @@ impl AsmBuilderMethods<'tcx> 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(),
|
||||
|
|
|
@ -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<CaptureBy>;
|
|||
// 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<ID = HirId> {
|
||||
pub struct TraitCandidate {
|
||||
pub def_id: DefId,
|
||||
pub import_ids: SmallVec<[ID; 1]>,
|
||||
pub import_ids: SmallVec<[LocalDefId; 1]>,
|
||||
}
|
||||
|
||||
impl<ID> TraitCandidate<ID> {
|
||||
pub fn map_import_ids<F, T>(self, f: F) -> TraitCandidate<T>
|
||||
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<ID = HirId> = NodeMap<Vec<TraitCandidate<ID>>>;
|
||||
|
||||
#[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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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_hir::def_id::LocalDefId>, rustc_data_structures::fx::FxHashSet<rustc_hir::def_id::LocalDefId>;
|
||||
], $tcx);
|
||||
)
|
||||
}
|
||||
|
|
|
@ -210,16 +210,15 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::TraitCandidate {
|
|||
}
|
||||
|
||||
impl<'a> ToStableHashKey<StableHashingContext<'a>> 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(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -526,7 +526,7 @@ rustc_queries! {
|
|||
}
|
||||
|
||||
Other {
|
||||
query used_trait_imports(key: LocalDefId) -> &'tcx DefIdSet {
|
||||
query used_trait_imports(key: LocalDefId) -> &'tcx FxHashSet<LocalDefId> {
|
||||
desc { |tcx| "used_trait_imports `{}`", tcx.def_path_str(key.to_def_id()) }
|
||||
cache_on_disk_if { true }
|
||||
}
|
||||
|
|
|
@ -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<DefIdSet>,
|
||||
pub used_trait_imports: Lrc<FxHashSet<LocalDefId>>,
|
||||
|
||||
/// If any errors occurred while type-checking this body,
|
||||
/// this field will be set to `Some(ErrorReported)`.
|
||||
|
|
|
@ -121,7 +121,7 @@ pub struct ResolverOutputs {
|
|||
pub definitions: rustc_hir::definitions::Definitions,
|
||||
pub cstore: Box<CrateStoreDyn>,
|
||||
pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
|
||||
pub trait_map: FxHashMap<hir::HirId, Vec<hir::TraitCandidate<hir::HirId>>>,
|
||||
pub trait_map: FxHashMap<hir::HirId, Vec<hir::TraitCandidate>>,
|
||||
pub maybe_unused_trait_imports: FxHashSet<LocalDefId>,
|
||||
pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
|
||||
pub export_map: ExportMap<LocalDefId>,
|
||||
|
|
|
@ -178,7 +178,7 @@ pub struct Parser<'a> {
|
|||
/// Error messages accumulated during parsing
|
||||
pub errors: Vec<ParseError>,
|
||||
/// 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<usize>,
|
||||
/// 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
|
||||
}
|
||||
|
|
|
@ -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<TraitCandidate<NodeId>> {
|
||||
) -> Vec<TraitCandidate> {
|
||||
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<TraitCandidate<NodeId>>,
|
||||
found_traits: &mut Vec<TraitCandidate>,
|
||||
) {
|
||||
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
|
||||
|
|
|
@ -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<LocalDefId, CrateNum>,
|
||||
export_map: ExportMap<LocalDefId>,
|
||||
trait_map: TraitMap<NodeId>,
|
||||
trait_map: NodeMap<Vec<TraitCandidate>>,
|
||||
|
||||
/// 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(),
|
||||
|
|
|
@ -518,24 +518,13 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn get_expr_data(&self, expr: &hir::Expr<'_>) -> Option<Data> {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,6 +88,8 @@ pub struct Lint {
|
|||
|
||||
/// `Some` if this lint is feature gated, otherwise `None`.
|
||||
pub feature_gate: Option<Symbol>,
|
||||
|
||||
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,
|
||||
};
|
||||
);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ declare_lint! {
|
|||
reference: "issue #57571 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/52234>",
|
||||
edition: None,
|
||||
};
|
||||
crate_level_only
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
|
|
93
src/librustc_target/asm/hexagon.rs
Normal file
93
src/librustc_target/asm/hexagon.rs
Normal file
|
@ -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<Self> {
|
||||
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<char>,
|
||||
) -> fmt::Result {
|
||||
out.write_str(self.name())
|
||||
}
|
||||
|
||||
pub fn overlapping_regs(self, mut _cb: impl FnMut(HexagonInlineAsmReg)) {}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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: ?Sized>(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<Span>,
|
||||
nested: bool,
|
||||
}
|
||||
|
||||
impl<'v> Visitor<'v> for FindTypeParam {
|
||||
type Map = rustc_hir::intravisit::ErasedMap<'v>;
|
||||
|
||||
fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
|
||||
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<T>` and `Vec<T>`, 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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<Self>` 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),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<Ty<'tcx>>,
|
||||
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);
|
||||
|
|
|
@ -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<LocalDefId> {
|
||||
&*tcx.typeck_tables_of(def_id).used_trait_imports
|
||||
}
|
||||
|
||||
|
|
|
@ -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<mc::Place<'tcx>> {
|
||||
fn constrain_adjustments(
|
||||
&mut self,
|
||||
expr: &hir::Expr<'_>,
|
||||
) -> mc::McResult<mc::PlaceWithHirId<'tcx>> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<LocalDefId>,
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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::Place<'tcx>> {
|
||||
) -> mc::McResult<mc::PlaceWithHirId<'tcx>> {
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<T>` 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<Projection<'tcx>>,
|
||||
}
|
||||
|
||||
/// 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<Projection<'tcx>>,
|
||||
) -> 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<Item = Ty<'tcx>> + '_ {
|
||||
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<Place<'tcx>> {
|
||||
crate fn cat_expr(&self, expr: &hir::Expr<'_>) -> McResult<PlaceWithHirId<'tcx>> {
|
||||
// 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<Place<'tcx>> {
|
||||
) -> McResult<PlaceWithHirId<'tcx>> {
|
||||
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<Place<'tcx>> {
|
||||
) -> McResult<PlaceWithHirId<'tcx>> {
|
||||
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<Place<'tcx>>
|
||||
) -> McResult<PlaceWithHirId<'tcx>>
|
||||
where
|
||||
F: FnOnce() -> McResult<Place<'tcx>>,
|
||||
F: FnOnce() -> McResult<PlaceWithHirId<'tcx>>,
|
||||
{
|
||||
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<Place<'tcx>> {
|
||||
crate fn cat_expr_unadjusted(&self, expr: &hir::Expr<'_>) -> McResult<PlaceWithHirId<'tcx>> {
|
||||
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<Place<'tcx>> {
|
||||
) -> McResult<PlaceWithHirId<'tcx>> {
|
||||
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<Place<'tcx>> {
|
||||
fn cat_upvar(&self, hir_id: hir::HirId, var_id: hir::HirId) -> McResult<PlaceWithHirId<'tcx>> {
|
||||
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<N: HirNode>(
|
||||
&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<Place<'tcx>> {
|
||||
) -> McResult<PlaceWithHirId<'tcx>> {
|
||||
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<Place<'tcx>> {
|
||||
fn cat_deref(
|
||||
&self,
|
||||
node: &impl HirNode,
|
||||
base_place: PlaceWithHirId<'tcx>,
|
||||
) -> McResult<PlaceWithHirId<'tcx>> {
|
||||
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 mut projections = base_place.place.projections;
|
||||
projections.push(Projection { kind: ProjectionKind::Deref(base_ty) });
|
||||
|
||||
let ret = Place {
|
||||
hir_id: node.hir_id(),
|
||||
span: node.span(),
|
||||
ty: deref_ty,
|
||||
base: base_place.base,
|
||||
projections,
|
||||
};
|
||||
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<F>(
|
||||
&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_<F>(
|
||||
&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>(*&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 {
|
||||
|
|
130
src/test/assembly/asm/hexagon-types.rs
Normal file
130
src/test/assembly/asm/hexagon-types.rs
Normal file
|
@ -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);
|
|
@ -22,5 +22,13 @@ pub fn main() {
|
|||
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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
--> <inline asm>:2:2
|
||||
|
|
||||
LL | invalid_instruction
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: invalid instruction mnemonic 'invalid_instruction'
|
||||
--> $DIR/srcloc.rs:51:14
|
||||
|
|
||||
LL | "invalid_instruction",
|
||||
| ^
|
||||
|
|
||||
note: instantiated into assembly here
|
||||
--> <inline asm>:3:1
|
||||
|
|
||||
LL | invalid_instruction
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: invalid instruction mnemonic 'invalid_instruction'
|
||||
--> $DIR/srcloc.rs:58:14
|
||||
|
|
||||
LL | "invalid_instruction",
|
||||
| ^
|
||||
|
|
||||
note: instantiated into assembly here
|
||||
--> <inline asm>: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
|
||||
--> <inline asm>: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
|
||||
--> <inline asm>:3:1
|
||||
|
|
||||
LL | invalid_instruction
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: invalid instruction mnemonic 'invalid_instruction1'
|
||||
--> $DIR/srcloc.rs:79:14
|
||||
|
|
||||
LL | "invalid_instruction1",
|
||||
| ^
|
||||
|
|
||||
note: instantiated into assembly here
|
||||
--> <inline asm>:2:2
|
||||
|
|
||||
LL | invalid_instruction1
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: invalid instruction mnemonic 'invalid_instruction2'
|
||||
--> $DIR/srcloc.rs:80:14
|
||||
|
|
||||
LL | "invalid_instruction2",
|
||||
| ^
|
||||
|
|
||||
note: instantiated into assembly here
|
||||
--> <inline asm>:3:1
|
||||
|
|
||||
LL | invalid_instruction2
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: invalid instruction mnemonic 'invalid_instruction1'
|
||||
--> $DIR/srcloc.rs:86:13
|
||||
|
|
||||
LL | concat!(
|
||||
| ^
|
||||
|
|
||||
note: instantiated into assembly here
|
||||
--> <inline asm>:2:2
|
||||
|
|
||||
LL | invalid_instruction1
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: invalid instruction mnemonic 'invalid_instruction2'
|
||||
--> $DIR/srcloc.rs:86:13
|
||||
|
|
||||
LL | concat!(
|
||||
| ^
|
||||
|
|
||||
note: instantiated into assembly here
|
||||
--> <inline asm>:3:1
|
||||
|
|
||||
LL | invalid_instruction2
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: invalid instruction mnemonic 'invalid_instruction1'
|
||||
--> $DIR/srcloc.rs:95:13
|
||||
|
|
||||
LL | concat!(
|
||||
| ^
|
||||
|
|
||||
note: instantiated into assembly here
|
||||
--> <inline asm>:2:2
|
||||
|
|
||||
LL | invalid_instruction1
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: invalid instruction mnemonic 'invalid_instruction2'
|
||||
--> $DIR/srcloc.rs:95:13
|
||||
|
|
||||
LL | concat!(
|
||||
| ^
|
||||
|
|
||||
note: instantiated into assembly here
|
||||
--> <inline asm>:3:1
|
||||
|
|
||||
LL | invalid_instruction2
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: invalid instruction mnemonic 'invalid_instruction3'
|
||||
--> $DIR/srcloc.rs:99:13
|
||||
|
|
||||
LL | concat!(
|
||||
| ^
|
||||
|
|
||||
note: instantiated into assembly here
|
||||
--> <inline asm>:4:1
|
||||
|
|
||||
LL | invalid_instruction3
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: invalid instruction mnemonic 'invalid_instruction4'
|
||||
--> $DIR/srcloc.rs:99:13
|
||||
|
|
||||
LL | concat!(
|
||||
| ^
|
||||
|
|
||||
note: instantiated into assembly here
|
||||
--> <inline asm>:5:1
|
||||
|
|
||||
LL | invalid_instruction4
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: invalid instruction mnemonic 'invalid_instruction1'
|
||||
--> $DIR/srcloc.rs:110:13
|
||||
|
|
||||
LL | concat!(
|
||||
| ^
|
||||
|
|
||||
note: instantiated into assembly here
|
||||
--> <inline asm>:2:2
|
||||
|
|
||||
LL | invalid_instruction1
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: invalid instruction mnemonic 'invalid_instruction2'
|
||||
--> $DIR/srcloc.rs:110:13
|
||||
|
|
||||
LL | concat!(
|
||||
| ^
|
||||
|
|
||||
note: instantiated into assembly here
|
||||
--> <inline asm>:3:1
|
||||
|
|
||||
LL | invalid_instruction2
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: invalid instruction mnemonic 'invalid_instruction3'
|
||||
--> $DIR/srcloc.rs:114:13
|
||||
|
|
||||
LL | concat!(
|
||||
| ^
|
||||
|
|
||||
note: instantiated into assembly here
|
||||
--> <inline asm>:5:1
|
||||
|
|
||||
LL | invalid_instruction3
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: invalid instruction mnemonic 'invalid_instruction4'
|
||||
--> $DIR/srcloc.rs:114:13
|
||||
|
|
||||
LL | concat!(
|
||||
| ^
|
||||
|
|
||||
note: instantiated into assembly here
|
||||
--> <inline asm>:6:1
|
||||
|
|
||||
LL | invalid_instruction4
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 23 previous errors; 1 warning emitted
|
||||
|
||||
|
|
|
@ -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 <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
|
||||
help: consider relaxing the implicit `Sized` restriction
|
||||
|
|
||||
LL | trait Foo<T: ?Sized> : 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
|
||||
|
|
12
src/test/ui/extern/extern-types-unsized.stderr
vendored
12
src/test/ui/extern/extern-types-unsized.stderr
vendored
|
@ -26,6 +26,10 @@ LL | assert_sized::<Foo>();
|
|||
= help: within `Foo`, the trait `std::marker::Sized` is not implemented for `A`
|
||||
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
|
||||
= note: required because it appears within the type `Foo`
|
||||
help: consider relaxing the implicit `Sized` restriction
|
||||
|
|
||||
LL | fn assert_sized<T: ?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::<Bar<A>>();
|
|||
= help: within `Bar<A>`, the trait `std::marker::Sized` is not implemented for `A`
|
||||
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
|
||||
= note: required because it appears within the type `Bar<A>`
|
||||
help: consider relaxing the implicit `Sized` restriction
|
||||
|
|
||||
LL | fn assert_sized<T: ?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::<Bar<Bar<A>>>();
|
|||
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
|
||||
= note: required because it appears within the type `Bar<A>`
|
||||
= note: required because it appears within the type `Bar<Bar<A>>`
|
||||
help: consider relaxing the implicit `Sized` restriction
|
||||
|
|
||||
LL | fn assert_sized<T: ?Sized>() { }
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
|
@ -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<std::rc::Rc<&mut std::boxed::Box<&char>>>` here
|
||||
| the method is available for `std::pin::Pin<std::rc::Rc<&mut std::boxed::Box<&char>>>` here
|
||||
| the method is available for `std::sync::Arc<std::rc::Rc<&mut std::boxed::Box<&char>>>` here
|
||||
| the method is available for `std::rc::Rc<std::rc::Rc<&mut std::boxed::Box<&char>>>` 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<std::rc::Rc<&mut std::boxed::Box<&i32>>>` here
|
||||
| the method is available for `std::pin::Pin<std::rc::Rc<&mut std::boxed::Box<&i32>>>` here
|
||||
| the method is available for `std::sync::Arc<std::rc::Rc<&mut std::boxed::Box<&i32>>>` here
|
||||
| the method is available for `std::rc::Rc<std::rc::Rc<&mut std::boxed::Box<&i32>>>` 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:
|
||||
|
|
|
@ -57,6 +57,10 @@ LL | impl<'self> Serializable<str> for &'self str {
|
|||
|
|
||||
= help: the trait `std::marker::Sized` is not implemented for `str`
|
||||
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
|
||||
help: consider relaxing the implicit `Sized` restriction
|
||||
|
|
||||
LL | trait Serializable<'self, T: ?Sized> {
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
|
||||
|
|
|
@ -9,6 +9,13 @@ LL | enum Option<T> {
|
|||
|
|
||||
= help: the trait `std::marker::Sized` is not implemented for `dyn for<'r> std::ops::Fn(&'r isize) -> isize`
|
||||
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
|
||||
help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
|
||||
--> $DIR/issue-18919.rs:7:13
|
||||
|
|
||||
LL | enum Option<T> {
|
||||
| ^ this could be changed to `T: ?Sized`...
|
||||
LL | Some(T),
|
||||
| - ...if indirection was used here: `Box<T>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -9,6 +9,13 @@ LL | struct Vec<T> {
|
|||
|
|
||||
= help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::Fn() + 'static)`
|
||||
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
|
||||
help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
|
||||
--> $DIR/issue-23281.rs:8:12
|
||||
|
|
||||
LL | struct Vec<T> {
|
||||
| ^ this could be changed to `T: ?Sized`...
|
||||
LL | t: T,
|
||||
| - ...if indirection was used here: `Box<T>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
22
src/test/ui/lint/crate_level_only_lint.rs
Normal file
22
src/test/ui/lint/crate_level_only_lint.rs
Normal file
|
@ -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() {
|
||||
}
|
62
src/test/ui/lint/crate_level_only_lint.stderr
Normal file
62
src/test/ui/lint/crate_level_only_lint.stderr
Normal file
|
@ -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
|
||||
|
87
src/test/ui/numeric/numeric-cast-no-fix.rs
Normal file
87
src/test/ui/numeric/numeric-cast-no-fix.rs
Normal file
|
@ -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
|
||||
}
|
324
src/test/ui/numeric/numeric-cast-no-fix.stderr
Normal file
324
src/test/ui/numeric/numeric-cast-no-fix.stderr
Normal file
|
@ -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`.
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
trait Trait {
|
||||
fn func1() -> Struct1<Self>; //~ ERROR E0277
|
||||
fn func2<'a>() -> Struct2<'a, Self>; //~ ERROR E0277
|
||||
fn func3() -> Struct3<Self>; //~ ERROR E0277
|
||||
fn func4() -> Struct4<Self>; //~ ERROR E0277
|
||||
}
|
||||
|
||||
struct Struct1<T>{
|
||||
_t: std::marker::PhantomData<*const T>,
|
||||
}
|
||||
struct Struct2<'a, T>{
|
||||
_t: &'a T,
|
||||
}
|
||||
struct Struct3<T>{
|
||||
_t: T,
|
||||
}
|
||||
|
||||
struct X<T>(T);
|
||||
|
||||
struct Struct4<T>{
|
||||
_t: X<T>,
|
||||
}
|
||||
|
||||
struct Struct5<T: ?Sized>{
|
||||
_t: X<T>, //~ ERROR E0277
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -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>(T);
|
||||
| - required by this bound in `X`
|
||||
...
|
||||
LL | struct Struct5<T: ?Sized>{
|
||||
| - this type parameter needs to be `std::marker::Sized`
|
||||
LL | _t: X<T>,
|
||||
| ^^^^^^^^ 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 <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
|
||||
help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
|
||||
--> $DIR/adt-param-with-implicit-sized-bound.rs:18:10
|
||||
|
|
||||
LL | struct X<T>(T);
|
||||
| ^ - ...if indirection was used here: `Box<T>`
|
||||
| |
|
||||
| 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<Self>;
|
||||
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
...
|
||||
LL | struct Struct1<T>{
|
||||
| - required by this bound in `Struct1`
|
||||
|
|
||||
= help: the trait `std::marker::Sized` is not implemented for `Self`
|
||||
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
|
||||
help: consider further restricting `Self`
|
||||
|
|
||||
LL | fn func1() -> Struct1<Self> where Self: std::marker::Sized;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: consider relaxing the implicit `Sized` restriction
|
||||
|
|
||||
LL | struct Struct1<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: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 <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
|
||||
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<Self>;
|
||||
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
...
|
||||
LL | struct Struct3<T>{
|
||||
| - required by this bound in `Struct3`
|
||||
|
|
||||
= help: the trait `std::marker::Sized` is not implemented for `Self`
|
||||
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
|
||||
help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
|
||||
--> $DIR/adt-param-with-implicit-sized-bound.rs:14:16
|
||||
|
|
||||
LL | struct Struct3<T>{
|
||||
| ^ this could be changed to `T: ?Sized`...
|
||||
LL | _t: T,
|
||||
| - ...if indirection was used here: `Box<T>`
|
||||
help: consider further restricting `Self`
|
||||
|
|
||||
LL | fn func3() -> Struct3<Self> 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<Self>;
|
||||
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
...
|
||||
LL | struct Struct4<T>{
|
||||
| - required by this bound in `Struct4`
|
||||
|
|
||||
= help: the trait `std::marker::Sized` is not implemented for `Self`
|
||||
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
|
||||
help: consider further restricting `Self`
|
||||
|
|
||||
LL | fn func4() -> Struct4<Self> where Self: std::marker::Sized;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: consider relaxing the implicit `Sized` restriction
|
||||
|
|
||||
LL | struct Struct4<T: ?Sized>{
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
|
@ -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<S>` here
|
||||
| the method is available for `std::sync::Arc<S>` here
|
||||
| the method is available for `std::rc::Rc<S>` here
|
||||
...
|
||||
LL | S.b();
|
||||
| ^ method not found in `S`
|
||||
|
|
||||
|
|
|
@ -11,6 +11,13 @@ LL | fn foo2<T: ?Sized>() { not_sized::<Foo<T>>() }
|
|||
|
|
||||
= help: the trait `std::marker::Sized` is not implemented for `T`
|
||||
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
|
||||
help: you could relax the implicit `Sized` bound on `U` if it were used through indirection like `&U` or `Box<U>`
|
||||
--> $DIR/unsized-enum.rs:4:10
|
||||
|
|
||||
LL | enum Foo<U> { FooSome(U), FooNone }
|
||||
| ^ - ...if indirection was used here: `Box<U>`
|
||||
| |
|
||||
| this could be changed to `U: ?Sized`...
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -11,6 +11,13 @@ LL | impl<X: ?Sized> S5<X> {
|
|||
|
|
||||
= help: the trait `std::marker::Sized` is not implemented for `X`
|
||||
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
|
||||
help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box<Y>`
|
||||
--> $DIR/unsized-inherent-impl-self-type.rs:5:11
|
||||
|
|
||||
LL | struct S5<Y>(Y);
|
||||
| ^ - ...if indirection was used here: `Box<Y>`
|
||||
| |
|
||||
| this could be changed to `Y: ?Sized`...
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -11,6 +11,13 @@ LL | fn foo2<T: ?Sized>() { not_sized::<Foo<T>>() }
|
|||
|
|
||||
= help: the trait `std::marker::Sized` is not implemented for `T`
|
||||
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
|
||||
help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
|
||||
--> $DIR/unsized-struct.rs:4:12
|
||||
|
|
||||
LL | struct Foo<T> { data: T }
|
||||
| ^ - ...if indirection was used here: `Box<T>`
|
||||
| |
|
||||
| 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
|
||||
|
|
|
@ -11,6 +11,13 @@ LL | impl<X: ?Sized> T3<X> for S5<X> {
|
|||
|
|
||||
= help: the trait `std::marker::Sized` is not implemented for `X`
|
||||
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
|
||||
help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box<Y>`
|
||||
--> $DIR/unsized-trait-impl-self-type.rs:8:11
|
||||
|
|
||||
LL | struct S5<Y>(Y);
|
||||
| ^ - ...if indirection was used here: `Box<Y>`
|
||||
| |
|
||||
| this could be changed to `Y: ?Sized`...
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -11,6 +11,10 @@ LL | impl<X: ?Sized> T2<X> for S4<X> {
|
|||
|
|
||||
= help: the trait `std::marker::Sized` is not implemented for `X`
|
||||
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
|
||||
help: consider relaxing the implicit `Sized` restriction
|
||||
|
|
||||
LL | trait T2<Z: ?Sized> {
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -48,6 +48,10 @@ LL | f5(x1);
|
|||
= help: within `S<X>`, the trait `std::marker::Sized` is not implemented for `X`
|
||||
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
|
||||
= note: required because it appears within the type `S<X>`
|
||||
help: consider relaxing the implicit `Sized` restriction
|
||||
|
|
||||
LL | fn f5<Y: ?Sized>(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 <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
|
||||
= note: required because it appears within the type `S<X>`
|
||||
= note: required because it appears within the type `({integer}, S<X>)`
|
||||
help: consider relaxing the implicit `Sized` restriction
|
||||
|
|
||||
LL | fn f5<Y: ?Sized>(x: &Y) {}
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
|
|
@ -11,6 +11,10 @@ LL | impl<X: ?Sized + T> T1<X> for S3<X> {
|
|||
|
|
||||
= help: the trait `std::marker::Sized` is not implemented for `X`
|
||||
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
|
||||
help: consider relaxing the implicit `Sized` restriction
|
||||
|
|
||||
LL | trait T1<Z: T + ?Sized> {
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -23,6 +23,13 @@ LL | struct Vec<T> {
|
|||
|
|
||||
= help: the trait `std::marker::Sized` is not implemented for `(dyn std::marker::Copy + 'static)`
|
||||
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
|
||||
help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
|
||||
--> $DIR/wf-fn-where-clause.rs:16:12
|
||||
|
|
||||
LL | struct Vec<T> {
|
||||
| ^ this could be changed to `T: ?Sized`...
|
||||
LL | t: T,
|
||||
| - ...if indirection was used here: `Box<T>`
|
||||
|
||||
error[E0038]: the trait `std::marker::Copy` cannot be made into an object
|
||||
--> $DIR/wf-fn-where-clause.rs:12:16
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<HirId>,
|
||||
hir_id_high: Option<HirId>,
|
||||
span_low: Option<Span>,
|
||||
span_high: Option<Span>,
|
||||
}
|
||||
|
||||
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<Span>, Option<Span>) {
|
||||
(self.span_low, self.span_high)
|
||||
}
|
||||
|
@ -1579,12 +1580,13 @@ fn check_for_mutability(cx: &LateContext<'_, '_>, bound: &Expr<'_>) -> Option<Hi
|
|||
None
|
||||
}
|
||||
|
||||
fn check_for_mutation(
|
||||
cx: &LateContext<'_, '_>,
|
||||
fn check_for_mutation<'a, 'tcx> (
|
||||
cx: &LateContext<'a, 'tcx>,
|
||||
body: &Expr<'_>,
|
||||
bound_ids: &[Option<HirId>],
|
||||
) -> (Option<Span>, Option<Span>) {
|
||||
let mut delegate = MutatePairDelegate {
|
||||
cx: cx,
|
||||
hir_id_low: bound_ids[0],
|
||||
hir_id_high: bound_ids[1],
|
||||
span_low: None,
|
||||
|
|
|
@ -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>) {}
|
||||
}
|
||||
|
|
|
@ -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<FxHashSet<HirId>> {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue