Skip to content

Commit 643300c

Browse files
committed
Add tests for asm goto
1 parent 33e65a4 commit 643300c

10 files changed

+269
-21
lines changed

tests/codegen/asm-goto.rs

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// compile-flags: -O
2+
// only-x86_64
3+
4+
#![crate_type = "rlib"]
5+
#![feature(asm_goto)]
6+
7+
use std::arch::asm;
8+
9+
#[no_mangle]
10+
pub extern "C" fn panicky() {}
11+
12+
struct Foo;
13+
14+
impl Drop for Foo {
15+
fn drop(&mut self) {
16+
println!();
17+
}
18+
}
19+
20+
// CHECK-LABEL: @asm_goto
21+
#[no_mangle]
22+
pub unsafe fn asm_goto() {
23+
// CHECK: callbr void asm sideeffect alignstack inteldialect "
24+
// CHECK-NEXT: to label %[[FALLTHROUGHBB:[a-b0-9]+]] [label %[[JUMPBB:[a-b0-9]+]]]
25+
asm!("jmp {}", label {});
26+
}
27+
28+
// CHECK-LABEL: @asm_goto_with_outputs
29+
#[no_mangle]
30+
pub unsafe fn asm_goto_with_outputs() -> u64 {
31+
let out: u64;
32+
// CHECK: [[RES:%[0-9]+]] = callbr i64 asm sideeffect alignstack inteldialect "
33+
// CHECK-NEXT: to label %[[FALLTHROUGHBB:[a-b0-9]+]] [label %[[JUMPBB:[a-b0-9]+]]]
34+
asm!("{} /* {} */", out(reg) out, label { return 1; });
35+
// CHECK: [[JUMPBB]]:
36+
// CHECK-NEXT: [[RET:%.+]] = phi i64 [ [[RES]], %[[FALLTHROUGHBB]] ], [ 1, %start ]
37+
// CHECK-NEXT: ret i64 [[RET]]
38+
out
39+
}
40+
41+
// CHECK-LABEL: @asm_goto_noreturn
42+
#[no_mangle]
43+
pub unsafe fn asm_goto_noreturn() -> u64 {
44+
let out: u64;
45+
// CHECK: callbr void asm sideeffect alignstack inteldialect "
46+
// CHECK-NEXT: to label %unreachable [label %[[JUMPBB:[a-b0-9]+]]]
47+
asm!("jmp {}", label { return 1; }, options(noreturn));
48+
// CHECK: [[JUMPBB]]:
49+
// CHECK-NEXT: ret i64 1
50+
out
51+
}

tests/ui/asm/parse-error.rs

+2
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,5 @@ global_asm!(format!("{{{}}}", 0), const FOO);
142142
//~^ ERROR asm template must be a string literal
143143
global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
144144
//~^ ERROR asm template must be a string literal
145+
global_asm!("{}", label {});
146+
//~^ ERROR expected operand, options, or additional template string

tests/ui/asm/parse-error.stderr

+11-5
Original file line numberDiff line numberDiff line change
@@ -176,17 +176,17 @@ LL | asm!("{a}", a = const foo, a = const bar);
176176
|
177177
= help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
178178

179-
error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""`
179+
error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `label`, `lateout`, `options`, `out`, or `sym`, found `""`
180180
--> $DIR/parse-error.rs:82:29
181181
|
182182
LL | asm!("", options(), "");
183-
| ^^ expected one of 9 possible tokens
183+
| ^^ expected one of 10 possible tokens
184184

185-
error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"`
185+
error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `label`, `lateout`, `options`, `out`, or `sym`, found `"{}"`
186186
--> $DIR/parse-error.rs:84:33
187187
|
188188
LL | asm!("{}", in(reg) foo, "{}", out(reg) foo);
189-
| ^^^^ expected one of 9 possible tokens
189+
| ^^^^ expected one of 10 possible tokens
190190

191191
error: asm template must be a string literal
192192
--> $DIR/parse-error.rs:86:14
@@ -362,6 +362,12 @@ LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
362362
|
363363
= note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
364364

365+
error: expected operand, options, or additional template string
366+
--> $DIR/parse-error.rs:145:19
367+
|
368+
LL | global_asm!("{}", label {});
369+
| ^^^^^^^^ expected operand, options, or additional template string
370+
365371
error[E0435]: attempt to use a non-constant value in a constant
366372
--> $DIR/parse-error.rs:39:37
367373
|
@@ -407,6 +413,6 @@ LL | let mut bar = 0;
407413
LL | asm!("{a}", a = const foo, a = const bar);
408414
| ^^^ non-constant value
409415

410-
error: aborting due to 63 previous errors
416+
error: aborting due to 64 previous errors
411417

