Skip to content

Commit 34c5cd9

Browse files
committed
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
2 parents 2d8bd9b + a88182f commit 34c5cd9

File tree

87 files changed

+2503
-803
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+2503
-803
lines changed

src/doc/unstable-book/src/library-features/asm.md

+46-24
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,13 @@ Let us see another example that also uses an input:
6868
let i: u64 = 3;
6969
let o: u64;
7070
unsafe {
71-
asm!("
72-
mov {0}, {1}
73-
add {0}, {number}
74-
", out(reg) o, in(reg) i, number = const 5);
71+
asm!(
72+
"mov {0}, {1}",
73+
"add {0}, {number}",
74+
out(reg) o,
75+
in(reg) i,
76+
number = const 5,
77+
);
7578
}
7679
assert_eq!(o, 8);
7780
```
@@ -82,13 +85,18 @@ and then adding `5` to it.
8285

8386
The example shows a few things:
8487

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

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

91-
Third we can see that we can specify an argument number, or name as in any format string.
99+
Fourth, we can see that we can specify an argument number, or name as in any format string.
92100
For inline assembly templates this is particularly useful as arguments are often used more than once.
93101
For more complex inline assembly using this facility is generally recommended, as it improves
94102
readability, and allows reordering instructions without changing the argument order.
@@ -137,10 +145,13 @@ let mut a: u64 = 4;
137145
let b: u64 = 4;
138146
let c: u64 = 4;
139147
unsafe {
140-
asm!("
141-
add {0}, {1}
142-
add {0}, {2}
143-
", inout(reg) a, in(reg) b, in(reg) c);
148+
asm!(
149+
"add {0}, {1}",
150+
"add {0}, {2}",
151+
inout(reg) a,
152+
in(reg) b,
153+
in(reg) c,
154+
);
144155
}
145156
assert_eq!(a, 12);
146157
```
@@ -233,7 +244,7 @@ unsafe {
233244
// ECX 0 selects the L0 cache information.
234245
inout("ecx") 0 => ecx,
235246
lateout("ebx") ebx,
236-
lateout("edx") _
247+
lateout("edx") _,
237248
);
238249
}
239250
@@ -255,12 +266,14 @@ This can also be used with a general register class (e.g. `reg`) to obtain a scr
255266
// Multiply x by 6 using shifts and adds
256267
let mut x: u64 = 4;
257268
unsafe {
258-
asm!("
259-
mov {tmp}, {x}
260-
shl {tmp}, 1
261-
shl {x}, 2
262-
add {x}, {tmp}
263-
", x = inout(reg) x, tmp = out(reg) _);
269+
asm!(
270+
"mov {tmp}, {x}",
271+
"shl {tmp}, 1",
272+
"shl {x}, 2",
273+
"add {x}, {tmp}",
274+
x = inout(reg) x,
275+
tmp = out(reg) _,
276+
);
264277
}
265278
assert_eq!(x, 4 * 6);
266279
```
@@ -338,7 +351,7 @@ unsafe {
338351
asm!(
339352
"add {0}, {1}",
340353
inlateout(reg) a, in(reg) b,
341-
options(pure, nomem, nostack)
354+
options(pure, nomem, nostack),
342355
);
343356
}
344357
assert_eq!(a, 8);
@@ -371,24 +384,26 @@ reg_operand := dir_spec "(" reg_spec ")" operand_expr
371384
operand := reg_operand / "const" const_expr / "sym" path
372385
option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "att_syntax"
373386
options := "options(" option *["," option] [","] ")"
374-
asm := "asm!(" format_string *("," [ident "="] operand) ["," options] [","] ")"
387+
asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) ["," options] [","] ")"
375388
```
376389

377-
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.
390+
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.
378391

379392
[format-syntax]: https://doc.rust-lang.org/std/fmt/#syntax
380393

381-
## Template string
394+
## Template string arguments
382395

383396
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.
384397

398+
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.
399+
385400
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.
386401

387402
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.
388403

389404
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.
390405

391-
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.
406+
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.
392407

393408
[rfc-2795]: https://github.com/rust-lang/rfcs/pull/2795
394409

@@ -475,6 +490,7 @@ Here is the list of currently supported register classes:
475490
| NVPTX | `reg64` | None\* | `l` |
476491
| RISC-V | `reg` | `x1`, `x[5-7]`, `x[9-15]`, `x[16-31]` (non-RV32E) | `r` |
477492
| RISC-V | `freg` | `f[0-31]` | `f` |
493+
| Hexagon | `reg` | `r[0-28]` | `r` |
478494

479495
> **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.
480496
>
@@ -509,6 +525,7 @@ Each register class has constraints on which value types they can be used with.
509525
| RISC-V64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
510526
| RISC-V | `freg` | `f` | `f32` |
511527
| RISC-V | `freg` | `d` | `f64` |
528+
| Hexagon | `reg` | None | `i8`, `i16`, `i32`, `f32` |
512529

513530
> **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).
514531
@@ -565,13 +582,16 @@ Some registers have multiple names. These are all treated by the compiler as ide
565582
| RISC-V | `f[10-17]` | `fa[0-7]` |
566583
| RISC-V | `f[18-27]` | `fs[2-11]` |
567584
| RISC-V | `f[28-31]` | `ft[8-11]` |
585+
| Hexagon | `r29` | `sp` |
586+
| Hexagon | `r30` | `fr` |
587+
| Hexagon | `r31` | `lr` |
568588

