Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 13 pull requests #73511

Merged
merged 46 commits into from
Jun 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
7349f2c
Added unsafety documentation to shift_head
hbina Apr 25, 2020
9e8b42c
Added unsafety documentation to shift_tail
hbina Apr 25, 2020
9e1e989
Document unsafety in partial_insertion_sort
hbina Apr 25, 2020
c471519
Added unsafety documentation with partition and partition equal
hbina Apr 26, 2020
c710461
Added some unsafety documentation to partition_equal
hbina Apr 26, 2020
afbbd38
Note numeric literals that can never fit in an expected type
ayazhafiz Jun 13, 2020
2b936bb
fixup! Note numeric literals that can never fit in an expected type
ayazhafiz Jun 14, 2020
840176a
asm: Unify pseudo-keyword parsing using `eat`, rather than a final `e…
joshtriplett Jun 14, 2020
50d6d4d
asm: When pretty-printing, don't escape characters twice
joshtriplett Jun 15, 2020
a4337cc
Use `LocalDefId` for import IDs in trait map
petrochenkov Jun 14, 2020
fc13fd0
typeck: Use `LocalDefId`s for the unused trait import set
petrochenkov Jun 15, 2020
8956a7f
Only display other method receiver candidates if they actually apply
Aaron1011 Jun 15, 2020
1078b6f
asm: Allow multiple template strings; interpret them as newline-separ…
joshtriplett Jun 15, 2020
fd9ed30
asm: Update chapter in unstable book for multiple template string arg…
joshtriplett Jun 15, 2020
95e5605
Suggest `?Sized` when applicable for ADTs
estebank Jun 12, 2020
d2b8e60
Account for derived obligations to suggest `?Sized` bound
estebank Jun 12, 2020
f0d3689
fixup! Note numeric literals that can never fit in an expected type
ayazhafiz Jun 16, 2020
7a9f29d
Add initial asm!() support for hexagon
androm3da Jun 9, 2020
5a9df84
Added some more documentations to unsafety blocks in slice/sort.rs
hbina Jun 13, 2020
aa84b0f
Provide `help` when `T: ?Sized` can't be suggested
estebank Jun 17, 2020
d7277df
fixup! Note numeric literals that can never fit in an expected type
ayazhafiz Jun 17, 2020
7a89a33
fixup! Note numeric literals that can never fit in an expected type
ayazhafiz Jun 17, 2020
f633dd3
Implement crate level only lints checking.
crlf0710 Jun 13, 2020
e5c5df8
Add specialization of `ToString for char`
tesuji Jun 18, 2020
40b27ff
review comments: add comment
estebank Jun 18, 2020
3659406
Refactor hir::Place
arora-aman Jun 17, 2020
d5b0737
ty: projections in `transparent_newtype_field`
davidtwco Jun 11, 2020
0e31380
save_analysis: improve handling of enum struct variant
marmeladema Jun 11, 2020
76ad38d
lint: prohibit fields with opaque types
davidtwco Jun 12, 2020
0cccaa0
lint: unify enum variant, union and struct logic
davidtwco Jun 12, 2020
a730d88
ty: simplify `transparent_newtype_field`
davidtwco Jun 12, 2020
39e29ce
`#[deny(unsafe_op_in_unsafe_fn)]` in liballoc
LeSeulArtichaut May 28, 2020
7b63986
Apply suggestions from code review
LeSeulArtichaut May 31, 2020
85e1c3b
Rollup merge of #71568 - hbina:document_unsafety_slice_sort, r=joshtr…
Manishearth Jun 19, 2020
55479de
Rollup merge of #72709 - LeSeulArtichaut:unsafe-liballoc, r=nikomatsakis
Manishearth Jun 19, 2020
bc773fe
Rollup merge of #73214 - androm3da:hex_inline_asm_00, r=Amanieu
Manishearth Jun 19, 2020
186640a
Rollup merge of #73248 - marmeladema:save-analysis-various-fixes, r=X…
Manishearth Jun 19, 2020
17064da
Rollup merge of #73257 - davidtwco:issue-73249-improper-ctypes-projec…
Manishearth Jun 19, 2020
4910206
Rollup merge of #73261 - estebank:generics-sized, r=nikomatsakis
Manishearth Jun 19, 2020
058971c
Rollup merge of #73300 - crlf0710:crate_level_only_check, r=petrochenkov
Manishearth Jun 19, 2020
b285d68
Rollup merge of #73334 - ayazhafiz:err/num-type-cannot-fit, r=estebank
Manishearth Jun 19, 2020
65c33ed
Rollup merge of #73357 - petrochenkov:tmap, r=davidtwco
Manishearth Jun 19, 2020
687f929
Rollup merge of #73364 - joshtriplett:inline-asm, r=Amanieu
Manishearth Jun 19, 2020
b443a10
Rollup merge of #73382 - Aaron1011:fix/self-receiver-candidates, r=pe…
Manishearth Jun 19, 2020
d2272d4
Rollup merge of #73465 - lzutao:spec-char-tostring, r=sfackler
Manishearth Jun 19, 2020
a88182f
Rollup merge of #73489 - sexxi-goose:init_place_refactor, r=nikomatsakis
Manishearth Jun 19, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 46 additions & 24 deletions src/doc/unstable-book/src/library-features/asm.md
Original file line number Diff line number Diff line change
Expand Up @@ -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);
```
Expand All @@ -82,13 +85,18 @@ and then adding `5` to it.

The example shows a few things:

First we can see that inputs are declared by writing `in` instead of `out`.
First, we can see that `asm!` allows multiple template string arguments; each
one is treated as a separate line of assembly code, as if they were all joined
together with newlines between them. This makes it easy to format assembly
code.

Second, we can see that inputs are declared by writing `in` instead of `out`.

Second one of our operands has a type we haven't seen yet, `const`.
Third, one of our operands has a type we haven't seen yet, `const`.
This tells the compiler to expand this argument to value directly inside the assembly template.
This is only possible for constants and literals.

Third we can see that we can specify an argument number, or name as in any format string.
Fourth, we can see that we can specify an argument number, or name as in any format string.
For inline assembly templates this is particularly useful as arguments are often used more than once.
For more complex inline assembly using this facility is generally recommended, as it improves
readability, and allows reordering instructions without changing the argument order.
Expand Down Expand Up @@ -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);
```
Expand Down Expand Up @@ -233,7 +244,7 @@ unsafe {
// ECX 0 selects the L0 cache information.
inout("ecx") 0 => ecx,
lateout("ebx") ebx,
lateout("edx") _
lateout("edx") _,
);
}

Expand All @@ -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);
```
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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.
>
Expand Down Expand Up @@ -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).

Expand Down Expand Up @@ -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). |
Expand All @@ -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

Expand Down Expand Up @@ -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.
Expand Down
45 changes: 28 additions & 17 deletions src/liballoc/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.
Expand All @@ -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.
Expand Down Expand Up @@ -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")]
Expand All @@ -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) }
}
}

Expand All @@ -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)
}
}
Expand All @@ -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 })
}
}
Expand All @@ -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),
Expand All @@ -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.
Expand Down
6 changes: 3 additions & 3 deletions src/liballoc/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) }
}
}

Expand Down Expand Up @@ -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]) }
}
}

Expand Down Expand Up @@ -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.
Expand Down
12 changes: 7 additions & 5 deletions src/liballoc/collections/binary_heap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
}

Expand All @@ -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
Expand All @@ -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;
}
}
Expand Down
Loading