412418
For more information about this error, try `rustc --explain E0435`.

tests/ui/asm/x86_64/bad-options.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// only-x86_64
22

3+
#![feature(asm_unwind, asm_goto)]
4+
35
use std::arch::{asm, global_asm};
46

57
fn main() {
@@ -14,6 +16,8 @@ fn main() {
1416
//~^ ERROR asm with the `pure` option must have at least one output
1517
asm!("{}", out(reg) foo, options(noreturn));
1618
//~^ ERROR asm outputs are not allowed with the `noreturn` option
19+
asm!("{}", label {}, options(may_unwind));
20+
//~^ ERROR asm labels are not allowed with the `may_unwind` option
1721
}
1822

1923
unsafe {
+22-16
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,49 @@
11
error: the `nomem` and `readonly` options are mutually exclusive
2-
--> $DIR/bad-options.rs:8:18
2+
--> $DIR/bad-options.rs:10:18
33
|
44
LL | asm!("", options(nomem, readonly));
55
| ^^^^^^^^^^^^^^^^^^^^^^^^
66

77
error: the `pure` and `noreturn` options are mutually exclusive
8-
--> $DIR/bad-options.rs:10:18
8+
--> $DIR/bad-options.rs:12:18
99
|
1010
LL | asm!("", options(pure, nomem, noreturn));
1111
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1212

1313
error: asm with the `pure` option must have at least one output
14-
--> $DIR/bad-options.rs:10:18
14+
--> $DIR/bad-options.rs:12:18
1515
|
1616
LL | asm!("", options(pure, nomem, noreturn));
1717
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1818

1919
error: asm with the `pure` option must have at least one output
20-
--> $DIR/bad-options.rs:13:33
20+
--> $DIR/bad-options.rs:15:33
2121
|
2222
LL | asm!("{}", in(reg) foo, options(pure, nomem));
2323
| ^^^^^^^^^^^^^^^^^^^^
2424

2525
error: asm outputs are not allowed with the `noreturn` option
26-
--> $DIR/bad-options.rs:15:20
26+
--> $DIR/bad-options.rs:17:20
2727
|
2828
LL | asm!("{}", out(reg) foo, options(noreturn));
2929
| ^^^^^^^^^^^^
3030

31+
error: asm labels are not allowed with the `may_unwind` option
32+
--> $DIR/bad-options.rs:19:20
33+
|
34+
LL | asm!("{}", label {}, options(may_unwind));
35+
| ^^^^^^^^
36+
3137
error: asm with `clobber_abi` must specify explicit registers for outputs
32-
--> $DIR/bad-options.rs:22:20
38+
--> $DIR/bad-options.rs:26:20
3339
|
3440
LL | asm!("{}", out(reg) foo, clobber_abi("C"));
3541
| ^^^^^^^^^^^^ ---------------- clobber_abi
3642
| |
3743
| generic outputs
3844

3945
error: asm with `clobber_abi` must specify explicit registers for outputs
40-
--> $DIR/bad-options.rs:24:20
46+
--> $DIR/bad-options.rs:28:20
4147
|
4248
LL | asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C"));
4349
| ^^^^^^^^^^^^ ---------------- ---------------- clobber_abi
@@ -46,56 +52,56 @@ LL | asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C"));
4652
| generic outputs
4753

4854
error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
49-
--> $DIR/bad-options.rs:31:25
55+
--> $DIR/bad-options.rs:35:25
5056
|
5157
LL | global_asm!("", options(nomem));
5258
| ^^^^^ expected one of `)`, `att_syntax`, or `raw`
5359

5460
error: expected one of `)`, `att_syntax`, or `raw`, found `readonly`
55-
--> $DIR/bad-options.rs:33:25
61+
--> $DIR/bad-options.rs:37:25
5662
|
5763
LL | global_asm!("", options(readonly));
5864
| ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
5965

6066
error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn`
61-
--> $DIR/bad-options.rs:35:25
67+
--> $DIR/bad-options.rs:39:25
6268
|
6369
LL | global_asm!("", options(noreturn));
6470
| ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
6571

6672
error: expected one of `)`, `att_syntax`, or `raw`, found `pure`
67-
--> $DIR/bad-options.rs:37:25
73+
--> $DIR/bad-options.rs:41:25
6874
|
6975
LL | global_asm!("", options(pure));
7076
| ^^^^ expected one of `)`, `att_syntax`, or `raw`
7177

7278
error: expected one of `)`, `att_syntax`, or `raw`, found `nostack`
73-
--> $DIR/bad-options.rs:39:25
79+
--> $DIR/bad-options.rs:43:25
7480
|
7581
LL | global_asm!("", options(nostack));
7682
| ^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
7783

7884
error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags`
79-
--> $DIR/bad-options.rs:41:25
85+
--> $DIR/bad-options.rs:45:25
8086
|
8187
LL | global_asm!("", options(preserves_flags));
8288
| ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
8389

