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:
bors 2020-06-19 23:04:41 +00:00
commit 34c5cd9a64
87 changed files with 2505 additions and 805 deletions

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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;
}
}

View file

@ -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() }
}
}

View file

@ -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();
}
}
})
}

View file

@ -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))
})
}
}
}

View file

@ -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
}
}

View file

@ -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;

View file

@ -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);
}
}
}

View file

@ -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)]

View file

@ -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

View file

@ -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) }
}
}

View file

@ -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`.

View file

@ -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
}

View file

@ -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) }
}

View file

@ -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]

View file

@ -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`.

View file

@ -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(

View file

@ -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()` didnt 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;
}
}

View file

@ -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;
}

View file

@ -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(())

View file

@ -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(&note);
}
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(&note);
}
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 {

View file

@ -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(),

View file

@ -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,
}
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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]);

View file

@ -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);
)
}

View file

@ -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(),
)
}
}

View file

@ -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 }
}

View file

@ -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)`.

View file

@ -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>,

View file

@ -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
}

View file

@ -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

View file

@ -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(),

View file

@ -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
}
}

View file

@ -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,
};
);
}

View file

@ -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! {

View 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)) {}
}

View file

@ -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
}
}
}

View file

@ -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,

View file

@ -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;

View file

@ -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),
);
}
}
}
};

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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
}

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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;

View file

@ -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;
}

View file

@ -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
}
}

View file

@ -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 {

View 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);

View file

@ -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");
}
}

View file

@ -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");
}
}

View file

@ -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
}
}

View file

@ -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

View file

@ -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'
}
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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:

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;

View 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() {
}

View 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

View 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
}

View 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`.

View file

@ -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

View file

@ -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() {}

View file

@ -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`.

View file

@ -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`
|

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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,

View file

@ -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>) {}
}

View file

@ -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)
}
}