569589
Some registers cannot be used for input or output operands:
570590

571591
| Architecture | Unsupported register | Reason |
572592
| ------------ | -------------------- | ------ |
573593
| All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. |
574-
| All | `bp` (x86), `r11` (ARM), `x29` (AArch64), `x8` (RISC-V) | The frame pointer cannot be used as an input or output. |
594+
| All | `bp` (x86), `r11` (ARM), `x29` (AArch64), `x8` (RISC-V), `fr` (Hexagon) | The frame pointer cannot be used as an input or output. |
575595
| x86 | `k0` | This is a constant zero register which can't be modified. |
576596
| x86 | `ip` | This is the program counter, not a real register. |
577597
| 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:
580600
| ARM | `pc` | This is the program counter, not a real register. |
581601
| RISC-V | `x0` | This is a constant zero register which can't be modified. |
582602
| RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. |
603+
| Hexagon | `lr` | This is the link register which cannot be used as an input or output. |
583604

584605
## Template modifiers
585606

@@ -625,6 +646,7 @@ The supported modifiers are a subset of LLVM's (and GCC's) [asm template argumen
625646
| NVPTX | `reg64` | None | `rd0` | None |
626647
| RISC-V | `reg` | None | `x1` | None |
627648
| RISC-V | `freg` | None | `f0` | None |
649+
| Hexagon | `reg` | None | `r0` | None |
628650

629651
> Notes:
630652
> - on ARM `e` / `f`: this prints the low or high doubleword register name of a NEON quad (128-bit) register.

src/liballoc/alloc.rs

+28-17
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ pub struct Global;
7777
#[stable(feature = "global_alloc", since = "1.28.0")]
7878
#[inline]
7979
pub unsafe fn alloc(layout: Layout) -> *mut u8 {
80-
__rust_alloc(layout.size(), layout.align())
80+
unsafe { __rust_alloc(layout.size(), layout.align()) }
8181
}
8282

8383
/// Deallocate memory with the global allocator.
@@ -99,7 +99,7 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 {
9999
#[stable(feature = "global_alloc", since = "1.28.0")]
100100
#[inline]
101101
pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) {
102-
__rust_dealloc(ptr, layout.size(), layout.align())
102+
unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
103103
}
104104

105105
/// Reallocate memory with the global allocator.
@@ -121,7 +121,7 @@ pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) {
121121
#[stable(feature = "global_alloc", since = "1.28.0")]
122122
#[inline]
123123
pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
124-
__rust_realloc(ptr, layout.size(), layout.align(), new_size)
124+
unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) }
125125
}
126126

127127
/// 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
158158
#[stable(feature = "global_alloc", since = "1.28.0")]
159159
#[inline]
160160
pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
161-
__rust_alloc_zeroed(layout.size(), layout.align())
161+
unsafe { __rust_alloc_zeroed(layout.size(), layout.align()) }
162162
}
163163

164164
#[unstable(feature = "allocator_api", issue = "32838")]
@@ -183,7 +183,7 @@ unsafe impl AllocRef for Global {
183183
#[inline]
184184
unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
185185
if layout.size() != 0 {
186-
dealloc(ptr.as_ptr(), layout)
186+
unsafe { dealloc(ptr.as_ptr(), layout) }
187187
}
188188
}
189189