8490
error: invalid ABI for `clobber_abi`
85-
--> $DIR/bad-options.rs:20:18
91+
--> $DIR/bad-options.rs:24:18
8692
|
8793
LL | asm!("", clobber_abi("foo"));
8894
| ^^^^^^^^^^^^^^^^^^
8995
|
9096
= note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64`
9197

9298
error: `C` ABI specified multiple times
93-
--> $DIR/bad-options.rs:24:52
99+
--> $DIR/bad-options.rs:28:52
94100
|
95101
LL | asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C"));
96102
| ---------------- ^^^^^^^^^^^^^^^^
97103
| |
98104
| previously specified here
99105

100-
error: aborting due to 15 previous errors
106+
error: aborting due to 16 previous errors
101107

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
warning: unreachable statement
2+
--> $DIR/goto.rs:99:9
3+
|
4+
LL | / asm!(
5+
LL | | "jmp {}",
6+
LL | | label {
7+
LL | | return;
8+
LL | | },
9+
LL | | options(noreturn)
10+
LL | | );
11+
| |_________- any code following this expression is unreachable
12+
LL | unreachable!();
13+
| ^^^^^^^^^^^^^^ unreachable statement
14+
|
15+
note: the lint level is defined here
16+
--> $DIR/goto.rs:89:8
17+
|
18+
LL | #[warn(unreachable_code)]
19+
| ^^^^^^^^^^^^^^^^
20+
= note: this warning originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info)
21+
22+
warning: 1 warning emitted
23+

tests/ui/asm/x86_64/goto.rs

+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// only-x86_64
2+
// run-pass
3+
// needs-asm-support
4+
// revisions: mirunsafeck thirunsafeck
5+
// [thirunsafeck]compile-flags: -Z thir-unsafeck
6+
7+
#![deny(unreachable_code)]
8+
#![feature(asm_goto)]
9+
10+
use std::arch::asm;
11+
12+
fn goto_fallthough() {
13+
unsafe {
14+
asm!(
15+
"/* {} */",
16+
label {
17+
unreachable!();
18+
}
19+
)
20+
}
21+
}
22+
23+
fn goto_jump() {
24+
unsafe {
25+
let mut value = false;
26+
asm!(
27+
"jmp {}",
28+
label {
29+
value = true;
30+
}
31+
);
32+
assert!(value);
33+
}
34+
}
35+
36+
// asm goto with outputs cause miscompilation in LLVM. UB can be triggered
37+
// when outputs are used inside the label block when optimisation is enabled.
38+
// See: https://github.com/llvm/llvm-project/issues/74483
39+
/*
40+
fn goto_out_fallthrough() {
41+
unsafe {
42+
let mut out: usize;
43+
asm!(
44+
"lea {}, [{} + 1]",
45+
"/* {} */",
46+
out(reg) out,
47+
in(reg) 0x12345678usize,
48+
label {
49+
unreachable!();
50+
}
51+
);
52+
assert_eq!(out, 0x12345679);
53+
}
54+
}
55+
56+
fn goto_out_jump() {
57+
unsafe {
58+
let mut value = false;
59+
let mut out: usize;
60+
asm!(
61+
"lea {}, [{} + 1]",
62+
"jmp {}",
63+
out(reg) out,
64+
in(reg) 0x12345678usize,
65+
label {
66+
value = true;
67+
assert_eq!(out, 0x12345679);
68+
}
69+
);
70+
assert!(value);
71+
}
72+
}
73+
*/
74+
75+
fn goto_noreturn() {
76+
unsafe {
77+
let a;
78+
asm!(
79+
"jmp {}",
80+
label {
81+
a = 1;
82+
},
83+
options(noreturn)
84+
);
85+
assert_eq!(a, 1);
86+
}
87+
}
88+
89+
#[warn(unreachable_code)]
90+
fn goto_noreturn_diverge() {
91+
unsafe {
92+
asm!(
93+
"jmp {}",
94+
label {
95+
return;
96+
},
97+
options(noreturn)
98+
);
99+
unreachable!();
100+
//~^ WARN unreachable statement
101+
}
102+
}
103+
104+
fn main() {
105+
goto_fallthough();
106+
goto_jump();
107+
// goto_out_fallthrough();
108+
// goto_out_jump();
109+
goto_noreturn();
110+
goto_noreturn_diverge();
111+
}

0 commit comments

Comments
 (0)