Skip to content
This repository was archived by the owner on Oct 31, 2025. It is now read-only.

Commit 34dffa0

Browse files
committed
inline asm!: ban OpReturn/OpReturnValue (they're always UB).
1 parent ee3e420 commit 34dffa0

File tree

5 files changed

+114
-5
lines changed

5 files changed

+114
-5
lines changed

crates/rustc_codegen_spirv/src/builder/spirv_asm.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ impl<'a, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'tcx> {
163163
(false, AsmBlock::Open) => (),
164164
(false, AsmBlock::End(terminator)) => {
165165
self.err(&format!(
166-
"trailing terminator {terminator:?} requires `options(noreturn)`"
166+
"trailing terminator `Op{terminator:?}` requires `options(noreturn)`"
167167
));
168168
}
169169
}
@@ -356,6 +356,19 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> {
356356
}
357357

358358
op => {
359+
// NOTE(eddyb) allowing the instruction to be added below avoids
360+
// spurious "`noreturn` requires a terminator at the end" errors.
361+
if let Op::Return | Op::ReturnValue = op {
362+
self.struct_err(&format!(
363+
"using `Op{op:?}` to return from within `asm!` is disallowed"
364+
))
365+
.note(
366+
"resuming execution, without falling through the end \
367+
of the `asm!` block, is always undefined behavior",
368+
)
369+
.emit();
370+
}
371+
359372
self.emit()
360373
.insert_into_block(dr::InsertPoint::End, inst)
361374
.unwrap();
@@ -370,7 +383,9 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> {
370383
}
371384
AsmBlock::End(terminator) => {
372385
if op != Op::Label {
373-
self.err(&format!("expected OpLabel after terminator {terminator:?}"));
386+
self.err(&format!(
387+
"expected `OpLabel` after terminator `Op{terminator:?}`"
388+
));
374389
}
375390

376391
AsmBlock::Open

tests/ui/lang/asm/block_tracking_fail.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ error: `noreturn` requires a terminator at the end
44
11 | asm!("", options(noreturn));
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
66

7-
error: trailing terminator Unreachable requires `options(noreturn)`
7+
error: trailing terminator `OpUnreachable` requires `options(noreturn)`
88
--> $DIR/block_tracking_fail.rs:18:9
99
|
1010
18 | asm!("OpUnreachable");
1111
| ^^^^^^^^^^^^^^^^^^^^^
1212

13-
error: expected OpLabel after terminator Kill
13+
error: expected `OpLabel` after terminator `OpKill`
1414
--> $DIR/block_tracking_fail.rs:25:9
1515
|
1616
25 | / asm!(

tests/ui/lang/asm/block_tracking_pass.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use spirv_std::spirv;
88
fn asm_label() {
99
unsafe {
1010
asm!(
11-
"OpReturn", // close active block
11+
"OpKill", // close active block
1212
"%unused = OpLabel", // open new block
1313
);
1414
}

tests/ui/lang/asm/issue-1002.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Tests that we don't allow returning from `asm!` (which would always be UB).
2+
// build-fail
3+
4+
use core::arch::asm;
5+
use spirv_std::spirv;
6+
7+
fn asm_return() {
8+
unsafe {
9+
asm!("OpReturn", options(noreturn));
10+
}
11+
}
12+
13+
fn asm_return_value(x: u32) -> u32 {
14+
unsafe {
15+
asm!(
16+
"OpReturnValue {x}",
17+
x = in(reg) x,
18+
options(noreturn),
19+
);
20+
}
21+
}
22+
23+
fn asm_return_label() {
24+
unsafe {
25+
asm!(
26+
"OpReturn", // close active block
27+
"%unused = OpLabel", // open new block
28+
);
29+
}
30+
}
31+
32+
fn asm_return_value_label(x: u32) -> u32 {
33+
unsafe {
34+
asm!(
35+
"OpReturnValue {x}", // close active block
36+
"%unused = OpLabel", // open new block
37+
x = in(reg) x
38+
);
39+
}
40+
0
41+
}
42+
43+
#[spirv(fragment)]
44+
pub fn main() {
45+
asm_return();
46+
asm_return_value(123);
47+
asm_return_label();
48+
asm_return_value_label(123);
49+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
error: using `OpReturn` to return from within `asm!` is disallowed
2+
--> $DIR/issue-1002.rs:9:9
3+
|
4+
9 | asm!("OpReturn", options(noreturn));
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: resuming execution, without falling through the end of the `asm!` block, is always undefined behavior
8+
9+
error: using `OpReturnValue` to return from within `asm!` is disallowed
10+
--> $DIR/issue-1002.rs:15:9
11+
|
12+
15 | / asm!(
13+
16 | | "OpReturnValue {x}",
14+
17 | | x = in(reg) x,
15+
18 | | options(noreturn),
16+
19 | | );
17+
| |_________^
18+
|
19+
= note: resuming execution, without falling through the end of the `asm!` block, is always undefined behavior
20+
21+
error: using `OpReturn` to return from within `asm!` is disallowed
22+
--> $DIR/issue-1002.rs:25:9
23+
|
24+
25 | / asm!(
25+
26 | | "OpReturn", // close active block
26+
27 | | "%unused = OpLabel", // open new block
27+
28 | | );
28+
| |_________^
29+
|
30+
= note: resuming execution, without falling through the end of the `asm!` block, is always undefined behavior
31+
32+
error: using `OpReturnValue` to return from within `asm!` is disallowed
33+
--> $DIR/issue-1002.rs:34:9
34+
|
35+
34 | / asm!(
36+
35 | | "OpReturnValue {x}", // close active block
37+
36 | | "%unused = OpLabel", // open new block
38+
37 | | x = in(reg) x
39+
38 | | );
40+
| |_________^
41+
|
42+
= note: resuming execution, without falling through the end of the `asm!` block, is always undefined behavior
43+
44+
error: aborting due to 4 previous errors
45+

0 commit comments

Comments
 (0)