@@ -209,16 +209,21 @@ unsafe impl AllocRef for Global {
209209
match placement {
210210
ReallocPlacement::InPlace => Err(AllocErr),
211211
ReallocPlacement::MayMove if layout.size() == 0 => {
212-
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
212+
let new_layout =
213+
unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
213214
self.alloc(new_layout, init)
214215
}
215216
ReallocPlacement::MayMove => {
216217
// `realloc` probably checks for `new_size > size` or something similar.
217-
intrinsics::assume(new_size > size);
218-
let ptr = realloc(ptr.as_ptr(), layout, new_size);
218+
let ptr = unsafe {
219+
intrinsics::assume(new_size > size);
220+
realloc(ptr.as_ptr(), layout, new_size)
221+
};
219222
let memory =
220223
MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size };
221-
init.init_offset(memory, size);
224+
unsafe {
225+
init.init_offset(memory, size);
226+
}
222227
Ok(memory)
223228
}
224229
}
@@ -245,13 +250,17 @@ unsafe impl AllocRef for Global {
245250
match placement {
246251
ReallocPlacement::InPlace => Err(AllocErr),
247252
ReallocPlacement::MayMove if new_size == 0 => {
248-
self.dealloc(ptr, layout);
253+
unsafe {
254+
self.dealloc(ptr, layout);
255+
}
249256
Ok(MemoryBlock { ptr: layout.dangling(), size: 0 })
250257
}
251258
ReallocPlacement::MayMove => {
252259
// `realloc` probably checks for `new_size < size` or something similar.
253-
intrinsics::assume(new_size < size);
254-
let ptr = realloc(ptr.as_ptr(), layout, new_size);
260+
let ptr = unsafe {
261+
intrinsics::assume(new_size < size);
262+
realloc(ptr.as_ptr(), layout, new_size)
263+
};
255264
Ok(MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size })
256265
}
257266
}
@@ -264,7 +273,7 @@ unsafe impl AllocRef for Global {
264273
#[lang = "exchange_malloc"]
265274
#[inline]
266275
unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
267-
let layout = Layout::from_size_align_unchecked(size, align);
276+
let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
268277
match Global.alloc(layout, AllocInit::Uninitialized) {
269278
Ok(memory) => memory.ptr.as_ptr(),
270279
Err(_) => handle_alloc_error(layout),
@@ -279,10 +288,12 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
279288
// For example if `Box` is changed to `struct Box<T: ?Sized, A: AllocRef>(Unique<T>, A)`,
280289
// this function has to be changed to `fn box_free<T: ?Sized, A: AllocRef>(Unique<T>, A)` as well.
281290
pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
282-
let size = size_of_val(ptr.as_ref());
283-
let align = min_align_of_val(ptr.as_ref());
284-
let layout = Layout::from_size_align_unchecked(size, align);
285-
Global.dealloc(ptr.cast().into(), layout)
291+
unsafe {
292+
let size = size_of_val(ptr.as_ref());
293+
let align = min_align_of_val(ptr.as_ref());
294+
let layout = Layout::from_size_align_unchecked(size, align);
295+
Global.dealloc(ptr.cast().into(), layout)
296+
}
286297
}
287298

288299
/// Abort on memory allocation error or failure.

src/liballoc/boxed.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ impl<T> Box<mem::MaybeUninit<T>> {
311311
#[unstable(feature = "new_uninit", issue = "63291")]
312312
#[inline]
313313
pub unsafe fn assume_init(self) -> Box<T> {
314-
Box::from_raw(Box::into_raw(self) as *mut T)
314+
unsafe { Box::from_raw(Box::into_raw(self) as *mut T) }
315315
}
316316
}
317317

@@ -349,7 +349,7 @@ impl<T> Box<[mem::MaybeUninit<T>]> {
349349
#[unstable(feature = "new_uninit", issue = "63291")]
350350
#[inline]
351351
pub unsafe fn assume_init(self) -> Box<[T]> {
352-
Box::from_raw(Box::into_raw(self) as *mut [T])
352+
unsafe { Box::from_raw(Box::into_raw(self) as *mut [T]) }
353353
}
354354
}
355355

@@ -393,7 +393,7 @@ impl<T: ?Sized> Box<T> {
393393
#[stable(feature = "box_raw", since = "1.4.0")]
394394
#[inline]
395395
pub unsafe fn from_raw(raw: *mut T) -> Self {
396-
Box(Unique::new_unchecked(raw))
396+
Box(unsafe { Unique::new_unchecked(raw) })
397397
}
398398

399399
/// Consumes the `Box`, returning a wrapped raw pointer.

src/liballoc/collections/binary_heap.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -1003,7 +1003,7 @@ impl<'a, T> Hole<'a, T> {
10031003
unsafe fn new(data: &'a mut [T], pos: usize) -> Self {
10041004
debug_assert!(pos < data.len());
10051005
// SAFE: pos should be inside the slice
1006-
let elt = ptr::read(data.get_unchecked(pos));
1006+
let elt = unsafe { ptr::read(data.get_unchecked(pos)) };
10071007
Hole { data, elt: ManuallyDrop::new(elt), pos }
10081008
}
10091009

@@ -1025,7 +1025,7 @@ impl<'a, T> Hole<'a, T> {
10251025
unsafe fn get(&self, index: usize) -> &T {
10261026
debug_assert!(index != self.pos);
10271027
debug_assert!(index < self.data.len());
1028-
self.data.get_unchecked(index)
1028+
unsafe { self.data.get_unchecked(index) }
10291029
}
10301030

10311031
/// Move hole to new location
@@ -1035,9 +1035,11 @@ impl<'a, T> Hole<'a, T> {
10351035
unsafe fn move_to(&mut self, index: usize) {
10361036
debug_assert!(index != self.pos);
10371037
debug_assert!(index < self.data.len());
1038-
let index_ptr: *const _ = self.data.get_unchecked(index);
1039-
let hole_ptr = self.data.get_unchecked_mut(self.pos);
1040-
ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1);
1038+
unsafe {
1039+
let index_ptr: *const _ = self.data.get_unchecked(index);
1040+
let hole_ptr = self.data.get_unchecked_mut(self.pos);
1041+
ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1);
1042+
}
10411043
self.pos = index;
10421044
}
10431045
}

0 commit comments

Comments
 (0)